1/** @file
2  The implementation of Payloads Creation.
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#include "IpSecCryptIo.h"
21
22//
23// The Constant String of "Key Pad for IKEv2" for Authentication Payload generation.
24//
25#define CONSTANT_KEY_SIZE     17
26GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mConstantKey[CONSTANT_KEY_SIZE] =
27{
28  'K', 'e', 'y', ' ', 'P', 'a', 'd', ' ', 'f', 'o', 'r', ' ', 'I', 'K', 'E', 'v', '2'
29};
30
31/**
32  Generate Ikev2 SA payload according to SessionSaData
33
34  @param[in] SessionSaData   The data used in SA payload.
35  @param[in] NextPayload     The payload type presented in NextPayload field of
36                             SA Payload header.
37  @param[in] Type            The SA type. It MUST be neither (1) for IKE_SA or
38                             (2) for CHILD_SA or (3) for INFO.
39
40  @retval a Pointer to SA IKE payload.
41
42**/
43IKE_PAYLOAD *
44Ikev2GenerateSaPayload (
45  IN IKEV2_SA_DATA    *SessionSaData,
46  IN UINT8            NextPayload,
47  IN IKE_SESSION_TYPE Type
48  )
49{
50  IKE_PAYLOAD   *SaPayload;
51  IKEV2_SA_DATA *SaData;
52  UINTN         SaDataSize;
53
54  SaPayload = IkePayloadAlloc ();
55  if (SaPayload == NULL) {
56    return NULL;
57  }
58
59  //
60  // TODO: Get the Proposal Number and Transform Number from IPsec Config,
61  // after the Ipsecconfig Application is support it.
62  //
63
64  if (Type == IkeSessionTypeIkeSa) {
65    SaDataSize = sizeof (IKEV2_SA_DATA) +
66                 SessionSaData->NumProposals * sizeof (IKEV2_PROPOSAL_DATA) +
67                 sizeof (IKEV2_TRANSFORM_DATA) * SessionSaData->NumProposals * 4;
68  } else {
69    SaDataSize = sizeof (IKEV2_SA_DATA) +
70                 SessionSaData->NumProposals * sizeof (IKEV2_PROPOSAL_DATA) +
71                 sizeof (IKEV2_TRANSFORM_DATA) * SessionSaData->NumProposals * 3;
72
73  }
74
75  SaData = AllocateZeroPool (SaDataSize);
76  if (SaData == NULL) {
77    IkePayloadFree (SaPayload);
78    return NULL;
79  }
80
81  CopyMem (SaData, SessionSaData, SaDataSize);
82  SaData->SaHeader.Header.NextPayload = NextPayload;
83  SaPayload->PayloadType              = IKEV2_PAYLOAD_TYPE_SA;
84  SaPayload->PayloadBuf               = (UINT8 *) SaData;
85
86  return SaPayload;
87}
88
89/**
90  Generate a Nonce payload containing the input parameter NonceBuf.
91
92  @param[in]  NonceBuf      The nonce buffer contains the whole Nonce payload block
93                            except the payload header.
94  @param[in]  NonceSize     The buffer size of the NonceBuf
95  @param[in]  NextPayload   The payload type presented in the NextPayload field
96                            of Nonce Payload header.
97
98  @retval Pointer to Nonce IKE paload.
99
100**/
101IKE_PAYLOAD *
102Ikev2GenerateNoncePayload (
103  IN UINT8            *NonceBuf,
104  IN UINTN            NonceSize,
105  IN UINT8            NextPayload
106  )
107{
108  IKE_PAYLOAD *NoncePayload;
109  IKEV2_NONCE *Nonce;
110  UINTN       Size;
111  UINT8       *NonceBlock;
112
113  //                           1                   2                   3
114  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
115  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
116  //    ! Next Payload  !C!  RESERVED   !         Payload Length        !
117  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
118  //    !                                                               !
119  //    ~                            Nonce Data                         ~
120  //    !                                                               !
121  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
122  //
123  Size        = sizeof (IKEV2_NONCE) + NonceSize;
124  NonceBlock  = NonceBuf;
125
126  Nonce       = AllocateZeroPool (Size);
127  if (Nonce == NULL) {
128    return NULL;
129  }
130
131  CopyMem (Nonce + 1, NonceBlock, Size - sizeof (IKEV2_NONCE));
132
133  Nonce->Header.NextPayload   = NextPayload;
134  Nonce->Header.PayloadLength = (UINT16) Size;
135  NoncePayload                = IkePayloadAlloc ();
136  if (NoncePayload == NULL) {
137    FreePool (Nonce);
138    return NULL;
139  }
140
141  NoncePayload->PayloadType = IKEV2_PAYLOAD_TYPE_NONCE;
142  NoncePayload->PayloadBuf  = (UINT8 *) Nonce;
143  NoncePayload->PayloadSize = Size;
144
145  return NoncePayload;
146}
147
148/**
149  Generate a Key Exchange payload according to the DH group type and save the
150  public Key into IkeSaSession IkeKey field.
151
152  @param[in, out] IkeSaSession    Pointer of the IKE_SA_SESSION.
153  @param[in]      NextPayload     The payload type presented in the NextPayload field of Key
154                                  Exchange Payload header.
155
156  @retval Pointer to Key IKE payload.
157
158**/
159IKE_PAYLOAD*
160Ikev2GenerateKePayload (
161  IN OUT IKEV2_SA_SESSION *IkeSaSession,
162  IN     UINT8            NextPayload
163  )
164{
165  IKE_PAYLOAD         *KePayload;
166  IKEV2_KEY_EXCHANGE  *Ke;
167  UINTN               KeSize;
168  IKEV2_SESSION_KEYS  *IkeKeys;
169
170  //
171  //                        1                   2                   3
172  //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
173  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
174  //   ! Next Payload  !C!  RESERVED   !         Payload Length        !
175  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
176  //   !          DH Group #           !           RESERVED            !
177  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
178  //   !                                                               !
179  //   ~                       Key Exchange Data                       ~
180  //   !                                                               !
181  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
182  //
183  IkeKeys = IkeSaSession->IkeKeys;
184
185  if (IkeSaSession->SessionCommon.IsInitiator) {
186    KeSize = sizeof (IKEV2_KEY_EXCHANGE) + IkeKeys->DhBuffer->GxSize;
187  } else {
188    KeSize = sizeof (IKEV2_KEY_EXCHANGE) + IkeKeys->DhBuffer->GxSize;
189  }
190
191  //
192  // Allocate buffer for Key Exchange
193  //
194  Ke = AllocateZeroPool (KeSize);
195  if (Ke == NULL) {
196    return NULL;
197  }
198
199  Ke->Header.NextPayload    = NextPayload;
200  Ke->Header.PayloadLength  = (UINT16) KeSize;
201  Ke->DhGroup               = IkeSaSession->SessionCommon.PreferDhGroup;
202
203  CopyMem (Ke + 1, IkeKeys->DhBuffer->GxBuffer, IkeKeys->DhBuffer->GxSize);
204
205  //
206  // Create IKE_PAYLOAD to point to Key Exchange payload
207  //
208  KePayload = IkePayloadAlloc ();
209  if (KePayload == NULL) {
210    FreePool (Ke);
211    return NULL;
212  }
213
214  KePayload->PayloadType = IKEV2_PAYLOAD_TYPE_KE;
215  KePayload->PayloadBuf  = (UINT8 *) Ke;
216  KePayload->PayloadSize = KeSize;
217  return KePayload;
218}
219
220/**
221  Generate a ID payload.
222
223  @param[in] CommonSession   Pointer to IKEV2_SESSION_COMMON related to ID payload.
224  @param[in] NextPayload     The payload type presented in the NextPayload field
225                             of ID Payload header.
226
227  @retval Pointer to ID IKE payload.
228
229**/
230IKE_PAYLOAD *
231Ikev2GenerateIdPayload (
232  IN IKEV2_SESSION_COMMON *CommonSession,
233  IN UINT8                NextPayload
234  )
235{
236  IKE_PAYLOAD    *IdPayload;
237  IKEV2_ID       *Id;
238  UINTN          IdSize;
239  UINT8          IpVersion;
240  UINT8          AddrSize;
241
242  //
243  // ID payload
244  //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
245  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
246  //   ! Next Payload  !   RESERVED    !         Payload Length        !
247  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
248  //   !   ID Type     !             RESERVED                          !
249  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
250  //   !                                                               !
251  //   ~                   Identification Data                         ~
252  //   !                                                               !
253  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
254  //
255
256  IpVersion = CommonSession->UdpService->IpVersion;
257  AddrSize  = (UINT8) ((IpVersion == IP_VERSION_4) ? sizeof(EFI_IPv4_ADDRESS) : sizeof(EFI_IPv6_ADDRESS));
258  IdSize    = sizeof (IKEV2_ID) + AddrSize;
259
260  Id = (IKEV2_ID *) AllocateZeroPool (IdSize);
261  if (Id == NULL) {
262    return NULL;
263  }
264
265  IdPayload = IkePayloadAlloc ();
266  if (IdPayload == NULL) {
267    FreePool (Id);
268    return NULL;
269  }
270
271  IdPayload->PayloadType  = (UINT8) ((CommonSession->IsInitiator) ? IKEV2_PAYLOAD_TYPE_ID_INIT : IKEV2_PAYLOAD_TYPE_ID_RSP);
272  IdPayload->PayloadBuf   = (UINT8 *) Id;
273  IdPayload->PayloadSize  = IdSize;
274
275  //
276  // Set generic header of identification payload
277  //
278  Id->Header.NextPayload    = NextPayload;
279  Id->Header.PayloadLength  = (UINT16) IdSize;
280  Id->IdType                = (UINT8) ((IpVersion == IP_VERSION_4) ? IKEV2_ID_TYPE_IPV4_ADDR : IKEV2_ID_TYPE_IPV6_ADDR);
281  CopyMem (Id + 1, &CommonSession->LocalPeerIp, AddrSize);
282
283  return IdPayload;
284}
285
286/**
287  Generate a ID payload.
288
289  @param[in] CommonSession   Pointer to IKEV2_SESSION_COMMON related to ID payload.
290  @param[in] NextPayload     The payload type presented in the NextPayload field
291                             of ID Payload header.
292  @param[in] InCert          Pointer to the Certificate which distinguished name
293                             will be added into the Id payload.
294  @param[in] CertSize        Size of the Certificate.
295
296  @retval Pointer to ID IKE payload.
297
298**/
299IKE_PAYLOAD *
300Ikev2GenerateCertIdPayload (
301  IN IKEV2_SESSION_COMMON *CommonSession,
302  IN UINT8                NextPayload,
303  IN UINT8                *InCert,
304  IN UINTN                CertSize
305  )
306{
307  IKE_PAYLOAD    *IdPayload;
308  IKEV2_ID       *Id;
309  UINTN          IdSize;
310  UINTN          SubjectSize;
311  UINT8          *CertSubject;
312
313  //
314  // ID payload
315  //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
316  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
317  //   ! Next Payload  !   RESERVED    !         Payload Length        !
318  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
319  //   !   ID Type     !             RESERVED                          !
320  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
321  //   !                                                               !
322  //   ~                   Identification Data                         ~
323  //   !                                                               !
324  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
325  //
326
327  SubjectSize = 0;
328  CertSubject = NULL;
329  IpSecCryptoIoGetSubjectFromCert (
330    InCert,
331    CertSize,
332    &CertSubject,
333    &SubjectSize
334    );
335  if (SubjectSize != 0) {
336    ASSERT (CertSubject != NULL);
337  }
338
339  IdSize = sizeof (IKEV2_ID) + SubjectSize;
340
341  Id = (IKEV2_ID *) AllocateZeroPool (IdSize);
342  if (Id == NULL) {
343    return NULL;
344  }
345
346  IdPayload = IkePayloadAlloc ();
347  if (IdPayload == NULL) {
348    FreePool (Id);
349    return NULL;
350  }
351
352  IdPayload->PayloadType  = (UINT8) ((CommonSession->IsInitiator) ? IKEV2_PAYLOAD_TYPE_ID_INIT : IKEV2_PAYLOAD_TYPE_ID_RSP);
353  IdPayload->PayloadBuf   = (UINT8 *) Id;
354  IdPayload->PayloadSize  = IdSize;
355
356  //
357  // Set generic header of identification payload
358  //
359  Id->Header.NextPayload    = NextPayload;
360  Id->Header.PayloadLength  = (UINT16) IdSize;
361  Id->IdType                = 9;
362  CopyMem (Id + 1, CertSubject, SubjectSize);
363
364  if (CertSubject != NULL) {
365    FreePool (CertSubject);
366  }
367  return IdPayload;
368}
369
370/**
371  Generate a Authentication Payload.
372
373  This function is used for both Authentication generation and verification. When the
374  IsVerify is TRUE, it create a Auth Data for verification. This function choose the
375  related IKE_SA_INIT Message for Auth data creation according to the IKE Session's type
376  and the value of IsVerify parameter.
377
378  @param[in]  IkeSaSession  Pointer to IKEV2_SA_SESSION related to.
379  @param[in]  IdPayload     Pointer to the ID payload to be used for Authentication
380                            payload generation.
381  @param[in]  NextPayload   The type filled into the Authentication Payload next
382                            payload field.
383  @param[in]  IsVerify      If it is TURE, the Authentication payload is used for
384                            verification.
385
386  @return pointer to IKE Authentication payload for Pre-shared key method.
387
388**/
389IKE_PAYLOAD *
390Ikev2PskGenerateAuthPayload (
391  IN IKEV2_SA_SESSION *IkeSaSession,
392  IN IKE_PAYLOAD      *IdPayload,
393  IN UINT8            NextPayload,
394  IN BOOLEAN          IsVerify
395  )
396{
397  UINT8              *Digest;
398  UINTN              DigestSize;
399  PRF_DATA_FRAGMENT  Fragments[3];
400  UINT8              *KeyBuf;
401  UINTN              KeySize;
402  IKE_PAYLOAD        *AuthPayload;
403  IKEV2_AUTH         *PayloadBuf;
404  EFI_STATUS         Status;
405
406  //
407  // Auth = Prf(Prf(Secret,"Key Pad for IKEv2),IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
408  //
409  //                           1                   2                   3
410  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
411  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
412  //    ! Next Payload  !C!  RESERVED   !         Payload Length        !
413  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
414  //    ! Auth Method   !                RESERVED                       !
415  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
416  //    !                                                               !
417  //    ~                      Authentication Data                      ~
418  //    !                                                               !
419  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
420  //
421
422  KeyBuf      = NULL;
423  AuthPayload = NULL;
424  Digest      = NULL;
425
426  DigestSize = IpSecGetHmacDigestLength ((UINT8)IkeSaSession->SessionCommon.SaParams->Prf);
427  Digest     = AllocateZeroPool (DigestSize);
428  if (Digest == NULL) {
429    return NULL;
430  }
431
432  if (IdPayload == NULL) {
433    return NULL;
434  }
435
436  //
437  // Calcualte Prf(Seceret, "Key Pad for IKEv2");
438  //
439  Fragments[0].Data     = (UINT8 *) mConstantKey;
440  Fragments[0].DataSize = CONSTANT_KEY_SIZE;
441
442  Status = IpSecCryptoIoHmac (
443             (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
444             IkeSaSession->Pad->Data->AuthData,
445             IkeSaSession->Pad->Data->AuthDataSize,
446             (HASH_DATA_FRAGMENT *)Fragments,
447             1,
448             Digest,
449             DigestSize
450             );
451  if (EFI_ERROR (Status)) {
452    goto EXIT;
453  }
454
455  //
456  // Store the AuthKey into KeyBuf
457  //
458  KeyBuf = AllocateZeroPool (DigestSize);
459  if (KeyBuf == NULL) {
460    Status = EFI_OUT_OF_RESOURCES;
461    goto EXIT;
462  }
463
464  CopyMem (KeyBuf, Digest, DigestSize);
465  KeySize = DigestSize;
466
467  //
468  // Calculate Prf(SK_Pi/r, IDi/r)
469  //
470  Fragments[0].Data     = IdPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
471  Fragments[0].DataSize = IdPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
472
473  if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
474      (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
475     ) {
476     Status = IpSecCryptoIoHmac (
477                (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
478                IkeSaSession->IkeKeys->SkPrKey,
479                IkeSaSession->IkeKeys->SkPrKeySize,
480                (HASH_DATA_FRAGMENT *) Fragments,
481                1,
482                Digest,
483                DigestSize
484                );
485  } else {
486    Status = IpSecCryptoIoHmac (
487               (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
488               IkeSaSession->IkeKeys->SkPiKey,
489               IkeSaSession->IkeKeys->SkPiKeySize,
490               (HASH_DATA_FRAGMENT *) Fragments,
491               1,
492               Digest,
493               DigestSize
494               );
495  }
496  if (EFI_ERROR (Status)) {
497    goto EXIT;
498  }
499
500  //
501  // Copy data to Fragments.
502  //
503  if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
504      (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
505     )  {
506    Fragments[0].Data     = IkeSaSession->RespPacket;
507    Fragments[0].DataSize = IkeSaSession->RespPacketSize;
508    Fragments[1].Data     = IkeSaSession->NiBlock;
509    Fragments[1].DataSize = IkeSaSession->NiBlkSize;
510  } else {
511    Fragments[0].Data     = IkeSaSession->InitPacket;
512    Fragments[0].DataSize = IkeSaSession->InitPacketSize;
513    Fragments[1].Data     = IkeSaSession->NrBlock;
514    Fragments[1].DataSize = IkeSaSession->NrBlkSize;
515  }
516
517  //
518  // Copy the result of Prf(SK_Pr, IDi/r) to Fragments[2].
519  //
520  Fragments[2].Data     = AllocateZeroPool (DigestSize);
521  if (Fragments[2].Data == NULL) {
522    Status = EFI_OUT_OF_RESOURCES;
523    goto EXIT;
524  }
525
526  Fragments[2].DataSize = DigestSize;
527  CopyMem (Fragments[2].Data, Digest, DigestSize);
528
529  //
530  // Calculate Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
531  //
532  Status = IpSecCryptoIoHmac (
533             (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
534             KeyBuf,
535             KeySize,
536             (HASH_DATA_FRAGMENT *) Fragments,
537             3,
538             Digest,
539             DigestSize
540             );
541  if (EFI_ERROR (Status)) {
542    goto EXIT;
543  }
544
545  //
546  // Allocate buffer for Auth Payload
547  //
548  AuthPayload               = IkePayloadAlloc ();
549  if (AuthPayload == NULL) {
550    Status = EFI_OUT_OF_RESOURCES;
551    goto EXIT;
552  }
553
554  AuthPayload->PayloadSize  = sizeof (IKEV2_AUTH) + DigestSize;
555  PayloadBuf                = (IKEV2_AUTH *) AllocateZeroPool (AuthPayload->PayloadSize);
556  if (PayloadBuf == NULL) {
557    Status = EFI_OUT_OF_RESOURCES;
558    goto EXIT;
559  }
560
561  //
562  // Fill in Auth payload.
563  //
564  PayloadBuf->Header.NextPayload   = NextPayload;
565  PayloadBuf->Header.PayloadLength = (UINT16) (AuthPayload->PayloadSize);
566  if (IkeSaSession->Pad->Data->AuthMethod == EfiIPsecAuthMethodPreSharedSecret) {
567    //
568    // Only support Shared Key Message Integrity
569    //
570    PayloadBuf->AuthMethod = IKEV2_AUTH_METHOD_SKMI;
571  } else {
572    //
573    // Not support other Auth method.
574    //
575    Status = EFI_UNSUPPORTED;
576    goto EXIT;
577  }
578
579  //
580  // Copy the result of Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) to Auth
581  // payload block.
582  //
583  CopyMem (
584    PayloadBuf + 1,
585    Digest,
586    DigestSize
587    );
588
589  //
590  // Fill in IKE_PACKET
591  //
592  AuthPayload->PayloadBuf   = (UINT8 *) PayloadBuf;
593  AuthPayload->PayloadType  = IKEV2_PAYLOAD_TYPE_AUTH;
594
595EXIT:
596  if (KeyBuf != NULL) {
597    FreePool (KeyBuf);
598  }
599  if (Digest != NULL) {
600    FreePool (Digest);
601  }
602  if (Fragments[2].Data != NULL) {
603    //
604    // Free the buffer which contains the result of Prf(SK_Pr, IDi/r)
605    //
606    FreePool (Fragments[2].Data);
607  }
608
609  if (EFI_ERROR (Status)) {
610    if (AuthPayload != NULL) {
611      IkePayloadFree (AuthPayload);
612    }
613    return NULL;
614  } else {
615    return AuthPayload;
616  }
617}
618
619/**
620  Generate a Authentication Payload for Certificate Auth method.
621
622  This function has two functions. One is creating a local Authentication
623  Payload for sending and other is creating the remote Authentication data
624  for verification when the IsVerify is TURE.
625
626  @param[in]  IkeSaSession      Pointer to IKEV2_SA_SESSION related to.
627  @param[in]  IdPayload         Pointer to the ID payload to be used for Authentication
628                                payload generation.
629  @param[in]  NextPayload       The type filled into the Authentication Payload
630                                next payload field.
631  @param[in]  IsVerify          If it is TURE, the Authentication payload is used
632                                for verification.
633  @param[in]  UefiPrivateKey    Pointer to the UEFI private key. Ignore it when
634                                verify the authenticate payload.
635  @param[in]  UefiPrivateKeyLen The size of UefiPrivateKey in bytes. Ignore it
636                                when verify the authenticate payload.
637  @param[in]  UefiKeyPwd        Pointer to the password of UEFI private key.
638                                Ignore it when verify the authenticate payload.
639  @param[in]  UefiKeyPwdLen     The size of UefiKeyPwd in bytes.Ignore it when
640                                verify the authenticate payload.
641
642  @return pointer to IKE Authentication payload for Cerifitcation method.
643
644**/
645IKE_PAYLOAD *
646Ikev2CertGenerateAuthPayload (
647  IN IKEV2_SA_SESSION *IkeSaSession,
648  IN IKE_PAYLOAD      *IdPayload,
649  IN UINT8            NextPayload,
650  IN BOOLEAN          IsVerify,
651  IN UINT8            *UefiPrivateKey,
652  IN UINTN            UefiPrivateKeyLen,
653  IN UINT8            *UefiKeyPwd,
654  IN UINTN            UefiKeyPwdLen
655  )
656{
657  UINT8              *Digest;
658  UINTN              DigestSize;
659  PRF_DATA_FRAGMENT  Fragments[3];
660  IKE_PAYLOAD        *AuthPayload;
661  IKEV2_AUTH         *PayloadBuf;
662  EFI_STATUS         Status;
663  UINT8              *Signature;
664  UINTN              SigSize;
665
666  //
667  // Auth = Prf(Scert,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
668  //
669  //                           1                   2                   3
670  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
671  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
672  //    ! Next Payload  !C!  RESERVED   !         Payload Length        !
673  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
674  //    ! Auth Method   !                RESERVED                       !
675  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
676  //    !                                                               !
677  //    ~                      Authentication Data                      ~
678  //    !                                                               !
679  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
680  //
681  //
682  // Initial point
683  //
684  AuthPayload = NULL;
685  Digest      = NULL;
686  Signature   = NULL;
687  SigSize     = 0;
688
689  if (IdPayload == NULL) {
690    return NULL;
691  }
692  DigestSize = IpSecGetHmacDigestLength ((UINT8)IkeSaSession->SessionCommon.SaParams->Prf);
693  Digest     = AllocateZeroPool (DigestSize);
694  if (Digest == NULL) {
695    return NULL;
696  }
697
698  //
699  // Calculate Prf(SK_Pi/r, IDi/r)
700  //
701  Fragments[0].Data     = IdPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
702  Fragments[0].DataSize = IdPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
703
704  IpSecDumpBuf ("RestofIDPayload", Fragments[0].Data, Fragments[0].DataSize);
705
706  if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
707      (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
708     ) {
709     Status = IpSecCryptoIoHmac(
710                (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
711                IkeSaSession->IkeKeys->SkPrKey,
712                IkeSaSession->IkeKeys->SkPrKeySize,
713                (HASH_DATA_FRAGMENT *) Fragments,
714                1,
715                Digest,
716                DigestSize
717                );
718    IpSecDumpBuf ("MACedIDForR", Digest, DigestSize);
719  } else {
720    Status = IpSecCryptoIoHmac (
721               (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
722               IkeSaSession->IkeKeys->SkPiKey,
723               IkeSaSession->IkeKeys->SkPiKeySize,
724               (HASH_DATA_FRAGMENT *) Fragments,
725               1,
726               Digest,
727               DigestSize
728               );
729    IpSecDumpBuf ("MACedIDForI", Digest, DigestSize);
730  }
731  if (EFI_ERROR (Status)) {
732    goto EXIT;
733  }
734
735  //
736  // Copy data to Fragments.
737  //
738  if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
739      (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
740     )  {
741    Fragments[0].Data     = IkeSaSession->RespPacket;
742    Fragments[0].DataSize = IkeSaSession->RespPacketSize;
743    Fragments[1].Data     = IkeSaSession->NiBlock;
744    Fragments[1].DataSize = IkeSaSession->NiBlkSize;
745    IpSecDumpBuf ("RealMessage2", Fragments[0].Data, Fragments[0].DataSize);
746    IpSecDumpBuf ("NonceIDdata", Fragments[1].Data, Fragments[1].DataSize);
747  } else {
748    Fragments[0].Data     = IkeSaSession->InitPacket;
749    Fragments[0].DataSize = IkeSaSession->InitPacketSize;
750    Fragments[1].Data     = IkeSaSession->NrBlock;
751    Fragments[1].DataSize = IkeSaSession->NrBlkSize;
752    IpSecDumpBuf ("RealMessage1", Fragments[0].Data, Fragments[0].DataSize);
753    IpSecDumpBuf ("NonceRDdata", Fragments[1].Data, Fragments[1].DataSize);
754  }
755
756  //
757  // Copy the result of Prf(SK_Pr, IDi/r) to Fragments[2].
758  //
759  Fragments[2].Data     = AllocateZeroPool (DigestSize);
760  if (Fragments[2].Data == NULL) {
761    Status = EFI_OUT_OF_RESOURCES;
762    goto EXIT;
763  }
764
765  Fragments[2].DataSize = DigestSize;
766  CopyMem (Fragments[2].Data, Digest, DigestSize);
767
768  //
769  // Calculate Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
770  //
771  Status = IpSecCryptoIoHash (
772             (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
773             (HASH_DATA_FRAGMENT *) Fragments,
774             3,
775             Digest,
776             DigestSize
777             );
778  if (EFI_ERROR (Status)) {
779    goto EXIT;
780  }
781
782  IpSecDumpBuf ("HashSignedOctects", Digest, DigestSize);
783  //
784  // Sign the data by the private Key
785  //
786  if (!IsVerify) {
787    IpSecCryptoIoAuthDataWithCertificate (
788      Digest,
789      DigestSize,
790      UefiPrivateKey,
791      UefiPrivateKeyLen,
792      UefiKeyPwd,
793      UefiKeyPwdLen,
794      &Signature,
795      &SigSize
796      );
797
798    if (SigSize == 0 || Signature == NULL) {
799      goto EXIT;
800    }
801  }
802
803  //
804  // Allocate buffer for Auth Payload
805  //
806  AuthPayload = IkePayloadAlloc ();
807  if (AuthPayload == NULL) {
808    Status = EFI_OUT_OF_RESOURCES;
809    goto EXIT;
810  }
811
812  if (!IsVerify) {
813    AuthPayload->PayloadSize  = sizeof (IKEV2_AUTH) + SigSize;
814  } else {
815    AuthPayload->PayloadSize  = sizeof (IKEV2_AUTH) + DigestSize;
816  }
817
818  PayloadBuf = (IKEV2_AUTH *) AllocateZeroPool (AuthPayload->PayloadSize);
819  if (PayloadBuf == NULL) {
820    Status = EFI_OUT_OF_RESOURCES;
821    goto EXIT;
822  }
823
824  //
825  // Fill in Auth payload.
826  //
827  PayloadBuf->Header.NextPayload   = NextPayload;
828  PayloadBuf->Header.PayloadLength = (UINT16) (AuthPayload->PayloadSize);
829  if (IkeSaSession->Pad->Data->AuthMethod == EfiIPsecAuthMethodCertificates) {
830      PayloadBuf->AuthMethod = IKEV2_AUTH_METHOD_RSA;
831  } else {
832    Status = EFI_INVALID_PARAMETER;
833    goto EXIT;
834  }
835
836  //
837  // Copy the result of Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) to Auth
838  // payload block.
839  //
840  if (!IsVerify) {
841    CopyMem (PayloadBuf + 1, Signature, SigSize);
842  } else {
843    CopyMem (PayloadBuf + 1, Digest, DigestSize);
844  }
845
846  //
847  // Fill in IKE_PACKET
848  //
849  AuthPayload->PayloadBuf   = (UINT8 *) PayloadBuf;
850  AuthPayload->PayloadType  = IKEV2_PAYLOAD_TYPE_AUTH;
851
852EXIT:
853  if (Digest != NULL) {
854    FreePool (Digest);
855  }
856  if (Signature != NULL) {
857    FreePool (Signature);
858  }
859  if (Fragments[2].Data != NULL) {
860    //
861    // Free the buffer which contains the result of Prf(SK_Pr, IDi/r)
862    //
863    FreePool (Fragments[2].Data);
864  }
865
866  if (EFI_ERROR (Status)) {
867    if (AuthPayload != NULL) {
868      IkePayloadFree (AuthPayload);
869    }
870    return NULL;
871  } else {
872    return AuthPayload;
873  }
874}
875
876/**
877  Generate TS payload.
878
879  This function generates TSi or TSr payload according to type of next payload.
880  If the next payload is Responder TS, gereate TSi Payload. Otherwise, generate
881  TSr payload.
882
883  @param[in] ChildSa        Pointer to IKEV2_CHILD_SA_SESSION related to this TS payload.
884  @param[in] NextPayload    The payload type presented in the NextPayload field
885                            of ID Payload header.
886  @param[in] IsTunnel       It indicates that if the Ts Payload is after the CP payload.
887                            If yes, it means the Tsi and Tsr payload should be with
888                            Max port range and address range and protocol is marked
889                            as zero.
890
891  @retval Pointer to Ts IKE payload.
892
893**/
894IKE_PAYLOAD *
895Ikev2GenerateTsPayload (
896  IN IKEV2_CHILD_SA_SESSION *ChildSa,
897  IN UINT8                  NextPayload,
898  IN BOOLEAN                IsTunnel
899  )
900{
901  IKE_PAYLOAD        *TsPayload;
902  IKEV2_TS           *TsPayloadBuf;
903  TRAFFIC_SELECTOR   *TsSelector;
904  UINTN              SelectorSize;
905  UINTN              TsPayloadSize;
906  UINT8              IpVersion;
907  UINT8              AddrSize;
908
909  //
910  //                           1                   2                   3
911  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
912  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
913  //    ! Next Payload  !C!  RESERVED   !         Payload Length        !
914  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
915  //    ! Number of TSs !                 RESERVED                      !
916  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
917  //    !                                                               !
918  //    ~                       <Traffic Selectors>                     ~
919  //    !                                                               !
920  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
921  //
922
923  TsPayload    = IkePayloadAlloc();
924  if (TsPayload == NULL) {
925    return NULL;
926  }
927
928  IpVersion    = ChildSa->SessionCommon.UdpService->IpVersion;
929  //
930  // The Starting Address and Ending Address is variable length depends on
931  // is IPv4 or IPv6
932  //
933  AddrSize      = (UINT8)((IpVersion == IP_VERSION_4) ? sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS));
934  SelectorSize  = sizeof (TRAFFIC_SELECTOR) + 2 * AddrSize;
935  TsPayloadSize = sizeof (IKEV2_TS) + SelectorSize;
936  TsPayloadBuf = AllocateZeroPool (TsPayloadSize);
937  if (TsPayloadBuf == NULL) {
938    goto ON_ERROR;
939  }
940
941  TsPayload->PayloadBuf = (UINT8 *) TsPayloadBuf;
942  TsSelector            = (TRAFFIC_SELECTOR*)(TsPayloadBuf + 1);
943
944  TsSelector->TSType = (UINT8)((IpVersion == IP_VERSION_4) ? IKEV2_TS_TYPE_IPV4_ADDR_RANGE : IKEV2_TS_TYPS_IPV6_ADDR_RANGE);
945
946  //
947  // For tunnel mode
948  //
949  if (IsTunnel) {
950    TsSelector->IpProtocolId = IKEV2_TS_ANY_PROTOCOL;
951    TsSelector->SelecorLen   = (UINT16) SelectorSize;
952    TsSelector->StartPort    = 0;
953    TsSelector->EndPort      = IKEV2_TS_ANY_PORT;
954    ZeroMem ((UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR), AddrSize);
955    SetMem  ((UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize, AddrSize, 0xff);
956
957  } else {
958    //
959    // TODO: Support port range and address range
960    //
961    if (NextPayload == IKEV2_PAYLOAD_TYPE_TS_RSP){
962      //
963      // Create initiator Traffic Selector
964      //
965      TsSelector->SelecorLen   = (UINT16)SelectorSize;
966
967      //
968      // Currently only support the port range from 0~0xffff. Don't support other
969      // port range.
970      // TODO: support Port range
971      //
972      if (ChildSa->SessionCommon.IsInitiator) {
973        if (ChildSa->Spd->Selector->LocalPort != 0 &&
974            ChildSa->Spd->Selector->LocalPortRange == 0) {
975          //
976          // For not port range.
977          //
978          TsSelector->StartPort = ChildSa->Spd->Selector->LocalPort;
979          TsSelector->EndPort   = ChildSa->Spd->Selector->LocalPort;
980        } else if (ChildSa->Spd->Selector->LocalPort == 0){
981          //
982          // For port from 0~0xffff
983          //
984          TsSelector->StartPort = 0;
985          TsSelector->EndPort   = IKEV2_TS_ANY_PORT;
986        } else {
987          //
988          // Not support now.
989          //
990          goto ON_ERROR;
991        }
992      } else {
993        if (ChildSa->Spd->Selector->RemotePort != 0 &&
994            ChildSa->Spd->Selector->RemotePortRange == 0) {
995          //
996          // For not port range.
997          //
998          TsSelector->StartPort = ChildSa->Spd->Selector->RemotePort;
999          TsSelector->EndPort   = ChildSa->Spd->Selector->RemotePort;
1000        } else if (ChildSa->Spd->Selector->RemotePort == 0) {
1001          //
1002          // For port from 0~0xffff
1003          //
1004          TsSelector->StartPort = 0;
1005          TsSelector->EndPort   = IKEV2_TS_ANY_PORT;
1006        } else {
1007          //
1008          // Not support now.
1009          //
1010          goto ON_ERROR;
1011        }
1012      }
1013      //
1014      // Copy Address.Currently the address range is not supported.
1015      // The Starting address is same as Ending address
1016      // TODO: Support Address Range.
1017      //
1018      CopyMem (
1019        (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR),
1020        ChildSa->SessionCommon.IsInitiator ?
1021        ChildSa->Spd->Selector->LocalAddress :
1022        ChildSa->Spd->Selector->RemoteAddress,
1023        AddrSize
1024        );
1025      CopyMem (
1026        (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize,
1027        ChildSa->SessionCommon.IsInitiator ?
1028        ChildSa->Spd->Selector->LocalAddress :
1029        ChildSa->Spd->Selector->RemoteAddress,
1030        AddrSize
1031        );
1032      //
1033      // If the Next Payload is not TS responder, this TS payload type is the TS responder.
1034      //
1035      TsPayload->PayloadType             = IKEV2_PAYLOAD_TYPE_TS_INIT;
1036    }else{
1037        //
1038        // Create responder Traffic Selector
1039        //
1040        TsSelector->SelecorLen   = (UINT16)SelectorSize;
1041
1042        //
1043        // Currently only support the port range from 0~0xffff. Don't support other
1044        // port range.
1045        // TODO: support Port range
1046        //
1047        if (!ChildSa->SessionCommon.IsInitiator) {
1048          if (ChildSa->Spd->Selector->LocalPort != 0 &&
1049              ChildSa->Spd->Selector->LocalPortRange == 0) {
1050            //
1051            // For not port range.
1052            //
1053            TsSelector->StartPort = ChildSa->Spd->Selector->LocalPort;
1054            TsSelector->EndPort   = ChildSa->Spd->Selector->LocalPort;
1055          } else if (ChildSa->Spd->Selector->LocalPort == 0){
1056            //
1057            // For port from 0~0xffff
1058            //
1059            TsSelector->StartPort = 0;
1060            TsSelector->EndPort   = IKEV2_TS_ANY_PORT;
1061          } else {
1062            //
1063            // Not support now.
1064            //
1065            goto ON_ERROR;
1066          }
1067        } else {
1068          if (ChildSa->Spd->Selector->RemotePort != 0 &&
1069              ChildSa->Spd->Selector->RemotePortRange == 0) {
1070            //
1071            // For not port range.
1072            //
1073            TsSelector->StartPort = ChildSa->Spd->Selector->RemotePort;
1074            TsSelector->EndPort   = ChildSa->Spd->Selector->RemotePort;
1075          } else if (ChildSa->Spd->Selector->RemotePort == 0){
1076            //
1077            // For port from 0~0xffff
1078            //
1079            TsSelector->StartPort = 0;
1080            TsSelector->EndPort   = IKEV2_TS_ANY_PORT;
1081          } else {
1082            //
1083            // Not support now.
1084            //
1085            goto ON_ERROR;
1086          }
1087        }
1088        //
1089        // Copy Address.Currently the address range is not supported.
1090        // The Starting address is same as Ending address
1091        // TODO: Support Address Range.
1092        //
1093        CopyMem (
1094          (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR),
1095          ChildSa->SessionCommon.IsInitiator ?
1096          ChildSa->Spd->Selector->RemoteAddress :
1097          ChildSa->Spd->Selector->LocalAddress,
1098          AddrSize
1099          );
1100        CopyMem (
1101          (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize,
1102          ChildSa->SessionCommon.IsInitiator ?
1103          ChildSa->Spd->Selector->RemoteAddress :
1104          ChildSa->Spd->Selector->LocalAddress,
1105          AddrSize
1106          );
1107        //
1108        // If the Next Payload is not TS responder, this TS payload type is the TS responder.
1109        //
1110        TsPayload->PayloadType          = IKEV2_PAYLOAD_TYPE_TS_RSP;
1111      }
1112    }
1113
1114    if (ChildSa->Spd->Selector->NextLayerProtocol != 0xffff) {
1115      TsSelector->IpProtocolId = (UINT8)ChildSa->Spd->Selector->NextLayerProtocol;
1116    } else {
1117      TsSelector->IpProtocolId = IKEV2_TS_ANY_PROTOCOL;
1118    }
1119
1120  TsPayloadBuf->Header.NextPayload    = NextPayload;
1121  TsPayloadBuf->Header.PayloadLength  = (UINT16)TsPayloadSize;
1122  TsPayloadBuf->TSNumbers             = 1;
1123  TsPayload->PayloadSize              = TsPayloadSize;
1124  goto ON_EXIT;
1125
1126ON_ERROR:
1127  if (TsPayload != NULL) {
1128    IkePayloadFree (TsPayload);
1129    TsPayload = NULL;
1130  }
1131ON_EXIT:
1132  return TsPayload;
1133}
1134
1135/**
1136  Generate the Notify payload.
1137
1138  Since the structure of Notify payload which defined in RFC 4306 is simple, so
1139  there is no internal data structure for Notify payload. This function generate
1140  Notify payload defined in RFC 4306, but all the fields in this payload are still
1141  in host order and need call Ikev2EncodePayload() to convert those fields from
1142  the host order to network order beforing sending it.
1143
1144  @param[in]  ProtocolId        The protocol type ID. For IKE_SA it MUST be one (1).
1145                                For IPsec SAs it MUST be neither (2) for AH or (3)
1146                                for ESP.
1147  @param[in]  NextPayload       The next paylaod type in NextPayload field of
1148                                the Notify payload.
1149  @param[in]  SpiSize           Size of the SPI in SPI size field of the Notify Payload.
1150  @param[in]  MessageType       The message type in NotifyMessageType field of the
1151                                Notify Payload.
1152  @param[in]  SpiBuf            Pointer to buffer contains the SPI value.
1153  @param[in]  NotifyData        Pointer to buffer contains the notification data.
1154  @param[in]  NotifyDataSize    The size of NotifyData in bytes.
1155
1156
1157  @retval Pointer to IKE Notify Payload.
1158
1159**/
1160IKE_PAYLOAD *
1161Ikev2GenerateNotifyPayload (
1162  IN UINT8            ProtocolId,
1163  IN UINT8            NextPayload,
1164  IN UINT8            SpiSize,
1165  IN UINT16           MessageType,
1166  IN UINT8            *SpiBuf,
1167  IN UINT8            *NotifyData,
1168  IN UINTN            NotifyDataSize
1169  )
1170{
1171  IKE_PAYLOAD         *NotifyPayload;
1172  IKEV2_NOTIFY        *Notify;
1173  UINT16              NotifyPayloadLen;
1174  UINT8               *MessageData;
1175
1176  //                       1                   2                   3
1177  //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1178  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1179  //  ! Next Payload  !C!  RESERVED   !         Payload Length        !
1180  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1181  //  !  Protocol ID  !   SPI Size    !      Notify Message Type      !
1182  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1183  //  !                                                               !
1184  //  ~                Security Parameter Index (SPI)                 ~
1185  //  !                                                               !
1186  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1187  //  !                                                               !
1188  //  ~                       Notification Data                       ~
1189  //  !                                                               !
1190  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1191  //
1192  //
1193  NotifyPayloadLen  = (UINT16) (sizeof (IKEV2_NOTIFY) + NotifyDataSize + SpiSize);
1194  Notify            = (IKEV2_NOTIFY *) AllocateZeroPool (NotifyPayloadLen);
1195  if (Notify == NULL) {
1196    return NULL;
1197  }
1198
1199  //
1200  // Set Delete Payload's Generic Header
1201  //
1202  Notify->Header.NextPayload    = NextPayload;
1203  Notify->Header.PayloadLength  = NotifyPayloadLen;
1204  Notify->SpiSize               = SpiSize;
1205  Notify->ProtocolId            = ProtocolId;
1206  Notify->MessageType           = MessageType;
1207
1208  //
1209  // Copy Spi , for Cookie Notify, there is no SPI.
1210  //
1211  if (SpiBuf != NULL && SpiSize != 0 ) {
1212    CopyMem (Notify + 1, SpiBuf, SpiSize);
1213  }
1214
1215  MessageData = ((UINT8 *) (Notify + 1)) + SpiSize;
1216
1217  //
1218  // Copy Notification Data
1219  //
1220  if (NotifyDataSize != 0) {
1221    CopyMem (MessageData, NotifyData, NotifyDataSize);
1222  }
1223
1224  //
1225  // Create Payload for and set type as IKEV2_PAYLOAD_TYPE_NOTIFY
1226  //
1227  NotifyPayload = IkePayloadAlloc ();
1228  if (NotifyPayload == NULL) {
1229    FreePool (Notify);
1230    return NULL;
1231  }
1232
1233  NotifyPayload->PayloadType  = IKEV2_PAYLOAD_TYPE_NOTIFY;
1234  NotifyPayload->PayloadBuf   = (UINT8 *) Notify;
1235  NotifyPayload->PayloadSize  = NotifyPayloadLen;
1236  return NotifyPayload;
1237}
1238
1239/**
1240  Generate the Delete payload.
1241
1242  Since the structure of Delete payload which defined in RFC 4306 is simple,
1243  there is no internal data structure for Delete payload. This function generate
1244  Delete payload defined in RFC 4306, but all the fields in this payload are still
1245  in host order and need call Ikev2EncodePayload() to convert those fields from
1246  the host order to network order beforing sending it.
1247
1248  @param[in]  IkeSaSession      Pointer to IKE SA Session to be used of Delete payload generation.
1249  @param[in]  NextPayload       The next paylaod type in NextPayload field of
1250                                the Delete payload.
1251  @param[in]  SpiSize           Size of the SPI in SPI size field of the Delete Payload.
1252  @param[in]  SpiNum            Number of SPI in NumofSPIs field of the Delete Payload.
1253  @param[in]  SpiBuf            Pointer to buffer contains the SPI value.
1254
1255  @retval a Pointer of IKE Delete Payload.
1256
1257**/
1258IKE_PAYLOAD *
1259Ikev2GenerateDeletePayload (
1260  IN IKEV2_SA_SESSION  *IkeSaSession,
1261  IN UINT8             NextPayload,
1262  IN UINT8             SpiSize,
1263  IN UINT16            SpiNum,
1264  IN UINT8             *SpiBuf
1265
1266  )
1267{
1268  IKE_PAYLOAD  *DelPayload;
1269  IKEV2_DELETE *Del;
1270  UINT16       SpiBufSize;
1271  UINT16       DelPayloadLen;
1272
1273  //                         1                   2                   3
1274  //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1275  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1276  //  ! Next Payload  !C!  RESERVED   !         Payload Length        !
1277  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1278  //  ! Protocol ID   !   SPI Size    !           # of SPIs           !
1279  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1280  //  !                                                               !
1281  //  ~               Security Parameter Index(es) (SPI)              ~
1282  //  !                                                               !
1283  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1284  //
1285  SpiBufSize    = (UINT16) (SpiSize * SpiNum);
1286  if (SpiBufSize != 0 && SpiBuf == NULL) {
1287    return NULL;
1288  }
1289
1290  DelPayloadLen = (UINT16) (sizeof (IKEV2_DELETE) + SpiBufSize);
1291
1292  Del           = AllocateZeroPool (DelPayloadLen);
1293  if (Del == NULL) {
1294    return NULL;
1295  }
1296
1297  //
1298  // Set Delete Payload's Generic Header
1299  //
1300  Del->Header.NextPayload   = NextPayload;
1301  Del->Header.PayloadLength = DelPayloadLen;
1302  Del->NumSpis              = SpiNum;
1303  Del->SpiSize              = SpiSize;
1304
1305  if (SpiSize == 4) {
1306    //
1307    // TODO: should consider the AH if needs to support.
1308    //
1309    Del->ProtocolId = IPSEC_PROTO_IPSEC_ESP;
1310  } else {
1311    Del->ProtocolId = IPSEC_PROTO_ISAKMP;
1312  }
1313
1314  //
1315  // Set Del Payload's Idntification Data
1316  //
1317  CopyMem (Del + 1, SpiBuf, SpiBufSize);
1318  DelPayload = IkePayloadAlloc ();
1319  if (DelPayload == NULL) {
1320    FreePool (Del);
1321    return NULL;
1322  }
1323
1324  DelPayload->PayloadType = IKEV2_PAYLOAD_TYPE_DELETE;
1325  DelPayload->PayloadBuf  = (UINT8 *) Del;
1326  DelPayload->PayloadSize = DelPayloadLen;
1327  return DelPayload;
1328}
1329
1330/**
1331  Generate the Configuration payload.
1332
1333  This function generate configuration payload defined in RFC 4306, but all the
1334  fields in this payload are still in host order and need call Ikev2EncodePayload()
1335  to convert those fields from the host order to network order beforing sending it.
1336
1337  @param[in]  IkeSaSession      Pointer to IKE SA Session to be used for Delete payload
1338                                generation.
1339  @param[in]  NextPayload       The next paylaod type in NextPayload field of
1340                                the Delete payload.
1341  @param[in]  CfgType           The attribute type in the Configuration attribute.
1342
1343  @retval Pointer to IKE CP Payload.
1344
1345**/
1346IKE_PAYLOAD *
1347Ikev2GenerateCpPayload (
1348  IN IKEV2_SA_SESSION  *IkeSaSession,
1349  IN UINT8             NextPayload,
1350  IN UINT8             CfgType
1351  )
1352{
1353  IKE_PAYLOAD           *CpPayload;
1354  IKEV2_CFG             *Cfg;
1355  UINT16                PayloadLen;
1356  IKEV2_CFG_ATTRIBUTES  *CfgAttributes;
1357
1358  //
1359  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1360  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1361  //    ! Next Payload  !C! RESERVED    !         Payload Length        !
1362  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1363  //    !   CFG Type    !                    RESERVED                   !
1364  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1365  //    !                                                               !
1366  //    ~                   Configuration Attributes                    ~
1367  //    !                                                               !
1368  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1369  //
1370
1371  PayloadLen = (UINT16) (sizeof (IKEV2_CFG) + sizeof (IKEV2_CFG_ATTRIBUTES));
1372  Cfg        = (IKEV2_CFG *) AllocateZeroPool (PayloadLen);
1373
1374  if (Cfg == NULL) {
1375    return NULL;
1376  }
1377
1378  CfgAttributes = (IKEV2_CFG_ATTRIBUTES *)((UINT8 *)Cfg + sizeof (IKEV2_CFG));
1379
1380  //
1381  // Only generate the configuration payload with an empty INTERNAL_IP4_ADDRESS
1382  // or INTERNAL_IP6_ADDRESS.
1383  //
1384
1385  Cfg->Header.NextPayload   = NextPayload;
1386  Cfg->Header.PayloadLength = PayloadLen;
1387  Cfg->CfgType              = IKEV2_CFG_TYPE_REQUEST;
1388
1389  CfgAttributes->AttritType  = CfgType;
1390  CfgAttributes->ValueLength = 0;
1391
1392  CpPayload = IkePayloadAlloc ();
1393  if (CpPayload == NULL) {
1394    if (Cfg != NULL) {
1395      FreePool (Cfg);
1396    }
1397    return NULL;
1398  }
1399
1400  CpPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CP;
1401  CpPayload->PayloadBuf  = (UINT8 *) Cfg;
1402  CpPayload->PayloadSize = PayloadLen;
1403  return CpPayload;
1404}
1405
1406/**
1407  Parser the Notify Cookie payload.
1408
1409  This function parses the Notify Cookie payload.If the Notify ProtocolId is not
1410  IPSEC_PROTO_ISAKMP or if the SpiSize is not zero or if the MessageType is not
1411  the COOKIE, return EFI_INVALID_PARAMETER.
1412
1413  @param[in]      IkeNCookie    Pointer to the IKE_PAYLOAD which contians the
1414                                Notify Cookie payload.
1415                                the Notify payload.
1416  @param[in, out] IkeSaSession  Pointer to the relevant IKE SA Session.
1417
1418  @retval EFI_SUCCESS           The Notify Cookie Payload is valid.
1419  @retval EFI_INVALID_PARAMETER The Notify Cookie Payload is invalid.
1420  @retval EFI_OUT_OF_RESOURCE   The required resource can't be allocated.
1421
1422**/
1423EFI_STATUS
1424Ikev2ParserNotifyCookiePayload (
1425  IN     IKE_PAYLOAD      *IkeNCookie,
1426  IN OUT IKEV2_SA_SESSION *IkeSaSession
1427  )
1428{
1429  IKEV2_NOTIFY      *NotifyPayload;
1430  UINTN             NotifyDataSize;
1431
1432  NotifyPayload = (IKEV2_NOTIFY *)IkeNCookie->PayloadBuf;
1433
1434  if ((NotifyPayload->ProtocolId != IPSEC_PROTO_ISAKMP) ||
1435      (NotifyPayload->SpiSize != 0) ||
1436      (NotifyPayload->MessageType != IKEV2_NOTIFICATION_COOKIE)
1437      ) {
1438    return EFI_INVALID_PARAMETER;
1439  }
1440
1441  NotifyDataSize        = NotifyPayload->Header.PayloadLength - sizeof (IKEV2_NOTIFY);
1442  IkeSaSession->NCookie = AllocateZeroPool (NotifyDataSize);
1443  if (IkeSaSession->NCookie == NULL) {
1444    return EFI_OUT_OF_RESOURCES;
1445  }
1446
1447  IkeSaSession->NCookieSize = NotifyDataSize;
1448
1449  CopyMem (
1450    IkeSaSession->NCookie,
1451    (UINT8 *)NotifyPayload + sizeof (IKEV2_NOTIFY),
1452    NotifyDataSize
1453    );
1454
1455  return EFI_SUCCESS;
1456}
1457
1458
1459/**
1460  Generate the Certificate payload or Certificate Request Payload.
1461
1462  Since the Certificate Payload structure is same with Certificate Request Payload,
1463  the only difference is that one contains the Certificate Data, other contains
1464  the acceptable certificateion CA. This function generate Certificate payload
1465  or Certificate Request Payload defined in RFC 4306, but all the fields
1466  in the payload are still in host order and need call Ikev2EncodePayload()
1467  to convert those fields from the host order to network order beforing sending it.
1468
1469  @param[in]  IkeSaSession      Pointer to IKE SA Session to be used of Delete payload
1470                                generation.
1471  @param[in]  NextPayload       The next paylaod type in NextPayload field of
1472                                the Delete payload.
1473  @param[in]  Certificate       Pointer of buffer contains the certification data.
1474  @param[in]  CertificateLen    The length of Certificate in byte.
1475  @param[in]  EncodeType        Specified the Certificate Encodeing which is defined
1476                                in RFC 4306.
1477  @param[in]  IsRequest         To indicate create Certificate Payload or Certificate
1478                                Request Payload. If it is TURE, create Certificate
1479                                Request Payload. Otherwise, create Certificate Payload.
1480
1481  @retval  a Pointer to IKE Payload whose payload buffer containing the Certificate
1482           payload or Certificated Request payload.
1483
1484**/
1485IKE_PAYLOAD *
1486Ikev2GenerateCertificatePayload (
1487  IN IKEV2_SA_SESSION  *IkeSaSession,
1488  IN UINT8             NextPayload,
1489  IN UINT8             *Certificate,
1490  IN UINTN             CertificateLen,
1491  IN UINT8             EncodeType,
1492  IN BOOLEAN           IsRequest
1493  )
1494{
1495  IKE_PAYLOAD           *CertPayload;
1496  IKEV2_CERT            *Cert;
1497  UINT16                PayloadLen;
1498  UINT8                 *PublicKey;
1499  UINTN                 PublicKeyLen;
1500  HASH_DATA_FRAGMENT    Fragment[1];
1501  UINT8                 *HashData;
1502  UINTN                 HashDataSize;
1503  EFI_STATUS            Status;
1504
1505  //
1506  //                         1                   2                   3
1507  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1508  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1509  //    ! Next Payload  !C!  RESERVED   !         Payload Length        !
1510  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1511  //    ! Cert Encoding !                                               !
1512  //    +-+-+-+-+-+-+-+-+                                               !
1513  //    ~                       Certificate Data/Authority              ~
1514  //    !                                                               !
1515  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1516  //
1517
1518  Status       = EFI_SUCCESS;
1519  PublicKey    = NULL;
1520  PublicKeyLen = 0;
1521
1522  if (!IsRequest) {
1523    PayloadLen = (UINT16) (sizeof (IKEV2_CERT) + CertificateLen);
1524  } else {
1525    //
1526    // SHA1 Hash length is 20.
1527    //
1528    PayloadLen = (UINT16) (sizeof (IKEV2_CERT) + 20);
1529  }
1530
1531  Cert = AllocateZeroPool (PayloadLen);
1532  if (Cert == NULL) {
1533    return NULL;
1534  }
1535
1536  //
1537  // Generate Certificate Payload or Certificate Request Payload.
1538  //
1539  Cert->Header.NextPayload   = NextPayload;
1540  Cert->Header.PayloadLength = PayloadLen;
1541  Cert->CertEncoding         = EncodeType;
1542  if (!IsRequest) {
1543    CopyMem (
1544      ((UINT8 *)Cert) + sizeof (IKEV2_CERT),
1545      Certificate,
1546      CertificateLen
1547      );
1548  } else {
1549    Status = IpSecCryptoIoGetPublicKeyFromCert (
1550               Certificate,
1551               CertificateLen,
1552               &PublicKey,
1553               &PublicKeyLen
1554               );
1555    if (EFI_ERROR (Status)) {
1556      goto ON_EXIT;
1557    }
1558
1559    Fragment[0].Data     = PublicKey;
1560    Fragment[0].DataSize = PublicKeyLen;
1561    HashDataSize      = IpSecGetHmacDigestLength (IKE_AALG_SHA1HMAC);
1562    HashData          = AllocateZeroPool (HashDataSize);
1563    if (HashData == NULL) {
1564      goto ON_EXIT;
1565    }
1566
1567    Status = IpSecCryptoIoHash (
1568               IKE_AALG_SHA1HMAC,
1569               Fragment,
1570               1,
1571               HashData,
1572               HashDataSize
1573               );
1574    if (EFI_ERROR (Status)) {
1575      goto ON_EXIT;
1576    }
1577
1578    CopyMem (
1579      ((UINT8 *)Cert) + sizeof (IKEV2_CERT),
1580      HashData,
1581      HashDataSize
1582      );
1583  }
1584
1585  CertPayload = IkePayloadAlloc ();
1586  if (CertPayload == NULL) {
1587    goto ON_EXIT;
1588  }
1589
1590  if (!IsRequest) {
1591    CertPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CERT;
1592  } else {
1593    CertPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CERTREQ;
1594  }
1595
1596  CertPayload->PayloadBuf  = (UINT8 *) Cert;
1597  CertPayload->PayloadSize = PayloadLen;
1598  return CertPayload;
1599
1600ON_EXIT:
1601  if (Cert != NULL) {
1602    FreePool (Cert);
1603  }
1604  if (PublicKey != NULL) {
1605    FreePool (PublicKey);
1606  }
1607  return NULL;
1608}
1609
1610/**
1611  Remove and free all IkePayloads in the specified IkePacket.
1612
1613  @param[in] IkePacket   The pointer of IKE_PACKET.
1614
1615**/
1616VOID
1617ClearAllPayloads (
1618  IN IKE_PACKET     *IkePacket
1619  )
1620{
1621  LIST_ENTRY      *PayloadEntry;
1622  IKE_PAYLOAD     *IkePayload;
1623  //
1624  // remove all payloads from list and free each payload.
1625  //
1626  while (!IsListEmpty (&IkePacket->PayloadList)) {
1627    PayloadEntry  = IkePacket->PayloadList.ForwardLink;
1628    IkePayload    = IKE_PAYLOAD_BY_PACKET (PayloadEntry);
1629    IKE_PACKET_REMOVE_PAYLOAD (IkePacket, IkePayload);
1630    IkePayloadFree (IkePayload);
1631  }
1632}
1633
1634/**
1635  Transfer the intrnal data structure IKEV2_SA_DATA to IKEV2_SA structure defined in RFC.
1636
1637  @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the SA Session.
1638  @param[in] SaData        Pointer to IKEV2_SA_DATA to be transfered.
1639
1640  @retval  return the pointer of IKEV2_SA.
1641
1642**/
1643IKEV2_SA*
1644Ikev2EncodeSa (
1645  IN IKEV2_SESSION_COMMON *SessionCommon,
1646  IN IKEV2_SA_DATA        *SaData
1647  )
1648{
1649  IKEV2_SA              *Sa;
1650  UINTN                 SaSize;
1651  IKEV2_PROPOSAL_DATA   *ProposalData;
1652  IKEV2_TRANSFORM_DATA  *TransformData;
1653  UINTN                 TotalTransforms;
1654  UINTN                 SaAttrsSize;
1655  UINTN                 TransformsSize;
1656  UINTN                 TransformSize;
1657  UINTN                 ProposalsSize;
1658  UINTN                 ProposalSize;
1659  UINTN                 ProposalIndex;
1660  UINTN                 TransformIndex;
1661  IKE_SA_ATTRIBUTE      *SaAttribute;
1662  IKEV2_PROPOSAL        *Proposal;
1663  IKEV2_TRANSFORM       *Transform;
1664
1665  //
1666  // Transform IKE_SA_DATA structure to IKE_SA Payload.
1667  // Header length is host order.
1668  // The returned IKE_SA struct should be freed by caller.
1669  //
1670  TotalTransforms = 0;
1671  //
1672  // Calculate the Proposal numbers and Transform numbers.
1673  //
1674  for (ProposalIndex = 0; ProposalIndex < SaData->NumProposals; ProposalIndex++) {
1675
1676    ProposalData     = (IKEV2_PROPOSAL_DATA *) (SaData + 1) + ProposalIndex;
1677    TotalTransforms += ProposalData->NumTransforms;
1678
1679  }
1680  SaSize = sizeof (IKEV2_SA) +
1681           SaData->NumProposals * sizeof (IKEV2_PROPOSAL) +
1682           TotalTransforms * (sizeof (IKEV2_TRANSFORM) + MAX_SA_ATTRS_SIZE);
1683  //
1684  // Allocate buffer for IKE_SA.
1685  //
1686  Sa = AllocateZeroPool (SaSize);
1687  if (Sa == NULL) {
1688    return NULL;
1689  }
1690
1691  CopyMem (Sa, SaData, sizeof (IKEV2_SA));
1692  Sa->Header.PayloadLength  = (UINT16) sizeof (IKEV2_SA);
1693  ProposalsSize             = 0;
1694  Proposal                  = (IKEV2_PROPOSAL *) (Sa + 1);
1695
1696  //
1697  // Set IKE_PROPOSAL
1698  //
1699  ProposalData  = (IKEV2_PROPOSAL_DATA *) (SaData + 1);
1700  for (ProposalIndex = 0; ProposalIndex < SaData->NumProposals; ProposalIndex++) {
1701    Proposal->ProposalIndex   = ProposalData->ProposalIndex;
1702    Proposal->ProtocolId      = ProposalData->ProtocolId;
1703    Proposal->NumTransforms   = ProposalData->NumTransforms;
1704
1705    if (ProposalData->Spi == 0) {
1706      Proposal->SpiSize = 0;
1707    } else {
1708      Proposal->SpiSize           = 4;
1709      *(UINT32 *) (Proposal + 1)  = HTONL (*((UINT32*)ProposalData->Spi));
1710    }
1711
1712    TransformsSize  = 0;
1713    Transform       = (IKEV2_TRANSFORM *) ((UINT8 *) (Proposal + 1) + Proposal->SpiSize);
1714
1715    //
1716    // Set IKE_TRANSFORM
1717    //
1718    for (TransformIndex = 0; TransformIndex < ProposalData->NumTransforms; TransformIndex++) {
1719      TransformData               = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1) + TransformIndex;
1720      Transform->TransformType    = TransformData->TransformType;
1721      Transform->TransformId      = HTONS (TransformData->TransformId);
1722      SaAttrsSize                 = 0;
1723
1724      //
1725      // If the Encryption Algorithm is variable key length set the key length in attribute.
1726      // Note that only a single attribute type (Key Length) is defined and it is fixed length.
1727      //
1728      if (Transform->TransformType == IKEV2_TRANSFORM_TYPE_ENCR && TransformData->Attribute.Attr.AttrValue != 0) {
1729        SaAttribute                 = (IKE_SA_ATTRIBUTE *) (Transform + 1);
1730        SaAttribute->AttrType       = HTONS (IKEV2_ATTRIBUTE_TYPE_KEYLEN | SA_ATTR_FORMAT_BIT);
1731        SaAttribute->Attr.AttrValue = HTONS (TransformData->Attribute.Attr.AttrValue);
1732        SaAttrsSize                 = sizeof (IKE_SA_ATTRIBUTE);
1733      }
1734
1735      //
1736      // If the Integrity Algorithm is variable key length set the key length in attribute.
1737      //
1738      if (Transform->TransformType == IKEV2_TRANSFORM_TYPE_INTEG && TransformData->Attribute.Attr.AttrValue != 0) {
1739        SaAttribute                 = (IKE_SA_ATTRIBUTE *) (Transform + 1);
1740        SaAttribute->AttrType       = HTONS (IKEV2_ATTRIBUTE_TYPE_KEYLEN | SA_ATTR_FORMAT_BIT);
1741        SaAttribute->Attr.AttrValue = HTONS (TransformData->Attribute.Attr.AttrValue);
1742        SaAttrsSize                 = sizeof (IKE_SA_ATTRIBUTE);
1743      }
1744
1745      TransformSize                 = sizeof (IKEV2_TRANSFORM) + SaAttrsSize;
1746      TransformsSize               += TransformSize;
1747
1748      Transform->Header.NextPayload   = IKE_TRANSFORM_NEXT_PAYLOAD_MORE;
1749      Transform->Header.PayloadLength = HTONS ((UINT16)TransformSize);
1750
1751      if (TransformIndex == (UINTN)(ProposalData->NumTransforms - 1)) {
1752        Transform->Header.NextPayload = IKE_TRANSFORM_NEXT_PAYLOAD_NONE;
1753      }
1754
1755      Transform     = (IKEV2_TRANSFORM *)((UINT8 *) Transform + TransformSize);
1756    }
1757
1758    //
1759    // Set Proposal's Generic Header.
1760    //
1761    ProposalSize                   = sizeof (IKEV2_PROPOSAL) + Proposal->SpiSize + TransformsSize;
1762    ProposalsSize                 += ProposalSize;
1763    Proposal->Header.NextPayload   = IKE_PROPOSAL_NEXT_PAYLOAD_MORE;
1764    Proposal->Header.PayloadLength = HTONS ((UINT16)ProposalSize);
1765
1766    if (ProposalIndex == (UINTN)(SaData->NumProposals - 1)) {
1767      Proposal->Header.NextPayload = IKE_PROPOSAL_NEXT_PAYLOAD_NONE;
1768    }
1769
1770    //
1771    // Point to next Proposal Payload
1772    //
1773    Proposal     = (IKEV2_PROPOSAL *) ((UINT8 *) Proposal + ProposalSize);
1774    ProposalData = (IKEV2_PROPOSAL_DATA *)(((UINT8 *)ProposalData) + sizeof (IKEV2_PROPOSAL_DATA) + (TransformIndex * sizeof (IKEV2_TRANSFORM_DATA)));
1775  }
1776  //
1777  // Set SA's Generic Header.
1778  //
1779  Sa->Header.PayloadLength = (UINT16) (Sa->Header.PayloadLength + ProposalsSize);
1780  return Sa;
1781}
1782
1783/**
1784  Decode SA payload.
1785
1786  This function converts the received SA payload to internal data structure.
1787
1788  @param[in]  SessionCommon       Pointer to IKE Common Session used to decode the SA
1789                                  Payload.
1790  @param[in]  Sa                  Pointer to SA Payload
1791
1792  @return a Pointer to internal data structure for SA payload.
1793
1794**/
1795IKEV2_SA_DATA *
1796Ikev2DecodeSa (
1797  IN IKEV2_SESSION_COMMON *SessionCommon,
1798  IN IKEV2_SA             *Sa
1799  )
1800{
1801  IKEV2_SA_DATA         *SaData;
1802  EFI_STATUS            Status;
1803  IKEV2_PROPOSAL        *Proposal;
1804  IKEV2_TRANSFORM       *Transform;
1805  UINTN                 TotalProposals;
1806  UINTN                 TotalTransforms;
1807  UINTN                 ProposalNextPayloadSum;
1808  UINTN                 ProposalIndex;
1809  UINTN                 TransformIndex;
1810  UINTN                 SaRemaining;
1811  UINT16                ProposalSize;
1812  UINTN                 ProposalRemaining;
1813  UINT16                TransformSize;
1814  UINTN                 SaAttrRemaining;
1815  IKE_SA_ATTRIBUTE      *SaAttribute;
1816  IKEV2_PROPOSAL_DATA   *ProposalData;
1817  IKEV2_TRANSFORM_DATA  *TransformData;
1818  UINT8                 *Spi;
1819
1820  //
1821  // Transfrom from IKE_SA payload to IKE_SA_DATA structure.
1822  // Header length NTOH is already done
1823  // The returned IKE_SA_DATA should be freed by caller
1824  //
1825  SaData    = NULL;
1826  Status    = EFI_SUCCESS;
1827
1828  //
1829  // First round sanity check and size calculae
1830  //
1831  TotalProposals         = 0;
1832  TotalTransforms        = 0;
1833  ProposalNextPayloadSum = 0;
1834  SaRemaining            = Sa->Header.PayloadLength - sizeof (IKEV2_SA);// Point to current position in SA
1835  Proposal               = (IKEV2_PROPOSAL *)((IKEV2_SA *)(Sa)+1);
1836
1837  //
1838  // Calculate the number of Proposal payload and the total numbers of
1839  // Transforms payload (the transforms in all proposal payload).
1840  //
1841  while (SaRemaining > sizeof (IKEV2_PROPOSAL)) {
1842    ProposalSize = NTOHS (Proposal->Header.PayloadLength);
1843    if (SaRemaining < ProposalSize) {
1844      Status = EFI_INVALID_PARAMETER;
1845      goto Exit;
1846    }
1847
1848    if (Proposal->SpiSize != 0 && Proposal->SpiSize != 4) {
1849      Status = EFI_INVALID_PARAMETER;
1850      goto Exit;
1851    }
1852
1853    TotalProposals++;
1854    TotalTransforms        += Proposal->NumTransforms;
1855    SaRemaining            -= ProposalSize;
1856    ProposalNextPayloadSum += Proposal->Header.NextPayload;
1857    Proposal                = IKEV2_NEXT_PROPOSAL_WITH_SIZE (Proposal, ProposalSize);
1858  }
1859
1860  //
1861  // Check the proposal number.
1862  // The proposal Substructure, the NextPayLoad field indicates : 0 (last) or 2 (more)
1863  // which Specifies whether this is the last Proposal Substructure in the SA.
1864  // Here suming all Proposal NextPayLoad field to check the proposal number is correct
1865  // or not.
1866  //
1867  if (TotalProposals == 0 ||
1868      (TotalProposals - 1) * IKE_PROPOSAL_NEXT_PAYLOAD_MORE != ProposalNextPayloadSum
1869      ) {
1870    Status = EFI_INVALID_PARAMETER;
1871    goto Exit;
1872  }
1873
1874  //
1875  // Second round sanity check and decode. Transform the SA payload into
1876  // a IKE_SA_DATA structure.
1877  //
1878  SaData = (IKEV2_SA_DATA *) AllocateZeroPool (
1879                               sizeof (IKEV2_SA_DATA) +
1880                               TotalProposals * sizeof (IKEV2_PROPOSAL_DATA) +
1881                               TotalTransforms * sizeof (IKEV2_TRANSFORM_DATA)
1882                               );
1883  if (SaData == NULL) {
1884    Status = EFI_OUT_OF_RESOURCES;
1885    goto Exit;
1886  }
1887
1888  CopyMem (SaData, Sa, sizeof (IKEV2_SA));
1889  SaData->NumProposals        = TotalProposals;
1890  ProposalData                = (IKEV2_PROPOSAL_DATA *) (SaData + 1);
1891
1892  //
1893  // Proposal Payload
1894  //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1895  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1896  //   ! Next Payload  !   RESERVED    !         Payload Length        !
1897  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1898  //   !  Proposal #   !  Protocol-Id  !    SPI Size   !# of Transforms!
1899  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1900  //   !                        SPI (variable)                         !
1901  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1902  //
1903  for (ProposalIndex = 0, Proposal = IKEV2_SA_FIRST_PROPOSAL (Sa);
1904       ProposalIndex < TotalProposals;
1905       ProposalIndex++
1906       ) {
1907
1908    //
1909    // TODO: check ProposalId
1910    //
1911    ProposalData->ProposalIndex   = Proposal->ProposalIndex;
1912    ProposalData->ProtocolId      = Proposal->ProtocolId;
1913    if (Proposal->SpiSize == 0) {
1914      ProposalData->Spi = 0;
1915    } else {
1916      //
1917      // SpiSize == 4
1918      //
1919      Spi = AllocateZeroPool (Proposal->SpiSize);
1920      if (Spi == NULL) {
1921        Status = EFI_OUT_OF_RESOURCES;
1922        goto Exit;
1923      }
1924
1925      CopyMem (Spi, (UINT32 *) (Proposal + 1), Proposal->SpiSize);
1926      *((UINT32*) Spi) = NTOHL (*((UINT32*) Spi));
1927      ProposalData->Spi = Spi;
1928    }
1929
1930    ProposalData->NumTransforms = Proposal->NumTransforms;
1931    ProposalSize                = NTOHS (Proposal->Header.PayloadLength);
1932    ProposalRemaining           = ProposalSize;
1933    //
1934    // Transform Payload
1935    //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1936    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1937    //   ! Next Payload  !   RESERVED    !         Payload Length        !
1938    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1939    //   !Transform Type !   RESERVED    !         Transform ID          !
1940    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1941    //   !                                                               !
1942    //   ~                        SA Attributes                          ~
1943    //   !                                                               !
1944    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1945    //
1946    Transform = IKEV2_PROPOSAL_FIRST_TRANSFORM (Proposal);
1947    for (TransformIndex = 0; TransformIndex < Proposal->NumTransforms; TransformIndex++) {
1948
1949      //
1950      // Transfer the IKEV2_TRANSFORM structure into internal IKEV2_TRANSFORM_DATA struture.
1951      //
1952      TransformData                   = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1) + TransformIndex;
1953      TransformData->TransformId      = NTOHS (Transform->TransformId);
1954      TransformData->TransformType    = Transform->TransformType;
1955      TransformSize                   = NTOHS (Transform->Header.PayloadLength);
1956      //
1957      // Check the Proposal Data is correct.
1958      //
1959      if (ProposalRemaining < TransformSize) {
1960        Status = EFI_INVALID_PARAMETER;
1961        goto Exit;
1962      }
1963
1964      //
1965      // Check if the Transform payload includes Attribution.
1966      //
1967      SaAttrRemaining = TransformSize - sizeof (IKEV2_TRANSFORM);
1968
1969      //
1970      // According to RFC 4603, currently only the Key length attribute type is
1971      // supported. For each Transform, there is only one attributeion.
1972      //
1973      if (SaAttrRemaining > 0) {
1974        if (SaAttrRemaining != sizeof (IKE_SA_ATTRIBUTE)) {
1975          Status = EFI_INVALID_PARAMETER;
1976          goto Exit;
1977        }
1978        SaAttribute                             = (IKE_SA_ATTRIBUTE *) ((IKEV2_TRANSFORM *)(Transform) + 1);
1979        TransformData->Attribute.AttrType       = (UINT16)((NTOHS (SaAttribute->AttrType))  & ~SA_ATTR_FORMAT_BIT);
1980        TransformData->Attribute.Attr.AttrValue = NTOHS (SaAttribute->Attr.AttrValue);
1981
1982        //
1983        // Currently, only supports the Key Length Attribution.
1984        //
1985        if (TransformData->Attribute.AttrType != IKEV2_ATTRIBUTE_TYPE_KEYLEN) {
1986          Status = EFI_INVALID_PARAMETER;
1987          goto Exit;
1988        }
1989      }
1990
1991      //
1992      // Move to next Transform
1993      //
1994      Transform = IKEV2_NEXT_TRANSFORM_WITH_SIZE (Transform, TransformSize);
1995    }
1996    Proposal     = IKEV2_NEXT_PROPOSAL_WITH_SIZE (Proposal, ProposalSize);
1997    ProposalData = (IKEV2_PROPOSAL_DATA *) ((UINT8 *)(ProposalData + 1) +
1998                                                ProposalData->NumTransforms *
1999                                                sizeof (IKEV2_TRANSFORM_DATA));
2000  }
2001
2002Exit:
2003  if (EFI_ERROR (Status) && SaData != NULL) {
2004    FreePool (SaData);
2005    SaData = NULL;
2006  }
2007  return SaData;
2008}
2009
2010/**
2011  General interface of payload encoding.
2012
2013  This function encodes the internal data structure into payload which
2014  is defined in RFC 4306. The IkePayload->PayloadBuf is used to store both the input
2015  payload and converted payload. Only the SA payload use the interal structure
2016  to store the attribute. Other payload use structure which is same with the RFC
2017  defined, for this kind payloads just do host order to network order change of
2018  some fields.
2019
2020  @param[in]      SessionCommon       Pointer to IKE Session Common used to encode the payload.
2021  @param[in, out] IkePayload          Pointer to IKE payload to be encoded as input, and
2022                                      store the encoded result as output.
2023
2024  @retval EFI_INVALID_PARAMETER  Meet error when encoding the SA payload.
2025  @retval EFI_SUCCESS            Encoded successfully.
2026
2027**/
2028EFI_STATUS
2029Ikev2EncodePayload (
2030  IN     UINT8               *SessionCommon,
2031  IN OUT IKE_PAYLOAD         *IkePayload
2032  )
2033{
2034  IKEV2_SA_DATA               *SaData;
2035  IKEV2_SA                    *SaPayload;
2036  IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;
2037  IKEV2_NOTIFY                *NotifyPayload;
2038  IKEV2_DELETE                *DeletePayload;
2039  IKEV2_KEY_EXCHANGE          *KeyPayload;
2040  IKEV2_TS                    *TsPayload;
2041  IKEV2_CFG_ATTRIBUTES        *CfgAttribute;
2042  UINT8                       *TsBuffer;
2043  UINT8                       Index;
2044  TRAFFIC_SELECTOR            *TrafficSelector;
2045
2046  //
2047  // Transform the Internal IKE structure to IKE payload.
2048  // Only the SA payload use the interal structure to store the attribute.
2049  // Other payload use structure which same with the RFC defined, so there is
2050  // no need to tranform them to IKE payload.
2051  //
2052  switch (IkePayload->PayloadType) {
2053  case IKEV2_PAYLOAD_TYPE_SA:
2054    //
2055    // Transform IKE_SA_DATA to IK_SA payload
2056    //
2057    SaData    = (IKEV2_SA_DATA *) IkePayload->PayloadBuf;
2058    SaPayload = Ikev2EncodeSa ((IKEV2_SESSION_COMMON *) SessionCommon, SaData);
2059
2060    if (SaPayload == NULL) {
2061      return EFI_INVALID_PARAMETER;
2062    }
2063    if (!IkePayload->IsPayloadBufExt) {
2064      FreePool (IkePayload->PayloadBuf);
2065    }
2066    IkePayload->PayloadBuf      = (UINT8 *) SaPayload;
2067    IkePayload->IsPayloadBufExt = FALSE;
2068    break;
2069
2070  case IKEV2_PAYLOAD_TYPE_NOTIFY:
2071    NotifyPayload               = (IKEV2_NOTIFY *) IkePayload->PayloadBuf;
2072    NotifyPayload->MessageType  = HTONS (NotifyPayload->MessageType);
2073    break;
2074
2075  case IKEV2_PAYLOAD_TYPE_DELETE:
2076    DeletePayload           = (IKEV2_DELETE *) IkePayload->PayloadBuf;
2077    DeletePayload->NumSpis  = HTONS (DeletePayload->NumSpis);
2078    break;
2079
2080  case IKEV2_PAYLOAD_TYPE_KE:
2081    KeyPayload              = (IKEV2_KEY_EXCHANGE *) IkePayload->PayloadBuf;
2082    KeyPayload->DhGroup     = HTONS (KeyPayload->DhGroup);
2083    break;
2084
2085  case IKEV2_PAYLOAD_TYPE_TS_INIT:
2086  case IKEV2_PAYLOAD_TYPE_TS_RSP:
2087    TsPayload = (IKEV2_TS *) IkePayload->PayloadBuf;
2088    TsBuffer  = IkePayload->PayloadBuf + sizeof (IKEV2_TS);
2089
2090    for (Index = 0; Index < TsPayload->TSNumbers; Index++) {
2091      TrafficSelector = (TRAFFIC_SELECTOR *) TsBuffer;
2092      TsBuffer        = TsBuffer + TrafficSelector->SelecorLen;
2093      //
2094      // Host order to network order
2095      //
2096      TrafficSelector->SelecorLen = HTONS (TrafficSelector->SelecorLen);
2097      TrafficSelector->StartPort  = HTONS (TrafficSelector->StartPort);
2098      TrafficSelector->EndPort    = HTONS (TrafficSelector->EndPort);
2099
2100    }
2101
2102    break;
2103
2104  case IKEV2_PAYLOAD_TYPE_CP:
2105    CfgAttribute = (IKEV2_CFG_ATTRIBUTES *)(((IKEV2_CFG *) IkePayload->PayloadBuf) + 1);
2106    CfgAttribute->AttritType  = HTONS (CfgAttribute->AttritType);
2107    CfgAttribute->ValueLength = HTONS (CfgAttribute->ValueLength);
2108
2109  case IKEV2_PAYLOAD_TYPE_ID_INIT:
2110  case IKEV2_PAYLOAD_TYPE_ID_RSP:
2111  case IKEV2_PAYLOAD_TYPE_AUTH:
2112  default:
2113    break;
2114  }
2115
2116  PayloadHdr  = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePayload->PayloadBuf;
2117  IkePayload->PayloadSize = PayloadHdr->PayloadLength;
2118  PayloadHdr->PayloadLength = HTONS (PayloadHdr->PayloadLength);
2119  IKEV2_DUMP_PAYLOAD (IkePayload);
2120  return EFI_SUCCESS;
2121}
2122
2123/**
2124  The general interface for decoding Payload.
2125
2126  This function converts the received Payload into internal structure.
2127
2128  @param[in]      SessionCommon     Pointer to IKE Session Common used for decoding.
2129  @param[in, out] IkePayload        Pointer to IKE payload to be decoded as input, and
2130                                    store the decoded result as output.
2131
2132  @retval EFI_INVALID_PARAMETER  Meet error when decoding the SA payload.
2133  @retval EFI_SUCCESS            Decoded successfully.
2134
2135**/
2136EFI_STATUS
2137Ikev2DecodePayload (
2138  IN     UINT8       *SessionCommon,
2139  IN OUT IKE_PAYLOAD *IkePayload
2140  )
2141{
2142  IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;
2143  UINT16                      PayloadSize;
2144  UINT8                       PayloadType;
2145  IKEV2_SA_DATA               *SaData;
2146  EFI_STATUS                  Status;
2147  IKEV2_NOTIFY                *NotifyPayload;
2148  IKEV2_DELETE                *DeletePayload;
2149  UINT16                      TsTotalSize;
2150  TRAFFIC_SELECTOR            *TsSelector;
2151  IKEV2_TS                    *TsPayload;
2152  IKEV2_KEY_EXCHANGE          *KeyPayload;
2153  IKEV2_CFG_ATTRIBUTES        *CfgAttribute;
2154  UINT8                       Index;
2155
2156  //
2157  // Transform the IKE payload to Internal IKE structure.
2158  // Only the SA payload and Hash Payload use the interal
2159  // structure to store the attribute. Other payloads use
2160  // structure which is same with the definitions in RFC,
2161  // so there is no need to tranform them to internal IKE
2162  // structure.
2163  //
2164  Status      = EFI_SUCCESS;
2165  PayloadSize = (UINT16) IkePayload->PayloadSize;
2166  PayloadType = IkePayload->PayloadType;
2167  PayloadHdr  = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePayload->PayloadBuf;
2168  //
2169  // The PayloadSize is the size of whole payload.
2170  // Replace HTONS operation to assignment statements, since the result is same.
2171  //
2172  PayloadHdr->PayloadLength = PayloadSize;
2173
2174  IKEV2_DUMP_PAYLOAD (IkePayload);
2175  switch (PayloadType) {
2176  case IKEV2_PAYLOAD_TYPE_SA:
2177    if (PayloadSize < sizeof (IKEV2_SA)) {
2178      Status = EFI_INVALID_PARAMETER;
2179      goto Exit;
2180    }
2181
2182    SaData = Ikev2DecodeSa ((IKEV2_SESSION_COMMON *) SessionCommon, (IKEV2_SA *) PayloadHdr);
2183    if (SaData == NULL) {
2184      Status = EFI_INVALID_PARAMETER;
2185      goto Exit;
2186    }
2187
2188    if (!IkePayload->IsPayloadBufExt) {
2189      FreePool (IkePayload->PayloadBuf);
2190    }
2191
2192    IkePayload->PayloadBuf      = (UINT8 *) SaData;
2193    IkePayload->IsPayloadBufExt = FALSE;
2194    break;
2195
2196  case IKEV2_PAYLOAD_TYPE_ID_INIT:
2197  case IKEV2_PAYLOAD_TYPE_ID_RSP :
2198    if (PayloadSize < sizeof (IKEV2_ID)) {
2199      Status = EFI_INVALID_PARAMETER;
2200      goto Exit;
2201    }
2202    break;
2203
2204  case IKEV2_PAYLOAD_TYPE_NOTIFY:
2205    if (PayloadSize < sizeof (IKEV2_NOTIFY)) {
2206      Status = EFI_INVALID_PARAMETER;
2207      goto Exit;
2208    }
2209
2210    NotifyPayload               = (IKEV2_NOTIFY *) PayloadHdr;
2211    NotifyPayload->MessageType  = NTOHS (NotifyPayload->MessageType);
2212    break;
2213
2214  case IKEV2_PAYLOAD_TYPE_DELETE:
2215    if (PayloadSize < sizeof (IKEV2_DELETE)) {
2216      Status = EFI_INVALID_PARAMETER;
2217      goto Exit;
2218    }
2219
2220    DeletePayload           = (IKEV2_DELETE *) PayloadHdr;
2221    DeletePayload->NumSpis  = NTOHS (DeletePayload->NumSpis);
2222    break;
2223
2224  case IKEV2_PAYLOAD_TYPE_AUTH:
2225    if (PayloadSize < sizeof (IKEV2_AUTH)) {
2226      Status = EFI_INVALID_PARAMETER;
2227      goto Exit;
2228    }
2229    break;
2230
2231  case IKEV2_PAYLOAD_TYPE_KE:
2232    KeyPayload              = (IKEV2_KEY_EXCHANGE *) IkePayload->PayloadBuf;
2233    KeyPayload->DhGroup     = HTONS (KeyPayload->DhGroup);
2234    break;
2235
2236  case IKEV2_PAYLOAD_TYPE_TS_INIT:
2237  case IKEV2_PAYLOAD_TYPE_TS_RSP :
2238    TsTotalSize = 0;
2239    if (PayloadSize < sizeof (IKEV2_TS)) {
2240      Status = EFI_INVALID_PARAMETER;
2241      goto Exit;
2242    }
2243    //
2244    // Parse each traffic selector and transfer network-order to host-order
2245    //
2246    TsPayload   = (IKEV2_TS *) IkePayload->PayloadBuf;
2247    TsSelector  = (TRAFFIC_SELECTOR *) (IkePayload->PayloadBuf + sizeof (IKEV2_TS));
2248
2249    for (Index = 0; Index < TsPayload->TSNumbers; Index++) {
2250      TsSelector->SelecorLen  = NTOHS (TsSelector->SelecorLen);
2251      TsSelector->StartPort   = NTOHS (TsSelector->StartPort);
2252      TsSelector->EndPort     = NTOHS (TsSelector->EndPort);
2253
2254      TsTotalSize             = (UINT16) (TsTotalSize + TsSelector->SelecorLen);
2255      TsSelector              = (TRAFFIC_SELECTOR *) ((UINT8 *) TsSelector + TsSelector->SelecorLen);
2256    }
2257    //
2258    // Check if the total size of Traffic Selectors is correct.
2259    //
2260    if (TsTotalSize != PayloadSize - sizeof(IKEV2_TS)) {
2261      Status = EFI_INVALID_PARAMETER;
2262    }
2263
2264  case IKEV2_PAYLOAD_TYPE_CP:
2265    CfgAttribute = (IKEV2_CFG_ATTRIBUTES *)(((IKEV2_CFG *) IkePayload->PayloadBuf) + 1);
2266    CfgAttribute->AttritType  = NTOHS (CfgAttribute->AttritType);
2267    CfgAttribute->ValueLength = NTOHS (CfgAttribute->ValueLength);
2268
2269  default:
2270    break;
2271  }
2272
2273 Exit:
2274  return Status;
2275}
2276
2277/**
2278  Decode the IKE packet.
2279
2280  This function first decrypts the IKE packet if needed , then separates the whole
2281  IKE packet from the IkePacket->PayloadBuf into IkePacket payload list.
2282
2283  @param[in]      SessionCommon          Pointer to IKEV1_SESSION_COMMON containing
2284                                         some parameter used by IKE packet decoding.
2285  @param[in, out] IkePacket              The IKE Packet to be decoded on input, and
2286                                         the decoded result on return.
2287  @param[in]      IkeType                The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
2288                                         IKE_CHILD_TYPE are supported.
2289
2290  @retval         EFI_SUCCESS            The IKE packet is decoded successfully.
2291  @retval         Otherwise              The IKE packet decoding is failed.
2292
2293**/
2294EFI_STATUS
2295Ikev2DecodePacket (
2296  IN     IKEV2_SESSION_COMMON  *SessionCommon,
2297  IN OUT IKE_PACKET            *IkePacket,
2298  IN     UINTN                 IkeType
2299  )
2300{
2301  EFI_STATUS                  Status;
2302  IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;
2303  UINT8                       PayloadType;
2304  UINTN                       RemainBytes;
2305  UINT16                      PayloadSize;
2306  IKE_PAYLOAD                 *IkePayload;
2307  IKE_HEADER                  *IkeHeader;
2308  IKEV2_SA_SESSION            *IkeSaSession;
2309
2310  IkeHeader = NULL;
2311
2312  //
2313  // Check if the IkePacket need decrypt.
2314  //
2315  if (SessionCommon->State >= IkeStateAuth) {
2316    Status = Ikev2DecryptPacket (SessionCommon, IkePacket, IkeType);
2317    if (EFI_ERROR (Status)) {
2318      return Status;
2319    }
2320  }
2321
2322  Status = EFI_SUCCESS;
2323
2324  //
2325  // If the IkePacket doesn't contain any payload return invalid parameter.
2326  //
2327  if (IkePacket->Header->NextPayload == IKEV2_PAYLOAD_TYPE_NONE) {
2328    if ((SessionCommon->State >= IkeStateAuth) &&
2329        (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INFO)
2330        ) {
2331      //
2332      // If it is Liveness check, there will be no payload load in the encrypt payload.
2333      //
2334      Status = EFI_SUCCESS;
2335    } else {
2336      Status = EFI_INVALID_PARAMETER;
2337    }
2338  }
2339
2340  //
2341  // If the PayloadTotalSize < Header length, return invalid parameter.
2342  //
2343  RemainBytes = IkePacket->PayloadTotalSize;
2344  if (RemainBytes < sizeof (IKEV2_COMMON_PAYLOAD_HEADER)) {
2345    Status = EFI_INVALID_PARAMETER;
2346    goto Exit;
2347  }
2348
2349  //
2350  // If the packet is first or second message, store whole message in
2351  // IkeSa->InitiPacket or IkeSa->RespPacket for following Auth Payload
2352  // calculate.
2353  //
2354  if (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INIT) {
2355    IkeHeader = AllocateZeroPool (sizeof (IKE_HEADER));
2356    if (IkeHeader == NULL) {
2357      Status = EFI_OUT_OF_RESOURCES;
2358      goto Exit;
2359    }
2360
2361    CopyMem (IkeHeader, IkePacket->Header, sizeof (IKE_HEADER));
2362
2363    //
2364    // Before store the whole packet, roll back the host order to network order,
2365    // since the header order was changed in the IkePacketFromNetbuf.
2366    //
2367    IkeHdrNetToHost (IkeHeader);
2368    IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
2369    if (SessionCommon->IsInitiator) {
2370      IkeSaSession->RespPacket     = AllocateZeroPool (IkePacket->Header->Length);
2371      if (IkeSaSession->RespPacket == NULL) {
2372        Status = EFI_OUT_OF_RESOURCES;
2373        goto Exit;
2374      }
2375      IkeSaSession->RespPacketSize = IkePacket->Header->Length;
2376      CopyMem (IkeSaSession->RespPacket, IkeHeader, sizeof (IKE_HEADER));
2377      CopyMem (
2378        IkeSaSession->RespPacket + sizeof (IKE_HEADER),
2379        IkePacket->PayloadsBuf,
2380        IkePacket->Header->Length - sizeof (IKE_HEADER)
2381        );
2382    } else {
2383      IkeSaSession->InitPacket     = AllocateZeroPool (IkePacket->Header->Length);
2384      if (IkeSaSession->InitPacket == NULL) {
2385        Status = EFI_OUT_OF_RESOURCES;
2386        goto Exit;
2387      }
2388      IkeSaSession->InitPacketSize = IkePacket->Header->Length;
2389      CopyMem (IkeSaSession->InitPacket, IkeHeader, sizeof (IKE_HEADER));
2390      CopyMem (
2391        IkeSaSession->InitPacket + sizeof (IKE_HEADER),
2392        IkePacket->PayloadsBuf,
2393        IkePacket->Header->Length - sizeof (IKE_HEADER)
2394        );
2395    }
2396  }
2397
2398  //
2399  // Point to the first Payload
2400  //
2401  PayloadHdr  = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePacket->PayloadsBuf;
2402  PayloadType = IkePacket->Header->NextPayload;
2403
2404  //
2405  // Parse each payload
2406  //
2407  while (RemainBytes >= sizeof (IKEV2_COMMON_PAYLOAD_HEADER)) {
2408    PayloadSize = NTOHS (PayloadHdr->PayloadLength);
2409
2410    //
2411    //Check the size of the payload is correct.
2412    //
2413    if (RemainBytes < PayloadSize) {
2414      Status = EFI_INVALID_PARAMETER;
2415      goto Exit;
2416    }
2417
2418    //
2419    // At certain states, it should save some datas before decoding.
2420    //
2421    if (SessionCommon->BeforeDecodePayload != NULL) {
2422      SessionCommon->BeforeDecodePayload (
2423                       (UINT8 *) SessionCommon,
2424                       (UINT8 *) PayloadHdr,
2425                       PayloadSize,
2426                       PayloadType
2427                       );
2428    }
2429
2430    //
2431    // Initial IkePayload
2432    //
2433    IkePayload = IkePayloadAlloc ();
2434    if (IkePayload == NULL) {
2435      Status = EFI_OUT_OF_RESOURCES;
2436      goto Exit;
2437    }
2438
2439    IkePayload->PayloadType     = PayloadType;
2440    IkePayload->PayloadBuf      = (UINT8 *) PayloadHdr;
2441    IkePayload->PayloadSize     = PayloadSize;
2442    IkePayload->IsPayloadBufExt = TRUE;
2443
2444    Status = Ikev2DecodePayload ((UINT8 *) SessionCommon, IkePayload);
2445    if (EFI_ERROR (Status)) {
2446      goto Exit;
2447    }
2448
2449    IPSEC_DUMP_BUF ("After Decoding Payload", IkePayload->PayloadBuf, IkePayload->PayloadSize);
2450    //
2451    // Add each payload into packet
2452    // Notice, the IkePacket->Hdr->Lenght still recode the whole IkePacket length
2453    // which is before the decoding.
2454    //
2455    IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
2456
2457    RemainBytes -= PayloadSize;
2458    PayloadType  = PayloadHdr->NextPayload;
2459    if (PayloadType == IKEV2_PAYLOAD_TYPE_NONE) {
2460      break;
2461    }
2462
2463    PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) ((UINT8 *) PayloadHdr + PayloadSize);
2464  }
2465
2466  if (PayloadType != IKEV2_PAYLOAD_TYPE_NONE) {
2467    Status = EFI_INVALID_PARAMETER;
2468    goto Exit;
2469  }
2470
2471Exit:
2472  if (EFI_ERROR (Status)) {
2473    ClearAllPayloads (IkePacket);
2474  }
2475
2476  if (IkeHeader != NULL) {
2477    FreePool (IkeHeader);
2478  }
2479  return Status;
2480}
2481
2482/**
2483  Encode the IKE packet.
2484
2485  This function puts all Payloads into one payload then encrypt it if needed.
2486
2487  @param[in]      SessionCommon      Pointer to IKEV2_SESSION_COMMON containing
2488                                     some parameter used during IKE packet encoding.
2489  @param[in, out] IkePacket          Pointer to IKE_PACKET to be encoded as input,
2490                                     and the encoded result as output.
2491  @param[in]      IkeType            The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
2492                                     IKE_CHILD_TYPE are supportted.
2493
2494  @retval         EFI_SUCCESS        Encode IKE packet successfully.
2495  @retval         Otherwise          Encode IKE packet failed.
2496
2497**/
2498EFI_STATUS
2499Ikev2EncodePacket (
2500  IN     IKEV2_SESSION_COMMON *SessionCommon,
2501  IN OUT IKE_PACKET           *IkePacket,
2502  IN     UINTN                IkeType
2503  )
2504{
2505  IKE_PAYLOAD       *IkePayload;
2506  UINTN             PayloadTotalSize;
2507  LIST_ENTRY        *Entry;
2508  EFI_STATUS        Status;
2509  IKEV2_SA_SESSION  *IkeSaSession;
2510
2511  PayloadTotalSize = 0;
2512  //
2513  // Encode each payload
2514  //
2515  for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {
2516    IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);
2517    Entry       = Entry->ForwardLink;
2518    Status      = Ikev2EncodePayload ((UINT8 *) SessionCommon, IkePayload);
2519    if (EFI_ERROR (Status)) {
2520      return Status;
2521    }
2522
2523    if (SessionCommon->AfterEncodePayload != NULL) {
2524      //
2525      // For certain states, save some payload for further calculation
2526      //
2527      SessionCommon->AfterEncodePayload (
2528                      (UINT8 *) SessionCommon,
2529                      IkePayload->PayloadBuf,
2530                      IkePayload->PayloadSize,
2531                      IkePayload->PayloadType
2532                      );
2533    }
2534
2535    PayloadTotalSize += IkePayload->PayloadSize;
2536  }
2537  IkePacket->PayloadTotalSize = PayloadTotalSize;
2538
2539  Status = EFI_SUCCESS;
2540  if (SessionCommon->State >= IkeStateAuth) {
2541    //
2542    // Encrypt all payload and transfer IKE packet header from Host order to Network order.
2543    //
2544    Status = Ikev2EncryptPacket (SessionCommon, IkePacket);
2545    if (EFI_ERROR (Status)) {
2546      return Status;
2547    }
2548  } else {
2549    //
2550    // Fill in the lenght into IkePacket header and transfer Host order to Network order.
2551    //
2552    IkePacket->Header->Length = (UINT32) (sizeof (IKE_HEADER) + IkePacket->PayloadTotalSize);
2553    IkeHdrHostToNet (IkePacket->Header);
2554  }
2555
2556  //
2557  // If the packet is first message, store whole message in IkeSa->InitiPacket
2558  // for following Auth Payload calculation.
2559  //
2560  if (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INIT) {
2561    IkeSaSession =  IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
2562    if (SessionCommon->IsInitiator) {
2563      IkeSaSession->InitPacketSize = IkePacket->PayloadTotalSize + sizeof (IKE_HEADER);
2564      IkeSaSession->InitPacket     = AllocateZeroPool (IkeSaSession->InitPacketSize);
2565      if (IkeSaSession->InitPacket == NULL) {
2566        return EFI_OUT_OF_RESOURCES;
2567      }
2568
2569      CopyMem (IkeSaSession->InitPacket, IkePacket->Header, sizeof (IKE_HEADER));
2570      PayloadTotalSize = 0;
2571      for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {
2572        IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);
2573        Entry       = Entry->ForwardLink;
2574        CopyMem (
2575          IkeSaSession->InitPacket + sizeof (IKE_HEADER) + PayloadTotalSize,
2576          IkePayload->PayloadBuf,
2577          IkePayload->PayloadSize
2578          );
2579        PayloadTotalSize = PayloadTotalSize + IkePayload->PayloadSize;
2580      }
2581    } else {
2582      IkeSaSession->RespPacketSize = IkePacket->PayloadTotalSize + sizeof(IKE_HEADER);
2583      IkeSaSession->RespPacket     = AllocateZeroPool (IkeSaSession->RespPacketSize);
2584      if (IkeSaSession->RespPacket == NULL) {
2585        return EFI_OUT_OF_RESOURCES;
2586      }
2587
2588      CopyMem (IkeSaSession->RespPacket, IkePacket->Header, sizeof (IKE_HEADER));
2589      PayloadTotalSize = 0;
2590      for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {
2591        IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);
2592        Entry       = Entry->ForwardLink;
2593
2594        CopyMem (
2595          IkeSaSession->RespPacket + sizeof (IKE_HEADER) + PayloadTotalSize,
2596          IkePayload->PayloadBuf,
2597          IkePayload->PayloadSize
2598          );
2599        PayloadTotalSize = PayloadTotalSize + IkePayload->PayloadSize;
2600      }
2601    }
2602  }
2603
2604  return Status;
2605}
2606
2607/**
2608  Decrypt IKE packet.
2609
2610  This function decrypts the Encrypted IKE packet and put the result into IkePacket->PayloadBuf.
2611
2612  @param[in]      SessionCommon       Pointer to IKEV2_SESSION_COMMON containing
2613                                      some parameter used during decrypting.
2614  @param[in, out] IkePacket           Pointer to IKE_PACKET to be decrypted as input,
2615                                      and the decrypted result as output.
2616  @param[in, out] IkeType             The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
2617                                      IKE_CHILD_TYPE are supportted.
2618
2619  @retval EFI_INVALID_PARAMETER      If the IKE packet length is zero or the
2620                                     IKE packet length is not aligned with Algorithm Block Size
2621  @retval EFI_SUCCESS                Decrypt IKE packet successfully.
2622
2623**/
2624EFI_STATUS
2625Ikev2DecryptPacket (
2626  IN     IKEV2_SESSION_COMMON *SessionCommon,
2627  IN OUT IKE_PACKET           *IkePacket,
2628  IN OUT UINTN                IkeType
2629  )
2630{
2631  UINT8                  CryptBlockSize;      // Encrypt Block Size
2632  UINTN                  DecryptedSize;       // Encrypted IKE Payload Size
2633  UINT8                  *DecryptedBuf;       // Encrypted IKE Payload buffer
2634  UINTN                  IntegritySize;
2635  UINT8                  *IntegrityBuffer;
2636  UINTN                  IvSize;              // Iv Size
2637  UINT8                  CheckSumSize;        // Integrity Check Sum Size depends on intergrity Auth
2638  UINT8                  *CheckSumData;       // Check Sum data
2639  IKEV2_SA_SESSION       *IkeSaSession;
2640  IKEV2_CHILD_SA_SESSION *ChildSaSession;
2641  EFI_STATUS             Status;
2642  UINT8                  PadLen;
2643  HASH_DATA_FRAGMENT     Fragments[1];
2644
2645  IvSize         = 0;
2646  IkeSaSession   = NULL;
2647  CryptBlockSize = 0;
2648  CheckSumSize   = 0;
2649
2650  //
2651  // Check if the first payload is the Encrypted payload
2652  //
2653  if (IkePacket->Header->NextPayload != IKEV2_PAYLOAD_TYPE_ENCRYPT) {
2654    return EFI_ACCESS_DENIED;
2655  }
2656  CheckSumData    = NULL;
2657  DecryptedBuf    = NULL;
2658  IntegrityBuffer = NULL;
2659
2660  //
2661  // Get the Block Size
2662  //
2663  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
2664
2665    CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) SessionCommon->SaParams->EncAlgId);
2666
2667    CheckSumSize   = (UINT8) IpSecGetIcvLength ((UINT8) SessionCommon->SaParams->IntegAlgId);
2668    IkeSaSession   = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
2669
2670  } else if (SessionCommon->IkeSessionType == IkeSessionTypeChildSa) {
2671
2672    ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);
2673    IkeSaSession   = ChildSaSession->IkeSaSession;
2674    CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId);
2675    CheckSumSize   = (UINT8) IpSecGetIcvLength ((UINT8) IkeSaSession->SessionCommon.SaParams->IntegAlgId);
2676  } else {
2677    //
2678    // The type of SA Session would either be IkeSa or ChildSa.
2679    //
2680    return EFI_INVALID_PARAMETER;
2681  }
2682
2683  CheckSumData = AllocateZeroPool (CheckSumSize);
2684  if (CheckSumData == NULL) {
2685    Status = EFI_OUT_OF_RESOURCES;
2686    goto ON_EXIT;
2687  }
2688
2689  //
2690  // Fill in the Integrity buffer
2691  //
2692  IntegritySize   = IkePacket->PayloadTotalSize + sizeof (IKE_HEADER);
2693  IntegrityBuffer = AllocateZeroPool (IntegritySize);
2694  if (IntegrityBuffer == NULL) {
2695    Status = EFI_OUT_OF_RESOURCES;
2696    goto ON_EXIT;
2697  }
2698
2699  CopyMem (IntegrityBuffer, IkePacket->Header, sizeof(IKE_HEADER));
2700  CopyMem (IntegrityBuffer + sizeof (IKE_HEADER), IkePacket->PayloadsBuf, IkePacket->PayloadTotalSize);
2701
2702  //
2703  // Change Host order to Network order, since the header order was changed
2704  // in the IkePacketFromNetbuf.
2705  //
2706  IkeHdrHostToNet ((IKE_HEADER *)IntegrityBuffer);
2707
2708  //
2709  // Calculate the Integrity CheckSum Data
2710  //
2711  Fragments[0].Data     = IntegrityBuffer;
2712  Fragments[0].DataSize = IntegritySize - CheckSumSize;
2713
2714  if (SessionCommon->IsInitiator) {
2715    Status = IpSecCryptoIoHmac (
2716               (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
2717               IkeSaSession->IkeKeys->SkArKey,
2718               IkeSaSession->IkeKeys->SkArKeySize,
2719               (HASH_DATA_FRAGMENT *) Fragments,
2720               1,
2721               CheckSumData,
2722               CheckSumSize
2723               );
2724  } else {
2725    Status = IpSecCryptoIoHmac (
2726               (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
2727               IkeSaSession->IkeKeys->SkAiKey,
2728               IkeSaSession->IkeKeys->SkAiKeySize,
2729               (HASH_DATA_FRAGMENT *) Fragments,
2730               1,
2731               CheckSumData,
2732               CheckSumSize
2733               );
2734  }
2735
2736  if (EFI_ERROR (Status)) {
2737    goto ON_EXIT;
2738  }
2739  //
2740  // Compare the Integrity CheckSum Data with the one in IkePacket
2741  //
2742  if (CompareMem (
2743        IkePacket->PayloadsBuf + IkePacket->PayloadTotalSize - CheckSumSize,
2744        CheckSumData,
2745        CheckSumSize
2746        ) != 0) {
2747    DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));
2748    Status = EFI_ACCESS_DENIED;
2749    goto ON_EXIT;
2750  }
2751
2752  IvSize = CryptBlockSize;
2753
2754  //
2755  // Decrypt the payload with the key.
2756  //
2757  DecryptedSize = IkePacket->PayloadTotalSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER) - IvSize - CheckSumSize;
2758  DecryptedBuf  = AllocateZeroPool (DecryptedSize);
2759  if (DecryptedBuf == NULL) {
2760    Status = EFI_OUT_OF_RESOURCES;
2761    goto ON_EXIT;
2762  }
2763
2764  CopyMem (
2765    DecryptedBuf,
2766    IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER) + IvSize,
2767    DecryptedSize
2768    );
2769
2770  if (SessionCommon->IsInitiator) {
2771   Status = IpSecCryptoIoDecrypt (
2772              (UINT8) SessionCommon->SaParams->EncAlgId,
2773              IkeSaSession->IkeKeys->SkErKey,
2774              IkeSaSession->IkeKeys->SkErKeySize << 3,
2775              IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
2776              DecryptedBuf,
2777              DecryptedSize,
2778              DecryptedBuf
2779              );
2780  } else {
2781    Status = IpSecCryptoIoDecrypt (
2782               (UINT8) SessionCommon->SaParams->EncAlgId,
2783               IkeSaSession->IkeKeys->SkEiKey,
2784               IkeSaSession->IkeKeys->SkEiKeySize << 3,
2785               IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
2786               DecryptedBuf,
2787               DecryptedSize,
2788               DecryptedBuf
2789               );
2790  }
2791
2792  if (EFI_ERROR (Status)) {
2793    DEBUG ((DEBUG_ERROR, "Error decrypt buffer with %r\n", Status));
2794    goto ON_EXIT;
2795  }
2796
2797  //
2798  // Get the Padding length
2799  //
2800  //
2801  PadLen = (UINT8) (*(DecryptedBuf + DecryptedSize - sizeof (IKEV2_PAD_LEN)));
2802
2803  //
2804  // Save the next payload of encrypted payload into IkePacket->Hdr->NextPayload
2805  //
2806  IkePacket->Header->NextPayload = ((IKEV2_ENCRYPTED *) IkePacket->PayloadsBuf)->Header.NextPayload;
2807
2808  //
2809  // Free old IkePacket->PayloadBuf and point it to decrypted paylaod buffer.
2810  //
2811  FreePool (IkePacket->PayloadsBuf);
2812  IkePacket->PayloadsBuf      = DecryptedBuf;
2813  IkePacket->PayloadTotalSize = DecryptedSize - PadLen;
2814
2815  IPSEC_DUMP_BUF ("Decrypted Buffer", DecryptedBuf, DecryptedSize);
2816
2817
2818ON_EXIT:
2819  if (CheckSumData != NULL) {
2820    FreePool (CheckSumData);
2821  }
2822
2823  if (EFI_ERROR (Status) && DecryptedBuf != NULL) {
2824    FreePool (DecryptedBuf);
2825  }
2826
2827  if (IntegrityBuffer != NULL) {
2828    FreePool (IntegrityBuffer);
2829  }
2830
2831  return Status;
2832}
2833
2834/**
2835  Encrypt IKE packet.
2836
2837  This function encrypt IKE packet before sending it. The Encrypted IKE packet
2838  is put in to IKEV2 Encrypted Payload.
2839
2840  @param[in]        SessionCommon     Pointer to IKEV2_SESSION_COMMON related to the IKE packet.
2841  @param[in, out]   IkePacket         Pointer to IKE packet to be encrypted.
2842
2843  @retval      EFI_SUCCESS       Operation is successful.
2844  @retval      Others            Operation is failed.
2845
2846**/
2847EFI_STATUS
2848Ikev2EncryptPacket (
2849  IN IKEV2_SESSION_COMMON *SessionCommon,
2850  IN OUT IKE_PACKET       *IkePacket
2851  )
2852{
2853  UINT8                  CryptBlockSize;      // Encrypt Block Size
2854  UINT8                  CryptBlockSizeMask;  // Block Mask
2855  UINTN                  EncryptedSize;       // Encrypted IKE Payload Size
2856  UINT8                  *EncryptedBuf;       // Encrypted IKE Payload buffer
2857  UINT8                  *EncryptPayloadBuf;  // Contain whole Encrypted Payload
2858  UINTN                  EncryptPayloadSize;  // Total size of the Encrypted payload
2859  UINT8                  *IntegrityBuf;       // Buffer to be intergity
2860  UINT8                  *IvBuffer;           // Initialization Vector
2861  UINT8                  IvSize;              // Iv Size
2862  UINT8                  CheckSumSize;        // Integrity Check Sum Size depends on intergrity Auth
2863  UINT8                  *CheckSumData;       // Check Sum data
2864  UINTN                  Index;
2865  IKE_PAYLOAD            *EncryptPayload;
2866  IKEV2_SA_SESSION       *IkeSaSession;
2867  IKEV2_CHILD_SA_SESSION *ChildSaSession;
2868  EFI_STATUS             Status;
2869  LIST_ENTRY             *Entry;
2870  IKE_PAYLOAD            *IkePayload;
2871  HASH_DATA_FRAGMENT     Fragments[1];
2872
2873  Status = EFI_SUCCESS;
2874
2875  //
2876  // Initial all buffers to NULL.
2877  //
2878  EncryptedBuf      = NULL;
2879  EncryptPayloadBuf = NULL;
2880  IvBuffer          = NULL;
2881  CheckSumData      = NULL;
2882  IkeSaSession      = NULL;
2883  CryptBlockSize    = 0;
2884  CheckSumSize      = 0;
2885  IntegrityBuf      = NULL;
2886  //
2887  // Get the Block Size
2888  //
2889  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
2890
2891    CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) SessionCommon->SaParams->EncAlgId);
2892    CheckSumSize   = (UINT8) IpSecGetIcvLength ((UINT8) SessionCommon->SaParams->IntegAlgId);
2893    IkeSaSession   = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
2894
2895  } else if (SessionCommon->IkeSessionType == IkeSessionTypeChildSa) {
2896
2897    ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);
2898    IkeSaSession   = ChildSaSession->IkeSaSession;
2899    CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId);
2900    CheckSumSize   = (UINT8) IpSecGetIcvLength ((UINT8) IkeSaSession->SessionCommon.SaParams->IntegAlgId);
2901  }
2902
2903  //
2904  // Calcualte the EncryptPayloadSize and the PAD length
2905  //
2906  CryptBlockSizeMask  = (UINT8) (CryptBlockSize - 1);
2907  EncryptedSize       = (IkePacket->PayloadTotalSize + sizeof (IKEV2_PAD_LEN) + CryptBlockSizeMask) & ~CryptBlockSizeMask;
2908  EncryptedBuf        = (UINT8 *) AllocateZeroPool (EncryptedSize);
2909  if (EncryptedBuf == NULL) {
2910    Status = EFI_OUT_OF_RESOURCES;
2911    goto ON_EXIT;
2912  }
2913
2914  //
2915  // Copy all payload into EncryptedIkePayload
2916  //
2917  Index = 0;
2918  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
2919    IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
2920
2921    CopyMem (EncryptedBuf + Index, IkePayload->PayloadBuf, IkePayload->PayloadSize);
2922    Index += IkePayload->PayloadSize;
2923
2924  };
2925
2926  //
2927  // Fill in the Pading Length
2928  //
2929  *(EncryptedBuf + EncryptedSize - 1) = (UINT8)(EncryptedSize - IkePacket->PayloadTotalSize - 1);
2930
2931  //
2932  // The IV size is equal with block size
2933  //
2934  IvSize    = CryptBlockSize;
2935  IvBuffer  = (UINT8 *) AllocateZeroPool (IvSize);
2936  if (IvBuffer == NULL) {
2937    Status = EFI_OUT_OF_RESOURCES;
2938    goto ON_EXIT;
2939  }
2940
2941  //
2942  // Generate IV
2943  //
2944  IkeGenerateIv (IvBuffer, IvSize);
2945
2946  //
2947  // Encrypt payload buf
2948  //
2949  if (SessionCommon->IsInitiator) {
2950    Status = IpSecCryptoIoEncrypt (
2951               (UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId,
2952               IkeSaSession->IkeKeys->SkEiKey,
2953               IkeSaSession->IkeKeys->SkEiKeySize << 3,
2954               IvBuffer,
2955               EncryptedBuf,
2956               EncryptedSize,
2957               EncryptedBuf
2958               );
2959  } else {
2960    Status = IpSecCryptoIoEncrypt (
2961               (UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId,
2962               IkeSaSession->IkeKeys->SkErKey,
2963               IkeSaSession->IkeKeys->SkErKeySize << 3,
2964               IvBuffer,
2965               EncryptedBuf,
2966               EncryptedSize,
2967               EncryptedBuf
2968               );
2969  }
2970  if (EFI_ERROR (Status)) {
2971    goto ON_EXIT;
2972  }
2973
2974  //
2975  // Allocate the buffer for the whole IKE payload (Encrypted Payload).
2976  //
2977  EncryptPayloadSize = sizeof(IKEV2_ENCRYPTED) + IvSize + EncryptedSize + CheckSumSize;
2978  EncryptPayloadBuf  = AllocateZeroPool (EncryptPayloadSize);
2979  if (EncryptPayloadBuf == NULL) {
2980    Status = EFI_OUT_OF_RESOURCES;
2981    goto ON_EXIT;
2982  }
2983
2984  //
2985  // Fill in Header of  Encrypted Payload
2986  //
2987  ((IKEV2_ENCRYPTED *) EncryptPayloadBuf)->Header.NextPayload   = IkePacket->Header->NextPayload;
2988  ((IKEV2_ENCRYPTED *) EncryptPayloadBuf)->Header.PayloadLength = HTONS ((UINT16)EncryptPayloadSize);
2989
2990  //
2991  // Fill in Iv
2992  //
2993  CopyMem (EncryptPayloadBuf + sizeof (IKEV2_ENCRYPTED), IvBuffer, IvSize);
2994
2995  //
2996  // Fill in encrypted data
2997  //
2998  CopyMem (EncryptPayloadBuf + sizeof (IKEV2_ENCRYPTED) + IvSize, EncryptedBuf, EncryptedSize);
2999
3000  //
3001  // Fill in the IKE Packet header
3002  //
3003  IkePacket->PayloadTotalSize    = EncryptPayloadSize;
3004  IkePacket->Header->Length      = (UINT32) (sizeof (IKE_HEADER) + IkePacket->PayloadTotalSize);
3005  IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ENCRYPT;
3006
3007  IntegrityBuf                   = AllocateZeroPool (IkePacket->Header->Length);
3008  if (IntegrityBuf == NULL) {
3009    Status = EFI_OUT_OF_RESOURCES;
3010    goto ON_EXIT;
3011  }
3012  IkeHdrHostToNet (IkePacket->Header);
3013
3014  CopyMem (IntegrityBuf, IkePacket->Header, sizeof (IKE_HEADER));
3015  CopyMem (IntegrityBuf + sizeof (IKE_HEADER), EncryptPayloadBuf, EncryptPayloadSize);
3016
3017  //
3018  // Calcualte Integrity CheckSum
3019  //
3020  Fragments[0].Data     = IntegrityBuf;
3021  Fragments[0].DataSize = EncryptPayloadSize + sizeof (IKE_HEADER) - CheckSumSize;
3022
3023  CheckSumData = AllocateZeroPool (CheckSumSize);
3024  if (CheckSumData == NULL) {
3025    Status = EFI_OUT_OF_RESOURCES;
3026    goto ON_EXIT;
3027  }
3028  if (SessionCommon->IsInitiator) {
3029
3030    IpSecCryptoIoHmac (
3031      (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
3032      IkeSaSession->IkeKeys->SkAiKey,
3033      IkeSaSession->IkeKeys->SkAiKeySize,
3034      (HASH_DATA_FRAGMENT *) Fragments,
3035      1,
3036      CheckSumData,
3037      CheckSumSize
3038      );
3039  } else {
3040
3041    IpSecCryptoIoHmac (
3042      (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
3043      IkeSaSession->IkeKeys->SkArKey,
3044      IkeSaSession->IkeKeys->SkArKeySize,
3045      (HASH_DATA_FRAGMENT *) Fragments,
3046      1,
3047      CheckSumData,
3048      CheckSumSize
3049      );
3050  }
3051
3052  //
3053  // Copy CheckSum into Encrypted Payload
3054  //
3055  CopyMem (EncryptPayloadBuf + EncryptPayloadSize - CheckSumSize, CheckSumData, CheckSumSize);
3056
3057  IPSEC_DUMP_BUF ("Encrypted payload buffer", EncryptPayloadBuf, EncryptPayloadSize);
3058  IPSEC_DUMP_BUF ("Integrith CheckSum Data", CheckSumData, CheckSumSize);
3059
3060  //
3061  // Clean all payload under IkePacket->PayloadList.
3062  //
3063  ClearAllPayloads (IkePacket);
3064
3065  //
3066  // Create Encrypted Payload and add into IkePacket->PayloadList
3067  //
3068  EncryptPayload = IkePayloadAlloc ();
3069  if (EncryptPayload == NULL) {
3070    Status = EFI_OUT_OF_RESOURCES;
3071    goto ON_EXIT;
3072  }
3073
3074  //
3075  // Fill the encrypted payload into the IKE_PAYLOAD structure.
3076  //
3077  EncryptPayload->PayloadBuf  = EncryptPayloadBuf;
3078  EncryptPayload->PayloadSize = EncryptPayloadSize;
3079  EncryptPayload->PayloadType = IKEV2_PAYLOAD_TYPE_ENCRYPT;
3080
3081  IKE_PACKET_APPEND_PAYLOAD (IkePacket, EncryptPayload);
3082
3083ON_EXIT:
3084  if (EncryptedBuf != NULL) {
3085    FreePool (EncryptedBuf);
3086  }
3087
3088  if (EFI_ERROR (Status) && EncryptPayloadBuf != NULL) {
3089    FreePool (EncryptPayloadBuf);
3090  }
3091
3092  if (IvBuffer != NULL) {
3093    FreePool (IvBuffer);
3094  }
3095
3096  if (CheckSumData != NULL) {
3097    FreePool (CheckSumData);
3098  }
3099
3100  if (IntegrityBuf != NULL) {
3101    FreePool (IntegrityBuf);
3102  }
3103
3104  return Status;
3105}
3106
3107/**
3108  Save some useful payloads after accepting the Packet.
3109
3110  @param[in] SessionCommon   Pointer to IKEV2_SESSION_COMMON related to the operation.
3111  @param[in] IkePacket       Pointer to received IkePacet.
3112  @param[in] IkeType         The type used to indicate it is in IkeSa or ChildSa or Info
3113                             exchange.
3114
3115**/
3116VOID
3117Ikev2OnPacketAccepted (
3118  IN IKEV2_SESSION_COMMON *SessionCommon,
3119  IN IKE_PACKET           *IkePacket,
3120  IN UINT8                IkeType
3121  )
3122{
3123  return;
3124}
3125
3126/**
3127
3128  The notification function. It will be called when the related UDP_TX_TOKEN's event
3129  is signaled.
3130
3131  This function frees the Net Buffer pointed to the input Packet.
3132
3133  @param[in]  Packet           Pointer to Net buffer containing the sending IKE packet.
3134  @param[in]  EndPoint         Pointer to UDP_END_POINT containing the remote and local
3135                               address information.
3136  @param[in]  IoStatus         The Status of the related UDP_TX_TOKEN.
3137  @param[in]  Context          Pointer to data passed from the caller.
3138
3139**/
3140VOID
3141EFIAPI
3142Ikev2OnPacketSent (
3143  IN NET_BUF                   *Packet,
3144  IN UDP_END_POINT             *EndPoint,
3145  IN EFI_STATUS                IoStatus,
3146  IN VOID                      *Context
3147  )
3148{
3149 IKE_PACKET             *IkePacket;
3150 IKEV2_SA_SESSION       *IkeSaSession;
3151 IKEV2_CHILD_SA_SESSION *ChildSaSession;
3152 UINT8                  Value;
3153 IPSEC_PRIVATE_DATA     *Private;
3154 EFI_STATUS             Status;
3155
3156 IkePacket  = (IKE_PACKET *) Context;
3157 Private    = NULL;
3158
3159 if (EFI_ERROR (IoStatus)) {
3160    DEBUG ((DEBUG_ERROR, "Error send the last packet in IkeSessionTypeIkeSa with %r\n", IoStatus));
3161  }
3162
3163  NetbufFree (Packet);
3164
3165  if (IkePacket->IsDeleteInfo) {
3166    //
3167    // For each RemotePeerIP, there are only one IKESA.
3168    //
3169    IkeSaSession = Ikev2SaSessionLookup (
3170                     &IkePacket->Private->Ikev2EstablishedList,
3171                     &IkePacket->RemotePeerIp
3172                     );
3173    if (IkeSaSession == NULL) {
3174      IkePacketFree (IkePacket);
3175      return;
3176    }
3177
3178    Private = IkePacket->Private;
3179    if (IkePacket->Spi != 0 ) {
3180      //
3181      // At that time, the established Child SA still in eht ChildSaEstablishSessionList.
3182      // And meanwhile, if the Child SA is in the the ChildSa in Delete list,
3183      // remove it from delete list and delete it direclty.
3184      //
3185      ChildSaSession = Ikev2ChildSaSessionLookupBySpi (
3186                         &IkeSaSession->ChildSaEstablishSessionList,
3187                         IkePacket->Spi
3188                         );
3189      if (ChildSaSession != NULL) {
3190        Ikev2ChildSaSessionRemove (
3191          &IkeSaSession->DeleteSaList,
3192          ChildSaSession->LocalPeerSpi,
3193          IKEV2_DELET_CHILDSA_LIST
3194          );
3195
3196        //
3197        // Delete the Child SA.
3198        //
3199        Ikev2ChildSaSilentDelete (
3200          IkeSaSession,
3201          IkePacket->Spi
3202          );
3203      }
3204
3205    } else {
3206      //
3207      // Delete the IKE SA
3208      //
3209      DEBUG (
3210        (DEBUG_INFO,
3211        "\n------ deleted Packet (cookie_i, cookie_r):(0x%lx, 0x%lx)------\n",
3212        IkeSaSession->InitiatorCookie,
3213        IkeSaSession->ResponderCookie)
3214        );
3215
3216      RemoveEntryList (&IkeSaSession->BySessionTable);
3217      Ikev2SaSessionFree (IkeSaSession);
3218    }
3219  }
3220  IkePacketFree (IkePacket);
3221
3222  //
3223  // when all IKE SAs were disabled by calling "IPsecConfig -disable", the IPsec status
3224  // should be changed.
3225  //
3226  if (Private != NULL && Private->IsIPsecDisabling) {
3227    //
3228    // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in
3229    // IPsec status variable.
3230    //
3231    if (IsListEmpty (&Private->Ikev1EstablishedList) && IsListEmpty (&Private->Ikev2EstablishedList)) {
3232      Value = IPSEC_STATUS_DISABLED;
3233      Status = gRT->SetVariable (
3234                 IPSECCONFIG_STATUS_NAME,
3235                 &gEfiIpSecConfigProtocolGuid,
3236                 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
3237                 sizeof (Value),
3238                 &Value
3239                 );
3240      if (!EFI_ERROR (Status)) {
3241        //
3242        // Set the DisabledFlag in Private data.
3243        //
3244        Private->IpSec.DisabledFlag = TRUE;
3245        Private->IsIPsecDisabling   = FALSE;
3246      }
3247    }
3248  }
3249}
3250
3251/**
3252  Send out IKEV2 packet.
3253
3254  @param[in]  IkeUdpService     Pointer to IKE_UDP_SERVICE used to send the IKE packet.
3255  @param[in]  SessionCommon     Pointer to IKEV1_SESSION_COMMON related to the IKE packet.
3256  @param[in]  IkePacket         Pointer to IKE_PACKET to be sent out.
3257  @param[in]  IkeType           The type of IKE to point what's kind of the IKE
3258                                packet is to be sent out. IKE_SA_TYPE, IKE_INFO_TYPE
3259                                and IKE_CHILD_TYPE are supportted.
3260
3261  @retval     EFI_SUCCESS       The operation complete successfully.
3262  @retval     Otherwise         The operation is failed.
3263
3264**/
3265EFI_STATUS
3266Ikev2SendIkePacket (
3267  IN IKE_UDP_SERVICE     *IkeUdpService,
3268  IN UINT8               *SessionCommon,
3269  IN IKE_PACKET          *IkePacket,
3270  IN UINTN               IkeType
3271  )
3272{
3273  EFI_STATUS            Status;
3274  NET_BUF               *IkePacketNetbuf;
3275  UDP_END_POINT         EndPoint;
3276  IKEV2_SESSION_COMMON  *Common;
3277
3278  Common = (IKEV2_SESSION_COMMON *) SessionCommon;
3279
3280  //
3281  // Set the resend interval
3282  //
3283  if (Common->TimeoutInterval == 0) {
3284    Common->TimeoutInterval = IKE_DEFAULT_TIMEOUT_INTERVAL;
3285  }
3286
3287  //
3288  // Retransfer the packet if it is initial packet.
3289  //
3290  if (IkePacket->Header->Flags == IKE_HEADER_FLAGS_INIT) {
3291    //
3292    // Set timer for next retry, this will cancel previous timer
3293    //
3294    Status = gBS->SetTimer (
3295                    Common->TimeoutEvent,
3296                    TimerRelative,
3297                    MultU64x32 (Common->TimeoutInterval, 10000) // ms->100ns
3298                    );
3299    if (EFI_ERROR (Status)) {
3300      return Status;
3301    }
3302  }
3303
3304  IKE_PACKET_REF (IkePacket);
3305  //
3306  // If the last sent packet is same with this round packet, the packet is resent packet.
3307  //
3308  if (IkePacket != Common->LastSentPacket && Common->LastSentPacket != NULL) {
3309    IkePacketFree (Common->LastSentPacket);
3310  }
3311
3312  Common->LastSentPacket = IkePacket;
3313
3314  //
3315  // Transform IkePacke to NetBuf
3316  //
3317  IkePacketNetbuf = IkeNetbufFromPacket ((UINT8 *) SessionCommon, IkePacket, IkeType);
3318  if (IkePacketNetbuf == NULL) {
3319    return EFI_OUT_OF_RESOURCES;
3320  }
3321
3322  ZeroMem (&EndPoint, sizeof (UDP_END_POINT));
3323  EndPoint.RemotePort = IKE_DEFAULT_PORT;
3324  CopyMem (&IkePacket->RemotePeerIp, &Common->RemotePeerIp, sizeof (EFI_IP_ADDRESS));
3325  CopyMem (&EndPoint.RemoteAddr, &Common->RemotePeerIp, sizeof (EFI_IP_ADDRESS));
3326  CopyMem (&EndPoint.LocalAddr, &Common->LocalPeerIp, sizeof (EFI_IP_ADDRESS));
3327
3328  IPSEC_DUMP_PACKET (IkePacket, EfiIPsecOutBound, IkeUdpService->IpVersion);
3329
3330  if (IkeUdpService->IpVersion == IP_VERSION_4) {
3331    EndPoint.RemoteAddr.Addr[0] = HTONL (EndPoint.RemoteAddr.Addr[0]);
3332    EndPoint.LocalAddr.Addr[0]  = HTONL (EndPoint.LocalAddr.Addr[0]);
3333  }
3334
3335  //
3336  // Call UDPIO to send out the IKE packet.
3337  //
3338  Status = UdpIoSendDatagram (
3339             IkeUdpService->Output,
3340             IkePacketNetbuf,
3341             &EndPoint,
3342             NULL,
3343             Ikev2OnPacketSent,
3344             (VOID*)IkePacket
3345             );
3346
3347  if (EFI_ERROR (Status)) {
3348    DEBUG ((DEBUG_ERROR, "Error send packet with %r\n", Status));
3349  }
3350
3351  return Status;
3352}
3353
3354