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