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