]>
Commit | Line | Data |
---|---|---|
a3bcde70 HT |
1 | /** @file\r |
2 | IPsec inbound and outbound traffic processing.\r | |
3 | \r | |
4 | Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r | |
5 | \r | |
6 | This program and the accompanying materials\r | |
7 | are licensed and made available under the terms and conditions of the BSD License\r | |
8 | which accompanies this distribution. The full text of the license may be found at\r | |
9 | http://opensource.org/licenses/bsd-license.php.\r | |
10 | \r | |
11 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
12 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
13 | \r | |
14 | **/\r | |
15 | \r | |
16 | #include "IpSecImpl.h"\r | |
17 | #include "IpSecDebug.h"\r | |
18 | #include "IpSecCryptIo.h"\r | |
19 | \r | |
20 | extern LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum];\r | |
21 | \r | |
22 | /**\r | |
23 | The call back function of NetbufFromExt.\r | |
24 | \r | |
25 | @param[in] Arg The argument passed from the caller.\r | |
26 | \r | |
27 | **/\r | |
28 | VOID\r | |
29 | EFIAPI\r | |
30 | IpSecOnRecyclePacket (\r | |
31 | IN VOID *Arg\r | |
32 | )\r | |
33 | {\r | |
34 | }\r | |
35 | \r | |
36 | /**\r | |
37 | This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP\r | |
38 | is released.\r | |
39 | \r | |
40 | @param[in] Event The related event.\r | |
41 | @param[in] Context The data passed by the caller.\r | |
42 | \r | |
43 | **/\r | |
44 | VOID\r | |
45 | EFIAPI\r | |
46 | IpSecRecycleCallback (\r | |
47 | IN EFI_EVENT Event,\r | |
48 | IN VOID *Context\r | |
49 | )\r | |
50 | {\r | |
51 | IPSEC_RECYCLE_CONTEXT *RecycleContext;\r | |
52 | \r | |
53 | RecycleContext = (IPSEC_RECYCLE_CONTEXT *) Context;\r | |
54 | \r | |
55 | if (RecycleContext->FragmentTable != NULL) {\r | |
56 | FreePool (RecycleContext->FragmentTable);\r | |
57 | }\r | |
58 | \r | |
59 | if (RecycleContext->PayloadBuffer != NULL) {\r | |
60 | FreePool (RecycleContext->PayloadBuffer);\r | |
61 | }\r | |
62 | \r | |
63 | FreePool (RecycleContext);\r | |
64 | gBS->CloseEvent (Event);\r | |
65 | \r | |
66 | }\r | |
67 | \r | |
68 | /**\r | |
69 | Calculate the extension header of IP. The return length only doesn't contain\r | |
70 | the fixed IP header length.\r | |
71 | \r | |
72 | @param[in] IpHead Points to an IP head to be calculated.\r | |
73 | @param[in] LastHead Points to the last header of the IP header.\r | |
74 | \r | |
75 | @return The length of the extension header.\r | |
76 | \r | |
77 | **/\r | |
78 | UINT16\r | |
79 | IpSecGetPlainExtHeadSize (\r | |
80 | IN VOID *IpHead,\r | |
81 | IN UINT8 *LastHead\r | |
82 | )\r | |
83 | {\r | |
84 | UINT16 Size;\r | |
85 | \r | |
86 | Size = (UINT16) (LastHead - (UINT8 *) IpHead);\r | |
87 | \r | |
88 | if (Size > sizeof (EFI_IP6_HEADER)) {\r | |
89 | //\r | |
90 | // * (LastHead+1) point the last header's length but not include the first\r | |
91 | // 8 octers, so this formluation add 8 at the end.\r | |
92 | //\r | |
93 | Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8);\r | |
94 | } else {\r | |
95 | Size = 0;\r | |
96 | }\r | |
97 | \r | |
98 | return Size;\r | |
99 | }\r | |
100 | \r | |
101 | /**\r | |
102 | Authenticate the IpSec Payload and store the result in the IcvBuffer.\r | |
103 | \r | |
104 | @param[in] BufferToAuth The buffer to be Authenticated.\r | |
105 | @param[in] AuthSize The size of the buffer to be Authenticated.\r | |
106 | @param[in, out] IcvBuffer The buffer to store the ICV.\r | |
107 | @param[in] IcvSize The size of ICV.\r | |
108 | @param[in] Key The Key passed to the CryptLib to generate a\r | |
109 | CRYPT_HANDLE.\r | |
110 | @param[in] AuthAlgId The Authentication Algorithm ID.\r | |
111 | \r | |
112 | @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list.\r | |
113 | @retval EFI_SUCCESS Authenticated the payload successfully.\r | |
114 | @retval otherwise Authentication of the payload failed.\r | |
115 | **/\r | |
116 | EFI_STATUS\r | |
117 | IpSecAuthPayload (\r | |
118 | IN UINT8 *BufferToAuth,\r | |
119 | IN UINTN AuthSize,\r | |
120 | IN OUT UINT8 *IcvBuffer,\r | |
121 | IN UINTN IcvSize,\r | |
122 | IN VOID *Key,\r | |
123 | IN UINT8 AuthAlgId\r | |
124 | )\r | |
125 | {\r | |
126 | switch (AuthAlgId) {\r | |
127 | case EFI_IPSEC_AALG_NONE :\r | |
128 | case EFI_IPSEC_AALG_NULL :\r | |
129 | return EFI_SUCCESS;\r | |
130 | \r | |
131 | default:\r | |
132 | return EFI_UNSUPPORTED;\r | |
133 | }\r | |
134 | }\r | |
135 | \r | |
136 | /**\r | |
137 | Verify if the Authentication payload is correct.\r | |
138 | \r | |
139 | @param[in] EspBuffer Points to the ESP wrapped buffer.\r | |
140 | @param[in] EspSize The size of the ESP wrapped buffer.\r | |
141 | @param[in] SadEntry The related SAD entry to store the authentication\r | |
142 | algorithm key.\r | |
143 | @param[in] IcvSize The length of ICV.\r | |
144 | \r | |
145 | @retval EFI_SUCCESS The authentication data is correct.\r | |
146 | @retval EFI_ACCESS_DENIED The authentication data is not correct.\r | |
147 | \r | |
148 | **/\r | |
149 | EFI_STATUS\r | |
150 | IpSecEspAuthVerifyPayload (\r | |
151 | IN UINT8 *EspBuffer,\r | |
152 | IN UINTN EspSize,\r | |
153 | IN IPSEC_SAD_ENTRY *SadEntry,\r | |
154 | IN UINTN *IcvSize\r | |
155 | )\r | |
156 | {\r | |
157 | EFI_STATUS Status;\r | |
158 | UINTN AuthSize;\r | |
159 | UINT8 IcvBuffer[12];\r | |
160 | \r | |
161 | //\r | |
162 | // Calculate the size of authentication payload.\r | |
163 | //\r | |
164 | *IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);\r | |
165 | AuthSize = EspSize - *IcvSize;\r | |
166 | \r | |
167 | //\r | |
168 | // Calculate the icv buffer and size of the payload.\r | |
169 | //\r | |
170 | Status = IpSecAuthPayload (\r | |
171 | EspBuffer,\r | |
172 | AuthSize,\r | |
173 | IcvBuffer,\r | |
174 | *IcvSize,\r | |
175 | SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,\r | |
176 | SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId\r | |
177 | );\r | |
178 | if (EFI_ERROR (Status)) {\r | |
179 | return Status;\r | |
180 | }\r | |
181 | //\r | |
182 | // Compare the calculated icv and the appended original icv.\r | |
183 | //\r | |
184 | if (CompareMem (EspBuffer + AuthSize, IcvBuffer, *IcvSize) == 0) {\r | |
185 | return EFI_SUCCESS;\r | |
186 | }\r | |
187 | \r | |
188 | DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));\r | |
189 | return EFI_ACCESS_DENIED;\r | |
190 | }\r | |
191 | \r | |
192 | /**\r | |
193 | ESP Decrypt the payload.\r | |
194 | \r | |
195 | @param[in, out] PayloadBuffer Pointer to the buffer containing the ESP wrapped;\r | |
196 | to be decrypted on input, and plaintext on return. The\r | |
197 | number of bytes of data to be decrypted is\r | |
198 | specified by EncryptSize.\r | |
199 | @param[in] EncryptSize The size of the PayloadBuffer as input.\r | |
200 | @param[in] SadEntry The related SAD entry.\r | |
201 | @param[in] IvSize The size of IV.\r | |
202 | @param[out] PlainPayloadSize Contains the return value of decrypted size.\r | |
203 | @param[out] PaddingSize Contains the return value of Padding size.\r | |
204 | @param[out] NextHeader Contains the return value of the last protocol header\r | |
205 | of the IP packet.\r | |
206 | \r | |
207 | @retval EFI_UNSUPPORTED The Algorithm pointed to by the SAD entry is not supported.\r | |
208 | @retval EFI_SUCCESS The operation completed successfully.\r | |
209 | \r | |
210 | **/\r | |
211 | EFI_STATUS\r | |
212 | IpSecEspDecryptPayload (\r | |
213 | IN OUT UINT8 *PayloadBuffer,\r | |
214 | IN UINTN EncryptSize,\r | |
215 | IN IPSEC_SAD_ENTRY *SadEntry,\r | |
216 | IN UINTN *IvSize,\r | |
217 | OUT UINTN *PlainPayloadSize,\r | |
218 | OUT UINTN *PaddingSize,\r | |
219 | OUT UINT8 *NextHeader\r | |
220 | )\r | |
221 | {\r | |
222 | EFI_ESP_TAIL *EspTail;\r | |
223 | \r | |
224 | switch (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId) {\r | |
225 | case EFI_IPSEC_EALG_NULL:\r | |
226 | EspTail = (EFI_ESP_TAIL *) (PayloadBuffer + EncryptSize - sizeof (EFI_ESP_TAIL));\r | |
227 | *PaddingSize = EspTail->PaddingLength;\r | |
228 | *NextHeader = EspTail->NextHeader;\r | |
229 | *PlainPayloadSize = EncryptSize - EspTail->PaddingLength - sizeof (EFI_ESP_TAIL);\r | |
230 | break;\r | |
231 | \r | |
232 | case EFI_IPSEC_EALG_3DESCBC:\r | |
233 | case EFI_IPSEC_EALG_AESCBC:\r | |
234 | //\r | |
235 | // TODO: support these algorithm\r | |
236 | //\r | |
237 | return EFI_UNSUPPORTED;\r | |
238 | default :\r | |
239 | return EFI_UNSUPPORTED;\r | |
240 | }\r | |
241 | \r | |
242 | return EFI_SUCCESS;\r | |
243 | }\r | |
244 | \r | |
245 | /**\r | |
246 | ESP Encrypt the payload.\r | |
247 | \r | |
248 | @param[in, out] BufferToEncrypt Pointer to the buffer containing plaintext to be\r | |
249 | encrypted on input, and ciphertext on return. The\r | |
250 | number of bytes of data to be encrypted is\r | |
251 | specified by EncryptSize.\r | |
252 | @param[in, out] EncryptSize The size of the plaintext on input, and the size of the\r | |
253 | ciphertext on return.\r | |
254 | @param[in] IvBuffer Points to IV data.\r | |
255 | @param[in] IvSize Size of IV.\r | |
256 | @param[in] SadEntry Related SAD entry.\r | |
257 | \r | |
258 | @retval EFI_UNSUPPORTED The Algorithm pointed by SAD entry is not supported.\r | |
259 | @retval EFI_SUCCESS The operation completed successfully.\r | |
260 | \r | |
261 | **/\r | |
262 | EFI_STATUS\r | |
263 | IpSecEspEncryptPayload (\r | |
264 | IN OUT UINT8 *BufferToEncrypt,\r | |
265 | IN OUT UINTN EncryptSize,\r | |
266 | IN UINT8 *IvBuffer,\r | |
267 | IN UINTN IvSize,\r | |
268 | IN IPSEC_SAD_ENTRY *SadEntry\r | |
269 | )\r | |
270 | {\r | |
271 | switch (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId) {\r | |
272 | case EFI_IPSEC_EALG_NULL:\r | |
273 | return EFI_SUCCESS;\r | |
274 | \r | |
275 | case EFI_IPSEC_EALG_3DESCBC:\r | |
276 | case EFI_IPSEC_EALG_AESCBC:\r | |
277 | //\r | |
278 | // TODO: support these algorithms\r | |
279 | //\r | |
280 | return EFI_UNSUPPORTED;\r | |
281 | default :\r | |
282 | return EFI_UNSUPPORTED;\r | |
283 | \r | |
284 | }\r | |
285 | }\r | |
286 | \r | |
287 | /**\r | |
288 | The actual entry to relative function processes the inbound traffic of ESP header.\r | |
289 | \r | |
290 | This function is the subfunction of IpSecProtectInboundPacket(). It checks the\r | |
291 | received packet security property and trim the ESP header and then returns without\r | |
292 | an IPsec protected IP Header and FramgmentTable.\r | |
293 | \r | |
294 | @param[in] IpVersion The version of IP.\r | |
295 | @param[in, out] IpHead Points to the IP header containing the ESP header\r | |
296 | to be trimed on input, and without ESP header\r | |
297 | on return.\r | |
298 | @param[out] LastHead The Last Header in IP header on return.\r | |
299 | @param[in] OptionsBuffer Pointer to the options buffer. It is optional.\r | |
300 | @param[in] OptionsLength Length of the options buffer. It is optional.\r | |
301 | @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec\r | |
302 | protected on input, and without IPsec protected\r | |
303 | on return.\r | |
304 | @param[in] FragmentCount The number of fragments.\r | |
305 | @param[out] SpdEntry Pointer to contain the address of SPD entry on return.\r | |
306 | @param[out] RecycleEvent The event for recycling of resources.\r | |
307 | \r | |
308 | @retval EFI_SUCCESS The operation was successful.\r | |
309 | @retval EFI_ACCESS_DENIED One or more following conditions is TRUE:\r | |
310 | - ESP header was not found.\r | |
311 | - The related SAD entry was not found.\r | |
312 | - The related SAD entry does not support the ESP protocol.\r | |
313 | @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.\r | |
314 | \r | |
315 | **/\r | |
316 | EFI_STATUS\r | |
317 | IpSecEspInboundPacket (\r | |
318 | IN UINT8 IpVersion,\r | |
319 | IN OUT VOID *IpHead,\r | |
320 | OUT UINT8 *LastHead,\r | |
321 | IN VOID *OptionsBuffer, OPTIONAL\r | |
322 | IN UINT32 OptionsLength, OPTIONAL\r | |
323 | IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,\r | |
324 | IN UINT32 *FragmentCount,\r | |
325 | OUT IPSEC_SPD_ENTRY **SpdEntry,\r | |
326 | OUT EFI_EVENT *RecycleEvent\r | |
327 | )\r | |
328 | {\r | |
329 | EFI_STATUS Status;\r | |
330 | NET_BUF *Payload;\r | |
331 | UINTN EspSize;\r | |
332 | UINTN IvSize;\r | |
333 | UINTN PlainPayloadSize;\r | |
334 | UINTN PaddingSize;\r | |
335 | UINTN IcvSize;\r | |
336 | UINT8 *ProcessBuffer;\r | |
337 | EFI_IP_ADDRESS DestIp;\r | |
338 | EFI_ESP_HEADER *EspHeader;\r | |
339 | EFI_ESP_TAIL *EspTail;\r | |
340 | EFI_IPSEC_SA_ID *SaId;\r | |
341 | IPSEC_SAD_DATA *SadData;\r | |
342 | IPSEC_SAD_ENTRY *SadEntry;\r | |
343 | IPSEC_RECYCLE_CONTEXT *RecycleContext;\r | |
344 | UINT32 Spi;\r | |
345 | UINT8 NextHeader;\r | |
346 | UINT16 IpSecHeadSize;\r | |
347 | \r | |
348 | Status = EFI_SUCCESS;\r | |
349 | Payload = NULL;\r | |
350 | ProcessBuffer = NULL;\r | |
351 | RecycleContext = NULL;\r | |
352 | *RecycleEvent = NULL;\r | |
353 | PlainPayloadSize = 0;\r | |
354 | NextHeader = 0;\r | |
355 | //\r | |
356 | // Build netbuf from fragment table first.\r | |
357 | //\r | |
358 | Payload = NetbufFromExt (\r | |
359 | (NET_FRAGMENT *) *FragmentTable,\r | |
360 | *FragmentCount,\r | |
361 | 0,\r | |
362 | sizeof (EFI_ESP_HEADER),\r | |
363 | IpSecOnRecyclePacket,\r | |
364 | NULL\r | |
365 | );\r | |
366 | if (Payload == NULL) {\r | |
367 | Status = EFI_OUT_OF_RESOURCES;\r | |
368 | goto ON_EXIT;\r | |
369 | }\r | |
370 | //\r | |
371 | // Get the esp size and eso header from netbuf.\r | |
372 | //\r | |
373 | EspSize = Payload->TotalSize;\r | |
374 | EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL);\r | |
375 | if (EspHeader == NULL) {\r | |
376 | Status = EFI_ACCESS_DENIED;\r | |
377 | goto ON_EXIT;\r | |
378 | }\r | |
379 | //\r | |
380 | // Parse destination address from ip header.\r | |
381 | //\r | |
382 | ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));\r | |
383 | if (IpVersion == IP_VERSION_4) {\r | |
384 | CopyMem (\r | |
385 | &DestIp,\r | |
386 | &((IP4_HEAD *) IpHead)->Dst,\r | |
387 | sizeof (IP4_ADDR)\r | |
388 | );\r | |
389 | } else {\r | |
390 | CopyMem (\r | |
391 | &DestIp,\r | |
392 | &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,\r | |
393 | sizeof (EFI_IPv6_ADDRESS)\r | |
394 | );\r | |
395 | }\r | |
396 | //\r | |
397 | // Lookup sad entry according to the spi and dest address.\r | |
398 | //\r | |
399 | Spi = NTOHL (EspHeader->Spi);\r | |
400 | SadEntry = IpSecLookupSadBySpi (Spi, &DestIp);\r | |
401 | if (SadEntry == NULL) {\r | |
402 | Status = EFI_ACCESS_DENIED;\r | |
403 | goto ON_EXIT;\r | |
404 | }\r | |
405 | \r | |
406 | SaId = SadEntry->Id;\r | |
407 | SadData = SadEntry->Data;\r | |
408 | \r | |
409 | //\r | |
410 | // Only support esp protocol currently.\r | |
411 | //\r | |
412 | if (SaId->Proto != EfiIPsecESP) {\r | |
413 | Status = EFI_ACCESS_DENIED;\r | |
414 | goto ON_EXIT;\r | |
415 | }\r | |
416 | \r | |
417 | if (!SadData->ManualSet) {\r | |
418 | //\r | |
419 | // TODO: Check sa lifetime and sequence number\r | |
420 | //\r | |
421 | }\r | |
422 | //\r | |
423 | // Allocate buffer for decryption and authentication by esp.\r | |
424 | //\r | |
425 | ProcessBuffer = AllocateZeroPool (EspSize);\r | |
426 | if (ProcessBuffer == NULL) {\r | |
427 | Status = EFI_OUT_OF_RESOURCES;\r | |
428 | goto ON_EXIT;\r | |
429 | }\r | |
430 | \r | |
431 | NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer);\r | |
432 | \r | |
433 | //\r | |
434 | // Authenticate the esp wrapped buffer by the sad entry if has auth key.\r | |
435 | //\r | |
436 | IcvSize = 0;\r | |
437 | if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r | |
438 | Status = IpSecEspAuthVerifyPayload (\r | |
439 | ProcessBuffer,\r | |
440 | EspSize,\r | |
441 | SadEntry,\r | |
442 | &IcvSize\r | |
443 | );\r | |
444 | if (EFI_ERROR (Status)) {\r | |
445 | goto ON_EXIT;\r | |
446 | }\r | |
447 | }\r | |
448 | //\r | |
449 | // Decrypt the payload by the sad entry if has decrypt key.\r | |
450 | //\r | |
451 | IvSize = 0;\r | |
452 | if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r | |
453 | Status = IpSecEspDecryptPayload (\r | |
454 | ProcessBuffer + sizeof (EFI_ESP_HEADER),\r | |
455 | EspSize - sizeof (EFI_ESP_HEADER) - IcvSize,\r | |
456 | SadEntry,\r | |
457 | &IvSize,\r | |
458 | &PlainPayloadSize,\r | |
459 | &PaddingSize,\r | |
460 | &NextHeader\r | |
461 | );\r | |
462 | if (EFI_ERROR (Status)) {\r | |
463 | goto ON_EXIT;\r | |
464 | }\r | |
465 | } else {\r | |
466 | EspTail = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL));\r | |
467 | PaddingSize = EspTail->PaddingLength;\r | |
468 | NextHeader = EspTail->NextHeader;\r | |
469 | PlainPayloadSize = EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize - sizeof (EFI_ESP_TAIL) - PaddingSize;\r | |
470 | }\r | |
471 | //\r | |
472 | // TODO: handle anti-replay window\r | |
473 | //\r | |
474 | //\r | |
475 | // Decryption and authentication with esp has been done, so it's time to\r | |
476 | // reload the new packet, create recycle event and fixup ip header.\r | |
477 | //\r | |
478 | RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));\r | |
479 | if (RecycleContext == NULL) {\r | |
480 | Status = EFI_OUT_OF_RESOURCES;\r | |
481 | goto ON_EXIT;\r | |
482 | }\r | |
483 | \r | |
484 | Status = gBS->CreateEvent (\r | |
485 | EVT_NOTIFY_SIGNAL,\r | |
486 | TPL_NOTIFY,\r | |
487 | IpSecRecycleCallback,\r | |
488 | RecycleContext,\r | |
489 | RecycleEvent\r | |
490 | );\r | |
491 | if (EFI_ERROR (Status)) {\r | |
492 | goto ON_EXIT;\r | |
493 | }\r | |
494 | //\r | |
495 | // TODO: Who take responsible to handle the original fragment table?\r | |
496 | //\r | |
497 | *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));\r | |
498 | if (*FragmentTable == NULL) {\r | |
499 | Status = EFI_OUT_OF_RESOURCES;\r | |
500 | goto ON_EXIT;\r | |
501 | }\r | |
502 | \r | |
503 | RecycleContext->PayloadBuffer = ProcessBuffer;\r | |
504 | RecycleContext->FragmentTable = *FragmentTable;\r | |
505 | (*FragmentTable)[0].FragmentBuffer = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;\r | |
506 | (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;\r | |
507 | *FragmentCount = 1;\r | |
508 | \r | |
509 | //\r | |
510 | // Update the total length field in ip header since processed by esp.\r | |
511 | //\r | |
512 | if (IpVersion == IP_VERSION_4) {\r | |
513 | ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) (((IP4_HEAD *) IpHead)->HeadLen + PlainPayloadSize));\r | |
514 | } else {\r | |
515 | IpSecHeadSize = IpSecGetPlainExtHeadSize (IpHead, LastHead);\r | |
516 | ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize));\r | |
517 | }\r | |
518 | //\r | |
519 | // Update the next layer field in ip header since esp header inserted.\r | |
520 | //\r | |
521 | *LastHead = NextHeader;\r | |
522 | \r | |
523 | //\r | |
524 | // Update the spd association of the sad entry.\r | |
525 | //\r | |
526 | *SpdEntry = SadData->SpdEntry;\r | |
527 | \r | |
528 | ON_EXIT:\r | |
529 | if (Payload != NULL) {\r | |
530 | NetbufFree (Payload);\r | |
531 | }\r | |
532 | \r | |
533 | if (EFI_ERROR (Status)) {\r | |
534 | if (ProcessBuffer != NULL) {\r | |
535 | FreePool (ProcessBuffer);\r | |
536 | }\r | |
537 | \r | |
538 | if (RecycleContext != NULL) {\r | |
539 | FreePool (RecycleContext);\r | |
540 | }\r | |
541 | \r | |
542 | if (*RecycleEvent != NULL) {\r | |
543 | gBS->CloseEvent (*RecycleEvent);\r | |
544 | }\r | |
545 | }\r | |
546 | \r | |
547 | return Status;\r | |
548 | }\r | |
549 | \r | |
550 | /**\r | |
551 | The actual entry to the relative function processes the output traffic using the ESP protocol.\r | |
552 | \r | |
553 | This function is the subfunction of IpSecProtectOutboundPacket(). It protected\r | |
554 | the sending packet by encrypting its payload and inserting ESP header in the orginal\r | |
555 | IP header, then return the IpHeader and IPsec protected Fragmentable.\r | |
556 | \r | |
557 | @param[in] IpVersion The version of IP.\r | |
558 | @param[in, out] IpHead Points to IP header containing the orginal IP header\r | |
559 | to be processed on input, and inserted ESP header\r | |
560 | on return.\r | |
561 | @param[in] LastHead The Last Header in IP header.\r | |
562 | @param[in] OptionsBuffer Pointer to the options buffer. It is optional.\r | |
563 | @param[in] OptionsLength Length of the options buffer. It is optional.\r | |
564 | @param[in, out] FragmentTable Pointer to a list of fragments to be protected by\r | |
565 | IPsec on input, and with IPsec protected\r | |
566 | on return.\r | |
567 | @param[in] FragmentCount The number of fragments.\r | |
568 | @param[in] SadEntry The related SAD entry.\r | |
569 | @param[out] RecycleEvent The event for recycling of resources.\r | |
570 | \r | |
571 | @retval EFI_SUCCESS The operation was successful.\r | |
572 | @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated.\r | |
573 | \r | |
574 | **/\r | |
575 | EFI_STATUS\r | |
576 | IpSecEspOutboundPacket (\r | |
577 | IN UINT8 IpVersion,\r | |
578 | IN OUT VOID *IpHead,\r | |
579 | IN UINT8 *LastHead,\r | |
580 | IN VOID *OptionsBuffer, OPTIONAL\r | |
581 | IN UINT32 OptionsLength, OPTIONAL\r | |
582 | IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,\r | |
583 | IN UINT32 *FragmentCount,\r | |
584 | IN IPSEC_SAD_ENTRY *SadEntry,\r | |
585 | OUT EFI_EVENT *RecycleEvent\r | |
586 | )\r | |
587 | {\r | |
588 | EFI_STATUS Status;\r | |
589 | UINTN Index;\r | |
590 | EFI_IPSEC_SA_ID *SaId;\r | |
591 | IPSEC_SAD_DATA *SadData;\r | |
592 | IPSEC_RECYCLE_CONTEXT *RecycleContext;\r | |
593 | UINT8 *ProcessBuffer;\r | |
594 | UINTN BytesCopied;\r | |
595 | INTN EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4\r | |
596 | UINTN EspSize; // Total size of esp wrapped ip payload\r | |
597 | UINTN IvSize; // Size of IV, optional, might be 0\r | |
598 | UINTN PlainPayloadSize;// Original IP payload size\r | |
599 | UINTN PaddingSize; // Size of padding\r | |
600 | UINTN EncryptSize; // Size of data to be encrypted, start after IV and\r | |
601 | // stop before ICV\r | |
602 | UINTN IcvSize; // Size of ICV, optional, might be 0\r | |
603 | UINT8 *RestOfPayload; // Start of Payload after IV\r | |
604 | UINT8 *Padding; // Start address of padding\r | |
605 | EFI_ESP_HEADER *EspHeader; // Start address of ESP frame\r | |
606 | EFI_ESP_TAIL *EspTail; // Address behind padding\r | |
607 | \r | |
608 | Status = EFI_ACCESS_DENIED;\r | |
609 | SaId = SadEntry->Id;\r | |
610 | SadData = SadEntry->Data;\r | |
611 | ProcessBuffer = NULL;\r | |
612 | RecycleContext = NULL;\r | |
613 | *RecycleEvent = NULL;\r | |
614 | \r | |
615 | if (!SadData->ManualSet &&\r | |
616 | SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL &&\r | |
617 | SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL\r | |
618 | ) {\r | |
619 | //\r | |
620 | // Invalid manual sad entry configuration.\r | |
621 | //\r | |
622 | goto ON_EXIT;\r | |
623 | }\r | |
624 | //\r | |
625 | // Calculate enctrypt block size, need iv by default and 4 bytes alignment.\r | |
626 | //\r | |
627 | EncryptBlockSize = 4;\r | |
628 | \r | |
629 | if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r | |
630 | EncryptBlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);\r | |
631 | \r | |
632 | if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) {\r | |
633 | goto ON_EXIT;\r | |
634 | }\r | |
635 | }\r | |
636 | //\r | |
637 | // Calculate the plain payload size accroding to the fragment table.\r | |
638 | //\r | |
639 | PlainPayloadSize = 0;\r | |
640 | for (Index = 0; Index < *FragmentCount; Index++) {\r | |
641 | PlainPayloadSize += (*FragmentTable)[Index].FragmentLength;\r | |
642 | }\r | |
643 | //\r | |
644 | // Calculate icv size, optional by default and 4 bytes alignment.\r | |
645 | //\r | |
646 | IcvSize = 0;\r | |
647 | if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r | |
648 | IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);\r | |
649 | if (IcvSize % 4 != 0) {\r | |
650 | goto ON_EXIT;\r | |
651 | }\r | |
652 | }\r | |
653 | //\r | |
654 | // Calcuate the total size of esp wrapped ip payload.\r | |
655 | //\r | |
656 | IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);\r | |
657 | EncryptSize = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize;\r | |
658 | PaddingSize = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL);\r | |
659 | EspSize = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize;\r | |
660 | \r | |
661 | ProcessBuffer = AllocateZeroPool (EspSize);\r | |
662 | if (ProcessBuffer == NULL) {\r | |
663 | Status = EFI_OUT_OF_RESOURCES;\r | |
664 | goto ON_EXIT;\r | |
665 | }\r | |
666 | //\r | |
667 | // Calculate esp header and esp tail including header, payload and padding.\r | |
668 | //\r | |
669 | EspHeader = (EFI_ESP_HEADER *) ProcessBuffer;\r | |
670 | RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize;\r | |
671 | Padding = RestOfPayload + PlainPayloadSize;\r | |
672 | EspTail = (EFI_ESP_TAIL *) (Padding + PaddingSize);\r | |
673 | \r | |
674 | //\r | |
675 | // Fill the sn and spi fields in esp header.\r | |
676 | //\r | |
677 | EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1);\r | |
678 | EspHeader->Spi = HTONL (SaId->Spi);\r | |
679 | \r | |
680 | //\r | |
681 | // Copy the rest of payload (after iv) from the original fragment buffer.\r | |
682 | //\r | |
683 | BytesCopied = 0;\r | |
684 | for (Index = 0; Index < *FragmentCount; Index++) {\r | |
685 | CopyMem (\r | |
686 | (RestOfPayload + BytesCopied),\r | |
687 | (*FragmentTable)[Index].FragmentBuffer,\r | |
688 | (*FragmentTable)[Index].FragmentLength\r | |
689 | );\r | |
690 | BytesCopied += (*FragmentTable)[Index].FragmentLength;\r | |
691 | }\r | |
692 | //\r | |
693 | // Fill the padding buffer by natural number sequence.\r | |
694 | //\r | |
695 | for (Index = 0; Index < PaddingSize; Index++) {\r | |
696 | Padding[Index] = (UINT8) (Index + 1);\r | |
697 | }\r | |
698 | //\r | |
699 | // Fill the padding length and next header fields in esp tail.\r | |
700 | //\r | |
701 | EspTail->PaddingLength = (UINT8) PaddingSize;\r | |
702 | EspTail->NextHeader = *LastHead;\r | |
703 | \r | |
704 | //\r | |
705 | // Generate iv at random by crypt library.\r | |
706 | //\r | |
707 | Status = IpSecGenerateIv (\r | |
708 | (UINT8 *) (EspHeader + 1),\r | |
709 | IvSize\r | |
710 | );\r | |
711 | \r | |
712 | \r | |
713 | if (EFI_ERROR (Status)) {\r | |
714 | goto ON_EXIT;\r | |
715 | }\r | |
716 | //\r | |
717 | // Encrypt the payload (after iv) by the sad entry if has encrypt key.\r | |
718 | //\r | |
719 | if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r | |
720 | Status = IpSecEspEncryptPayload (\r | |
721 | RestOfPayload,\r | |
722 | EncryptSize,\r | |
723 | (UINT8 *) (EspHeader + 1),\r | |
724 | IvSize,\r | |
725 | SadEntry\r | |
726 | );\r | |
727 | if (EFI_ERROR (Status)) {\r | |
728 | goto ON_EXIT;\r | |
729 | }\r | |
730 | }\r | |
731 | //\r | |
732 | // Authenticate the esp wrapped buffer by the sad entry if has auth key.\r | |
733 | //\r | |
734 | if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r | |
735 | Status = IpSecAuthPayload (\r | |
736 | ProcessBuffer,\r | |
737 | EspSize - IcvSize,\r | |
738 | ProcessBuffer + EspSize - IcvSize,\r | |
739 | IcvSize,\r | |
740 | SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,\r | |
741 | SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId\r | |
742 | );\r | |
743 | if (EFI_ERROR (Status)) {\r | |
744 | goto ON_EXIT;\r | |
745 | }\r | |
746 | }\r | |
747 | //\r | |
748 | // Encryption and authentication with esp has been done, so it's time to\r | |
749 | // reload the new packet, create recycle event and fixup ip header.\r | |
750 | //\r | |
751 | RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));\r | |
752 | if (RecycleContext == NULL) {\r | |
753 | Status = EFI_OUT_OF_RESOURCES;\r | |
754 | goto ON_EXIT;\r | |
755 | }\r | |
756 | \r | |
757 | Status = gBS->CreateEvent (\r | |
758 | EVT_NOTIFY_SIGNAL,\r | |
759 | TPL_NOTIFY,\r | |
760 | IpSecRecycleCallback,\r | |
761 | RecycleContext,\r | |
762 | RecycleEvent\r | |
763 | );\r | |
764 | if (EFI_ERROR (Status)) {\r | |
765 | goto ON_EXIT;\r | |
766 | }\r | |
767 | //\r | |
768 | // TODO: Who take responsible to handle the original fragment table?\r | |
769 | //\r | |
770 | *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));\r | |
771 | if (*FragmentTable == NULL) {\r | |
772 | Status = EFI_OUT_OF_RESOURCES;\r | |
773 | goto ON_EXIT;\r | |
774 | }\r | |
775 | \r | |
776 | RecycleContext->FragmentTable = *FragmentTable;\r | |
777 | RecycleContext->PayloadBuffer = ProcessBuffer;\r | |
778 | (*FragmentTable)[0].FragmentBuffer = ProcessBuffer;\r | |
779 | (*FragmentTable)[0].FragmentLength = (UINT32) EspSize;\r | |
780 | *FragmentCount = 1;\r | |
781 | \r | |
782 | //\r | |
783 | // Update the total length field in ip header since processed by esp.\r | |
784 | //\r | |
785 | if (IpVersion == IP_VERSION_4) {\r | |
786 | ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) (((IP4_HEAD *) IpHead)->HeadLen + EspSize));\r | |
787 | } else {\r | |
788 | ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize);\r | |
789 | }\r | |
790 | //\r | |
791 | // Update the next layer field in ip header since esp header inserted.\r | |
792 | //\r | |
793 | *LastHead = IPSEC_ESP_PROTOCOL;\r | |
794 | \r | |
795 | //\r | |
796 | // Increase the sn number in sad entry according to rfc4303.\r | |
797 | //\r | |
798 | SadData->SequenceNumber++;\r | |
799 | \r | |
800 | ON_EXIT:\r | |
801 | if (EFI_ERROR (Status)) {\r | |
802 | if (ProcessBuffer != NULL) {\r | |
803 | FreePool (ProcessBuffer);\r | |
804 | }\r | |
805 | \r | |
806 | if (RecycleContext != NULL) {\r | |
807 | FreePool (RecycleContext);\r | |
808 | }\r | |
809 | \r | |
810 | if (*RecycleEvent != NULL) {\r | |
811 | gBS->CloseEvent (*RecycleEvent);\r | |
812 | }\r | |
813 | }\r | |
814 | \r | |
815 | return Status;\r | |
816 | }\r | |
817 | \r | |
818 | /**\r | |
819 | This function processes the inbound traffic with IPsec.\r | |
820 | \r | |
821 | It checks the received packet security property, trims the ESP/AH header, and then\r | |
822 | returns without an IPsec protected IP Header and FragmentTable.\r | |
823 | \r | |
824 | @param[in] IpVersion The version of IP.\r | |
825 | @param[in, out] IpHead Points to IP header containing the ESP/AH header\r | |
826 | to be trimed on input, and without ESP/AH header\r | |
827 | on return.\r | |
828 | @param[in] LastHead The Last Header in IP header on return.\r | |
829 | @param[in] OptionsBuffer Pointer to the options buffer. It is optional.\r | |
830 | @param[in] OptionsLength Length of the options buffer. It is optional.\r | |
831 | @param[in, out] FragmentTable Pointer to a list of fragments in form of IPsec\r | |
832 | protected on input, and without IPsec protected\r | |
833 | on return.\r | |
834 | @param[in] FragmentCount The number of fragments.\r | |
835 | @param[out] SpdEntry Pointer to contain the address of SPD entry on return.\r | |
836 | @param[out] RecycleEvent The event for recycling of resources.\r | |
837 | \r | |
838 | @retval EFI_SUCCESS The operation was successful.\r | |
839 | @retval EFI_UNSUPPORTED The IPSEC protocol is not supported.\r | |
840 | \r | |
841 | **/\r | |
842 | EFI_STATUS\r | |
843 | IpSecProtectInboundPacket (\r | |
844 | IN UINT8 IpVersion,\r | |
845 | IN OUT VOID *IpHead,\r | |
846 | IN UINT8 *LastHead,\r | |
847 | IN VOID *OptionsBuffer, OPTIONAL\r | |
848 | IN UINT32 OptionsLength, OPTIONAL\r | |
849 | IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,\r | |
850 | IN UINT32 *FragmentCount,\r | |
851 | OUT IPSEC_SPD_ENTRY **SpdEntry,\r | |
852 | OUT EFI_EVENT *RecycleEvent\r | |
853 | )\r | |
854 | {\r | |
855 | if (*LastHead == IPSEC_ESP_PROTOCOL) {\r | |
856 | //\r | |
857 | // Process the esp ipsec header of the inbound traffic.\r | |
858 | //\r | |
859 | return IpSecEspInboundPacket (\r | |
860 | IpVersion,\r | |
861 | IpHead,\r | |
862 | LastHead,\r | |
863 | OptionsBuffer,\r | |
864 | OptionsLength,\r | |
865 | FragmentTable,\r | |
866 | FragmentCount,\r | |
867 | SpdEntry,\r | |
868 | RecycleEvent\r | |
869 | );\r | |
870 | }\r | |
871 | //\r | |
872 | // The other protocols are not supported.\r | |
873 | //\r | |
874 | return EFI_UNSUPPORTED;\r | |
875 | }\r | |
876 | \r | |
877 | /**\r | |
878 | This function processes the output traffic with IPsec.\r | |
879 | \r | |
880 | It protected the sending packet by encrypting it payload and inserting ESP/AH header\r | |
881 | in the orginal IP header, then returns the IpHeader and IPsec protected Fragmentable.\r | |
882 | \r | |
883 | @param[in] IpVersion The version of IP.\r | |
884 | @param[in, out] IpHead Points to IP header containing the orginal IP header\r | |
885 | to be processed on input, and inserted ESP/AH header\r | |
886 | on return.\r | |
887 | @param[in] LastHead The Last Header in the IP header.\r | |
888 | @param[in] OptionsBuffer Pointer to the options buffer. It is optional.\r | |
889 | @param[in] OptionsLength Length of the options buffer. It is optional.\r | |
890 | @param[in, out] FragmentTable Pointer to a list of fragments to be protected by\r | |
891 | IPsec on input, and with IPsec protected\r | |
892 | on return.\r | |
893 | @param[in] FragmentCount The number of fragments.\r | |
894 | @param[in] SadEntry The related SAD entry.\r | |
895 | @param[out] RecycleEvent The event for recycling of resources.\r | |
896 | \r | |
897 | @retval EFI_SUCCESS The operation was successful.\r | |
898 | @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported.\r | |
899 | \r | |
900 | **/\r | |
901 | EFI_STATUS\r | |
902 | IpSecProtectOutboundPacket (\r | |
903 | IN UINT8 IpVersion,\r | |
904 | IN OUT VOID *IpHead,\r | |
905 | IN UINT8 *LastHead,\r | |
906 | IN VOID *OptionsBuffer, OPTIONAL\r | |
907 | IN UINT32 OptionsLength, OPTIONAL\r | |
908 | IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,\r | |
909 | IN UINT32 *FragmentCount,\r | |
910 | IN IPSEC_SAD_ENTRY *SadEntry,\r | |
911 | OUT EFI_EVENT *RecycleEvent\r | |
912 | )\r | |
913 | {\r | |
914 | if (SadEntry->Id->Proto == EfiIPsecESP) {\r | |
915 | //\r | |
916 | // Process the esp ipsec header of the outbound traffic.\r | |
917 | //\r | |
918 | return IpSecEspOutboundPacket (\r | |
919 | IpVersion,\r | |
920 | IpHead,\r | |
921 | LastHead,\r | |
922 | OptionsBuffer,\r | |
923 | OptionsLength,\r | |
924 | FragmentTable,\r | |
925 | FragmentCount,\r | |
926 | SadEntry,\r | |
927 | RecycleEvent\r | |
928 | );\r | |
929 | }\r | |
930 | //\r | |
931 | // The other protocols are not supported.\r | |
932 | //\r | |
933 | return EFI_UNSUPPORTED;\r | |
934 | }\r |