From 9166f840d2a70b924b0ff66528f056515443e4e8 Mon Sep 17 00:00:00 2001 From: qianouyang Date: Fri, 31 Dec 2010 10:43:54 +0000 Subject: [PATCH] Add IPsec/Ikev2 support. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11219 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/IpSecDxe/IetfConstants.c | 388 +++ NetworkPkg/IpSecDxe/Ike.h | 266 ++ NetworkPkg/IpSecDxe/IkeCommon.c | 255 ++ NetworkPkg/IpSecDxe/IkeCommon.h | 191 ++ NetworkPkg/IpSecDxe/IkePacket.c | 257 ++ NetworkPkg/IpSecDxe/IkePacket.h | 82 + NetworkPkg/IpSecDxe/IkeService.c | 769 ++++++ NetworkPkg/IpSecDxe/IkeService.h | 254 ++ NetworkPkg/IpSecDxe/Ikev2/ChildSa.c | 192 ++ NetworkPkg/IpSecDxe/Ikev2/Exchange.c | 803 ++++++ NetworkPkg/IpSecDxe/Ikev2/Ikev2.h | 258 ++ NetworkPkg/IpSecDxe/Ikev2/Info.c | 401 +++ NetworkPkg/IpSecDxe/Ikev2/Payload.c | 3227 +++++++++++++++++++++++++ NetworkPkg/IpSecDxe/Ikev2/Payload.h | 438 ++++ NetworkPkg/IpSecDxe/Ikev2/Sa.c | 1949 +++++++++++++++ NetworkPkg/IpSecDxe/Ikev2/Utility.c | 2692 +++++++++++++++++++++ NetworkPkg/IpSecDxe/Ikev2/Utility.h | 1131 +++++++++ NetworkPkg/IpSecDxe/IpSecConfigImpl.c | 641 +++-- NetworkPkg/IpSecDxe/IpSecConfigImpl.h | 23 +- NetworkPkg/IpSecDxe/IpSecCryptIo.c | 929 ++++++- NetworkPkg/IpSecDxe/IpSecCryptIo.h | 676 +++++- NetworkPkg/IpSecDxe/IpSecDebug.c | 184 +- NetworkPkg/IpSecDxe/IpSecDebug.h | 41 +- NetworkPkg/IpSecDxe/IpSecDriver.c | 212 +- NetworkPkg/IpSecDxe/IpSecDxe.inf | 48 +- NetworkPkg/IpSecDxe/IpSecImpl.c | 1722 +++++++++++-- NetworkPkg/IpSecDxe/IpSecImpl.h | 97 +- NetworkPkg/IpSecDxe/IpSecMain.c | 235 ++ NetworkPkg/IpSecDxe/IpSecSaEngine.c | 934 ------- NetworkPkg/NetworkPkg.dec | 16 + NetworkPkg/NetworkPkg.dsc | 3 + 31 files changed, 17737 insertions(+), 1577 deletions(-) create mode 100644 NetworkPkg/IpSecDxe/IetfConstants.c create mode 100644 NetworkPkg/IpSecDxe/Ike.h create mode 100644 NetworkPkg/IpSecDxe/IkeCommon.c create mode 100644 NetworkPkg/IpSecDxe/IkeCommon.h create mode 100644 NetworkPkg/IpSecDxe/IkePacket.c create mode 100644 NetworkPkg/IpSecDxe/IkePacket.h create mode 100644 NetworkPkg/IpSecDxe/IkeService.c create mode 100644 NetworkPkg/IpSecDxe/IkeService.h create mode 100644 NetworkPkg/IpSecDxe/Ikev2/ChildSa.c create mode 100644 NetworkPkg/IpSecDxe/Ikev2/Exchange.c create mode 100644 NetworkPkg/IpSecDxe/Ikev2/Ikev2.h create mode 100644 NetworkPkg/IpSecDxe/Ikev2/Info.c create mode 100644 NetworkPkg/IpSecDxe/Ikev2/Payload.c create mode 100644 NetworkPkg/IpSecDxe/Ikev2/Payload.h create mode 100644 NetworkPkg/IpSecDxe/Ikev2/Sa.c create mode 100644 NetworkPkg/IpSecDxe/Ikev2/Utility.c create mode 100644 NetworkPkg/IpSecDxe/Ikev2/Utility.h create mode 100644 NetworkPkg/IpSecDxe/IpSecMain.c delete mode 100644 NetworkPkg/IpSecDxe/IpSecSaEngine.c diff --git a/NetworkPkg/IpSecDxe/IetfConstants.c b/NetworkPkg/IpSecDxe/IetfConstants.c new file mode 100644 index 0000000000..7bd5c81da8 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IetfConstants.c @@ -0,0 +1,388 @@ +/** @file + Cryptographic Parameter Constant Definitions from IETF; + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ike.h" + +// +// "First Oakley Default Group" from RFC2409, section 6.1. +// +// The prime is: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp768Modulus[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, + 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, + 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, + 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, + 0xA6, 0x3A, 0x36, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + +// +// "Second Oakley Default Group" from RFC2409, section 6.2. +// +// The prime is: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp1024Modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, + 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, + 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, + 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, + 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, + 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, + 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, + 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + }; + +// +// "1536-bit MODP Group" from RFC3526, Section 2. +// +// The prime is: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp1536Modulus[]={ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, + 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, + 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, + 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, + 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, + 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, + 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, + 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, + 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, + 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, + 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, + 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, + 0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + }; + +// +// "2048-bit MODP Group" from RFC3526, Section 3. +// +// The prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp2048Modulus[]={ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, + 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, + 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, + 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, + 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, + 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, + 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, + 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, + 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, + 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, + 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, + 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, + 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2, + 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9, + 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C, + 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, + }; + +// +// "3072-bit MODP Group" from RFC3526, Section 4. +// +// The prime is: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp3072Modulus[]={ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, + 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, + 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, + 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, + 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, + 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, + 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, + 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, + 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, + 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, + 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, + 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, + 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2, + 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9, + 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C, + 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D, + 0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64, + 0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57, + 0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0, + 0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B, + 0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73, + 0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0, + 0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31, + 0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20, + 0xA9,0x3A,0xD2,0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + }; + +// +// "4096-bit MODP Group" from RFC3526, Section 5. +// +// The prime is: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp4096Modulus[]={ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, + 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, + 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, + 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, + 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, + 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, + 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, + 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, + 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, + 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, + 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, + 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, + 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2, + 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9, + 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C, + 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D, + 0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64, + 0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57, + 0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0, + 0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B, + 0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73, + 0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0, + 0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31, + 0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20, + 0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18, + 0x6A,0xF4,0xE2,0x3C,0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA, + 0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,0xDB,0xBB,0xC2,0xDB, + 0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F, + 0xA0,0x90,0xC3,0xA2,0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED, + 0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,0xB8,0x1B,0xDD,0x76, + 0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9, + 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC, + 0x90,0xA6,0xC0,0x8F,0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + }; + +// +// "6144-bit MODP Group" from RFC3526, Section 6. +// +// The prime is: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp6144Modulus[]={ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, + 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, + 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, + 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, + 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, + 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, + 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, + 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, + 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, + 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, + 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, + 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, + 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2, + 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9, + 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C, + 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D, + 0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64, + 0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57, + 0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0, + 0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B, + 0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73, + 0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0, + 0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31, + 0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20, + 0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18, + 0x6A,0xF4,0xE2,0x3C,0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA, + 0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,0xDB,0xBB,0xC2,0xDB, + 0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F, + 0xA0,0x90,0xC3,0xA2,0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED, + 0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,0xB8,0x1B,0xDD,0x76, + 0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9, + 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC, + 0x90,0xA6,0xC0,0x8F,0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92, + 0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26,0xC1,0xD4,0xDC,0xB2, + 0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD, + 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F, + 0x41,0x30,0x01,0xAE,0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31, + 0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18,0xDA,0x3E,0xDB,0xEB, + 0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B, + 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51, + 0x2B,0xD7,0xAF,0x42,0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF, + 0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC,0xF0,0x32,0xEA,0x15, + 0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6, + 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31, + 0x90,0x0B,0x1C,0x9E,0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3, + 0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE,0x0F,0x1D,0x45,0xB7, + 0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA, + 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2, + 0x0F,0x80,0x37,0xE0,0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28, + 0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76,0xF5,0x50,0xAA,0x3D, + 0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C, + 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7, + 0x6E,0x3C,0x04,0x68,0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE, + 0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,0xE6,0x94,0xF9,0x1E, + 0x6D,0xCC,0x40,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + }; + +// +// "8192-bit MODP Group" from RFC3526, Section 7. +// +// The prime is: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp8192Modulus[]={ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, + 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, + 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, + 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, + 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, + 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, + 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, + 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, + 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, + 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, + 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, + 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, + 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2, + 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9, + 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C, + 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D, + 0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64, + 0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57, + 0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0, + 0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B, + 0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73, + 0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0, + 0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31, + 0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20, + 0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18, + 0x6A,0xF4,0xE2,0x3C,0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA, + 0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,0xDB,0xBB,0xC2,0xDB, + 0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F, + 0xA0,0x90,0xC3,0xA2,0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED, + 0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,0xB8,0x1B,0xDD,0x76, + 0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9, + 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC, + 0x90,0xA6,0xC0,0x8F,0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92, + 0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26,0xC1,0xD4,0xDC,0xB2, + 0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD, + 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F, + 0x41,0x30,0x01,0xAE,0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31, + 0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18,0xDA,0x3E,0xDB,0xEB, + 0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B, + 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51, + 0x2B,0xD7,0xAF,0x42,0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF, + 0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC,0xF0,0x32,0xEA,0x15, + 0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6, + 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31, + 0x90,0x0B,0x1C,0x9E,0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3, + 0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE,0x0F,0x1D,0x45,0xB7, + 0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA, + 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2, + 0x0F,0x80,0x37,0xE0,0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28, + 0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76,0xF5,0x50,0xAA,0x3D, + 0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C, + 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7, + 0x6E,0x3C,0x04,0x68,0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE, + 0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,0xE6,0x94,0xF9,0x1E, + 0x6D,0xBE,0x11,0x59,0x74,0xA3,0x92,0x6F,0x12,0xFE,0xE5,0xE4, + 0x38,0x77,0x7C,0xB6,0xA9,0x32,0xDF,0x8C,0xD8,0xBE,0xC4,0xD0, + 0x73,0xB9,0x31,0xBA,0x3B,0xC8,0x32,0xB6,0x8D,0x9D,0xD3,0x00, + 0x74,0x1F,0xA7,0xBF,0x8A,0xFC,0x47,0xED,0x25,0x76,0xF6,0x93, + 0x6B,0xA4,0x24,0x66,0x3A,0xAB,0x63,0x9C,0x5A,0xE4,0xF5,0x68, + 0x34,0x23,0xB4,0x74,0x2B,0xF1,0xC9,0x78,0x23,0x8F,0x16,0xCB, + 0xE3,0x9D,0x65,0x2D,0xE3,0xFD,0xB8,0xBE,0xFC,0x84,0x8A,0xD9, + 0x22,0x22,0x2E,0x04,0xA4,0x03,0x7C,0x07,0x13,0xEB,0x57,0xA8, + 0x1A,0x23,0xF0,0xC7,0x34,0x73,0xFC,0x64,0x6C,0xEA,0x30,0x6B, + 0x4B,0xCB,0xC8,0x86,0x2F,0x83,0x85,0xDD,0xFA,0x9D,0x4B,0x7F, + 0xA2,0xC0,0x87,0xE8,0x79,0x68,0x33,0x03,0xED,0x5B,0xDD,0x3A, + 0x06,0x2B,0x3C,0xF5,0xB3,0xA2,0x78,0xA6,0x6D,0x2A,0x13,0xF8, + 0x3F,0x44,0xF8,0x2D,0xDF,0x31,0x0E,0xE0,0x74,0xAB,0x6A,0x36, + 0x45,0x97,0xE8,0x99,0xA0,0x25,0x5D,0xC1,0x64,0xF3,0x1C,0xC5, + 0x08,0x46,0x85,0x1D,0xF9,0xAB,0x48,0x19,0x5D,0xED,0x7E,0xA1, + 0xB1,0xD5,0x10,0xBD,0x7E,0xE7,0x4D,0x73,0xFA,0xF3,0x6B,0xC3, + 0x1E,0xCF,0xA2,0x68,0x35,0x90,0x46,0xF4,0xEB,0x87,0x9F,0x92, + 0x40,0x09,0x43,0x8B,0x48,0x1C,0x6C,0xD7,0x88,0x9A,0x00,0x2E, + 0xD5,0xEE,0x38,0x2B,0xC9,0x19,0x0D,0xA6,0xFC,0x02,0x6E,0x47, + 0x95,0x58,0xE4,0x47,0x56,0x77,0xE9,0xAA,0x9E,0x30,0x50,0xE2, + 0x76,0x56,0x94,0xDF,0xC8,0x1F,0x56,0xE8,0x80,0xB9,0x6E,0x71, + 0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, + }; + +// +// Pre-defined Oakley MODP Groups +// +#define DH_GENERATOR_2 2 +GLOBAL_REMOVE_IF_UNREFERENCED CONST MODP_GROUP OakleyModpGroup[] = { + {0, 0, NULL, 0}, //Undefined + {OakleyGroupModp768, 768, Modp768Modulus, DH_GENERATOR_2}, + {OakleyGroupModp1024, 1024, Modp1024Modulus, DH_GENERATOR_2}, + {0, 0, NULL, 0}, // For ECC. UnSupported + {0, 0, NULL, 0}, // For ECC. Unsupported + {OakleyGroupModp1536, 1536, Modp1536Modulus, DH_GENERATOR_2}, + {0, 0, NULL, 0}, //Undefined + {0, 0, NULL, 0}, //Undefined + {0, 0, NULL, 0}, //Undefined + {0, 0, NULL, 0}, //Undefined + {0, 0, NULL, 0}, //Undefined + {0, 0, NULL, 0}, //Undefined + {0, 0, NULL, 0}, //Undefined + {0, 0, NULL, 0}, //Undefined + {OakleyGroupModp2048, 2048, Modp2048Modulus, DH_GENERATOR_2}, + {OakleyGroupModp3072, 3072, Modp3072Modulus, DH_GENERATOR_2}, + {OakleyGroupModp4096, 4096, Modp4096Modulus, DH_GENERATOR_2}, + {OakleyGroupModp6144, 6144, Modp6144Modulus, DH_GENERATOR_2}, + {OakleyGroupModp8192, 8192, Modp8192Modulus, DH_GENERATOR_2}, +}; diff --git a/NetworkPkg/IpSecDxe/Ike.h b/NetworkPkg/IpSecDxe/Ike.h new file mode 100644 index 0000000000..48c21cf773 --- /dev/null +++ b/NetworkPkg/IpSecDxe/Ike.h @@ -0,0 +1,266 @@ +/** @file + The common definition of IPsec Key Exchange (IKE). + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#ifndef _IKE_H_ +#define _IKE_H_ + +#include +#include +#include "IpSecImpl.h" + +#define IKE_VERSION_MAJOR_MASK 0xf0 +#define IKE_VERSION_MINOR_MASK 0x0f + +#define IKE_MAJOR_VERSION(v) (((v) & IKE_VERSION_MAJOR_MASK) >> 4) +#define IKE_MINOR_VERSION(v) ((v) & IKE_VERSION_MINOR_MASK) + +// +// Protocol Value Use in IKEv1 and IKEv2 +// +#define IPSEC_PROTO_ISAKMP 1 +#define IPSEC_PROTO_IPSEC_AH 2 +#define IPSEC_PROTO_IPSEC_ESP 3 +#define IPSEC_PROTO_IPCOMP 4 // For IKEv1 this value is reserved + +// +// For Algorithm search in support list.Last two types are for IKEv2 only. +// +#define IKE_ENCRYPT_TYPE 0 +#define IKE_AUTH_TYPE 1 +#define IKE_PRF_TYPE 2 +#define IKE_DH_TYPE 3 + +// +// Encryption Algorithm present in IKEv1 phasrs2 and IKEv2 transform payload (Transform Type 1) +// +#define IPSEC_ESP_DES_IV64 1 +#define IPSEC_ESP_DES 2 +#define IPSEC_ESP_3DES 3 +#define IPSEC_ESP_RC5 4 +#define IPSEC_ESP_IDEA 5 +#define IPSEC_ESP_CAST 6 +#define IPSEC_ESP_BLOWFISH 7 +#define IPSEC_ESP_3IDEA 8 +#define IPSEC_ESP_DES_IV32 9 +#define IPSEC_ESP_RC4 10 // It's reserved in IKEv2 +#define IPSEC_ESP_NULL 11 +#define IPSEC_ESP_AES 12 + +#define IKE_XCG_TYPE_NONE 0 +#define IKE_XCG_TYPE_BASE 1 +#define IKE_XCG_TYPE_IDENTITY_PROTECT 2 +#define IKE_XCG_TYPE_AUTH_ONLY 3 +#define IKE_XCG_TYPE_AGGR 4 +#define IKE_XCG_TYPE_INFO 5 +#define IKE_XCG_TYPE_QM 32 +#define IKE_XCG_TYPE_NGM 33 +#define IKE_XCG_TYPE_SA_INIT 34 +#define IKE_XCG_TYPE_AUTH 35 +#define IKE_XCG_TYPE_CREATE_CHILD_SA 36 +#define IKE_XCG_TYPE_INFO2 37 + +#define IKE_LIFE_TYPE_SECONDS 1 +#define IKE_LIFE_TYPE_KILOBYTES 2 + +// +// Deafult IKE SA lifetime and CHILD SA lifetime +// +#define IKE_SA_DEFAULT_LIFETIME 1200 +#define CHILD_SA_DEFAULT_LIFETIME 3600 + +// +// Next payload type presented within Proposal payload +// +#define IKE_PROPOSAL_NEXT_PAYLOAD_MORE 2 +#define IKE_PROPOSAL_NEXT_PAYLOAD_NONE 0 + +// +// Next payload type presented within Transform payload +// +#define IKE_TRANSFORM_NEXT_PAYLOAD_MORE 3 +#define IKE_TRANSFORM_NEXT_PAYLOAD_NONE 0 + +// +// Max size of the SA attribute +// +#define MAX_SA_ATTRS_SIZE 48 +#define SA_ATTR_FORMAT_BIT 0x8000 +// +// The definition for Information Message ID. +// +#define INFO_MID_SIGNATURE SIGNATURE_32 ('I', 'N', 'F', 'M') + +// +// Type for the IKE SESSION COMMON +// +typedef enum { + IkeSessionTypeIkeSa, + IkeSessionTypeChildSa, + IkeSessionTypeInfo, + IkeSessionTypeMax +} IKE_SESSION_TYPE; + +// +// The DH Group ID defined RFC3526 and RFC 2409 +// +typedef enum { + OakleyGroupModp768 = 1, + OakleyGroupModp1024 = 2, + OakleyGroupGp155 = 3, // Unsupported Now. + OakleyGroupGp185 = 4, // Unsupported Now. + OakleyGroupModp1536 = 5, + + OakleyGroupModp2048 = 14, + OakleyGroupModp3072 = 15, + OakleyGroupModp4096 = 16, + OakleyGroupModp6144 = 17, + OakleyGroupModp8192 = 18, + OakleyGroupMax +} OAKLEY_GROUP_ID; + +// +// IKE Header +// +#pragma pack(1) +typedef struct { + UINT64 InitiatorCookie; + UINT64 ResponderCookie; + UINT8 NextPayload; + UINT8 Version; + UINT8 ExchangeType; + UINT8 Flags; + UINT32 MessageId; + UINT32 Length; +} IKE_HEADER; +#pragma pack() + +typedef union { + UINT16 AttrLength; + UINT16 AttrValue; +} IKE_SA_ATTR_UNION; + +// +// SA Attribute present in Transform Payload +// +#pragma pack(1) +typedef struct { + UINT16 AttrType; + IKE_SA_ATTR_UNION Attr; +} IKE_SA_ATTRIBUTE; +#pragma pack() + +// +// Contains the IKE packet information. +// +typedef struct { + UINTN RefCount; + BOOLEAN IsHdrExt; + IKE_HEADER *Header; + BOOLEAN IsPayloadsBufExt; + UINT8 *PayloadsBuf; // The whole IkePakcet trimed the IKE header. + UINTN PayloadTotalSize; + LIST_ENTRY PayloadList; + EFI_IP_ADDRESS RemotePeerIp; + BOOLEAN IsEncoded; // whether HTON is done when sending the packet + UINT32 Spi; // For the Delete Information Exchange + BOOLEAN IsDeleteInfo; // For the Delete Information Exchange + IPSEC_PRIVATE_DATA *Private; // For the Delete Information Exchange +} IKE_PACKET; + +// +// The generic structure to all kinds of IKE payloads. +// +typedef struct { + UINT32 Signature; + BOOLEAN IsPayloadBufExt; + UINT8 PayloadType; + UINT8 *PayloadBuf; + UINTN PayloadSize; + LIST_ENTRY ByPacket; +} IKE_PAYLOAD; + +// +// Udp Service +// +typedef struct { + UINT32 Signature; + UINT8 IpVersion; + LIST_ENTRY List; + LIST_ENTRY *ListHead; + EFI_HANDLE NicHandle; + EFI_HANDLE ImageHandle; + UDP_IO *Input; + UDP_IO *Output; + EFI_IP_ADDRESS DefaultAddress; + BOOLEAN IsConfigured; +} IKE_UDP_SERVICE; + +// +// Each IKE session has its own Key sets for local peer and remote peer. +// +typedef struct { + EFI_IPSEC_ALGO_INFO LocalPeerInfo; + EFI_IPSEC_ALGO_INFO RemotePeerInfo; +} SA_KEYMATS; + +// +// Each algorithm has its own Id, Guid, BlockSize and KeyLength. +// This struct contains these information for each algorithm. It is generic structure +// for both encryption and authentication algorithm. +// For authentication algorithm, the AlgSize means IcvSize. For encryption algorithm, +// it means IvSize. +// +#pragma pack(1) +typedef struct { + UINT8 AlgorithmId; // Encryption or Authentication Id used by ESP/AH + EFI_GUID *AlgGuid; + UINT8 AlgSize; // IcvSize or IvSize + UINT8 BlockSize; + UINTN KeyMateLen; +} IKE_ALG_GUID_INFO; // For IPsec Authentication and Encryption Algorithm. +#pragma pack() + +// +// Structure used to store the DH group +// +typedef struct { + UINT8 GroupId; + UINTN Size; + UINT8 *Modulus; + UINTN GroupGenerator; +} MODP_GROUP; + +/** + This is prototype definition of general interface to phase the payloads + after/before the decode/encode. + + @param[in] SessionCommon Point to the SessionCommon + @param[in] PayloadBuf Point to the buffer of Payload. + @param[in] PayloadSize The size of the PayloadBuf in bytes. + @param[in] PayloadType The type of Payload. + +**/ +typedef +VOID +(*IKE_ON_PAYLOAD_FROM_NET) ( + IN UINT8 *SessionCommon, + IN UINT8 *PayloadBuf, + IN UINTN PayloadSize, + IN UINT8 PayloadType + ); + +#endif + diff --git a/NetworkPkg/IpSecDxe/IkeCommon.c b/NetworkPkg/IpSecDxe/IkeCommon.c new file mode 100644 index 0000000000..7f563653e6 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IkeCommon.c @@ -0,0 +1,255 @@ +/** @file + Common operation of the IKE + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ike.h" +#include "IkeCommon.h" +#include "IpSecConfigImpl.h" +#include "IpSecDebug.h" + +// +// Initial the SPI +// +UINT32 mNextSpi = IKE_SPI_BASE; +EFI_GUID mZeroGuid = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/** + Call Crypto Lib to generate a random value with eight-octet length. + + @return the 64 byte vaule. + +**/ +UINT64 +IkeGenerateCookie ( + VOID + ) +{ + UINT64 Cookie; + EFI_STATUS Status; + + Status = IpSecCryptoIoGenerateRandomBytes ((UINT8 *)&Cookie, sizeof (UINT64)); + if (EFI_ERROR (Status)) { + return 0; + } else { + return Cookie; + } +} + +/** + Generate the random data for Nonce payload. + + @param[in] NonceSize Size of the data in bytes. + + @return Buffer which contains the random data of the spcified size. + +**/ +UINT8 * +IkeGenerateNonce ( + IN UINTN NonceSize + ) +{ + UINT8 *Nonce; + EFI_STATUS Status; + + Nonce = AllocateZeroPool (NonceSize); + if (Nonce == NULL) { + return NULL; + } + + Status = IpSecCryptoIoGenerateRandomBytes (Nonce, NonceSize); + if (EFI_ERROR (Status)) { + FreePool (Nonce); + return NULL; + } else { + return Nonce; + } +} + +/** + Convert the IKE Header from Network order to Host order. + + @param[in, out] Header The pointer of the IKE_HEADER. + +**/ +VOID +IkeHdrNetToHost ( + IN OUT IKE_HEADER *Header + ) +{ + Header->InitiatorCookie = NTOHLL (Header->InitiatorCookie); + Header->ResponderCookie = NTOHLL (Header->ResponderCookie); + Header->MessageId = NTOHL (Header->MessageId); + Header->Length = NTOHL (Header->Length); +} + +/** + Convert the IKE Header from Host order to Network order. + + @param[in, out] Header The pointer of the IKE_HEADER. + +**/ +VOID +IkeHdrHostToNet ( + IN OUT IKE_HEADER *Header + ) +{ + Header->InitiatorCookie = HTONLL (Header->InitiatorCookie); + Header->ResponderCookie = HTONLL (Header->ResponderCookie); + Header->MessageId = HTONL (Header->MessageId); + Header->Length = HTONL (Header->Length); +} + +/** + Allocate a buffer of IKE_PAYLOAD and set its Signature. + + @return A buffer of IKE_PAYLOAD. + +**/ +IKE_PAYLOAD * +IkePayloadAlloc ( + VOID + ) +{ + IKE_PAYLOAD *IkePayload; + + IkePayload = (IKE_PAYLOAD *) AllocateZeroPool (sizeof (IKE_PAYLOAD)); + if (IkePayload == NULL) { + return NULL; + } + + IkePayload->Signature = IKE_PAYLOAD_SIGNATURE; + + return IkePayload; +} + +/** + Free a specified IKE_PAYLOAD buffer. + + @param[in] IkePayload Pointer of IKE_PAYLOAD to be freed. + +**/ +VOID +IkePayloadFree ( + IN IKE_PAYLOAD *IkePayload + ) +{ + if (IkePayload == NULL) { + return; + } + // + // If this IkePayload is not referred by others, free it. + // + if (!IkePayload->IsPayloadBufExt && (IkePayload->PayloadBuf != NULL)) { + FreePool (IkePayload->PayloadBuf); + } + + FreePool (IkePayload); +} + +/** + Generate an new SPI. + + @return a SPI in 4 bytes. + +**/ +UINT32 +IkeGenerateSpi ( + VOID + ) +{ + // + // TODO: should generate SPI randomly to avoid security issue + // + return mNextSpi++; +} + +/** + Generate a random data for IV + + @param[in] IvBuffer The pointer of the IV buffer. + @param[in] IvSize The IV size. + + @retval EFI_SUCCESS Create a random data for IV. + @retval otherwise Failed. + +**/ +EFI_STATUS +IkeGenerateIv ( + IN UINT8 *IvBuffer, + IN UINTN IvSize + ) +{ + return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize); +} + + +/** + Find SPD entry by a specified SPD selector. + + @param[in] SpdSel Point to SPD Selector to be searched for. + + @retval Point to SPD Entry if the SPD entry found. + @retval NULL if not found. + +**/ +IPSEC_SPD_ENTRY * +IkeSearchSpdEntry ( + IN EFI_IPSEC_SPD_SELECTOR *SpdSel + ) +{ + IPSEC_SPD_ENTRY *SpdEntry; + LIST_ENTRY *SpdList; + LIST_ENTRY *Entry; + + SpdList = &mConfigData[IPsecConfigDataTypeSpd]; + + NET_LIST_FOR_EACH (Entry, SpdList) { + SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); + + // + // Find the required SPD entry + // + if (CompareSpdSelector ( + (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel, + (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector + )) { + return SpdEntry; + } + + } + + return NULL; +} + +/** + Get the IKE Version from the IKE_SA_SESSION. + + @param[in] Session Pointer of the IKE_SA_SESSION. + +**/ +UINT8 +IkeGetVersionFromSession ( + IN UINT8 *Session + ) +{ + if (*(UINT32 *) Session == IKEV2_SA_SESSION_SIGNATURE) { + return ((IKEV2_SA_SESSION *) Session)->SessionCommon.IkeVer; + } else { + // + // Add IKEv1 support here. + // + return 0; + } +} + diff --git a/NetworkPkg/IpSecDxe/IkeCommon.h b/NetworkPkg/IpSecDxe/IkeCommon.h new file mode 100644 index 0000000000..6041675efa --- /dev/null +++ b/NetworkPkg/IpSecDxe/IkeCommon.h @@ -0,0 +1,191 @@ +/** @file + Common operation of the IKE. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _IKE_COMMON_H_ +#define _IKE_COMMON_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Ikev2/Ikev2.h" +#include "IpSecImpl.h" +#include "IkePacket.h" +#include "IpSecCryptIo.h" + + +#define IKE_DEFAULT_PORT 500 +#define IKE_DEFAULT_TIMEOUT_INTERVAL 10000 // 10s +#define IKE_NONCE_SIZE 16 +#define IKE_MAX_RETRY 4 +#define IKE_SPI_BASE 0x10000 +#define PRF_HMAC_SHA1_GUID &gEfiCryptAlgorithmSha1Guid +#define IKE_PAYLOAD_SIGNATURE SIGNATURE_32('I','K','E','P') +#define IKE_PAYLOAD_BY_PACKET(a) CR(a,IKE_PAYLOAD,ByPacket,IKE_PAYLOAD_SIGNATURE) + + +#define IKE_PACKET_APPEND_PAYLOAD(IkePacket,IkePayload) \ + do { \ + InsertTailList(&(IkePacket)->PayloadList, &(IkePayload)->ByPacket); \ + } while (0) + +#define IKE_PACKET_REMOVE_PAYLOAD(IkePacket,IkePayload) \ + do { \ + RemoveEntryList(&(IkePayload)->ByPacket); \ + } while (0) + +#define IKE_PACKET_END_PAYLOAD(IkePacket, Node) \ + Node = GetFirstNode (&(IkePacket)->PayloadList); \ + while (!IsNodeAtEnd (&(IkePacket)->PayloadList, Node)) { \ + Node = GetNextNode (&(IkePacket)->PayloadList, Node); \ + } \ + +/** + Call Crypto Lib to generate a random value with eight-octet length. + + @return the 64 byte vaule. + +**/ +UINT64 +IkeGenerateCookie ( + VOID + ); + +/** + Generate the random data for Nonce payload. + + @param[in] NonceSize Size of the data in bytes. + + @return Buffer which contains the random data of the spcified size. + +**/ +UINT8 * +IkeGenerateNonce ( + IN UINTN NonceSize + ); + +/** + Convert the IKE Header from Network order to Host order. + + @param[in, out] Header The pointer of the IKE_HEADER. + +**/ +VOID +IkeHdrNetToHost ( + IN OUT IKE_HEADER *Header + ); + + +/** + Convert the IKE Header from Host order to Network order. + + @param[in, out] Header The pointer of the IKE_HEADER. + +**/ +VOID +IkeHdrHostToNet ( + IN OUT IKE_HEADER *Header + ); + +/** + Allocate a buffer of IKE_PAYLOAD and set its Signature. + + @return A buffer of IKE_PAYLOAD. + +**/ +IKE_PAYLOAD * +IkePayloadAlloc ( + VOID + ); + +/** + Free a specified IKE_PAYLOAD buffer. + + @param[in] IkePayload Pointer of IKE_PAYLOAD to be freed. + +**/ +VOID +IkePayloadFree ( + IN IKE_PAYLOAD *IkePayload + ); + +/** + Generate an unused SPI + + @return a SPI in 4 bytes. + +**/ +UINT32 +IkeGenerateSpi ( + VOID + ); + +/** + Generate a random data for IV + + @param[in] IvBuffer The pointer of the IV buffer. + @param[in] IvSize The IV size. + + @retval EFI_SUCCESS Create a random data for IV. + @retval otherwise Failed. + +**/ +EFI_STATUS +IkeGenerateIv ( + IN UINT8 *IvBuffer, + IN UINTN IvSize + ); + +/** + Get the IKE Version from the IKE_SA_SESSION. + + @param[in] Session Pointer of the IKE_SA_SESSION. + +**/ +UINT8 +IkeGetVersionFromSession ( + IN UINT8 *Session + ); + +/** + Find SPD entry by a specified SPD selector. + + @param[in] SpdSel Point to SPD Selector to be searched for. + + @retval Point to Spd Entry if the SPD entry found. + @retval NULL if not found. + +**/ +IPSEC_SPD_ENTRY * +IkeSearchSpdEntry ( + IN EFI_IPSEC_SPD_SELECTOR *SpdSel + ); + +extern EFI_GUID mZeroGuid; +extern MODP_GROUP OakleyModpGroup[]; +extern IKE_ALG_GUID_INFO mIPsecEncrAlgInfo[]; +extern IKE_ALG_GUID_INFO mIPsecAuthAlgInfo[]; + +#endif + diff --git a/NetworkPkg/IpSecDxe/IkePacket.c b/NetworkPkg/IpSecDxe/IkePacket.c new file mode 100644 index 0000000000..fa29d54876 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IkePacket.c @@ -0,0 +1,257 @@ +/** @file + IKE Packet related operation. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "IpSecDebug.h" +#include "Ikev2/Utility.h" + +/** + Allocate a buffer for the IKE_PACKET and intitalize its Header and payloadlist. + + @return The pointer of the IKE_PACKET. + +**/ +IKE_PACKET * +IkePacketAlloc ( + VOID + ) +{ + IKE_PACKET *IkePacket; + + IkePacket = (IKE_PACKET *) AllocateZeroPool (sizeof (IKE_PACKET)); + if (IkePacket == NULL) { + return NULL; + } + + IkePacket->RefCount = 1; + InitializeListHead (&IkePacket->PayloadList); + + IkePacket->Header = (IKE_HEADER *) AllocateZeroPool (sizeof (IKE_HEADER)); + if (IkePacket->Header == NULL) { + FreePool (IkePacket); + return NULL; + } + return IkePacket; +} + +/** + Free the IkePacket by the specified IKE_PACKET pointer. + + @param[in] IkePacket The pointer of the IKE_PACKET to be freed. + +**/ +VOID +IkePacketFree ( + IN IKE_PACKET *IkePacket + ) +{ + LIST_ENTRY *Entry; + IKE_PAYLOAD *IkePayload; + + if (IkePacket == NULL) { + return; + } + // + // Check if the Packet is referred by others. + // + if (--IkePacket->RefCount == 0) { + // + // Free IkePacket header + // + if (!IkePacket->IsHdrExt && IkePacket->Header != NULL) { + FreePool (IkePacket->Header); + } + // + // Free the PayloadsBuff + // + if (!IkePacket->IsPayloadsBufExt && IkePacket->PayloadsBuf != NULL) { + FreePool (IkePacket->PayloadsBuf); + } + // + // Iterate payloadlist and free all payloads + // + for (Entry = (IkePacket)->PayloadList.ForwardLink; Entry != &(IkePacket)->PayloadList;) { + IkePayload = IKE_PAYLOAD_BY_PACKET (Entry); + Entry = Entry->ForwardLink; + + IkePayloadFree (IkePayload); + } + + FreePool (IkePacket); + } +} + +/** + Callback funtion of NetbufFromExt() + + @param[in] Arg The data passed from the NetBufFromExe(). + +**/ +VOID +IkePacketNetbufFree ( + IN VOID *Arg + ) +{ + // + // TODO: add something if need. + // +} + +/** + Copy the NetBuf into a IKE_PACKET sturcture. + + Create a IKE_PACKET and fill the received IKE header into the header of IKE_PACKET + and copy the recieved packet without IKE HEADER to the PayloadBuf of IKE_PACKET. + + @param[in] Netbuf The pointer of the Netbuf which contains the whole received + IKE packet. + + @return The pointer of the IKE_PACKET which contains the received packet. + +**/ +IKE_PACKET * +IkePacketFromNetbuf ( + IN NET_BUF *Netbuf + ) +{ + IKE_PACKET *IkePacket; + + IkePacket = NULL; + if (Netbuf->TotalSize < sizeof (IKE_HEADER)) { + goto Error; + } + + IkePacket = IkePacketAlloc (); + if (IkePacket == NULL) { + return NULL; + } + // + // Copy the IKE header from Netbuf to IkePacket->Hdr + // + NetbufCopy (Netbuf, 0, sizeof (IKE_HEADER), (UINT8 *) IkePacket->Header); + // + // Net order to host order + // + IkeHdrNetToHost (IkePacket->Header); + if (IkePacket->Header->Length < Netbuf->TotalSize) { + goto Error; + } + + IkePacket->PayloadTotalSize = IkePacket->Header->Length - sizeof (IKE_HEADER); + IkePacket->PayloadsBuf = (UINT8 *) AllocateZeroPool (IkePacket->PayloadTotalSize); + + if (IkePacket->PayloadsBuf == NULL) { + goto Error; + } + // + // Copy the IKE packet without the header into the IkePacket->PayloadsBuf. + // + NetbufCopy (Netbuf, sizeof (IKE_HEADER), (UINT32) IkePacket->PayloadTotalSize, IkePacket->PayloadsBuf); + return IkePacket; + +Error: + if (IkePacket != NULL) { + IkePacketFree (IkePacket); + } + + return NULL; +} + +/** + Convert the format from IKE_PACKET to NetBuf. + + @param[in] SessionCommon Pointer of related IKE_COMMON_SESSION + @param[in] IkePacket Pointer of IKE_PACKET to be copy to NetBuf + @param[in] IkeType The IKE type to pointer the packet is for which IKE + phase. Now it supports IKE_SA_TYPE, IKE_CHILDSA_TYPE, + IKE_INFO_TYPE. + + @return a pointer of Netbuff which contains the IKE_PACKE in network order. + +**/ +NET_BUF * +IkeNetbufFromPacket ( + IN UINT8 *SessionCommon, + IN IKE_PACKET *IkePacket, + IN UINTN IkeType + ) +{ + NET_BUF *Netbuf; + NET_FRAGMENT *Fragments; + UINTN Index; + UINTN NumPayloads; + LIST_ENTRY *PacketEntry; + LIST_ENTRY *Entry; + IKE_PAYLOAD *IkePayload; + + if (!IkePacket->IsEncoded) { + IkePacket->IsEncoded = TRUE; + // + // Convert Host order to Network order for IKE_PACKET header and payloads + // Encryption payloads if needed + // + if (((IKEV2_SESSION_COMMON *) SessionCommon)->IkeVer == 2) { + Ikev2EncodePacket ((IKEV2_SESSION_COMMON *) SessionCommon, IkePacket, IkeType); + } else { + // + //If IKEv1 support, check it here. + // + return NULL; + } + } + + NumPayloads = 0; + // + // Get the number of the payloads + // + NET_LIST_FOR_EACH (PacketEntry, &(IkePacket)->PayloadList) { + + NumPayloads++; + } + // + // Allocate the Framgents according to the numbers of the IkePayload + // + Fragments = (NET_FRAGMENT *) AllocateZeroPool ((1 + NumPayloads) * sizeof (NET_FRAGMENT)); + if (Fragments == NULL) { + return NULL; + } + + Fragments[0].Bulk = (UINT8 *) IkePacket->Header; + Fragments[0].Len = sizeof (IKE_HEADER); + Index = 0; + + // + // Set payloads to the Framgments. + // + NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) { + IkePayload = IKE_PAYLOAD_BY_PACKET (Entry); + + Fragments[Index + 1].Bulk = IkePayload->PayloadBuf; + Fragments[Index + 1].Len = (UINT32) IkePayload->PayloadSize; + Index++; + } + + Netbuf = NetbufFromExt ( + Fragments, + (UINT32) (NumPayloads + 1), + 0, + 0, + IkePacketNetbufFree, + NULL + ); + + FreePool (Fragments); + return Netbuf; +} + diff --git a/NetworkPkg/IpSecDxe/IkePacket.h b/NetworkPkg/IpSecDxe/IkePacket.h new file mode 100644 index 0000000000..053d659d9c --- /dev/null +++ b/NetworkPkg/IpSecDxe/IkePacket.h @@ -0,0 +1,82 @@ +/** @file + IKE Packet related definitions and function declarations. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _IKE_V1_PACKET_H_ +#define _IKE_V1_PACKET_H_ + +#include "Ike.h" + +#define IKE_PACKET_REF(p) ((p)->RefCount++) + +/** + Allocate a buffer for the IKE_PACKET and intitalize its Header and payloadlist. + + @return The pointer of the IKE_PACKET. + +**/ +IKE_PACKET * +IkePacketAlloc ( + VOID + ); + + +/** + Free the IkePacket by the specified IKE_PACKET pointer. + + @param[in] IkePacket The pointer of the IKE_PACKET to be freed. + +**/ +VOID +IkePacketFree ( + IN IKE_PACKET *IkePacket + ); + + +/** + Copy the NetBuf into a IKE_PACKET sturcture. + + Create a IKE_PACKET and fill the received IKE header into the header of IKE_PACKET + and copy the recieved packet without IKE HEADER to the PayloadBuf of IKE_PACKET. + + @param[in] Netbuf The pointer of the Netbuf which contains the whole received + IKE packet. + + @return The pointer of the IKE_PACKET which contains the received packet. + +**/ +IKE_PACKET * +IkePacketFromNetbuf ( + IN NET_BUF *Netbuf + ); + +/** + Convert the format from IKE_PACKET to NetBuf. + + @param[in] SessionCommon Pointer of related IKE_COMMON_SESSION + @param[in] IkePacket Pointer of IKE_PACKET to be copy to NetBuf + @param[in] IkeType The IKE type to pointer the packet is for which IKE + phase. Now it supports IKE_SA_TYPE, IKE_CHILDSA_TYPE, + IKE_INFO_TYPE. + + @return A pointer of Netbuff which contains the contents of the IKE_PACKE in network order. +**/ +NET_BUF * +IkeNetbufFromPacket ( + IN UINT8 *SessionCommon, + IN IKE_PACKET *IkePacket, + IN UINTN IkeType + ); + +#endif diff --git a/NetworkPkg/IpSecDxe/IkeService.c b/NetworkPkg/IpSecDxe/IkeService.c new file mode 100644 index 0000000000..0550534f9c --- /dev/null +++ b/NetworkPkg/IpSecDxe/IkeService.c @@ -0,0 +1,769 @@ +/** @file + Provide IPsec Key Exchange (IKE) service general interfaces. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "IkeService.h" +#include "IpSecConfigImpl.h" +#include "Ikev2/Utility.h" + +IKE_EXCHANGE_INTERFACE *mIkeExchange[] = { + &mIkev1Exchange, + &mIkev2Exchange +}; + +EFI_UDP4_CONFIG_DATA mUdp4Conf = { + FALSE, + FALSE, + FALSE, + TRUE, + // + // IO parameters + // + 0, + 64, + FALSE, + 0, + 1000000, + FALSE, + {0,0,0,0}, + {0,0,0,0}, + IKE_DEFAULT_PORT, + {0,0,0,0}, + 0 +}; + +EFI_UDP6_CONFIG_DATA mUdp6Conf = { + FALSE, + FALSE, + TRUE, + // + // IO parameters + // + 0, + 128, + 0, + 1000000, + //Access Point + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + IKE_DEFAULT_PORT, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + 0 +}; + +/** + Check if the NIC handle is binded to a Udp service. + + @param[in] Private Pointer of IPSEC_PRIVATE_DATA. + @param[in] NicHandle The Handle of the NIC card. + @param[in] IpVersion The version of the IP stack. + + @return a pointer of IKE_UDP_SERVICE. + +**/ +IKE_UDP_SERVICE * +IkeLookupUdp ( + IN IPSEC_PRIVATE_DATA *Private, + IN EFI_HANDLE Handle, + IN UINT8 IpVersion + ) +{ + LIST_ENTRY *Head; + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + IKE_UDP_SERVICE *Udp; + + Udp = NULL; + Head = (IpVersion == IP_VERSION_4) ? &Private->Udp4List : &Private->Udp6List; + + NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) { + + Udp = IPSEC_UDP_SERVICE_FROM_LIST (Entry); + // + // Find the right udp service which installed on the appointed NIC handle. + // + if (Handle == Udp->NicHandle) { + break; + } else { + Udp = NULL; + } + } + + return Udp; +} + +/** + Configure a UDPIO's UDP4 instance. + + This fuction is called by the UdpIoCreateIo() to configures a + UDP4 instance. + + @param[in] UdpIo The UDP_IO to be configured. + @param[in] Context User-defined data when calling UdpIoCreateIo(). + + @retval EFI_SUCCESS The configuration succeeded. + @retval Others The UDP4 instance fails to configure. + +**/ +EFI_STATUS +IkeConfigUdp4 ( + IN UDP_IO *UdpIo, + IN VOID *Context + ) +{ + EFI_UDP4_CONFIG_DATA Udp4Cfg; + EFI_UDP4_PROTOCOL *Udp4; + + ZeroMem (&Udp4Cfg, sizeof (EFI_UDP4_CONFIG_DATA)); + + Udp4 = UdpIo->Protocol.Udp4; + CopyMem ( + &Udp4Cfg, + &mUdp4Conf, + sizeof (EFI_UDP4_CONFIG_DATA) + ); + + if (Context != NULL) { + // + // Configure udp4 io with local default address. + // + Udp4Cfg.UseDefaultAddress = TRUE; + } + + return Udp4->Configure (Udp4, &Udp4Cfg); +} + +/** + Configure a UDPIO's UDP6 instance. + + This fuction is called by the UdpIoCreateIo()to configure a + UDP6 instance. + + @param[in] UdpIo The UDP_IO to be configured. + @param[in] Context User-defined data when calling UdpIoCreateIo(). + + @retval EFI_SUCCESS The configuration succeeded. + @retval Others The configuration fails. + +**/ +EFI_STATUS +IkeConfigUdp6 ( + IN UDP_IO *UdpIo, + IN VOID *Context + ) +{ + EFI_UDP6_PROTOCOL *Udp6; + EFI_UDP6_CONFIG_DATA Udp6Cfg; + + ZeroMem (&Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA)); + + Udp6 = UdpIo->Protocol.Udp6; + CopyMem ( + &Udp6Cfg, + &mUdp6Conf, + sizeof (EFI_UDP6_CONFIG_DATA) + ); + + if (Context != NULL) { + // + // Configure instance with a destination address to start source address + // selection, and then get the configure data from the mode data to store + // the source address. + // + CopyMem ( + &Udp6Cfg.RemoteAddress, + Context, + sizeof (EFI_IPv6_ADDRESS) + ); + } + + return Udp6->Configure (Udp6, &Udp6Cfg); +} + +/** + Open and configure the related output UDPIO for IKE packet sending. + + If the UdpService is not configured, this fuction calls UdpIoCreatIo() to + create UDPIO to bind this UdpService for IKE packet sending. If the UdpService + has already been configured, then return. + + @param[in] UdpService The UDP_IO to be configured. + @param[in] RemoteIp User-defined data when calling UdpIoCreateIo(). + + @retval EFI_SUCCESS The configuration is successful. + @retval Others The configuration fails. + +**/ +EFI_STATUS +IkeOpenOutputUdp ( + IN IKE_UDP_SERVICE *UdpService, + IN EFI_IP_ADDRESS *RemoteIp + ) +{ + EFI_STATUS Status; + EFI_IP4_CONFIG_PROTOCOL *Ip4Cfg; + EFI_IP4_IPCONFIG_DATA *Ip4CfgData; + UINTN BufSize; + EFI_IP6_MODE_DATA Ip6ModeData; + EFI_UDP6_PROTOCOL *Udp6; + + Status = EFI_SUCCESS; + Ip4CfgData = NULL; + BufSize = 0; + + // + // Check whether the input and output udp io are both configured. + // + if (UdpService->IsConfigured) { + goto ON_EXIT; + } + + if (UdpService->IpVersion == UDP_IO_UDP4_VERSION) { + // + // Handle ip4config protocol to get local default address. + // + Status = gBS->HandleProtocol ( + UdpService->NicHandle, + &gEfiIp4ConfigProtocolGuid, + (VOID **) &Ip4Cfg + ); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = Ip4Cfg->GetData (Ip4Cfg, &BufSize, NULL); + + if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) { + goto ON_EXIT; + } + + Ip4CfgData = AllocateZeroPool (BufSize); + + if (Ip4CfgData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = Ip4Cfg->GetData (Ip4Cfg, &BufSize, Ip4CfgData); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + CopyMem ( + &UdpService->DefaultAddress.v4, + &Ip4CfgData->StationAddress, + sizeof (EFI_IPv4_ADDRESS) + ); + + // + // Create udp4 io for output with local default address. + // + UdpService->Output = UdpIoCreateIo ( + UdpService->NicHandle, + UdpService->ImageHandle, + IkeConfigUdp4, + UDP_IO_UDP4_VERSION, + &UdpService->DefaultAddress + ); + + if (UdpService->Output == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + } else { + // + // Create udp6 io for output with remote address. + // + UdpService->Output = UdpIoCreateIo ( + UdpService->NicHandle, + UdpService->ImageHandle, + IkeConfigUdp6, + UDP_IO_UDP6_VERSION, + RemoteIp + ); + + if (UdpService->Output == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + // + // Get ip6 mode data to get the result of source address selection. + // + ZeroMem (&Ip6ModeData, sizeof (EFI_IP6_MODE_DATA)); + + Udp6 = UdpService->Output->Protocol.Udp6; + Status = Udp6->GetModeData (Udp6, NULL, &Ip6ModeData, NULL, NULL); + + if (EFI_ERROR (Status)) { + UdpIoFreeIo (UdpService->Output); + goto ON_EXIT; + } + // + // Reconfigure udp6 io without remote address. + // + Udp6->Configure (Udp6, NULL); + Status = IkeConfigUdp6 (UdpService->Output, NULL); + + // + // Record the selected source address for ipsec process later. + // + CopyMem ( + &UdpService->DefaultAddress.v6, + &Ip6ModeData.ConfigData.StationAddress, + sizeof (EFI_IPv6_ADDRESS) + ); + } + + UdpService->IsConfigured = TRUE; + +ON_EXIT: + if (Ip4CfgData != NULL) { + FreePool (Ip4CfgData); + } + + return Status; +} + +/** + Open and configure a UDPIO of Udp4 for IKE packet receiving. + + This function is called at the IPsecDriverBinding start. IPsec create a UDP4 and + UDP4 IO for each NIC handle. + + @param[in] Private Point to IPSEC_PRIVATE_DATA + @param[in] Controller Handler for NIC card. + + @retval EFI_SUCCESS The Operation is successful. + @retval EFI_OUT_OF_RESOURCE The required system resource can't be allocated. + +**/ +EFI_STATUS +IkeOpenInputUdp4 ( + IN IPSEC_PRIVATE_DATA *Private, + IN EFI_HANDLE Controller + ) +{ + IKE_UDP_SERVICE *Udp4Srv; + + // + // Check whether udp4 io of the controller has already been opened. + // + Udp4Srv = IkeLookupUdp (Private, Controller, IP_VERSION_4); + + if (Udp4Srv != NULL) { + return EFI_ALREADY_STARTED; + } + + Udp4Srv = AllocateZeroPool (sizeof (IKE_UDP_SERVICE)); + + if (Udp4Srv == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Create udp4 io for iutput. + // + Udp4Srv->Input = UdpIoCreateIo ( + Controller, + Private->ImageHandle, + IkeConfigUdp4, + UDP_IO_UDP4_VERSION, + NULL + ); + + if (Udp4Srv->Input == NULL) { + FreePool (Udp4Srv); + return EFI_OUT_OF_RESOURCES; + } + + Udp4Srv->NicHandle = Controller; + Udp4Srv->ImageHandle = Private->ImageHandle; + Udp4Srv->ListHead = &(Private->Udp4List); + Udp4Srv->IpVersion = UDP_IO_UDP4_VERSION; + Udp4Srv->IsConfigured = FALSE; + + ZeroMem (&Udp4Srv->DefaultAddress, sizeof (EFI_IP_ADDRESS)); + + // + // Insert the udp4 io into the list and increase the count. + // + InsertTailList (&Private->Udp4List, &Udp4Srv->List); + + Private->Udp4Num++; + + UdpIoRecvDatagram (Udp4Srv->Input, IkeDispatch, Udp4Srv, 0); + + return EFI_SUCCESS; +} + +/** + Open and configure a UDPIO of Udp6 for IKE packet receiving. + + This function is called at the IPsecDriverBinding start. IPsec create a UDP6 and UDP6 + IO for each NIC handle. + + @param[in] Private Point to IPSEC_PRIVATE_DATA + @param[in] Controller Handler for NIC card. + + @retval EFI_SUCCESS The Operation is successful. + @retval EFI_OUT_OF_RESOURCE The required system resource can't be allocated. + +**/ +EFI_STATUS +IkeOpenInputUdp6 ( + IN IPSEC_PRIVATE_DATA *Private, + IN EFI_HANDLE Controller + ) +{ + IKE_UDP_SERVICE *Udp6Srv; + + Udp6Srv = IkeLookupUdp (Private, Controller, IP_VERSION_6); + + if (Udp6Srv != NULL) { + return EFI_ALREADY_STARTED; + } + + Udp6Srv = AllocateZeroPool (sizeof (IKE_UDP_SERVICE)); + + if (Udp6Srv == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Create udp6 io for input. + // + Udp6Srv->Input = UdpIoCreateIo ( + Controller, + Private->ImageHandle, + IkeConfigUdp6, + UDP_IO_UDP6_VERSION, + NULL + ); + + if (Udp6Srv->Input == NULL) { + FreePool (Udp6Srv); + return EFI_OUT_OF_RESOURCES; + } + + Udp6Srv->NicHandle = Controller; + Udp6Srv->ImageHandle = Private->ImageHandle; + Udp6Srv->ListHead = &(Private->Udp6List); + Udp6Srv->IpVersion = UDP_IO_UDP6_VERSION; + Udp6Srv->IsConfigured = FALSE; + + ZeroMem (&Udp6Srv->DefaultAddress, sizeof (EFI_IP_ADDRESS)); + + // + // Insert the udp6 io into the list and increase the count. + // + InsertTailList (&Private->Udp6List, &Udp6Srv->List); + + Private->Udp6Num++; + + UdpIoRecvDatagram (Udp6Srv->Input, IkeDispatch, Udp6Srv, 0); + + return EFI_SUCCESS; +} + +/** + The general interface of starting IPsec Key Exchange. + + This function is called when a IKE negotiation to start getting a Key. + + @param[in] UdpService Point to IKE_UDP_SERVICE which will be used for + IKE packet sending. + @param[in] SpdEntry Point to the SPD entry related to the IKE negotiation. + @param[in] RemoteIp Point to EFI_IP_ADDRESS related to the IKE negotiation. + + @retval EFI_SUCCESS The Operation is successful. + @retval EFI_ACCESS_DENIED No related PAD entry was found. + @retval EFI_INVALID_PARAMETER The IKE version is not supported. + +**/ +EFI_STATUS +IkeNegotiate ( + IN IKE_UDP_SERVICE *UdpService, + IN IPSEC_SPD_ENTRY *SpdEntry, + IN EFI_IP_ADDRESS *RemoteIp + ) +{ + EFI_STATUS Status; + UINT8 *IkeSaSession; + IKE_EXCHANGE_INTERFACE *Exchange; + IPSEC_PRIVATE_DATA *Private; + IPSEC_PAD_ENTRY *PadEntry; + UINT8 IkeVersion; + + Private = (UdpService->IpVersion == IP_VERSION_4) ? + IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) : + IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead); + + // + // Try to open udp io for output if it hasn't. + // + Status = IkeOpenOutputUdp (UdpService, RemoteIp); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Try to find the IKE SA session in the IKEv1 and IKEv2 established SA session list. + // + IkeSaSession = (UINT8 *) Ikev2SaSessionLookup (&Private->Ikev2EstablishedList, RemoteIp); + + + if (IkeSaSession == NULL) { + // + // Find the pad entry by the remote ip address. + // + PadEntry = IpSecLookupPadEntry (UdpService->IpVersion, RemoteIp); + if (PadEntry == NULL) { + return EFI_ACCESS_DENIED; + } + // + // Determine the IKE exchange instance by the auth protocol in pad entry. + // + ASSERT (PadEntry->Data->AuthProtocol < EfiIPsecAuthProtocolMaximum); + if (PadEntry->Data->AuthProtocol == EfiIPsecAuthProtocolIKEv1) { + return EFI_INVALID_PARAMETER; + } + Exchange = mIkeExchange[PadEntry->Data->AuthProtocol]; + // + // Start the main mode stage to negotiate IKE SA. + // + Status = Exchange->NegotiateSa (UdpService, SpdEntry, PadEntry, RemoteIp); + } else { + // + // Determine the IKE exchange instance by the IKE version in IKE SA session. + // + IkeVersion = IkeGetVersionFromSession (IkeSaSession); + if (IkeVersion != 2) { + return EFI_INVALID_PARAMETER; + } + + Exchange = mIkeExchange[IkeVersion - 1]; + // + // Start the quick mode stage to negotiate child SA. + // + Status = Exchange->NegotiateChildSa (IkeSaSession, SpdEntry, NULL); + } + + return Status; +} + +/** + The generic interface when receive a IKE packet. + + This function is called when UDP IO receives a IKE packet. + + @param[in] Packet Point to received IKE packet. + @param[in] EndPoint Point to UDP_END_POINT which contains the information of + Remote IP and Port. + @param[in] IoStatus The Status of Recieve Token. + @param[in] Context Point to data passed from the caller. + +**/ +VOID +IkeDispatch ( + IN NET_BUF *Packet, + IN UDP_END_POINT *EndPoint, + IN EFI_STATUS IoStatus, + IN VOID *Context + ) +{ + IPSEC_PRIVATE_DATA *Private; + IKE_PACKET *IkePacket; + IKE_HEADER *IkeHdr; + IKE_UDP_SERVICE *UdpService; + IKE_EXCHANGE_INTERFACE *Exchange; + EFI_STATUS Status; + + UdpService = (IKE_UDP_SERVICE *) Context; + IkePacket = NULL; + Private = (UdpService->IpVersion == IP_VERSION_4) ? + IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) : + IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead); + + if (EFI_ERROR (IoStatus)) { + goto ON_EXIT; + } + // + // Check whether the ipsec is enabled or not. + // + if (Private->IpSec.DisabledFlag == TRUE) { + goto ON_EXIT; + } + + if (EndPoint->RemotePort != IKE_DEFAULT_PORT) { + goto ON_EXIT; + } + + // + // Build IKE packet from the received netbuf. + // + IkePacket = IkePacketFromNetbuf (Packet); + + if (IkePacket == NULL) { + goto ON_EXIT; + } + // + // Get the remote address from the IKE packet. + // + if (UdpService->IpVersion == IP_VERSION_4) { + *(UINT32 *) IkePacket->RemotePeerIp.Addr = HTONL ((*(UINT32 *) EndPoint->RemoteAddr.Addr)); + } else { + CopyMem ( + &IkePacket->RemotePeerIp, + NTOHLLL (&EndPoint->RemoteAddr.v6), + sizeof (EFI_IPv6_ADDRESS) + ); + } + // + // Try to open udp io for output if hasn't. + // + Status = IkeOpenOutputUdp (UdpService, &IkePacket->RemotePeerIp); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + IkeHdr = IkePacket->Header; + + // + // Determine the IKE exchange instance by the IKE version in IKE header. + // + if (IKE_MAJOR_VERSION (IkeHdr->Version) == 2) { + Exchange = mIkeExchange[IKE_MAJOR_VERSION (IkeHdr->Version) - 1]; + } else { + goto ON_EXIT; + } + + switch (IkeHdr->ExchangeType) { + case IKE_XCG_TYPE_IDENTITY_PROTECT: + case IKE_XCG_TYPE_SA_INIT: + case IKE_XCG_TYPE_AUTH: + Exchange->HandleSa (UdpService, IkePacket); + break; + + case IKE_XCG_TYPE_QM: + case IKE_XCG_TYPE_CREATE_CHILD_SA: + Exchange->HandleChildSa (UdpService, IkePacket); + break; + + case IKE_XCG_TYPE_INFO: + case IKE_XCG_TYPE_INFO2: + Exchange->HandleInfo (UdpService, IkePacket); + break; + + default: + break; + } + +ON_EXIT: + if (IkePacket != NULL) { + IkePacketFree (IkePacket); + } + + if (Packet != NULL) { + NetbufFree (Packet); + } + + UdpIoRecvDatagram (UdpService->Input, IkeDispatch, UdpService, 0); + + return ; +} + +/** + Delete all established IKE SAs and related Child SAs. + + This function is the subfunction of the IpSecCleanupAllSa(). It first calls + IkeDeleteChildSa() to delete all Child SAs then send out the related + Information packet. + + @param[in] Private Pointer of the IPSEC_PRIVATE_DATA + +**/ +VOID +IkeDeleteAllSas ( + IN IPSEC_PRIVATE_DATA *Private + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + IKEV2_SA_SESSION *Ikev2SaSession; + UINT8 Value; + EFI_STATUS Status; + IKE_EXCHANGE_INTERFACE *Exchange; + UINT8 IkeVersion; + + Exchange = NULL; + + // + // If the IKEv1 is supported, first deal with the Ikev1Estatblished list. + // + + // + // If IKEv2 SAs are under establishing, delete it directly. + // + if (!IsListEmpty (&Private->Ikev2SessionList)) { + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Ikev2SessionList) { + Ikev2SaSession = IKEV2_SA_SESSION_BY_SESSION (Entry); + RemoveEntryList (Entry); + Ikev2SaSessionFree (Ikev2SaSession); + } + } + + // + // If there is no existing established IKE SA, set the Ipsec DisableFlag to TRUE + // and turn off the IsIPsecDisabling flag. + // + if (IsListEmpty (&Private->Ikev2EstablishedList)) { + Value = IPSEC_STATUS_DISABLED; + Status = gRT->SetVariable ( + IPSECCONFIG_STATUS_NAME, + &gEfiIpSecConfigProtocolGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (Value), + &Value + ); + if (!EFI_ERROR (Status)) { + Private->IpSec.DisabledFlag = TRUE; + Private->IsIPsecDisabling = FALSE; + return ; + } + } + + // + // Delete established IKEv2 SAs. + // + if (!IsListEmpty (&Private->Ikev2EstablishedList)) { + for (Entry = Private->Ikev2EstablishedList.ForwardLink; Entry != &Private->Ikev2EstablishedList;) { + Ikev2SaSession = IKEV2_SA_SESSION_BY_SESSION (Entry); + Entry = Entry->ForwardLink; + + Ikev2SaSession->SessionCommon.State = IkeStateSaDeleting; + + // + // Call for Information Exchange. + // + IkeVersion = IkeGetVersionFromSession ((UINT8*)Ikev2SaSession); + if (IkeVersion == 2) { + Exchange = mIkeExchange[IkeVersion - 1]; + Exchange->NegotiateInfo((UINT8*)Ikev2SaSession, NULL); + } + } + } + +} + + + diff --git a/NetworkPkg/IpSecDxe/IkeService.h b/NetworkPkg/IpSecDxe/IkeService.h new file mode 100644 index 0000000000..cbd58cc080 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IkeService.h @@ -0,0 +1,254 @@ +/** @file + Prototypes definitions of IKE service. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _IKE_SERVICE_H_ +#define _IKE_SERVICE_H_ + +#include "Ike.h" +#include "IpSecImpl.h" +#include "IkeCommon.h" + +#define IPSEC_CRYPTO_LIB_MEMORY 128 * 1024 + +/** + This is prototype definition of general interface to intialize a IKE negotiation. + + @param[in] UdpService Point to Udp Servcie used for the IKE packet sending. + @param[in] SpdEntry Point to SPD entry related to this IKE negotiation. + @param[in] PadEntry Point to PAD entry related to this IKE negotiation. + @param[in] RemoteIp Point to IP Address which the remote peer to negnotiate. + + @retval EFI_SUCCESS The operation is successful. + @return Otherwise The operation is failed. + +**/ +typedef +EFI_STATUS +(*IKE_NEGOTIATE_SA) ( + IN IKE_UDP_SERVICE * UdpService, + IN IPSEC_SPD_ENTRY * SpdEntry, + IN IPSEC_PAD_ENTRY * PadEntry, + IN EFI_IP_ADDRESS * RemoteIp + ); + +/** + This is prototype definition fo general interface to start a IKE negotiation at Quick Mode. + + This function will be called when the related IKE SA is existed and start to + create a Child SA. + + @param[in] IkeSaSession Point to IKE SA Session related to this Negotiation. + @param[in] SpdEntry Point to SPD entry related to this Negotiation. + @param[in] Context Point to data passed from the caller. + + @retval EFI_SUCCESS The operation is successful. + @retval Otherwise The operation is failed. + +**/ +typedef +EFI_STATUS +(*IKE_NEGOTIATE_CHILD_SA) ( + IN UINT8 *IkeSaSession, + IN IPSEC_SPD_ENTRY *SpdEntry, + IN UINT8 *Context + ); + +/** + This is prototype definition of the general interface when initialize a Inforamtion + Exchange. + + @param[in] IkeSaSession Point to IKE SA Session related to. + @param[in] Context Point to data passed from caller. + +**/ +typedef +EFI_STATUS +(*IKE_NEGOTIATE_INFO) ( + IN UINT8 *IkeSaSession, + IN UINT8 *Context + ); + +/** + This is prototype definition of the general interface when recived a IKE Pakcet + for the IKE SA establishing. + + @param[in] UdpService Point to UDP service used to send IKE Packet. + @param[in] IkePacket Point to received IKE packet. + +**/ +typedef +VOID +(*IKE_HANDLE_SA) ( + IN IKE_UDP_SERVICE *UdpService, + IN IKE_PACKET *IkePacket + ); + +/** + This is prototyp definition of the general interface when recived a IKE Packet + xfor the Child SA establishing. + + @param[in] UdpService Point to UDP service used to send IKE packet. + @param[in] IkePacket Point to received IKE packet. + +**/ +typedef +VOID +(*IKE_HANDLE_CHILD_SA) ( + IN IKE_UDP_SERVICE *UdpService, + IN IKE_PACKET *IkePacket + ); + +/** + This is prototype definition of the general interface when received a IKE + information Packet. + + @param[in] UdpService Point to UDP service used to send IKE packet. + @param[in] IkePacket Point to received IKE packet. + +**/ +typedef +VOID +(*IKE_HANDLE_INFO) ( + IN IKE_UDP_SERVICE *UdpService, + IN IKE_PACKET *IkePacket + ); + +typedef struct _IKE_EXCHANGE_INTERFACE { + UINT8 IkeVer; + IKE_NEGOTIATE_SA NegotiateSa; + IKE_NEGOTIATE_CHILD_SA NegotiateChildSa; + IKE_NEGOTIATE_INFO NegotiateInfo; + IKE_HANDLE_SA HandleSa; + IKE_HANDLE_CHILD_SA HandleChildSa; + IKE_HANDLE_INFO HandleInfo; +} IKE_EXCHANGE_INTERFACE; + +/** + Open and configure a UDPIO of Udp4 for IKE packet receiving. + + This function is called at the IPsecDriverBinding start. IPsec create a UDP4 and + a UDP4 IO for each NIC handle. + + @param[in] Private Point to IPSEC_PRIVATE_DATA + @param[in] Controller Handler for NIC card. + + @retval EFI_SUCCESS The Operation is successful. + @retval EFI_OUT_OF_RESOURCE The required system resource can't be allocated. + +**/ +EFI_STATUS +IkeOpenInputUdp4 ( + IN IPSEC_PRIVATE_DATA *Private, + IN EFI_HANDLE Controller + ); + +/** + Open and configure a UDPIO of Udp6 for IKE packet receiving. + + This function is called at the IPsecDriverBinding start. IPsec create a UDP6 and UDP6 + IO for each NIC handle. + + @param[in] Private Point to IPSEC_PRIVATE_DATA + @param[in] Controller Handler for NIC card. + + @retval EFI_SUCCESS The Operation is successful. + @retval EFI_OUT_OF_RESOURCE The required system resource can't be allocated. + +**/ +EFI_STATUS +IkeOpenInputUdp6 ( + IN IPSEC_PRIVATE_DATA *Private, + IN EFI_HANDLE Controller + ); + +/** + The general interface of starting IPsec Key Exchange. + + This function is called when start a IKE negotiation to get a Key. + + @param[in] UdpService Point to IKE_UDP_SERVICE which will be used for + IKE packet sending. + @param[in] SpdEntry Point to the SPD entry related to the IKE negotiation. + @param[in] RemoteIp Point to EFI_IP_ADDRESS related to the IKE negotiation. + + @retval EFI_SUCCESS The Operation is successful. + @retval EFI_ACCESS_DENIED No related PAD entry was found. + +**/ +EFI_STATUS +IkeNegotiate ( + IN IKE_UDP_SERVICE *UdpService, + IN IPSEC_SPD_ENTRY *SpdEntry, + IN EFI_IP_ADDRESS *RemoteIp + ); + +/** + The general interface when receive a IKE packet. + + This function is called when UDP IO receives a IKE packet. + + @param[in] Packet Point to received IKE packet. + @param[in] EndPoint Point to UDP_END_POINT which contains the information of + Remote IP and Port. + @param[in] IoStatus The Status of Recieve Token. + @param[in] Context Point to data passed from the caller. + +**/ +VOID +IkeDispatch ( + IN NET_BUF *Packet, + IN UDP_END_POINT *EndPoint, + IN EFI_STATUS IoStatus, + IN VOID *Context + ); + +/** + Check if the NIC handle is binded to a Udp service. + + @param[in] Private Pointer of IPSEC_PRIVATE_DATA + @param[in] NicHandle The Handle of the NIC card + @param[in] IpVersion The version of the IP stack. + + @return a pointer of IKE_UDP_SERVICE. + +**/ +IKE_UDP_SERVICE * +IkeLookupUdp ( + IN IPSEC_PRIVATE_DATA *Private, + IN EFI_HANDLE Handle, + IN UINT8 IpVersion + ); + + +/** + Delete all established IKE SAs and related Child SAs. + + This function is the subfunction of the IpSecCleanupAllSa(). It first calls + IkeDeleteChildSa() to delete all Child SAs then send out the related + Information packet. + + @param[in] Private Pointer of the IPSEC_PRIVATE_DATA. + +**/ +VOID +IkeDeleteAllSas ( + IN IPSEC_PRIVATE_DATA *Private + ); + + +extern IKE_EXCHANGE_INTERFACE mIkev1Exchange; +extern IKE_EXCHANGE_INTERFACE mIkev2Exchange; + +#endif diff --git a/NetworkPkg/IpSecDxe/Ikev2/ChildSa.c b/NetworkPkg/IpSecDxe/Ikev2/ChildSa.c new file mode 100644 index 0000000000..d3859e221d --- /dev/null +++ b/NetworkPkg/IpSecDxe/Ikev2/ChildSa.c @@ -0,0 +1,192 @@ +/** @file + The operations for Child SA. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Utility.h" + +/** + Generate IKE Packet for CREATE_CHILD_SA exchange. + + This IKE Packet would be the packet for creating new CHILD SA, or the packet for + rekeying existing IKE SA, or the packet for existing CHILD SA. + + @param[in] SaSession Pointer to related SA session. + @param[in] Context The data passed by the caller. + + return a pointer of IKE packet. + +**/ +IKE_PACKET * +Ikev2CreateChildGenerator ( + IN UINT8 *SaSession, + IN VOID *Context + ) +{ + + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SA_SESSION *IkeSaSession; + IKE_PACKET *IkePacket; + IKE_PAYLOAD *NotifyPayload; + UINT32 *MessageId; + + ChildSaSession = (IKEV2_CHILD_SA_SESSION *) SaSession; + IkePacket = IkePacketAlloc(); + MessageId = NULL; + + if (IkePacket == NULL) { + return NULL; + } + if (ChildSaSession == NULL) { + return NULL; + } + + if (Context != NULL) { + MessageId = (UINT32 *) Context; + } + + IkePacket->Header->Version = (UINT8) (2 << 4); + IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_NOTIFY; + IkePacket->Header->ExchangeType = IKE_XCG_TYPE_CREATE_CHILD_SA; + + if (ChildSaSession->SessionCommon.IkeSessionType == IkeSessionTypeChildSa) { + // + // 1.a Fill the IkePacket->Hdr + // + IkePacket->Header->InitiatorCookie = ChildSaSession->IkeSaSession->InitiatorCookie; + IkePacket->Header->ResponderCookie = ChildSaSession->IkeSaSession->ResponderCookie; + + if (MessageId != NULL) { + IkePacket->Header->MessageId = *MessageId; + } else { + IkePacket->Header->MessageId = ChildSaSession->MessageId; + } + + if (ChildSaSession->SessionCommon.IsInitiator) { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_CHILD_INIT; + } else { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND; + } + + } else { + IkeSaSession = (IKEV2_SA_SESSION *) SaSession; + // + // 1.a Fill the IkePacket->Hdr + // + IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie; + IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie; + + if (MessageId != NULL) { + IkePacket->Header->MessageId = *MessageId; + } else { + IkePacket->Header->MessageId = IkeSaSession->MessageId; + } + + if (IkeSaSession->SessionCommon.IsInitiator) { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_CHILD_INIT; + } else { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND; + } + } + + // + // According to RFC4306, Chapter 4. + // A minimal implementation may support the CREATE_CHILD_SA exchange only to + // recognize requests and reject them with a Notify payload of type NO_ADDITIONAL_SAS. + // + NotifyPayload = Ikev2GenerateNotifyPayload ( + 0, + IKEV2_PAYLOAD_TYPE_NONE, + 0, + IKEV2_NOTIFICATION_NO_ADDITIONAL_SAS, + NULL, + NULL, + 0 + ); + + IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload); + // + // TODO: Support the CREATE_CHILD_SA exchange. + // + return IkePacket; +} + +/** + Parse the IKE packet of CREATE_CHILD_SA exchange. + + This function parse the IKE packet and save the related information to further + calculation. + + @param[in] SaSession Pointer to IKEv2_CHILD_SA_SESSION related to this Exchange. + @param[in] IkePacket Received packet to be parsed. + + + @retval EFI_SUCCESS The IKE Packet is acceptable. + @retval EFI_UNSUPPORTED Not support the CREATE_CHILD_SA request. + +**/ +EFI_STATUS +Ikev2CreateChildParser ( + IN UINT8 *SaSession, + IN IKE_PACKET *IkePacket + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Routine process before the payload decoding. + + @param[in] SessionCommon Pointer to ChildSa SessionCommon. + @param[in] PayloadBuf Pointer to the payload. + @param[in] PayloadSize Size of PayloadBuf in byte. + @param[in] PayloadType Type of Payload. + +**/ +VOID +Ikev2ChildSaBeforeDecodePayload ( + IN UINT8 *SessionCommon, + IN UINT8 *PayloadBuf, + IN UINTN PayloadSize, + IN UINT8 PayloadType + ) +{ + +} + +/** + Routine Process after the payload encoding. + + @param[in] SessionCommon Pointer to ChildSa SessionCommon. + @param[in] PayloadBuf Pointer to the payload. + @param[in] PayloadSize Size of PayloadBuf in byte. + @param[in] PayloadType Type of Payload. + +**/ +VOID +Ikev2ChildSaAfterEncodePayload ( + IN UINT8 *SessionCommon, + IN UINT8 *PayloadBuf, + IN UINTN PayloadSize, + IN UINT8 PayloadType + ) +{ +} + +IKEV2_PACKET_HANDLER mIkev2CreateChild = { + // + // Create Child + // + Ikev2CreateChildParser, + Ikev2CreateChildGenerator +}; diff --git a/NetworkPkg/IpSecDxe/Ikev2/Exchange.c b/NetworkPkg/IpSecDxe/Ikev2/Exchange.c new file mode 100644 index 0000000000..94bdd86d90 --- /dev/null +++ b/NetworkPkg/IpSecDxe/Ikev2/Exchange.c @@ -0,0 +1,803 @@ +/** @file + The general interfaces of the IKEv2. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Utility.h" +#include "IpSecDebug.h" +#include "IkeService.h" +#include "IpSecConfigImpl.h" + +/** + General interface to intialize a IKEv2 negotiation. + + @param[in] UdpService Point to Udp Servcie used for the IKE packet sending. + @param[in] SpdEntry Point to SPD entry related to this IKE negotiation. + @param[in] PadEntry Point to PAD entry related to this IKE negotiation. + @param[in] RemoteIp Point to IP Address which the remote peer to negnotiate. + + @retval EFI_SUCCESS The operation is successful. + @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated. + @retval EFI_INVALID_PARAMETER If UdpService or RemoteIp is NULL. + @return Others The operation is failed. + +**/ +EFI_STATUS +Ikev2NegotiateSa ( + IN IKE_UDP_SERVICE *UdpService, + IN IPSEC_SPD_ENTRY *SpdEntry, + IN IPSEC_PAD_ENTRY *PadEntry, + IN EFI_IP_ADDRESS *RemoteIp + ) +{ + IPSEC_PRIVATE_DATA *Private; + IKEV2_SA_SESSION *IkeSaSession; + IKEV2_SESSION_COMMON *SessionCommon; + IKEV2_PACKET_HANDLER Handler; + IKE_PACKET *IkePacket; + EFI_STATUS Status; + + if (UdpService == NULL || RemoteIp == NULL) { + return EFI_INVALID_PARAMETER; + } + + IkePacket = NULL; + Private = (UdpService->IpVersion == IP_VERSION_4) ? + IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) : + IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead); + + // + // Lookup the remote ip address in the processing IKE SA session list. + // + IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2SessionList, RemoteIp); + if (IkeSaSession != NULL) { + // + // Drop the packet if already in process. + // + return EFI_SUCCESS; + } + + // + // Create a new IkeSaSession and initiate the common parameters. + // + IkeSaSession = Ikev2SaSessionAlloc (Private, UdpService); + if (IkeSaSession == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Set the specific parameters and state(IKE_STATE_INIT). + // + IkeSaSession->Spd = SpdEntry; + IkeSaSession->Pad = PadEntry; + SessionCommon = &IkeSaSession->SessionCommon; + SessionCommon->IsInitiator = TRUE; + SessionCommon->State = IkeStateInit; + // + // TODO: Get the prefer DH Group from the IPsec Configuration, after the IPsecconfig application update + // to support it. + // + SessionCommon->PreferDhGroup = IKEV2_TRANSFORM_ID_DH_1024MODP; + + CopyMem ( + &SessionCommon->RemotePeerIp, + RemoteIp, + sizeof (EFI_IP_ADDRESS) + ); + + CopyMem ( + &SessionCommon->LocalPeerIp, + &UdpService->DefaultAddress, + sizeof (EFI_IP_ADDRESS) + ); + + IKEV2_DUMP_STATE (SessionCommon->State, IkeStateInit); + + // + // Initiate the SAD data of the IkeSaSession. + // + IkeSaSession->SaData = Ikev2InitializeSaData (SessionCommon); + if (IkeSaSession->SaData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + // + // Generate an IKE request packet and send it out. + // + Handler = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][SessionCommon->State]; + IkePacket = Handler.Generator ((UINT8 *) IkeSaSession, NULL); + if (IkePacket == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + Status = Ikev2SendIkePacket (UdpService, (UINT8 *) SessionCommon, IkePacket, 0); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Insert the current IkeSaSession into the processing IKE SA list. + // + Ikev2SaSessionInsert (&Private->Ikev2SessionList, IkeSaSession, RemoteIp); + + return EFI_SUCCESS; + +ON_ERROR: + + if (IkePacket != NULL) { + IkePacketFree (IkePacket); + } + Ikev2SaSessionFree (IkeSaSession); + return Status; +} + +/** + It is general interface to negotiate the Child SA. + + There are three situations which will invoke this function. First, create a CHILD + SA if the input Context is NULL. Second, rekeying the existing IKE SA if the Context + is a IKEv2_SA_SESSION. Third, rekeying the existing CHILD SA if the context is a + IKEv2_CHILD_SA_SESSION. + + @param[in] IkeSaSession Pointer to IKEv2_SA_SESSION related to this operation. + @param[in] SpdEntry Pointer to IPSEC_SPD_ENTRY related to this operation. + @param[in] Context The data pass from the caller. + + @retval EFI_SUCCESS The operation is successful. + @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated. + @retval EFI_UNSUPPORTED The condition is not support yet. + @return Others The operation is failed. + +**/ +EFI_STATUS +Ikev2NegotiateChildSa ( + IN UINT8 *IkeSaSession, + IN IPSEC_SPD_ENTRY *SpdEntry, + IN UINT8 *Context + ) +{ + EFI_STATUS Status; + IKEV2_SA_SESSION *SaSession; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SESSION_COMMON *ChildSaCommon; + IKE_PACKET *IkePacket; + IKE_UDP_SERVICE *UdpService; + + SaSession = (IKEV2_SA_SESSION*) IkeSaSession; + UdpService = SaSession->SessionCommon.UdpService; + IkePacket = NULL; + + // + // 1. Create another child SA session if context is null. + // 2. Rekeying the IKE SA session if the context is IKE SA session. + // 3. Rekeying the child SA session if the context is child SA session. + // + if (Context == NULL) { + // + // Create a new ChildSaSession and initiate the common parameters. + // + ChildSaSession = Ikev2ChildSaSessionAlloc (UdpService, SaSession); + + if (ChildSaSession == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Set the specific parameters and state as IKE_STATE_CREATE_CHILD. + // + ChildSaSession->Spd = SpdEntry; + ChildSaCommon = &ChildSaSession->SessionCommon; + ChildSaCommon->IsInitiator = TRUE; + ChildSaCommon->State = IkeStateCreateChild; + + IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateCreateChild); + + if (SpdEntry->Selector->NextLayerProtocol != EFI_IPSEC_ANY_PROTOCOL) { + ChildSaSession->ProtoId = SpdEntry->Selector->NextLayerProtocol; + } + + if (SpdEntry->Selector->LocalPort != EFI_IPSEC_ANY_PORT) { + ChildSaSession->LocalPort = SpdEntry->Selector->LocalPort; + } + + if (SpdEntry->Selector->RemotePort != EFI_IPSEC_ANY_PORT) { + ChildSaSession->RemotePort = SpdEntry->Selector->RemotePort; + } + // + // Initiate the SAD data parameters of the ChildSaSession. + // + ChildSaSession->SaData = Ikev2InitializeSaData (ChildSaCommon); + if (ChildSaSession->SaData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // + // Generate an IKE request packet and send it out. + // + IkePacket = mIkev2CreateChild.Generator ((UINT8 *) ChildSaSession, NULL); + + if (IkePacket == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + Status = Ikev2SendIkePacket (UdpService, (UINT8 *) ChildSaCommon, IkePacket, 0); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Insert the ChildSaSession into processing child SA list. + // + Ikev2ChildSaSessionInsert (&SaSession->ChildSaSessionList, ChildSaSession); + } else { + // + // TODO: Rekeying IkeSaSession or ChildSaSession, NOT support yet. + // + // Rekey IkeSa, set IkeSaSession->State and pass over IkeSaSession + // Rekey ChildSa, set ChildSaSession->State and pass over ChildSaSession + // + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; + +ON_ERROR: + + if (ChildSaSession->SaData != NULL) { + FreePool (ChildSaSession->SaData); + } + + if (ChildSaSession->SessionCommon.TimeoutEvent != NULL) { + gBS->CloseEvent (ChildSaSession->SessionCommon.TimeoutEvent); + } + + if (IkePacket != NULL) { + IkePacketFree (IkePacket); + } + + Ikev2ChildSaSessionFree (ChildSaSession); + return Status; +} + +/** + It is general interface to start the Information Exchange. + + There are three situations which will invoke this function. First, deliver a Delete Information + to delete the IKE SA if the input Context is NULL and the state of related IkeSaSeesion's is on + deleting.Second, deliver a Notify Information without the contents if the input Context is NULL. + Third, deliver a Notify Information if the input Context is not NULL. + + @param[in] IkeSaSession Pointer to IKEv2_SA_SESSION related to this operation. + @param[in] Context Data passed by caller. + + @retval EFI_SUCCESS The operation is successful. + @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated. + @retval EFI_UNSUPPORTED The condition is not support yet. + @return Otherwise The operation is failed. + +**/ +EFI_STATUS +Ikev2NegotiateInfo ( + IN UINT8 *IkeSaSession, + IN UINT8 *Context + ) +{ + + EFI_STATUS Status; + IKEV2_SA_SESSION *Ikev2SaSession; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SESSION_COMMON *SaCommon; + IKE_PACKET *IkePacket; + IKE_UDP_SERVICE *UdpService; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + + Ikev2SaSession = (IKEV2_SA_SESSION *) IkeSaSession; + UdpService = Ikev2SaSession->SessionCommon.UdpService; + SaCommon = &Ikev2SaSession->SessionCommon; + IkePacket = NULL; + Status = EFI_SUCCESS; + + // + // Delete the IKE SA. + // + if (Ikev2SaSession->SessionCommon.State == IkeStateSaDeleting && Context == NULL) { + + // + // The IKE SA Session should be initiator if it triggers the deleting. + // + Ikev2SaSession->SessionCommon.IsInitiator = TRUE; + + // + // Generate Information Packet which contains the Delete Payload. + // + IkePacket = mIkev2Info.Generator ((UINT8 *) Ikev2SaSession, NULL); + if (IkePacket == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + // + // Send out the Packet + // + Status = Ikev2SendIkePacket (UdpService, (UINT8 *) SaCommon, IkePacket, 0); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } else if (!IsListEmpty (&Ikev2SaSession->DeleteSaList)) { + // + // Iterate all Deleting Child SAs. + // + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Ikev2SaSession->DeleteSaList) { + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_DEL_SA (Entry); + ChildSaSession->SessionCommon.State = IkeStateSaDeleting; + + // + // Generate Information Packet which contains the Child SA Delete Payload. + // + IkePacket = mIkev2Info.Generator ((UINT8 *) ChildSaSession, NULL); + if (IkePacket == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + // + // Send out the Packet + // + Status = Ikev2SendIkePacket (UdpService, (UINT8 *) &ChildSaSession->SessionCommon, IkePacket, 0); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } + } else if (Context == NULL) { + // + // TODO: Deliver null notification message. + // + } else if (Context != NULL) { + // + // TODO: Send out the Information Exchange which contains the Notify Payload. + // + } +ON_ERROR: + if (IkePacket != NULL) { + IkePacketFree (IkePacket); + } + return Status; + +} + +/** + The general interface when received a IKEv2 packet for the IKE SA establishing. + + This function first find the related IKE SA Session according to the IKE packet's + remote IP. Then call the corresponding function to handle this IKE packet according + to the related IKE SA Session's State. + + @param[in] UdpService Pointer of related UDP Service. + @param[in] IkePacket Data passed by caller. + +**/ +VOID +Ikev2HandleSa ( + IN IKE_UDP_SERVICE *UdpService, + IN IKE_PACKET *IkePacket + ) +{ + EFI_STATUS Status; + IKEV2_SA_SESSION *IkeSaSession; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SESSION_COMMON *IkeSaCommon; + IKEV2_SESSION_COMMON *ChildSaCommon; + IKEV2_PACKET_HANDLER Handler; + IKE_PACKET *Reply; + IPSEC_PAD_ENTRY *PadEntry; + IPSEC_PRIVATE_DATA *Private; + BOOLEAN IsNewSession; + + Private = (UdpService->IpVersion == IP_VERSION_4) ? + IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) : + IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead); + + ChildSaSession = NULL; + ChildSaCommon = NULL; + + // + // Lookup the remote ip address in the processing IKE SA session list. + // + IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2SessionList, &IkePacket->RemotePeerIp); + IsNewSession = FALSE; + + if (IkeSaSession == NULL) { + // + // Lookup the remote ip address in the pad. + // + PadEntry = IpSecLookupPadEntry (UdpService->IpVersion, &IkePacket->RemotePeerIp); + if (PadEntry == NULL) { + // + // Drop the packet if no pad entry matched, this is the request from RFC 4301. + // + return ; + } + + // + // Create a new IkeSaSession and initiate the common parameters. + // + IkeSaSession = Ikev2SaSessionAlloc (Private, UdpService); + if (IkeSaSession == NULL) { + return; + } + IkeSaSession->Pad = PadEntry; + IkeSaCommon = &IkeSaSession->SessionCommon; + IkeSaCommon->IsInitiator = FALSE; + IkeSaCommon->State = IkeStateInit; + + IKEV2_DUMP_STATE (IkeSaCommon->State, IkeStateInit); + + CopyMem ( + &IkeSaCommon->RemotePeerIp, + &IkePacket->RemotePeerIp, + sizeof (EFI_IP_ADDRESS) + ); + + CopyMem ( + &IkeSaCommon->LocalPeerIp, + &UdpService->DefaultAddress, + sizeof (EFI_IP_ADDRESS) + ); + + IsNewSession = TRUE; + } + + // + // Validate the IKE packet header. + // + Status = Ikev2ValidateHeader (IkeSaSession, IkePacket->Header); + if (EFI_ERROR (Status)) { + // + // Drop the packet if invalid IKE header. + // + goto ON_ERROR; + } + + // + // Decode all the payloads in the IKE packet. + // + IkeSaCommon = &IkeSaSession->SessionCommon; + Status = Ikev2DecodePacket (IkeSaCommon, IkePacket, IkeSessionTypeIkeSa); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Try to reate the first ChildSa Session of that IkeSaSession. + // If the IkeSaSession is responder, here will create the first ChildSaSession. + // + if (IkeSaCommon->State == IkeStateAuth && IsListEmpty(&IkeSaSession->ChildSaSessionList)) { + // + // Generate a piggyback child SA in IKE_STATE_AUTH state. + // + ASSERT (IsListEmpty (&IkeSaSession->ChildSaSessionList) && + IsListEmpty (&IkeSaSession->ChildSaEstablishSessionList)); + + ChildSaSession = Ikev2ChildSaSessionCreate (IkeSaSession, UdpService); + ChildSaCommon = &ChildSaSession->SessionCommon; + } + + // + // Parse the IKE request packet according to the auth method and current state. + // + Handler = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][IkeSaCommon->State]; + Status = Handler.Parser ((UINT8 *)IkeSaSession, IkePacket); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Try to reate the first ChildSa Session of that IkeSaSession. + // If the IkeSaSession is initiator, here will create the first ChildSaSession. + // + if (IkeSaCommon->State == IkeStateAuth && IsListEmpty(&IkeSaSession->ChildSaSessionList)) { + // + // Generate a piggyback child SA in IKE_STATE_AUTH state. + // + ASSERT (IsListEmpty (&IkeSaSession->ChildSaSessionList) && + IsListEmpty (&IkeSaSession->ChildSaEstablishSessionList)); + + ChildSaSession = Ikev2ChildSaSessionCreate (IkeSaSession, UdpService); + ChildSaCommon = &ChildSaSession->SessionCommon; + + // + // Initialize the SA data for Child SA. + // + ChildSaSession->SaData = Ikev2InitializeSaData (ChildSaCommon); + } + + // + // Generate the IKE response packet and send it out if not established. + // + if (IkeSaCommon->State != IkeStateIkeSaEstablished) { + Handler = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][IkeSaCommon->State]; + Reply = Handler.Generator ((UINT8 *) IkeSaSession, NULL); + if (Reply == NULL) { + goto ON_ERROR; + } + + Status = Ikev2SendIkePacket (UdpService, (UINT8 *) IkeSaCommon, Reply, 0); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + if (!IkeSaCommon->IsInitiator) { + IkeSaCommon->State ++; + IKEV2_DUMP_STATE (IkeSaCommon->State - 1, IkeSaCommon->State); + } + } + + // + // Insert the new IkeSaSession into the Private processing IkeSaSession List. + // + if (IsNewSession) { + Ikev2SaSessionInsert (&Private->Ikev2SessionList, IkeSaSession, &IkePacket->RemotePeerIp); + } + + // + // Register the IkeSaSession and remove it from processing list. + // + if (IkeSaCommon->State == IkeStateIkeSaEstablished) { + + // + // Remove the Established IKE SA Session from the IKE SA Session Negotiating list + // and insert it into IKE SA Session Established list. + // + Ikev2SaSessionRemove (&Private->Ikev2SessionList, &IkePacket->RemotePeerIp); + Ikev2SaSessionReg (IkeSaSession, Private); + + // + // Remove the Established Child SA Session from the IkeSaSession->ChildSaSessionList + // ,insert it into IkeSaSession->ChildSaEstablishSessionList and save this Child SA + // into SAD. + // + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (IkeSaSession->ChildSaSessionList.BackLink); + Ikev2ChildSaSessionRemove ( + &IkeSaSession->ChildSaSessionList, + ChildSaSession->LocalPeerSpi, + IKEV2_ESTABLISHING_CHILDSA_LIST + ); + Ikev2ChildSaSessionReg (ChildSaSession, Private); + } + + return ; + +ON_ERROR: + if (ChildSaSession != NULL) { + // + // Remove the ChildSa from the list (Established list or Negotiating list). + // + RemoveEntryList (&ChildSaSession->ByIkeSa); + Ikev2ChildSaSessionFree (ChildSaSession); + } + + if (IsNewSession && IkeSaSession != NULL) { + // + // Remove the IkeSa from the list (Established list or Negotiating list). + // + if ((&IkeSaSession->BySessionTable)->ForwardLink != NULL && + !IsListEmpty (&IkeSaSession->BySessionTable + )){ + RemoveEntryList (&IkeSaSession->BySessionTable); + } + Ikev2SaSessionFree (IkeSaSession); + } + + return ; +} + +/** + + The general interface when received a IKEv2 packet for the IKE Child SA establishing + or IKE SA/CHILD SA rekeying. + + This function first find the related IKE SA Session according to the IKE packet's + remote IP. Then call the corresponding function to handle this IKE packet according + to the related IKE Child Session's State. + + @param[in] UdpService Pointer of related UDP Service. + @param[in] IkePacket Data passed by caller. + +**/ +VOID +Ikev2HandleChildSa ( + IN IKE_UDP_SERVICE *UdpService, + IN IKE_PACKET *IkePacket + ) +{ + EFI_STATUS Status; + IKEV2_SA_SESSION *IkeSaSession; + IKEV2_CREATE_CHILD_REQUEST_TYPE RequestType; + IKE_PACKET *Reply; + IPSEC_PRIVATE_DATA *Private; + + Private = (UdpService->IpVersion == IP_VERSION_4) ? + IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) : + IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead); + + Reply = NULL; + + // + // Lookup the remote ip address in the processing IKE SA session list. + // + IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2EstablishedList, &IkePacket->RemotePeerIp); + + if (IkeSaSession == NULL) { + // + // Drop the packet if no IKE SA associated. + // + return ; + } + + // + // Validate the IKE packet header. + // + if (!Ikev2ValidateHeader (IkeSaSession, IkePacket->Header)) { + // + // Drop the packet if invalid IKE header. + // + return; + } + + // + // Decode all the payloads in the IKE packet. + // + Status = Ikev2DecodePacket (&IkeSaSession->SessionCommon, IkePacket, IkeSessionTypeIkeSa); + if (EFI_ERROR (Status)) { + return; + } + + // + // Get the request type: CreateChildSa/RekeyChildSa/RekeyIkeSa. + // + RequestType = Ikev2ChildExchangeRequestType (IkePacket); + + switch (RequestType) { + case IkeRequestTypeCreateChildSa: + case IkeRequestTypeRekeyChildSa: + case IkeRequestTypeRekeyIkeSa: + // + // Parse the IKE request packet. Not support CREATE_CHILD_SA exchange yet, so + // only EFI_UNSUPPORTED will be returned and that will trigger a reply with a + // Notify payload of type NO_ADDITIONAL_SAS. + // + Status = mIkev2CreateChild.Parser ((UINT8 *) IkeSaSession, IkePacket); + if (EFI_ERROR (Status)) { + goto ON_REPLY; + } + + default: + // + // No support. + // + return ; + } + +ON_REPLY: + // + // Generate the reply packet if needed and send it out. + // + if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) { + Reply = mIkev2CreateChild.Generator ((UINT8 *) IkeSaSession, &IkePacket->Header->MessageId); + if (Reply != NULL) { + Status = Ikev2SendIkePacket (UdpService, (UINT8 *) &(IkeSaSession->SessionCommon), Reply, 0); + if (EFI_ERROR (Status)) { + // + // Delete Reply payload. + // + if (Reply != NULL) { + IkePacketFree (Reply); + } + } + } + } + return ; +} + +/** + + It is general interface to handle IKEv2 information Exchange. + + @param[in] UdpService Point to IKE UPD Service related to this information exchange. + @param[in] IkePacket The IKE packet to be parsed. + +**/ +VOID +Ikev2HandleInfo ( + IN IKE_UDP_SERVICE *UdpService, + IN IKE_PACKET *IkePacket + ) +{ + EFI_STATUS Status; + IKEV2_SESSION_COMMON *SessionCommon; + IKEV2_SA_SESSION *IkeSaSession; + IPSEC_PRIVATE_DATA *Private; + + Private = (UdpService->IpVersion == IP_VERSION_4) ? + IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) : + IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead); + + // + // Lookup the remote ip address in the processing IKE SA session list. + // + IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2EstablishedList, &IkePacket->RemotePeerIp); + + if (IkeSaSession == NULL) { + // + // Drop the packet if no IKE SA associated. + // + return ; + } + // + // Validate the IKE packet header. + // + if (!Ikev2ValidateHeader (IkeSaSession, IkePacket->Header)) { + + // + // Drop the packet if invalid IKE header. + // + return; + } + + SessionCommon = &IkeSaSession->SessionCommon; + + // + // Decode all the payloads in the IKE packet. + // + Status = Ikev2DecodePacket (SessionCommon, IkePacket, IkeSessionTypeIkeSa); + if (EFI_ERROR (Status)) { + return; + } + + Status = mIkev2Info.Parser ((UINT8 *)IkeSaSession, IkePacket); + + if (EFI_ERROR (Status)) { + // + // Drop the packet if fail to parse. + // + return; + } +} + +IKE_EXCHANGE_INTERFACE mIkev1Exchange = { + 1, + NULL, //Ikev1NegotiateSa + NULL, //Ikev1NegotiateChildSa + NULL, + NULL, //Ikev1HandleSa, + NULL, //Ikev1HandleChildSa + NULL, //Ikev1HandleInfo +}; + +IKE_EXCHANGE_INTERFACE mIkev2Exchange = { + 2, + Ikev2NegotiateSa, + Ikev2NegotiateChildSa, + Ikev2NegotiateInfo, + Ikev2HandleSa, + Ikev2HandleChildSa, + Ikev2HandleInfo +}; + diff --git a/NetworkPkg/IpSecDxe/Ikev2/Ikev2.h b/NetworkPkg/IpSecDxe/Ikev2/Ikev2.h new file mode 100644 index 0000000000..a2b733a4d2 --- /dev/null +++ b/NetworkPkg/IpSecDxe/Ikev2/Ikev2.h @@ -0,0 +1,258 @@ +/** @file + IKEv2 related definitions. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#ifndef _IKE_V2_H_ +#define _IKE_V2_H_ + +#include "Ike.h" +#include "Payload.h" + +#define IKEV2_TS_ANY_PORT 0xffff +#define IKEV2_TS_ANY_PROTOCOL 0 + +#define IKEV2_DELET_CHILDSA_LIST 0 +#define IKEV2_ESTABLISHING_CHILDSA_LIST 1 +#define IKEV2_ESTABLISHED_CHILDSA_LIST 2 + +#define IKEV2_SA_SESSION_SIGNATURE SIGNATURE_32 ('I', 'K', 'E', 'I') +#define IKEV2_SA_SESSION_FROM_COMMON(a) CR (a, IKEV2_SA_SESSION, SessionCommon, IKEV2_SA_SESSION_SIGNATURE) +#define IKEV2_SA_SESSION_BY_SESSION(a) CR (a, IKEV2_SA_SESSION, BySessionTable, IKEV2_SA_SESSION_SIGNATURE) +#define IKEV2_SA_SESSION_BY_ESTABLISHED(a) CR (a, IKEV2_SA_SESSION, ByEstablishedTable, IKEV2_SA_SESSION_SIGNATURE) + +#define IKEV2_CHILD_SA_SESSION_SIGNATURE SIGNATURE_32 ('I', 'K', 'E', 'C') +#define IKEV2_CHILD_SA_SESSION_FROM_COMMON(a) CR (a, IKEV2_CHILD_SA_SESSION, SessionCommon, IKEV2_CHILD_SA_SESSION_SIGNATURE) +#define IKEV2_CHILD_SA_SESSION_BY_IKE_SA(a) CR (a, IKEV2_CHILD_SA_SESSION, ByIkeSa, IKEV2_CHILD_SA_SESSION_SIGNATURE) +#define IKEV2_CHILD_SA_SESSION_BY_DEL_SA(a) CR (a, IKEV2_CHILD_SA_SESSION, ByDelete, IKEV2_CHILD_SA_SESSION_SIGNATURE) + +#define IS_IKEV2_SA_SESSION(s) ((s)->Common.IkeSessionType == IkeSessionTypeIkeSa) +#define IKEV2_SA_FIRST_PROPOSAL(Sa) (IKEV2_PROPOSAL *)((IKEV2_SA *)(Sa)+1) +#define IKEV2_NEXT_TRANSFORM_WITH_SIZE(Transform,TransformSize) \ + (IKEV2_TRANSFORM *) ((UINT8 *)(Transform) + (TransformSize)) + +#define IKEV2_NEXT_PROPOSAL_WITH_SIZE(Proposal, ProposalSize) \ + (IKEV2_PROPOSAL *) ((UINT8 *)(Proposal) + (ProposalSize)) + +#define IKEV2_PROPOSAL_FIRST_TRANSFORM(Proposal) \ + (IKEV2_TRANSFORM *)((UINT8 *)((IKEV2_PROPOSAL *)(Proposal)+1) + \ + (((IKEV2_PROPOSAL *)(Proposal))->SpiSize)) +#define IKEV2_PROPOSAL_FIRST_TRANSFORM(Proposal) \ + (IKEV2_TRANSFORM *)((UINT8 *)((IKEV2_PROPOSAL *)(Proposal)+1) + \ + (((IKEV2_PROPOSAL *)(Proposal))->SpiSize)) + +typedef enum { + IkeStateInit, + IkeStateAuth, + IkeStateIkeSaEstablished, + IkeStateCreateChild, + IkeStateSaRekeying, + IkeStateChildSaEstablished, + IkeStateSaDeleting, + IkeStateMaximum +} IKEV2_SESSION_STATE; + +typedef enum { + IkeRequestTypeCreateChildSa, + IkeRequestTypeRekeyChildSa, + IkeRequestTypeRekeyIkeSa, + IkeRequestTypeMaximum +} IKEV2_CREATE_CHILD_REQUEST_TYPE; + +typedef struct { + UINT8 *GxBuffer; + UINTN GxSize; + UINT8 *GyBuffer; + UINTN GySize; + UINT8 *GxyBuffer; + UINTN GxySize; + UINT8 *DhContext; +} IKEV2_DH_BUFFER; + +typedef struct { + IKEV2_DH_BUFFER *DhBuffer; + UINT8 *SkdKey; + UINTN SkdKeySize; + UINT8 *SkAiKey; + UINTN SkAiKeySize; + UINT8 *SkArKey; + UINTN SkArKeySize; + UINT8 *SkEiKey; + UINTN SkEiKeySize; + UINT8 *SkErKey; + UINTN SkErKeySize; + UINT8 *SkPiKey; + UINTN SkPiKeySize; + UINT8 *SkPrKey; + UINTN SkPrKeySize; +} IKEV2_SESSION_KEYS; + +typedef struct { + UINT16 LifeType; + UINT64 LifeDuration; + UINT16 EncAlgId; + UINTN EnckeyLen; + UINT16 Prf; + UINT16 IntegAlgId; + UINTN IntegKeyLen; + UINT16 DhGroup; + UINT8 ExtSeq; +} IKEV2_SA_PARAMS; + +// +// Internal Payload +// +typedef struct { + IKEV2_SA SaHeader; + UINTN NumProposals; + // + // IKE_PROPOSAL_DATA Proposals[1]; + // +} IKEV2_SA_DATA; + +typedef struct { + UINT8 ProposalIndex; + UINT8 ProtocolId; + UINT8 *Spi; + UINT8 NumTransforms; + // + // IKE_TRANSFORM_DATA Transforms[1]; + // +} IKEV2_PROPOSAL_DATA; + +typedef struct { + UINT8 TransformIndex; + UINT8 TransformType; + UINT16 TransformId; + IKE_SA_ATTRIBUTE Attribute; +} IKEV2_TRANSFORM_DATA; + +typedef struct { + UINT8 IkeVer; + IKE_SESSION_TYPE IkeSessionType; + BOOLEAN IsInitiator; + BOOLEAN IsOnDeleting; // Flag to indicate whether the SA is on deleting. + IKEV2_SESSION_STATE State; + EFI_EVENT TimeoutEvent; + UINT64 TimeoutInterval; + UINTN RetryCount; + IKE_PACKET *LastSentPacket; + IKEV2_SA_PARAMS *SaParams; + UINT16 PreferDhGroup; + EFI_IP_ADDRESS RemotePeerIp; + EFI_IP_ADDRESS LocalPeerIp; + IKE_ON_PAYLOAD_FROM_NET BeforeDecodePayload; + IKE_ON_PAYLOAD_FROM_NET AfterEncodePayload; + IKE_UDP_SERVICE *UdpService; + IPSEC_PRIVATE_DATA *Private; +} IKEV2_SESSION_COMMON; + +typedef struct { + UINT32 Signature; + IKEV2_SESSION_COMMON SessionCommon; + UINT64 InitiatorCookie; + UINT64 ResponderCookie; + // + // Initiator: SA proposals to be sent + // Responder: SA proposals to be matched + // + IKEV2_SA_DATA *SaData; // SA Private struct used for SA payload generation + IKEV2_SESSION_KEYS *IkeKeys; + UINT8 *NiBlock; + UINTN NiBlkSize; + UINT8 *NrBlock; + UINTN NrBlkSize; + UINT8 *NCookie; // Buffer Contains the Notify Cookie + UINTN NCookieSize; // Size of NCookie + IPSEC_PAD_ENTRY *Pad; + IPSEC_SPD_ENTRY *Spd; // SPD that requested the negotiation, TODO: better use SPD selector + LIST_ENTRY ChildSaSessionList; + LIST_ENTRY ChildSaEstablishSessionList; // For Establish Child SA. + LIST_ENTRY InfoMIDList; // For Information MID + LIST_ENTRY DeleteSaList; // For deteling Child SA. + UINT8 *InitPacket; + UINTN InitPacketSize; + UINT8 *RespPacket; + UINTN RespPacketSize; + UINT32 MessageId; + LIST_ENTRY BySessionTable; // Use for all IkeSaSession Links +} IKEV2_SA_SESSION; + +typedef struct { + UINT32 Signature; + IKEV2_SESSION_COMMON SessionCommon; + IKEV2_SA_SESSION *IkeSaSession; + UINT32 MessageId; + IKEV2_SA_DATA *SaData; + UINT8 IpsecProtocol; + UINT32 LocalPeerSpi; + UINT32 RemotePeerSpi; + UINT8 *NiBlock; + UINTN NiBlkSize; + UINT8 *NrBlock; + UINTN NrBlkSize; + SA_KEYMATS ChildKeymats; + IKEV2_DH_BUFFER *DhBuffer; //New DH exchnaged by CREATE_CHILD_SA + IPSEC_SPD_ENTRY *Spd; + EFI_IPSEC_SPD_SELECTOR *SpdSelector; + UINT16 ProtoId; + UINT16 RemotePort; + UINT16 LocalPort; + LIST_ENTRY ByIkeSa; + LIST_ENTRY ByDelete; +} IKEV2_CHILD_SA_SESSION; + +typedef enum { + Ikev2InfoNotify, + Ikev2InfoDelete, + Ikev2InfoLiveCheck +} IKEV2_INFO_TYPE; + +// +// This struct is used to pass the detail infromation to the InfoGenerator() for +// the response Information Exchange Message creatation. +// +typedef struct { + UINT32 MessageId; + IKEV2_INFO_TYPE InfoType; +} IKEV2_INFO_EXCHANGE_CONTEXT; + +typedef struct { + UINTN DataSize; + UINT8 *Data; +} PRF_DATA_FRAGMENT; + +typedef +IKE_PACKET * +(*IKEV2_PACKET_GENERATOR) ( + IN UINT8 *SaSession, + IN VOID *Context +); + +typedef +EFI_STATUS +(*IKEV2_PACKET_PARSER) ( + IN UINT8 *SaSession, + IN IKE_PACKET *IkePacket +); + +typedef struct { + IKEV2_PACKET_PARSER Parser; + IKEV2_PACKET_GENERATOR Generator; +} IKEV2_PACKET_HANDLER; + +extern IKEV2_PACKET_HANDLER mIkev2Initial[][2]; +extern IKEV2_PACKET_HANDLER mIkev2CreateChild; +extern IKEV2_PACKET_HANDLER mIkev2Info; + +#endif + diff --git a/NetworkPkg/IpSecDxe/Ikev2/Info.c b/NetworkPkg/IpSecDxe/Ikev2/Info.c new file mode 100644 index 0000000000..d297564f11 --- /dev/null +++ b/NetworkPkg/IpSecDxe/Ikev2/Info.c @@ -0,0 +1,401 @@ +/** @file + The Implementations for Information Exchange. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Utility.h" +#include "IpSecDebug.h" +#include "IpSecConfigImpl.h" + +/** + Generate Information Packet. + + The information Packet may contain one Delete Payload, or Notify Payload, which + dependes on the Context's parameters. + + @param[in] SaSession Pointer to IKE SA Session or Child SA Session which is + related to the information Exchange. + @param[in] Context The Data passed from the caller. If the Context is not NULL + it should contain the information for Notification Data. + + @retval Pointer of IKE_PACKET generated. + +**/ +IKE_PACKET * +Ikev2InfoGenerator ( + IN UINT8 *SaSession, + IN VOID *Context + ) +{ + IKEV2_SA_SESSION *IkeSaSession; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKE_PACKET *IkePacket; + IKE_PAYLOAD *IkePayload; + IKEV2_INFO_EXCHANGE_CONTEXT *InfoContext; + + InfoContext = NULL; + IkeSaSession = (IKEV2_SA_SESSION *) SaSession; + IkePacket = IkePacketAlloc (); + ASSERT (IkePacket != NULL); + + // + // Fill IkePacket Header. + // + IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_INFO; + IkePacket->Header->Version = (UINT8) (2 << 4); + + if (Context != NULL) { + InfoContext = (IKEV2_INFO_EXCHANGE_CONTEXT *) Context; + } + + // + // For Liveness Check + // + if (InfoContext != NULL && + (InfoContext->InfoType == Ikev2InfoLiveCheck || InfoContext->InfoType == Ikev2InfoNotify) + ) { + IkePacket->Header->MessageId = InfoContext->MessageId; + IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie; + IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie; + IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_NONE; + IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND; + // + // TODO: add Notify Payload for Notification Information. + // + return IkePacket; + } + + // + // For delete SAs + // + if (IkeSaSession->SessionCommon.IkeSessionType == IkeSessionTypeIkeSa) { + + IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie; + IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie; + + // + // If the information message is response message,the MessageId should + // be same as the request MessageId which passed through the Context. + // + if (InfoContext != NULL) { + IkePacket->Header->MessageId = InfoContext->MessageId; + } else { + IkePacket->Header->MessageId = IkeSaSession->MessageId; + Ikev2SaSessionIncreaseMessageId (IkeSaSession); + } + // + // If the state is on deleting generate a Delete Payload for it. + // + if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting ) { + IkePayload = Ikev2GenerateDeletePayload ( + IkeSaSession, + IKEV2_PAYLOAD_TYPE_NONE, + 0, + 0, + NULL + ); + if (IkePayload == NULL) { + goto ERROR_EXIT; + } + // + // Fill the next payload in IkePacket's Header. + // + IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_DELETE; + IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload); + IkePacket->Private = IkeSaSession->SessionCommon.Private; + IkePacket->Spi = 0; + IkePacket->IsDeleteInfo = TRUE; + + } else if (Context != NULL) { + // + // TODO: If contest is not NULL Generate a Notify Payload. + // + } else { + // + // The input parameter is not correct. + // + goto ERROR_EXIT; + } + } else { + // + // Delete the Child SA Information Exchagne + // + ChildSaSession = (IKEV2_CHILD_SA_SESSION *) SaSession; + IkeSaSession = ChildSaSession->IkeSaSession; + IkePacket->Header->InitiatorCookie = ChildSaSession->IkeSaSession->InitiatorCookie; + IkePacket->Header->ResponderCookie = ChildSaSession->IkeSaSession->ResponderCookie; + + // + // If the information message is response message,the MessageId should + // be same as the request MessageId which passed through the Context. + // + if (InfoContext != NULL && InfoContext->MessageId != 0) { + IkePacket->Header->MessageId = InfoContext->MessageId; + } else { + IkePacket->Header->MessageId = ChildSaSession->IkeSaSession->MessageId; + Ikev2SaSessionIncreaseMessageId (IkeSaSession); + } + + IkePayload = Ikev2GenerateDeletePayload ( + ChildSaSession->IkeSaSession, + IKEV2_PAYLOAD_TYPE_DELETE, + 4, + 1, + (UINT8 *)&ChildSaSession->LocalPeerSpi + ); + if (IkePayload == NULL) { + goto ERROR_EXIT; + } + // + // Fill the Next Payload in IkePacket's Header. + // + IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_DELETE; + IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload); + + IkePacket->Private = IkeSaSession->SessionCommon.Private; + IkePacket->Spi = ChildSaSession->LocalPeerSpi; + IkePacket->IsDeleteInfo = TRUE; + + if (!ChildSaSession->SessionCommon.IsInitiator) { + // + // If responder, use the MessageId fromt the initiator. + // + IkePacket->Header->MessageId = ChildSaSession->MessageId; + } + + // + // Change the IsOnDeleting Flag + // + ChildSaSession->SessionCommon.IsOnDeleting = TRUE; + } + + if (InfoContext == NULL) { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT; + } else { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND; + } + return IkePacket; + +ERROR_EXIT: + if (IkePacket != NULL) { + FreePool (IkePacket); + } + return NULL; + +} + +/** + Parse the Info Exchange. + + @param[in] SaSession Pointer to IKEV2_SA_SESSION. + @param[in] IkePacket Pointer to IkePacket related to the Information Exchange. + + @retval EFI_SUCCESS The operation finised successed. + +**/ +EFI_STATUS +Ikev2InfoParser ( + IN UINT8 *SaSession, + IN IKE_PACKET *IkePacket + ) +{ + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SA_SESSION *IkeSaSession; + IKE_PAYLOAD *NotifyPayload; + IKE_PAYLOAD *DeletePayload; + IKE_PAYLOAD *IkePayload; + IKEV2_DELETE *Delete; + LIST_ENTRY *Entry; + LIST_ENTRY *ListEntry; + UINT8 Index; + UINT32 Spi; + UINT8 *SpiBuffer; + IPSEC_PRIVATE_DATA *Private; + UINT8 Value; + EFI_STATUS Status; + IKE_PACKET *RespondPacket; + + IKEV2_INFO_EXCHANGE_CONTEXT Context; + + IkeSaSession = (IKEV2_SA_SESSION *) SaSession; + + NotifyPayload = NULL; + DeletePayload = NULL; + Private = NULL; + RespondPacket = NULL; + Status = EFI_SUCCESS; + + // + // For Liveness Check + // + if (IkePacket->Header->NextPayload == IKEV2_PAYLOAD_TYPE_NONE && + (IkePacket->PayloadTotalSize == 0) + ) { + if (IkePacket->Header->Flags == IKE_HEADER_FLAGS_INIT) { + // + // If it is Liveness check request, reply it. + // + Context.InfoType = Ikev2InfoLiveCheck; + Context.MessageId = IkePacket->Header->MessageId; + RespondPacket = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context); + + if (RespondPacket == NULL) { + Status = EFI_INVALID_PARAMETER; + return Status; + } + Status = Ikev2SendIkePacket ( + IkeSaSession->SessionCommon.UdpService, + (UINT8 *)(&IkeSaSession->SessionCommon), + RespondPacket, + 0 + ); + + } else { + // + // Todo: verify the liveness check response packet. + // + } + return Status; + } + + // + // For SA Delete + // + NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) { + + // + // Iterate payloads to find the Delete/Notify Payload. + // + IkePayload = IKE_PAYLOAD_BY_PACKET (Entry); + + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_DELETE) { + DeletePayload = IkePayload; + Delete = (IKEV2_DELETE *)DeletePayload->PayloadBuf; + + if (Delete->SpiSize == 0) { + // + // Delete IKE SA. + // + if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting) { + RemoveEntryList (&IkeSaSession->BySessionTable); + Ikev2SaSessionFree (IkeSaSession); + // + // Checking the Private status. + // + // + // when all IKE SAs were disabled by calling "IPsecConfig -disable", the IPsec + // status should be changed. + // + Private = IkeSaSession->SessionCommon.Private; + if (Private != NULL && Private->IsIPsecDisabling) { + // + // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in + // IPsec status variable. + // + if (IsListEmpty (&Private->Ikev1EstablishedList) && + (IsListEmpty (&Private->Ikev2EstablishedList)) + ) { + Value = IPSEC_STATUS_DISABLED; + Status = gRT->SetVariable ( + IPSECCONFIG_STATUS_NAME, + &gEfiIpSecConfigProtocolGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (Value), + &Value + ); + if (!EFI_ERROR (Status)) { + // + // Set the DisabledFlag in Private data. + // + Private->IpSec.DisabledFlag = TRUE; + Private->IsIPsecDisabling = FALSE; + } + } + } + } else { + IkeSaSession->SessionCommon.State = IkeStateSaDeleting; + Context.InfoType = Ikev2InfoDelete; + Context.MessageId = IkePacket->Header->MessageId; + + RespondPacket = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context); + if (RespondPacket == NULL) { + Status = EFI_INVALID_PARAMETER; + return Status; + } + Status = Ikev2SendIkePacket ( + IkeSaSession->SessionCommon.UdpService, + (UINT8 *)(&IkeSaSession->SessionCommon), + RespondPacket, + 0 + ); + } + } else if (Delete->SpiSize == 4) { + // + // Move the Child SAs to DeleteList + // + SpiBuffer = (UINT8 *)(Delete + 1); + for (Index = 0; Index < Delete->NumSpis; Index++) { + Spi = ReadUnaligned32 ((UINT32 *)SpiBuffer); + for (ListEntry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink; + ListEntry != &IkeSaSession->ChildSaEstablishSessionList; + ) { + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (ListEntry); + ListEntry = ListEntry->ForwardLink; + + if (ChildSaSession->RemotePeerSpi == HTONL(Spi)) { + if (ChildSaSession->SessionCommon.State != IkeStateSaDeleting) { + + // + // Insert the ChildSa Session into Delete List. + // + InsertTailList (&IkeSaSession->DeleteSaList, &ChildSaSession->ByDelete); + ChildSaSession->SessionCommon.State = IkeStateSaDeleting; + ChildSaSession->SessionCommon.IsInitiator = FALSE; + ChildSaSession->MessageId = IkePacket->Header->MessageId; + + Context.InfoType = Ikev2InfoDelete; + Context.MessageId = IkePacket->Header->MessageId; + + RespondPacket = Ikev2InfoGenerator ((UINT8 *)ChildSaSession, &Context); + if (RespondPacket == NULL) { + Status = EFI_INVALID_PARAMETER; + return Status; + } + Status = Ikev2SendIkePacket ( + ChildSaSession->SessionCommon.UdpService, + (UINT8 *)(&ChildSaSession->SessionCommon), + RespondPacket, + 0 + ); + } else { + // + // Delete the Child SA. + // + Ikev2ChildSaSilentDelete (IkeSaSession, Spi); + RemoveEntryList (&ChildSaSession->ByDelete); + } + } + } + SpiBuffer = SpiBuffer + sizeof (Spi); + } + } + } + } + + return Status; +} + +GLOBAL_REMOVE_IF_UNREFERENCED IKEV2_PACKET_HANDLER mIkev2Info = { + Ikev2InfoParser, + Ikev2InfoGenerator +}; diff --git a/NetworkPkg/IpSecDxe/Ikev2/Payload.c b/NetworkPkg/IpSecDxe/Ikev2/Payload.c new file mode 100644 index 0000000000..35bebf7e43 --- /dev/null +++ b/NetworkPkg/IpSecDxe/Ikev2/Payload.c @@ -0,0 +1,3227 @@ +/** @file + The implementation of Payloads Creation. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Utility.h" +#include "IpSecDebug.h" +#include "IpSecConfigImpl.h" +#include "IpSecCryptIo.h" + +// +// The Constant String of "Key Pad for IKEv2" for Authentication Payload generation. +// +#define CONSTANT_KEY_SIZE 17 +GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mConstantKey[CONSTANT_KEY_SIZE] = +{ + 'K', 'e', 'y', ' ', 'P', 'a', 'd', ' ', 'f', 'o', 'r', ' ', 'I', 'K', 'E', 'v', '2' +}; + +/** + Generate Ikev2 SA payload according to SessionSaData + + @param[in] SessionSaData The data used in SA payload. + @param[in] NextPayload The payload type presented in NextPayload field of + SA Payload header. + @param[in] Type The SA type. It MUST be neither (1) for IKE_SA or + (2) for CHILD_SA or (3) for INFO. + + @retval a Pointer to SA IKE payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateSaPayload ( + IN IKEV2_SA_DATA *SessionSaData, + IN UINT8 NextPayload, + IN IKE_SESSION_TYPE Type + ) +{ + IKE_PAYLOAD *SaPayload; + IKEV2_SA_DATA *SaData; + UINTN SaDataSize; + + SaPayload = IkePayloadAlloc (); + ASSERT (SaPayload != NULL); + // + // TODO: Get the Proposal Number and Transform Number from IPsec Config, + // after the Ipsecconfig Application is support it. + // + + if (Type == IkeSessionTypeIkeSa) { + SaDataSize = sizeof (IKEV2_SA_DATA) + + SessionSaData->NumProposals * sizeof (IKEV2_PROPOSAL_DATA) + + sizeof (IKEV2_TRANSFORM_DATA) * SessionSaData->NumProposals * 4; + } else { + SaDataSize = sizeof (IKEV2_SA_DATA) + + SessionSaData->NumProposals * sizeof (IKEV2_PROPOSAL_DATA) + + sizeof (IKEV2_TRANSFORM_DATA) * SessionSaData->NumProposals * 3; + + } + + SaData = AllocateZeroPool (SaDataSize); + ASSERT (SaData != NULL); + + CopyMem (SaData, SessionSaData, SaDataSize); + SaData->SaHeader.Header.NextPayload = NextPayload; + SaPayload->PayloadType = IKEV2_PAYLOAD_TYPE_SA; + SaPayload->PayloadBuf = (UINT8 *) SaData; + + return SaPayload; +} + +/** + Generate a Nonce payload containing the input parameter NonceBuf. + + @param[in] NonceBuf The nonce buffer contains the whole Nonce payload block + except the payload header. + @param[in] NonceSize The buffer size of the NonceBuf + @param[in] NextPayload The payload type presented in the NextPayload field + of Nonce Payload header. + + @retval Pointer to Nonce IKE paload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateNoncePayload ( + IN UINT8 *NonceBuf, + IN UINTN NonceSize, + IN UINT8 NextPayload + ) +{ + IKE_PAYLOAD *NoncePayload; + IKEV2_NONCE *Nonce; + UINTN Size; + UINT8 *NonceBlock; + + // 1 2 3 + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload !C! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Nonce Data ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + Size = sizeof (IKEV2_NONCE) + NonceSize; + NonceBlock = NonceBuf; + + Nonce = AllocateZeroPool (Size); + ASSERT (Nonce != NULL); + CopyMem (Nonce + 1, NonceBlock, Size - sizeof (IKEV2_NONCE)); + + Nonce->Header.NextPayload = NextPayload; + Nonce->Header.PayloadLength = (UINT16) Size; + NoncePayload = IkePayloadAlloc (); + + ASSERT (NoncePayload != NULL); + NoncePayload->PayloadType = IKEV2_PAYLOAD_TYPE_NONCE; + NoncePayload->PayloadBuf = (UINT8 *) Nonce; + NoncePayload->PayloadSize = Size; + + return NoncePayload; +} + +/** + Generate a Key Exchange payload according to the DH group type and save the + public Key into IkeSaSession IkeKey field. + + @param[in, out] IkeSaSession Pointer of the IKE_SA_SESSION. + @param[in] NextPayload The payload type presented in the NextPayload field of Key + Exchange Payload header. + + @retval Pointer to Key IKE payload. + +**/ +IKE_PAYLOAD* +Ikev2GenerateKePayload ( + IN OUT IKEV2_SA_SESSION *IkeSaSession, + IN UINT8 NextPayload + ) +{ + IKE_PAYLOAD *KePayload; + IKEV2_KEY_EXCHANGE *Ke; + UINTN KeSize; + IKEV2_SESSION_KEYS *IkeKeys; + + // + // 1 2 3 + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload !C! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! DH Group # ! RESERVED ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Key Exchange Data ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + IkeKeys = IkeSaSession->IkeKeys; + + if (IkeSaSession->SessionCommon.IsInitiator) { + KeSize = sizeof (IKEV2_KEY_EXCHANGE) + IkeKeys->DhBuffer->GxSize; + } else { + KeSize = sizeof (IKEV2_KEY_EXCHANGE) + IkeKeys->DhBuffer->GxSize; + } + + // + // Allocate buffer for Key Exchange + // + Ke = AllocateZeroPool (KeSize); + ASSERT (Ke != NULL); + + Ke->Header.NextPayload = NextPayload; + Ke->Header.PayloadLength = (UINT16) KeSize; + Ke->DhGroup = IkeSaSession->SessionCommon.PreferDhGroup; + + CopyMem (Ke + 1, IkeKeys->DhBuffer->GxBuffer, IkeKeys->DhBuffer->GxSize); + + // + // Create IKE_PAYLOAD to point to Key Exchange payload + // + KePayload = IkePayloadAlloc (); + ASSERT (KePayload != NULL); + + KePayload->PayloadType = IKEV2_PAYLOAD_TYPE_KE; + KePayload->PayloadBuf = (UINT8 *) Ke; + KePayload->PayloadSize = KeSize; + return KePayload; +} + +/** + Generate a ID payload. + + @param[in] CommonSession Pointer to IKEV2_SESSION_COMMON related to ID payload. + @param[in] NextPayload The payload type presented in the NextPayload field + of ID Payload header. + + @retval Pointer to ID IKE payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateIdPayload ( + IN IKEV2_SESSION_COMMON *CommonSession, + IN UINT8 NextPayload + ) +{ + IKE_PAYLOAD *IdPayload; + IKEV2_ID *Id; + UINTN IdSize; + UINT8 IpVersion; + UINT8 AddrSize; + + // + // ID payload + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload ! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ID Type ! RESERVED ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Identification Data ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + + IpVersion = CommonSession->UdpService->IpVersion; + AddrSize = (UINT8) ((IpVersion == IP_VERSION_4) ? sizeof(EFI_IPv4_ADDRESS) : sizeof(EFI_IPv6_ADDRESS)); + IdSize = sizeof (IKEV2_ID) + AddrSize; + + Id = (IKEV2_ID *) AllocateZeroPool (IdSize); + ASSERT (Id != NULL); + + IdPayload = IkePayloadAlloc (); + ASSERT (IdPayload != NULL); + + IdPayload->PayloadType = (UINT8) ((CommonSession->IsInitiator) ? IKEV2_PAYLOAD_TYPE_ID_INIT : IKEV2_PAYLOAD_TYPE_ID_RSP); + IdPayload->PayloadBuf = (UINT8 *) Id; + IdPayload->PayloadSize = IdSize; + + // + // Set generic header of identification payload + // + Id->Header.NextPayload = NextPayload; + Id->Header.PayloadLength = (UINT16) IdSize; + Id->IdType = (UINT8) ((IpVersion == IP_VERSION_4) ? IKEV2_ID_TYPE_IPV4_ADDR : IKEV2_ID_TYPE_IPV6_ADDR); + CopyMem (Id + 1, &CommonSession->LocalPeerIp, AddrSize); + + return IdPayload; +} + +/** + Generate a ID payload. + + @param[in] CommonSession Pointer to IKEV2_SESSION_COMMON related to ID payload. + @param[in] NextPayload The payload type presented in the NextPayload field + of ID Payload header. + @param[in] InCert Pointer to the Certificate which distinguished name + will be added into the Id payload. + @param[in] CertSize Size of the Certificate. + + @retval Pointer to ID IKE payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateCertIdPayload ( + IN IKEV2_SESSION_COMMON *CommonSession, + IN UINT8 NextPayload, + IN UINT8 *InCert, + IN UINTN CertSize + ) +{ + IKE_PAYLOAD *IdPayload; + IKEV2_ID *Id; + UINTN IdSize; + UINT8 IpVersion; + UINTN SubjectSize; + UINT8 *CertSubject; + + // + // ID payload + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload ! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ID Type ! RESERVED ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Identification Data ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + + SubjectSize = 0; + CertSubject = NULL; + IpVersion = CommonSession->UdpService->IpVersion; + IpSecCryptoIoGetSubjectFromCert ( + InCert, + CertSize, + &CertSubject, + &SubjectSize + ); + + IdSize = sizeof (IKEV2_ID) + SubjectSize; + + Id = (IKEV2_ID *) AllocateZeroPool (IdSize); + ASSERT (Id != NULL); + + IdPayload = IkePayloadAlloc (); + ASSERT (IdPayload != NULL); + + IdPayload->PayloadType = (UINT8) ((CommonSession->IsInitiator) ? IKEV2_PAYLOAD_TYPE_ID_INIT : IKEV2_PAYLOAD_TYPE_ID_RSP); + IdPayload->PayloadBuf = (UINT8 *) Id; + IdPayload->PayloadSize = IdSize; + + // + // Set generic header of identification payload + // + Id->Header.NextPayload = NextPayload; + Id->Header.PayloadLength = (UINT16) IdSize; + Id->IdType = 9; + CopyMem (Id + 1, CertSubject, SubjectSize); + + if (CertSubject != NULL) { + FreePool (CertSubject); + } + return IdPayload; +} + +/** + Generate a Authentication Payload. + + This function is used for both Authentication generation and verification. When the + IsVerify is TRUE, it create a Auth Data for verification. This function choose the + related IKE_SA_INIT Message for Auth data creation according to the IKE Session's type + and the value of IsVerify parameter. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to. + @param[in] IdPayload Pointer to the ID payload to be used for Authentication + payload generation. + @param[in] NextPayload The type filled into the Authentication Payload next + payload field. + @param[in] IsVerify If it is TURE, the Authentication payload is used for + verification. + + @return pointer to IKE Authentication payload for Pre-shared key method. + +**/ +IKE_PAYLOAD * +Ikev2PskGenerateAuthPayload ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IKE_PAYLOAD *IdPayload, + IN UINT8 NextPayload, + IN BOOLEAN IsVerify + ) +{ + UINT8 *Digest; + UINTN DigestSize; + PRF_DATA_FRAGMENT Fragments[3]; + UINT8 *KeyBuf; + UINTN KeySize; + IKE_PAYLOAD *AuthPayload; + IKEV2_AUTH *PayloadBuf; + EFI_STATUS Status; + + // + // Auth = Prf(Prf(Secret,"Key Pad for IKEv2),IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) + // + // 1 2 3 + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload !C! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Auth Method ! RESERVED ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Authentication Data ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + + KeyBuf = NULL; + AuthPayload = NULL; + Digest = NULL; + + DigestSize = IpSecGetHmacDigestLength ((UINT8)IkeSaSession->SessionCommon.SaParams->Prf); + Digest = AllocateZeroPool (DigestSize); + + if (Digest == NULL) { + return NULL; + } + if (IdPayload == NULL) { + return NULL; + } + // + // Calcualte Prf(Seceret, "Key Pad for IKEv2"); + // + Fragments[0].Data = (UINT8 *) mConstantKey; + Fragments[0].DataSize = CONSTANT_KEY_SIZE; + + Status = IpSecCryptoIoHmac ( + (UINT8)IkeSaSession->SessionCommon.SaParams->Prf, + IkeSaSession->Pad->Data->AuthData, + IkeSaSession->Pad->Data->AuthDataSize, + (HASH_DATA_FRAGMENT *)Fragments, + 1, + Digest, + DigestSize + ); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + // + // Store the AuthKey into KeyBuf + // + KeyBuf = AllocateZeroPool (DigestSize); + ASSERT (KeyBuf != NULL); + CopyMem (KeyBuf, Digest, DigestSize); + KeySize = DigestSize; + + // + // Calculate Prf(SK_Pi/r, IDi/r) + // + Fragments[0].Data = IdPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER); + Fragments[0].DataSize = IdPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER); + + if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) || + (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify) + ) { + Status = IpSecCryptoIoHmac ( + (UINT8)IkeSaSession->SessionCommon.SaParams->Prf, + IkeSaSession->IkeKeys->SkPrKey, + IkeSaSession->IkeKeys->SkPrKeySize, + (HASH_DATA_FRAGMENT *) Fragments, + 1, + Digest, + DigestSize + ); + } else { + Status = IpSecCryptoIoHmac ( + (UINT8)IkeSaSession->SessionCommon.SaParams->Prf, + IkeSaSession->IkeKeys->SkPiKey, + IkeSaSession->IkeKeys->SkPiKeySize, + (HASH_DATA_FRAGMENT *) Fragments, + 1, + Digest, + DigestSize + ); + } + if (EFI_ERROR (Status)) { + goto EXIT; + } + + // + // Copy data to Fragments. + // + if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) || + (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify) + ) { + Fragments[0].Data = IkeSaSession->RespPacket; + Fragments[0].DataSize = IkeSaSession->RespPacketSize; + Fragments[1].Data = IkeSaSession->NiBlock; + Fragments[1].DataSize = IkeSaSession->NiBlkSize; + } else { + Fragments[0].Data = IkeSaSession->InitPacket; + Fragments[0].DataSize = IkeSaSession->InitPacketSize; + Fragments[1].Data = IkeSaSession->NrBlock; + Fragments[1].DataSize = IkeSaSession->NrBlkSize; + } + + // + // Copy the result of Prf(SK_Pr, IDi/r) to Fragments[2]. + // + Fragments[2].Data = AllocateZeroPool (DigestSize); + Fragments[2].DataSize = DigestSize; + CopyMem (Fragments[2].Data, Digest, DigestSize); + + // + // Calculate Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) + // + Status = IpSecCryptoIoHmac ( + (UINT8)IkeSaSession->SessionCommon.SaParams->Prf, + KeyBuf, + KeySize, + (HASH_DATA_FRAGMENT *) Fragments, + 3, + Digest, + DigestSize + ); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + // + // Allocate buffer for Auth Payload + // + AuthPayload = IkePayloadAlloc (); + ASSERT (AuthPayload != NULL); + + AuthPayload->PayloadSize = sizeof (IKEV2_AUTH) + DigestSize; + PayloadBuf = (IKEV2_AUTH *) AllocateZeroPool (AuthPayload->PayloadSize); + ASSERT (PayloadBuf != NULL); + // + // Fill in Auth payload. + // + PayloadBuf->Header.NextPayload = NextPayload; + PayloadBuf->Header.PayloadLength = (UINT16) (AuthPayload->PayloadSize); + if (IkeSaSession->Pad->Data->AuthMethod == EfiIPsecAuthMethodPreSharedSecret) { + // + // Only support Shared Key Message Integrity + // + PayloadBuf->AuthMethod = IKEV2_AUTH_METHOD_SKMI; + } else { + // + // Not support other Auth method. + // + Status = EFI_UNSUPPORTED; + goto EXIT; + } + + // + // Copy the result of Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) to Auth + // payload block. + // + CopyMem ( + PayloadBuf + 1, + Digest, + DigestSize + ); + + // + // Fill in IKE_PACKET + // + AuthPayload->PayloadBuf = (UINT8 *) PayloadBuf; + AuthPayload->PayloadType = IKEV2_PAYLOAD_TYPE_AUTH; + +EXIT: + if (KeyBuf != NULL) { + FreePool (KeyBuf); + } + if (Digest != NULL) { + FreePool (Digest); + } + if (Fragments[2].Data != NULL) { + // + // Free the buffer which contains the result of Prf(SK_Pr, IDi/r) + // + FreePool (Fragments[2].Data); + } + + if (EFI_ERROR (Status)) { + if (AuthPayload != NULL) { + IkePayloadFree (AuthPayload); + } + return NULL; + } else { + return AuthPayload; + } +} + +/** + Generate a Authentication Payload for Certificate Auth method. + + This function has two functions. One is creating a local Authentication + Payload for sending and other is creating the remote Authentication data + for verification when the IsVerify is TURE. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to. + @param[in] IdPayload Pointer to the ID payload to be used for Authentication + payload generation. + @param[in] NextPayload The type filled into the Authentication Payload + next payload field. + @param[in] IsVerify If it is TURE, the Authentication payload is used + for verification. + @param[in] UefiPrivateKey Pointer to the UEFI private key. Ignore it when + verify the authenticate payload. + @param[in] UefiPrivateKeyLen The size of UefiPrivateKey in bytes. Ignore it + when verify the authenticate payload. + @param[in] UefiKeyPwd Pointer to the password of UEFI private key. + Ignore it when verify the authenticate payload. + @param[in] UefiKeyPwdLen The size of UefiKeyPwd in bytes.Ignore it when + verify the authenticate payload. + + @return pointer to IKE Authentication payload for Cerifitcation method. + +**/ +IKE_PAYLOAD * +Ikev2CertGenerateAuthPayload ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IKE_PAYLOAD *IdPayload, + IN UINT8 NextPayload, + IN BOOLEAN IsVerify, + IN UINT8 *UefiPrivateKey, + IN UINTN UefiPrivateKeyLen, + IN UINT8 *UefiKeyPwd, + IN UINTN UefiKeyPwdLen + ) +{ + UINT8 *Digest; + UINTN DigestSize; + PRF_DATA_FRAGMENT Fragments[3]; + UINT8 *KeyBuf; + UINTN KeySize; + IKE_PAYLOAD *AuthPayload; + IKEV2_AUTH *PayloadBuf; + EFI_STATUS Status; + UINT8 *Signature; + UINTN SigSize; + + // + // Auth = Prf(Scert,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) + // + // 1 2 3 + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload !C! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Auth Method ! RESERVED ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Authentication Data ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + // + // Initial point + // + KeyBuf = NULL; + AuthPayload = NULL; + Digest = NULL; + Signature = NULL; + SigSize = 0; + + if (IdPayload == NULL) { + return NULL; + } + DigestSize = IpSecGetHmacDigestLength ((UINT8)IkeSaSession->SessionCommon.SaParams->Prf); + Digest = AllocateZeroPool (DigestSize); + + if (Digest == NULL) { + return NULL; + } + + // + // Store the AuthKey into KeyBuf + // + KeyBuf = AllocateZeroPool (DigestSize); + ASSERT (KeyBuf != NULL); + + CopyMem (KeyBuf, Digest, DigestSize); + KeySize = DigestSize; + + // + // Calculate Prf(SK_Pi/r, IDi/r) + // + Fragments[0].Data = IdPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER); + Fragments[0].DataSize = IdPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER); + + IpSecDumpBuf ("RestofIDPayload", Fragments[0].Data, Fragments[0].DataSize); + + if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) || + (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify) + ) { + Status = IpSecCryptoIoHmac( + (UINT8)IkeSaSession->SessionCommon.SaParams->Prf, + IkeSaSession->IkeKeys->SkPrKey, + IkeSaSession->IkeKeys->SkPrKeySize, + (HASH_DATA_FRAGMENT *) Fragments, + 1, + Digest, + DigestSize + ); + IpSecDumpBuf ("MACedIDForR", Digest, DigestSize); + } else { + Status = IpSecCryptoIoHmac ( + (UINT8)IkeSaSession->SessionCommon.SaParams->Prf, + IkeSaSession->IkeKeys->SkPiKey, + IkeSaSession->IkeKeys->SkPiKeySize, + (HASH_DATA_FRAGMENT *) Fragments, + 1, + Digest, + DigestSize + ); + IpSecDumpBuf ("MACedIDForI", Digest, DigestSize); + } + if (EFI_ERROR (Status)) { + goto EXIT; + } + + // + // Copy data to Fragments. + // + if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) || + (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify) + ) { + Fragments[0].Data = IkeSaSession->RespPacket; + Fragments[0].DataSize = IkeSaSession->RespPacketSize; + Fragments[1].Data = IkeSaSession->NiBlock; + Fragments[1].DataSize = IkeSaSession->NiBlkSize; + IpSecDumpBuf ("RealMessage2", Fragments[0].Data, Fragments[0].DataSize); + IpSecDumpBuf ("NonceIDdata", Fragments[1].Data, Fragments[1].DataSize); + } else { + Fragments[0].Data = IkeSaSession->InitPacket; + Fragments[0].DataSize = IkeSaSession->InitPacketSize; + Fragments[1].Data = IkeSaSession->NrBlock; + Fragments[1].DataSize = IkeSaSession->NrBlkSize; + IpSecDumpBuf ("RealMessage1", Fragments[0].Data, Fragments[0].DataSize); + IpSecDumpBuf ("NonceRDdata", Fragments[1].Data, Fragments[1].DataSize); + } + + // + // Copy the result of Prf(SK_Pr, IDi/r) to Fragments[2]. + // + Fragments[2].Data = AllocateZeroPool (DigestSize); + Fragments[2].DataSize = DigestSize; + CopyMem (Fragments[2].Data, Digest, DigestSize); + + // + // Calculate Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) + // + Status = IpSecCryptoIoHash ( + (UINT8)IkeSaSession->SessionCommon.SaParams->Prf, + (HASH_DATA_FRAGMENT *) Fragments, + 3, + Digest, + DigestSize + ); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + IpSecDumpBuf ("HashSignedOctects", Digest, DigestSize); + // + // Sign the data by the private Key + // + if (!IsVerify) { + IpSecCryptoIoAuthDataWithCertificate ( + Digest, + DigestSize, + UefiPrivateKey, + UefiPrivateKeyLen, + UefiKeyPwd, + UefiKeyPwdLen, + &Signature, + &SigSize + ); + + if (SigSize == 0) { + goto EXIT; + } + } + + // + // Allocate buffer for Auth Payload + // + AuthPayload = IkePayloadAlloc (); + ASSERT (AuthPayload != NULL); + + if (!IsVerify) { + AuthPayload->PayloadSize = sizeof (IKEV2_AUTH) + SigSize; + } else { + AuthPayload->PayloadSize = sizeof (IKEV2_AUTH) + DigestSize; + } + + PayloadBuf = (IKEV2_AUTH *) AllocateZeroPool (AuthPayload->PayloadSize); + ASSERT (PayloadBuf != NULL); + // + // Fill in Auth payload. + // + PayloadBuf->Header.NextPayload = NextPayload; + PayloadBuf->Header.PayloadLength = (UINT16) (AuthPayload->PayloadSize); + if (IkeSaSession->Pad->Data->AuthMethod == EfiIPsecAuthMethodCertificates) { + PayloadBuf->AuthMethod = IKEV2_AUTH_METHOD_RSA; + } else { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + // + // Copy the result of Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) to Auth + // payload block. + // + if (!IsVerify) { + CopyMem (PayloadBuf + 1, Signature, SigSize); + } else { + CopyMem (PayloadBuf + 1, Digest, DigestSize); + } + + // + // Fill in IKE_PACKET + // + AuthPayload->PayloadBuf = (UINT8 *) PayloadBuf; + AuthPayload->PayloadType = IKEV2_PAYLOAD_TYPE_AUTH; + +EXIT: + if (KeyBuf != NULL) { + FreePool (KeyBuf); + } + if (Digest != NULL) { + FreePool (Digest); + } + if (Signature != NULL) { + FreePool (Signature); + } + if (Fragments[2].Data != NULL) { + // + // Free the buffer which contains the result of Prf(SK_Pr, IDi/r) + // + FreePool (Fragments[2].Data); + } + + if (EFI_ERROR (Status)) { + if (AuthPayload != NULL) { + IkePayloadFree (AuthPayload); + } + return NULL; + } else { + return AuthPayload; + } +} + +/** + Generate TS payload. + + This function generates TSi or TSr payload according to type of next payload. + If the next payload is Responder TS, gereate TSi Payload. Otherwise, generate + TSr payload. + + @param[in] ChildSa Pointer to IKEV2_CHILD_SA_SESSION related to this TS payload. + @param[in] NextPayload The payload type presented in the NextPayload field + of ID Payload header. + @param[in] IsTunnel It indicates that if the Ts Payload is after the CP payload. + If yes, it means the Tsi and Tsr payload should be with + Max port range and address range and protocol is marked + as zero. + + @retval Pointer to Ts IKE payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateTsPayload ( + IN IKEV2_CHILD_SA_SESSION *ChildSa, + IN UINT8 NextPayload, + IN BOOLEAN IsTunnel + ) +{ + IKE_PAYLOAD *TsPayload; + IKEV2_TS *TsPayloadBuf; + TRAFFIC_SELECTOR *TsSelector; + UINTN SelectorSize; + UINTN TsPayloadSize; + UINT8 IpVersion; + UINT8 AddrSize; + + // + // 1 2 3 + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload !C! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Number of TSs ! RESERVED ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + + TsPayload = IkePayloadAlloc(); + ASSERT (TsPayload != NULL); + + IpVersion = ChildSa->SessionCommon.UdpService->IpVersion; + // + // The Starting Address and Ending Address is variable length depends on + // is IPv4 or IPv6 + // + AddrSize = (UINT8)((IpVersion == IP_VERSION_4) ? sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS)); + SelectorSize = sizeof (TRAFFIC_SELECTOR) + 2 * AddrSize; + TsPayloadSize = sizeof (IKEV2_TS) + SelectorSize; + TsPayloadBuf = AllocateZeroPool (TsPayloadSize); + ASSERT (TsPayloadBuf != NULL); + + TsPayload->PayloadBuf = (UINT8 *) TsPayloadBuf; + TsSelector = (TRAFFIC_SELECTOR*)(TsPayloadBuf + 1); + + TsSelector->TSType = (UINT8)((IpVersion == IP_VERSION_4) ? IKEV2_TS_TYPE_IPV4_ADDR_RANGE : IKEV2_TS_TYPS_IPV6_ADDR_RANGE); + + // + // For tunnel mode + // + if (IsTunnel) { + TsSelector->IpProtocolId = IKEV2_TS_ANY_PROTOCOL; + TsSelector->SelecorLen = (UINT16) SelectorSize; + TsSelector->StartPort = 0; + TsSelector->EndPort = IKEV2_TS_ANY_PORT; + ZeroMem ((UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR), AddrSize); + SetMem ((UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize, AddrSize, 0xff); + + } else { + // + // TODO: Support port range and address range + // + if (NextPayload == IKEV2_PAYLOAD_TYPE_TS_RSP){ + // + // Create initiator Traffic Selector + // + TsSelector->SelecorLen = (UINT16)SelectorSize; + + // + // Currently only support the port range from 0~0xffff. Don't support other + // port range. + // TODO: support Port range + // + if (ChildSa->SessionCommon.IsInitiator) { + if (ChildSa->Spd->Selector->LocalPort != 0 && + ChildSa->Spd->Selector->LocalPortRange == 0) { + // + // For not port range. + // + TsSelector->StartPort = ChildSa->Spd->Selector->LocalPort; + TsSelector->EndPort = ChildSa->Spd->Selector->LocalPort; + } else if (ChildSa->Spd->Selector->LocalPort == 0){ + // + // For port from 0~0xffff + // + TsSelector->StartPort = 0; + TsSelector->EndPort = IKEV2_TS_ANY_PORT; + } else { + // + // Not support now. + // + goto ON_ERROR; + } + } else { + if (ChildSa->Spd->Selector->RemotePort != 0 && + ChildSa->Spd->Selector->RemotePortRange == 0) { + // + // For not port range. + // + TsSelector->StartPort = ChildSa->Spd->Selector->RemotePort; + TsSelector->EndPort = ChildSa->Spd->Selector->RemotePort; + } else if (ChildSa->Spd->Selector->RemotePort == 0) { + // + // For port from 0~0xffff + // + TsSelector->StartPort = 0; + TsSelector->EndPort = IKEV2_TS_ANY_PORT; + } else { + // + // Not support now. + // + goto ON_ERROR; + } + } + // + // Copy Address.Currently the address range is not supported. + // The Starting address is same as Ending address + // TODO: Support Address Range. + // + CopyMem ( + (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR), + ChildSa->SessionCommon.IsInitiator ? + ChildSa->Spd->Selector->LocalAddress : + ChildSa->Spd->Selector->RemoteAddress, + AddrSize + ); + CopyMem ( + (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize, + ChildSa->SessionCommon.IsInitiator ? + ChildSa->Spd->Selector->LocalAddress : + ChildSa->Spd->Selector->RemoteAddress, + AddrSize + ); + // + // If the Next Payload is not TS responder, this TS payload type is the TS responder. + // + TsPayload->PayloadType = IKEV2_PAYLOAD_TYPE_TS_INIT; + }else{ + // + // Create responder Traffic Selector + // + TsSelector->SelecorLen = (UINT16)SelectorSize; + + // + // Currently only support the port range from 0~0xffff. Don't support other + // port range. + // TODO: support Port range + // + if (!ChildSa->SessionCommon.IsInitiator) { + if (ChildSa->Spd->Selector->LocalPort != 0 && + ChildSa->Spd->Selector->LocalPortRange == 0) { + // + // For not port range. + // + TsSelector->StartPort = ChildSa->Spd->Selector->LocalPort; + TsSelector->EndPort = ChildSa->Spd->Selector->LocalPort; + } else if (ChildSa->Spd->Selector->LocalPort == 0){ + // + // For port from 0~0xffff + // + TsSelector->StartPort = 0; + TsSelector->EndPort = IKEV2_TS_ANY_PORT; + } else { + // + // Not support now. + // + goto ON_ERROR; + } + } else { + if (ChildSa->Spd->Selector->RemotePort != 0 && + ChildSa->Spd->Selector->RemotePortRange == 0) { + // + // For not port range. + // + TsSelector->StartPort = ChildSa->Spd->Selector->RemotePort; + TsSelector->EndPort = ChildSa->Spd->Selector->RemotePort; + } else if (ChildSa->Spd->Selector->RemotePort == 0){ + // + // For port from 0~0xffff + // + TsSelector->StartPort = 0; + TsSelector->EndPort = IKEV2_TS_ANY_PORT; + } else { + // + // Not support now. + // + goto ON_ERROR; + } + } + // + // Copy Address.Currently the address range is not supported. + // The Starting address is same as Ending address + // TODO: Support Address Range. + // + CopyMem ( + (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR), + ChildSa->SessionCommon.IsInitiator ? + ChildSa->Spd->Selector->RemoteAddress : + ChildSa->Spd->Selector->LocalAddress, + AddrSize + ); + CopyMem ( + (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize, + ChildSa->SessionCommon.IsInitiator ? + ChildSa->Spd->Selector->RemoteAddress : + ChildSa->Spd->Selector->LocalAddress, + AddrSize + ); + // + // If the Next Payload is not TS responder, this TS payload type is the TS responder. + // + TsPayload->PayloadType = IKEV2_PAYLOAD_TYPE_TS_RSP; + } + } + + if (ChildSa->Spd->Selector->NextLayerProtocol != 0xffff) { + TsSelector->IpProtocolId = (UINT8)ChildSa->Spd->Selector->NextLayerProtocol; + } else { + TsSelector->IpProtocolId = IKEV2_TS_ANY_PROTOCOL; + } + + TsPayloadBuf->Header.NextPayload = NextPayload; + TsPayloadBuf->Header.PayloadLength = (UINT16)TsPayloadSize; + TsPayloadBuf->TSNumbers = 1; + TsPayload->PayloadSize = TsPayloadSize; + goto ON_EXIT; + +ON_ERROR: + if (TsPayload != NULL) { + IkePayloadFree (TsPayload); + TsPayload = NULL; + } +ON_EXIT: + return TsPayload; +} + +/** + Generate the Notify payload. + + Since the structure of Notify payload which defined in RFC 4306 is simple, so + there is no internal data structure for Notify payload. This function generate + Notify payload defined in RFC 4306, but all the fields in this payload are still + in host order and need call Ikev2EncodePayload() to convert those fields from + the host order to network order beforing sending it. + + @param[in] ProtocolId The protocol type ID. For IKE_SA it MUST be one (1). + For IPsec SAs it MUST be neither (2) for AH or (3) + for ESP. + @param[in] NextPayload The next paylaod type in NextPayload field of + the Notify payload. + @param[in] SpiSize Size of the SPI in SPI size field of the Notify Payload. + @param[in] MessageType The message type in NotifyMessageType field of the + Notify Payload. + @param[in] SpiBuf Pointer to buffer contains the SPI value. + @param[in] NotifyData Pointer to buffer contains the notification data. + @param[in] NotifyDataSize The size of NotifyData in bytes. + + + @retval Pointer to IKE Notify Payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateNotifyPayload ( + IN UINT8 ProtocolId, + IN UINT8 NextPayload, + IN UINT8 SpiSize, + IN UINT16 MessageType, + IN UINT8 *SpiBuf, + IN UINT8 *NotifyData, + IN UINTN NotifyDataSize + ) +{ + IKE_PAYLOAD *NotifyPayload; + IKEV2_NOTIFY *Notify; + UINT16 NotifyPayloadLen; + UINT8 *MessageData; + + // 1 2 3 + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload !C! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Protocol ID ! SPI Size ! Notify Message Type ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Security Parameter Index (SPI) ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Notification Data ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + // + NotifyPayloadLen = (UINT16) (sizeof (IKEV2_NOTIFY) + NotifyDataSize + SpiSize); + Notify = (IKEV2_NOTIFY *) AllocateZeroPool (NotifyPayloadLen); + ASSERT (Notify != NULL); + + // + // Set Delete Payload's Generic Header + // + Notify->Header.NextPayload = NextPayload; + Notify->Header.PayloadLength = NotifyPayloadLen; + Notify->SpiSize = SpiSize; + Notify->ProtocolId = ProtocolId; + Notify->MessageType = MessageType; + + // + // Copy Spi , for Cookie Notify, there is no SPI. + // + if (SpiBuf != NULL && SpiSize != 0 ) { + CopyMem (Notify + 1, SpiBuf, SpiSize); + } + + MessageData = ((UINT8 *) (Notify + 1)) + SpiSize; + + // + // Copy Notification Data + // + if (NotifyDataSize != 0) { + CopyMem (MessageData, NotifyData, NotifyDataSize); + } + + // + // Create Payload for and set type as IKEV2_PAYLOAD_TYPE_NOTIFY + // + NotifyPayload = IkePayloadAlloc (); + ASSERT (NotifyPayload != NULL); + NotifyPayload->PayloadType = IKEV2_PAYLOAD_TYPE_NOTIFY; + NotifyPayload->PayloadBuf = (UINT8 *) Notify; + NotifyPayload->PayloadSize = NotifyPayloadLen; + return NotifyPayload; +} + +/** + Generate the Delete payload. + + Since the structure of Delete payload which defined in RFC 4306 is simple, + there is no internal data structure for Delete payload. This function generate + Delete payload defined in RFC 4306, but all the fields in this payload are still + in host order and need call Ikev2EncodePayload() to convert those fields from + the host order to network order beforing sending it. + + @param[in] IkeSaSession Pointer to IKE SA Session to be used of Delete payload generation. + @param[in] NextPayload The next paylaod type in NextPayload field of + the Delete payload. + @param[in] SpiSize Size of the SPI in SPI size field of the Delete Payload. + @param[in] SpiNum Number of SPI in NumofSPIs field of the Delete Payload. + @param[in] SpiBuf Pointer to buffer contains the SPI value. + + @retval a Pointer of IKE Delete Payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateDeletePayload ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN UINT8 NextPayload, + IN UINT8 SpiSize, + IN UINT16 SpiNum, + IN UINT8 *SpiBuf + + ) +{ + IKE_PAYLOAD *DelPayload; + IKEV2_DELETE *Del; + UINT16 SpiBufSize; + UINT16 DelPayloadLen; + + // 1 2 3 + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload !C! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Protocol ID ! SPI Size ! # of SPIs ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Security Parameter Index(es) (SPI) ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + SpiBufSize = (UINT16) (SpiSize * SpiNum); + DelPayloadLen = (UINT16) (sizeof (IKEV2_DELETE) + SpiBufSize); + + Del = AllocateZeroPool (DelPayloadLen); + ASSERT (Del != NULL); + + // + // Set Delete Payload's Generic Header + // + Del->Header.NextPayload = NextPayload; + Del->Header.PayloadLength = DelPayloadLen; + Del->NumSpis = SpiNum; + Del->SpiSize = SpiSize; + + if (SpiSize == 4) { + // + // TODO: should consider the AH if needs to support. + // + Del->ProtocolId = IPSEC_PROTO_IPSEC_ESP; + } else { + Del->ProtocolId = IPSEC_PROTO_ISAKMP; + } + + // + // Set Del Payload's Idntification Data + // + CopyMem (Del + 1, SpiBuf, SpiBufSize); + DelPayload = IkePayloadAlloc (); + ASSERT (DelPayload != NULL); + DelPayload->PayloadType = IKEV2_PAYLOAD_TYPE_DELETE; + DelPayload->PayloadBuf = (UINT8 *) Del; + DelPayload->PayloadSize = DelPayloadLen; + return DelPayload; +} + +/** + Generate the Configuration payload. + + This function generate configuration payload defined in RFC 4306, but all the + fields in this payload are still in host order and need call Ikev2EncodePayload() + to convert those fields from the host order to network order beforing sending it. + + @param[in] IkeSaSession Pointer to IKE SA Session to be used for Delete payload + generation. + @param[in] NextPayload The next paylaod type in NextPayload field of + the Delete payload. + @param[in] CfgType The attribute type in the Configuration attribute. + + @retval Pointer to IKE CP Payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateCpPayload ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN UINT8 NextPayload, + IN UINT8 CfgType + ) +{ + IKE_PAYLOAD *CpPayload; + IKEV2_CFG *Cfg; + UINT16 PayloadLen; + IKEV2_CFG_ATTRIBUTES *CfgAttributes; + + // + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload !C! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! CFG Type ! RESERVED ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Configuration Attributes ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + + PayloadLen = (UINT16) (sizeof (IKEV2_CFG) + sizeof (IKEV2_CFG_ATTRIBUTES)); + Cfg = (IKEV2_CFG *) AllocateZeroPool (PayloadLen); + + if (Cfg == NULL) { + return NULL; + } + + CfgAttributes = (IKEV2_CFG_ATTRIBUTES *)((UINT8 *)Cfg + sizeof (IKEV2_CFG)); + + // + // Only generate the configuration payload with an empty INTERNAL_IP4_ADDRESS + // or INTERNAL_IP6_ADDRESS. + // + + Cfg->Header.NextPayload = NextPayload; + Cfg->Header.PayloadLength = PayloadLen; + Cfg->CfgType = IKEV2_CFG_TYPE_REQUEST; + + CfgAttributes->AttritType = CfgType; + CfgAttributes->ValueLength = 0; + + CpPayload = IkePayloadAlloc (); + if (CpPayload == NULL) { + if (Cfg != NULL) { + FreePool (Cfg); + } + return NULL; + } + + CpPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CP; + CpPayload->PayloadBuf = (UINT8 *) Cfg; + CpPayload->PayloadSize = PayloadLen; + return CpPayload; +} + +/** + Parser the Notify Cookie payload. + + This function parses the Notify Cookie payload.If the Notify ProtocolId is not + IPSEC_PROTO_ISAKMP or if the SpiSize is not zero or if the MessageType is not + the COOKIE, return EFI_INVALID_PARAMETER. + + @param[in] IkeNCookie Pointer to the IKE_PAYLOAD which contians the + Notify Cookie payload. + the Notify payload. + @param[in, out] IkeSaSession Pointer to the relevant IKE SA Session. + + @retval EFI_SUCCESS The Notify Cookie Payload is valid. + @retval EFI_INVALID_PARAMETER The Notify Cookie Payload is invalid. + @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated. + +**/ +EFI_STATUS +Ikev2ParserNotifyCookiePayload ( + IN IKE_PAYLOAD *IkeNCookie, + IN OUT IKEV2_SA_SESSION *IkeSaSession + ) +{ + IKEV2_NOTIFY *NotifyPayload; + UINTN NotifyDataSize; + + NotifyPayload = (IKEV2_NOTIFY *)IkeNCookie->PayloadBuf; + + if ((NotifyPayload->ProtocolId != IPSEC_PROTO_ISAKMP) || + (NotifyPayload->SpiSize != 0) || + (NotifyPayload->MessageType != IKEV2_NOTIFICATION_COOKIE) + ) { + return EFI_INVALID_PARAMETER; + } + + NotifyDataSize = NotifyPayload->Header.PayloadLength - sizeof (IKEV2_NOTIFY); + IkeSaSession->NCookie = AllocateZeroPool (NotifyDataSize); + if (IkeSaSession->NCookie == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + IkeSaSession->NCookieSize = NotifyDataSize; + + CopyMem ( + IkeSaSession->NCookie, + NotifyPayload + sizeof (IKEV2_NOTIFY), + NotifyDataSize + ); + + return EFI_SUCCESS; +} + + +/** + Generate the Certificate payload or Certificate Request Payload. + + Since the Certificate Payload structure is same with Certificate Request Payload, + the only difference is that one contains the Certificate Data, other contains + the acceptable certificateion CA. This function generate Certificate payload + or Certificate Request Payload defined in RFC 4306, but all the fields + in the payload are still in host order and need call Ikev2EncodePayload() + to convert those fields from the host order to network order beforing sending it. + + @param[in] IkeSaSession Pointer to IKE SA Session to be used of Delete payload + generation. + @param[in] NextPayload The next paylaod type in NextPayload field of + the Delete payload. + @param[in] Certificate Pointer of buffer contains the certification data. + @param[in] CertificateLen The length of Certificate in byte. + @param[in] EncodeType Specified the Certificate Encodeing which is defined + in RFC 4306. + @param[in] IsRequest To indicate create Certificate Payload or Certificate + Request Payload. If it is TURE, create Certificate + Payload. Otherwise, create Certificate Request Payload. + + @retval a Pointer to IKE Payload whose payload buffer containing the Certificate + payload or Certificated Request payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateCertificatePayload ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN UINT8 NextPayload, + IN UINT8 *Certificate, + IN UINTN CertificateLen, + IN UINT8 EncodeType, + IN BOOLEAN IsRequest + ) +{ + IKE_PAYLOAD *CertPayload; + IKEV2_CERT *Cert; + UINT16 PayloadLen; + UINT8 *PublicKey; + UINTN PublicKeyLen; + HASH_DATA_FRAGMENT Fragment[1]; + UINT8 *HashData; + UINTN HashDataSize; + EFI_STATUS Status; + + // + // 1 2 3 + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload !C! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Cert Encoding ! ! + // +-+-+-+-+-+-+-+-+ ! + // ~ Certificate Data/Authority ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + + Status = EFI_SUCCESS; + PublicKey = NULL; + PublicKeyLen = 0; + + if (!IsRequest) { + PayloadLen = (UINT16) (sizeof (IKEV2_CERT) + CertificateLen); + } else { + // + // SHA1 Hash length is 20. + // + PayloadLen = (UINT16) (sizeof (IKEV2_CERT) + 20); + } + + Cert = AllocateZeroPool (PayloadLen); + if (Cert == NULL) { + return NULL; + } + + // + // Generate Certificate Payload or Certificate Request Payload. + // + Cert->Header.NextPayload = NextPayload; + Cert->Header.PayloadLength = PayloadLen; + Cert->CertEncoding = EncodeType; + if (!IsRequest) { + CopyMem ( + ((UINT8 *)Cert) + sizeof (IKEV2_CERT), + Certificate, + CertificateLen + ); + } else { + Status = IpSecCryptoIoGetPublicKeyFromCert ( + Certificate, + CertificateLen, + &PublicKey, + &PublicKeyLen + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Fragment[0].Data = PublicKey; + Fragment[0].DataSize = PublicKeyLen; + HashDataSize = IpSecGetHmacDigestLength (IKE_AALG_SHA1HMAC); + HashData = AllocateZeroPool (HashDataSize); + + Status = IpSecCryptoIoHash ( + IKE_AALG_SHA1HMAC, + Fragment, + 1, + HashData, + HashDataSize + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + CopyMem ( + ((UINT8 *)Cert) + sizeof (IKEV2_CERT), + HashData, + HashDataSize + ); + } + + CertPayload = IkePayloadAlloc (); + if (CertPayload == NULL) { + goto ON_EXIT; + } + + if (!IsRequest) { + CertPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CERT; + } else { + CertPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CERTREQ; + } + + CertPayload->PayloadBuf = (UINT8 *) Cert; + CertPayload->PayloadSize = PayloadLen; + return CertPayload; + +ON_EXIT: + if (Cert != NULL) { + FreePool (Cert); + } + if (PublicKey != NULL) { + FreePool (PublicKey); + } + return NULL; +} + +/** + Remove and free all IkePayloads in the specified IkePacket. + + @param[in] IkePacket The pointer of IKE_PACKET. + +**/ +VOID +ClearAllPayloads ( + IN IKE_PACKET *IkePacket + ) +{ + LIST_ENTRY *PayloadEntry; + IKE_PAYLOAD *IkePayload; + // + // remove all payloads from list and free each payload. + // + while (!IsListEmpty (&IkePacket->PayloadList)) { + PayloadEntry = IkePacket->PayloadList.ForwardLink; + IkePayload = IKE_PAYLOAD_BY_PACKET (PayloadEntry); + IKE_PACKET_REMOVE_PAYLOAD (IkePacket, IkePayload); + IkePayloadFree (IkePayload); + } +} + +/** + Transfer the intrnal data structure IKEV2_SA_DATA to IKEV2_SA structure defined in RFC. + + @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the SA Session. + @param[in] SaData Pointer to IKEV2_SA_DATA to be transfered. + + @retval return the pointer of IKEV2_SA. + +**/ +IKEV2_SA* +Ikev2EncodeSa ( + IKEV2_SESSION_COMMON *SessionCommon, + IKEV2_SA_DATA *SaData + ) +{ + IKEV2_SA *Sa; + UINTN SaSize; + IKEV2_PROPOSAL_DATA *ProposalData; + IKEV2_TRANSFORM_DATA *TransformData; + UINTN TotalTransforms; + UINTN SaAttrsSize; + UINTN TransformsSize; + UINTN TransformSize; + UINTN ProposalsSize; + UINTN ProposalSize; + UINTN ProposalIndex; + UINTN TransformIndex; + IKE_SA_ATTRIBUTE *SaAttribute; + IKEV2_PROPOSAL *Proposal; + IKEV2_PROPOSAL *LastProposal; + IKEV2_TRANSFORM *Transform; + IKEV2_TRANSFORM *LastTransform; + + // + // Transform IKE_SA_DATA structure to IKE_SA Payload. + // Header length is host order. + // The returned IKE_SA struct should be freed by caller. + // + TotalTransforms = 0; + // + // Caculate the Proposal numbers and Transform numbers. + // + for (ProposalIndex = 0; ProposalIndex < SaData->NumProposals; ProposalIndex++) { + + ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1) + ProposalIndex; + TotalTransforms += ProposalData->NumTransforms; + + } + SaSize = sizeof (IKEV2_SA) + + SaData->NumProposals * sizeof (IKEV2_PROPOSAL) + + TotalTransforms * (sizeof (IKEV2_TRANSFORM) + MAX_SA_ATTRS_SIZE); + // + // Allocate buffer for IKE_SA. + // + Sa = AllocateZeroPool (SaSize); + ASSERT (Sa != NULL); + CopyMem (Sa, SaData, sizeof (IKEV2_SA)); + Sa->Header.PayloadLength = (UINT16) sizeof (IKEV2_SA); + ProposalsSize = 0; + LastProposal = NULL; + Proposal = (IKEV2_PROPOSAL *) (Sa + 1); + + // + // Set IKE_PROPOSAL + // + ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1); + for (ProposalIndex = 0; ProposalIndex < SaData->NumProposals; ProposalIndex++) { + Proposal->ProposalIndex = ProposalData->ProposalIndex; + Proposal->ProtocolId = ProposalData->ProtocolId; + Proposal->NumTransforms = ProposalData->NumTransforms; + + if (ProposalData->Spi == 0) { + Proposal->SpiSize = 0; + } else { + Proposal->SpiSize = 4; + *(UINT32 *) (Proposal + 1) = HTONL (*((UINT32*)ProposalData->Spi)); + } + + TransformsSize = 0; + LastTransform = NULL; + Transform = (IKEV2_TRANSFORM *) ((UINT8 *) (Proposal + 1) + Proposal->SpiSize); + + // + // Set IKE_TRANSFORM + // + for (TransformIndex = 0; TransformIndex < ProposalData->NumTransforms; TransformIndex++) { + TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1) + TransformIndex; + Transform->TransformType = TransformData->TransformType; + Transform->TransformId = HTONS (TransformData->TransformId); + SaAttrsSize = 0; + + // + // If the Encryption Algorithm is variable key length set the key length in attribute. + // Note that only a single attribute type (Key Length) is defined and it is fixed length. + // + if (Transform->TransformType == IKEV2_TRANSFORM_TYPE_ENCR && TransformData->Attribute.Attr.AttrValue != 0) { + SaAttribute = (IKE_SA_ATTRIBUTE *) (Transform + 1); + SaAttribute->AttrType = HTONS (IKEV2_ATTRIBUTE_TYPE_KEYLEN | SA_ATTR_FORMAT_BIT); + SaAttribute->Attr.AttrValue = HTONS (TransformData->Attribute.Attr.AttrValue); + SaAttrsSize = sizeof (IKE_SA_ATTRIBUTE); + } + + // + // If the Integrity Algorithm is variable key length set the key length in attribute. + // + if (Transform->TransformType == IKEV2_TRANSFORM_TYPE_INTEG && TransformData->Attribute.Attr.AttrValue != 0) { + SaAttribute = (IKE_SA_ATTRIBUTE *) (Transform + 1); + SaAttribute->AttrType = HTONS (IKEV2_ATTRIBUTE_TYPE_KEYLEN | SA_ATTR_FORMAT_BIT); + SaAttribute->Attr.AttrValue = HTONS (TransformData->Attribute.Attr.AttrValue); + SaAttrsSize = sizeof (IKE_SA_ATTRIBUTE); + } + + TransformSize = sizeof (IKEV2_TRANSFORM) + SaAttrsSize; + TransformsSize += TransformSize; + + Transform->Header.NextPayload = IKE_TRANSFORM_NEXT_PAYLOAD_MORE; + Transform->Header.PayloadLength = HTONS ((UINT16)TransformSize); + + if (TransformIndex == ProposalData->NumTransforms) { + LastTransform->Header.NextPayload = IKE_TRANSFORM_NEXT_PAYLOAD_NONE; + } + + Transform = (IKEV2_TRANSFORM *)((UINT8 *) Transform + TransformSize); + } + + // + // Set Proposal's Generic Header. + // + ProposalSize = sizeof (IKEV2_PROPOSAL) + Proposal->SpiSize + TransformsSize; + ProposalsSize += ProposalSize; + Proposal->Header.NextPayload = IKE_PROPOSAL_NEXT_PAYLOAD_MORE; + Proposal->Header.PayloadLength = HTONS ((UINT16)ProposalSize); + + if (ProposalIndex == SaData->NumProposals) { + LastProposal->Header.NextPayload = IKE_PROPOSAL_NEXT_PAYLOAD_NONE; + } + + // + // Point to next Proposal Payload + // + Proposal = (IKEV2_PROPOSAL *) ((UINT8 *) Proposal + ProposalSize); + ProposalData = (IKEV2_PROPOSAL_DATA *)(((UINT8 *)ProposalData) + sizeof (IKEV2_PROPOSAL_DATA) + (TransformIndex * sizeof (IKEV2_TRANSFORM_DATA))); + } + // + // Set SA's Generic Header. + // + Sa->Header.PayloadLength = (UINT16) (Sa->Header.PayloadLength + ProposalsSize); + return Sa; +} + +/** + Decode SA payload. + + This function converts the received SA payload to internal data structure. + + @param[in] SessionCommon Pointer to IKE Common Session used to decode the SA + Payload. + @param[in] Sa Pointer to SA Payload + + @return a Pointer to internal data structure for SA payload. + +**/ +IKEV2_SA_DATA * +Ikev2DecodeSa ( + IKEV2_SESSION_COMMON *SessionCommon, + IKEV2_SA *Sa + ) +{ + IKEV2_SA_DATA *SaData; + EFI_STATUS Status; + IKEV2_PROPOSAL *Proposal; + IKEV2_TRANSFORM *Transform; + UINTN TotalProposals; + UINTN TotalTransforms; + UINTN ProposalNextPayloadSum; + UINTN ProposalIndex; + UINTN TransformIndex; + UINTN SaRemaining; + UINT16 ProposalSize; + UINTN ProposalRemaining; + UINT16 TransformSize; + UINTN SaAttrRemaining; + IKE_SA_ATTRIBUTE *SaAttribute; + IKEV2_PROPOSAL_DATA *ProposalData; + IKEV2_TRANSFORM_DATA *TransformData; + UINT8 *Spi; + + // + // Transfrom from IKE_SA payload to IKE_SA_DATA structure. + // Header length NTOH is already done + // The returned IKE_SA_DATA should be freed by caller + // + SaData = NULL; + Status = EFI_SUCCESS; + + // + // First round sanity check and size calculae + // + TotalProposals = 0; + TotalTransforms = 0; + ProposalNextPayloadSum = 0; + SaRemaining = Sa->Header.PayloadLength - sizeof (IKEV2_SA);// Point to current position in SA + Proposal = (IKEV2_PROPOSAL *)((IKEV2_SA *)(Sa)+1); + + // + // Caculate the number of Proposal payload and the total numbers of + // Transforms payload (the transforms in all proposal payload). + // + while (SaRemaining > sizeof (IKEV2_PROPOSAL)) { + ProposalSize = NTOHS (Proposal->Header.PayloadLength); + if (SaRemaining < ProposalSize) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + if (Proposal->SpiSize != 0 && Proposal->SpiSize != 4) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + TotalProposals++; + TotalTransforms += Proposal->NumTransforms; + SaRemaining -= ProposalSize; + ProposalNextPayloadSum += Proposal->Header.NextPayload; + Proposal = IKEV2_NEXT_PROPOSAL_WITH_SIZE (Proposal, ProposalSize); + } + + // + // Check the proposal number. The Proposal Payload type is 2. Nonce Paylod is 0. + // SUM(ProposalNextPayload) = Proposal Num * 2 + Noce Payload Type (0). + // + if (TotalProposals == 0 || + (TotalProposals - 1) * IKE_PROPOSAL_NEXT_PAYLOAD_MORE + IKE_PROPOSAL_NEXT_PAYLOAD_NONE != ProposalNextPayloadSum + ) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Second round sanity check and decode. Transform the SA payload into + // a IKE_SA_DATA structure. + // + SaData = (IKEV2_SA_DATA *) AllocateZeroPool ( + sizeof (IKEV2_SA_DATA) + + TotalProposals * sizeof (IKEV2_PROPOSAL_DATA) + + TotalTransforms * sizeof (IKEV2_TRANSFORM_DATA) + ); + ASSERT (SaData != NULL); + CopyMem (SaData, Sa, sizeof (IKEV2_SA)); + SaData->NumProposals = TotalProposals; + ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1); + + // + // Proposal Payload + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload ! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! SPI (variable) ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + for (ProposalIndex = 0, Proposal = IKEV2_SA_FIRST_PROPOSAL (Sa); + ProposalIndex < TotalProposals; + ProposalIndex++ + ) { + + // + // TODO: check ProposalId + // + ProposalData->ProposalIndex = Proposal->ProposalIndex; + ProposalData->ProtocolId = Proposal->ProtocolId; + if (Proposal->SpiSize == 0) { + ProposalData->Spi = 0; + } else { + // + // SpiSize == 4 + // + Spi = AllocateZeroPool (Proposal->SpiSize); + ASSERT (Spi != NULL); + CopyMem (Spi, (UINT32 *) (Proposal + 1), Proposal->SpiSize); + *((UINT32*) Spi) = NTOHL (*((UINT32*) Spi)); + ProposalData->Spi = Spi; + } + + ProposalData->NumTransforms = Proposal->NumTransforms; + ProposalSize = NTOHS (Proposal->Header.PayloadLength); + ProposalRemaining = ProposalSize; + // + // Transform Payload + // 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 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! Next Payload ! RESERVED ! Payload Length ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // !Transform Type ! RESERVED ! Transform ID ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ SA Attributes ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + Transform = IKEV2_PROPOSAL_FIRST_TRANSFORM (Proposal); + for (TransformIndex = 0; TransformIndex < Proposal->NumTransforms; TransformIndex++) { + + // + // Transfer the IKEV2_TRANSFORM structure into internal IKEV2_TRANSFORM_DATA struture. + // + TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1) + TransformIndex; + TransformData->TransformId = NTOHS (Transform->TransformId); + TransformData->TransformType = Transform->TransformType; + TransformSize = NTOHS (Transform->Header.PayloadLength); + // + // Check the Proposal Data is correct. + // + if (ProposalRemaining < TransformSize) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Check if the Transform payload includes Attribution. + // + SaAttrRemaining = TransformSize - sizeof (IKEV2_TRANSFORM); + + // + // According to RFC 4603, currently only the Key length attribute type is + // supported. For each Transform, there is only one attributeion. + // + if (SaAttrRemaining > 0) { + if (SaAttrRemaining != sizeof (IKE_SA_ATTRIBUTE)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + SaAttribute = (IKE_SA_ATTRIBUTE *) ((IKEV2_TRANSFORM *)(Transform) + 1); + TransformData->Attribute.AttrType = (UINT16)((NTOHS (SaAttribute->AttrType)) & ~SA_ATTR_FORMAT_BIT); + TransformData->Attribute.Attr.AttrValue = NTOHS (SaAttribute->Attr.AttrValue); + + // + // Currently, only supports the Key Length Attribution. + // + if (TransformData->Attribute.AttrType != IKEV2_ATTRIBUTE_TYPE_KEYLEN) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + } + + // + // Move to next Transform + // + Transform = IKEV2_NEXT_TRANSFORM_WITH_SIZE (Transform, TransformSize); + } + Proposal = IKEV2_NEXT_PROPOSAL_WITH_SIZE (Proposal, ProposalSize); + ProposalData = (IKEV2_PROPOSAL_DATA *) ((UINT8 *)(ProposalData + 1) + + ProposalData->NumTransforms * + sizeof (IKEV2_TRANSFORM_DATA)); + } + +Exit: + if (EFI_ERROR (Status) && SaData != NULL) { + FreePool (SaData); + SaData = NULL; + } + return SaData; +} + +/** + General interface of payload encoding. + + This function encodes the internal data structure into payload which + is defined in RFC 4306. The IkePayload->PayloadBuf is used to store both the input + payload and converted payload. Only the SA payload use the interal structure + to store the attribute. Other payload use structure which is same with the RFC + defined, for this kind payloads just do host order to network order change of + some fields. + + @param[in] SessionCommon Pointer to IKE Session Common used to encode the payload. + @param[in, out] IkePayload Pointer to IKE payload to be encoded as input, and + store the encoded result as output. + + @retval EFI_INVALID_PARAMETER Meet error when encoding the SA payload. + @retval EFI_SUCCESS Encoded successfully. + +**/ +EFI_STATUS +Ikev2EncodePayload ( + IN UINT8 *SessionCommon, + IN OUT IKE_PAYLOAD *IkePayload + ) +{ + IKEV2_SA_DATA *SaData; + IKEV2_SA *SaPayload; + IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr; + IKEV2_NOTIFY *NotifyPayload; + IKEV2_DELETE *DeletePayload; + IKEV2_KEY_EXCHANGE *KeyPayload; + IKEV2_TS *TsPayload; + IKEV2_CFG_ATTRIBUTES *CfgAttribute; + UINT8 *TsBuffer; + UINT8 Index; + TRAFFIC_SELECTOR *TrafficSelector; + + // + // Transform the Internal IKE structure to IKE payload. + // Only the SA payload use the interal structure to store the attribute. + // Other payload use structure which same with the RFC defined, so there is + // no need to tranform them to IKE payload. + // + switch (IkePayload->PayloadType) { + case IKEV2_PAYLOAD_TYPE_SA: + // + // Transform IKE_SA_DATA to IK_SA payload + // + SaData = (IKEV2_SA_DATA *) IkePayload->PayloadBuf; + SaPayload = Ikev2EncodeSa ((IKEV2_SESSION_COMMON *) SessionCommon, SaData); + + if (SaPayload == NULL) { + return EFI_INVALID_PARAMETER; + } + if (!IkePayload->IsPayloadBufExt) { + FreePool (IkePayload->PayloadBuf); + } + IkePayload->PayloadBuf = (UINT8 *) SaPayload; + IkePayload->IsPayloadBufExt = FALSE; + break; + + case IKEV2_PAYLOAD_TYPE_NOTIFY: + NotifyPayload = (IKEV2_NOTIFY *) IkePayload->PayloadBuf; + NotifyPayload->MessageType = HTONS (NotifyPayload->MessageType); + break; + + case IKEV2_PAYLOAD_TYPE_DELETE: + DeletePayload = (IKEV2_DELETE *) IkePayload->PayloadBuf; + DeletePayload->NumSpis = HTONS (DeletePayload->NumSpis); + break; + + case IKEV2_PAYLOAD_TYPE_KE: + KeyPayload = (IKEV2_KEY_EXCHANGE *) IkePayload->PayloadBuf; + KeyPayload->DhGroup = HTONS (KeyPayload->DhGroup); + break; + + case IKEV2_PAYLOAD_TYPE_TS_INIT: + case IKEV2_PAYLOAD_TYPE_TS_RSP: + TsPayload = (IKEV2_TS *) IkePayload->PayloadBuf; + TsBuffer = IkePayload->PayloadBuf + sizeof (IKEV2_TS); + + for (Index = 0; Index < TsPayload->TSNumbers; Index++) { + TrafficSelector = (TRAFFIC_SELECTOR *) TsBuffer; + TsBuffer = TsBuffer + TrafficSelector->SelecorLen; + // + // Host order to network order + // + TrafficSelector->SelecorLen = HTONS (TrafficSelector->SelecorLen); + TrafficSelector->StartPort = HTONS (TrafficSelector->StartPort); + TrafficSelector->EndPort = HTONS (TrafficSelector->EndPort); + + } + + break; + + case IKEV2_PAYLOAD_TYPE_CP: + CfgAttribute = (IKEV2_CFG_ATTRIBUTES *)(((IKEV2_CFG *) IkePayload->PayloadBuf) + 1); + CfgAttribute->AttritType = HTONS (CfgAttribute->AttritType); + CfgAttribute->ValueLength = HTONS (CfgAttribute->ValueLength); + + case IKEV2_PAYLOAD_TYPE_ID_INIT: + case IKEV2_PAYLOAD_TYPE_ID_RSP: + case IKEV2_PAYLOAD_TYPE_AUTH: + default: + break; + } + + PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePayload->PayloadBuf; + IkePayload->PayloadSize = PayloadHdr->PayloadLength; + PayloadHdr->PayloadLength = HTONS (PayloadHdr->PayloadLength); + IKEV2_DUMP_PAYLOAD (IkePayload); + return EFI_SUCCESS; +} + +/** + The general interface for decoding Payload. + + This function converts the received Payload into internal structure. + + @param[in] SessionCommon Pointer to IKE Session Common used for decoding. + @param[in, out] IkePayload Pointer to IKE payload to be decoded as input, and + store the decoded result as output. + + @retval EFI_INVALID_PARAMETER Meet error when decoding the SA payload. + @retval EFI_SUCCESS Decoded successfully. + +**/ +EFI_STATUS +Ikev2DecodePayload ( + IN UINT8 *SessionCommon, + IN OUT IKE_PAYLOAD *IkePayload + ) +{ + IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr; + UINT16 PayloadSize; + UINT8 PayloadType; + IKEV2_SA_DATA *SaData; + EFI_STATUS Status; + IKEV2_NOTIFY *NotifyPayload; + IKEV2_DELETE *DeletePayload; + UINT16 TsTotalSize; + TRAFFIC_SELECTOR *TsSelector; + IKEV2_TS *TsPayload; + IKEV2_KEY_EXCHANGE *KeyPayload; + IKEV2_CFG_ATTRIBUTES *CfgAttribute; + UINT8 Index; + + // + // Transform the IKE payload to Internal IKE structure. + // Only the SA payload and Hash Payload use the interal + // structure to store the attribute. Other payloads use + // structure which is same with the definitions in RFC, + // so there is no need to tranform them to internal IKE + // structure. + // + Status = EFI_SUCCESS; + PayloadSize = (UINT16) IkePayload->PayloadSize; + PayloadType = IkePayload->PayloadType; + PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePayload->PayloadBuf; + // + // The PayloadSize is the size of whole payload. + // Replace HTONS operation to assignment statements, since the result is same. + // + PayloadHdr->PayloadLength = PayloadSize; + + IKEV2_DUMP_PAYLOAD (IkePayload); + switch (PayloadType) { + case IKEV2_PAYLOAD_TYPE_SA: + if (PayloadSize < sizeof (IKEV2_SA)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + SaData = Ikev2DecodeSa ((IKEV2_SESSION_COMMON *) SessionCommon, (IKEV2_SA *) PayloadHdr); + if (SaData == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + if (!IkePayload->IsPayloadBufExt) { + FreePool (IkePayload->PayloadBuf); + } + + IkePayload->PayloadBuf = (UINT8 *) SaData; + IkePayload->IsPayloadBufExt = FALSE; + break; + + case IKEV2_PAYLOAD_TYPE_ID_INIT: + case IKEV2_PAYLOAD_TYPE_ID_RSP : + if (PayloadSize < sizeof (IKEV2_ID)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + break; + + case IKEV2_PAYLOAD_TYPE_NOTIFY: + if (PayloadSize < sizeof (IKEV2_NOTIFY)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + NotifyPayload = (IKEV2_NOTIFY *) PayloadHdr; + NotifyPayload->MessageType = NTOHS (NotifyPayload->MessageType); + break; + + case IKEV2_PAYLOAD_TYPE_DELETE: + if (PayloadSize < sizeof (IKEV2_DELETE)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + DeletePayload = (IKEV2_DELETE *) PayloadHdr; + DeletePayload->NumSpis = NTOHS (DeletePayload->NumSpis); + break; + + case IKEV2_PAYLOAD_TYPE_AUTH: + if (PayloadSize < sizeof (IKEV2_AUTH)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + break; + + case IKEV2_PAYLOAD_TYPE_KE: + KeyPayload = (IKEV2_KEY_EXCHANGE *) IkePayload->PayloadBuf; + KeyPayload->DhGroup = HTONS (KeyPayload->DhGroup); + break; + + case IKEV2_PAYLOAD_TYPE_TS_INIT: + case IKEV2_PAYLOAD_TYPE_TS_RSP : + TsTotalSize = 0; + if (PayloadSize < sizeof (IKEV2_TS)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + // + // Parse each traffic selector and transfer network-order to host-order + // + TsPayload = (IKEV2_TS *) IkePayload->PayloadBuf; + TsSelector = (TRAFFIC_SELECTOR *) (IkePayload->PayloadBuf + sizeof (IKEV2_TS)); + + for (Index = 0; Index < TsPayload->TSNumbers; Index++) { + TsSelector->SelecorLen = NTOHS (TsSelector->SelecorLen); + TsSelector->StartPort = NTOHS (TsSelector->StartPort); + TsSelector->EndPort = NTOHS (TsSelector->EndPort); + + TsTotalSize = (UINT16) (TsTotalSize + TsSelector->SelecorLen); + TsSelector = (TRAFFIC_SELECTOR *) ((UINT8 *) TsSelector + TsSelector->SelecorLen); + } + // + // Check if the total size of Traffic Selectors is correct. + // + if (TsTotalSize != PayloadSize - sizeof(IKEV2_TS)) { + Status = EFI_INVALID_PARAMETER; + } + + case IKEV2_PAYLOAD_TYPE_CP: + CfgAttribute = (IKEV2_CFG_ATTRIBUTES *)(((IKEV2_CFG *) IkePayload->PayloadBuf) + 1); + CfgAttribute->AttritType = NTOHS (CfgAttribute->AttritType); + CfgAttribute->ValueLength = NTOHS (CfgAttribute->ValueLength); + + default: + break; + } + + Exit: + return Status; +} + +/** + Decode the IKE packet. + + This function first decrypts the IKE packet if needed , then separates the whole + IKE packet from the IkePacket->PayloadBuf into IkePacket payload list. + + @param[in] SessionCommon Pointer to IKEV1_SESSION_COMMON containing + some parameter used by IKE packet decoding. + @param[in, out] IkePacket The IKE Packet to be decoded on input, and + the decoded result on return. + @param[in] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and + IKE_CHILD_TYPE are supported. + + @retval EFI_SUCCESS The IKE packet is decoded successfully. + @retval Otherwise The IKE packet decoding is failed. + +**/ +EFI_STATUS +Ikev2DecodePacket ( + IN IKEV2_SESSION_COMMON *SessionCommon, + IN OUT IKE_PACKET *IkePacket, + IN UINTN IkeType + ) +{ + EFI_STATUS Status; + IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr; + UINT8 PayloadType; + UINTN RemainBytes; + UINT16 PayloadSize; + IKE_PAYLOAD *IkePayload; + IKE_HEADER *IkeHeader; + IKEV2_SA_SESSION *IkeSaSession; + + IkeHeader = NULL; + + // + // Check if the IkePacket need decrypt. + // + if (SessionCommon->State >= IkeStateAuth) { + Status = Ikev2DecryptPacket (SessionCommon, IkePacket, IkeType); + if (EFI_ERROR (Status)) { + return Status; + } + } + + Status = EFI_SUCCESS; + + // + // If the IkePacket doesn't contain any payload return invalid parameter. + // + if (IkePacket->Header->NextPayload == IKEV2_PAYLOAD_TYPE_NONE) { + if ((SessionCommon->State >= IkeStateAuth) && + (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INFO) + ) { + // + // If it is Liveness check, there will be no payload load in the encrypt payload. + // + Status = EFI_SUCCESS; + } else { + Status = EFI_INVALID_PARAMETER; + } + } + + // + // If the PayloadTotalSize < Header length, return invalid parameter. + // + RemainBytes = IkePacket->PayloadTotalSize; + if (RemainBytes < sizeof (IKEV2_COMMON_PAYLOAD_HEADER)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // If the packet is first or second message, store whole message in + // IkeSa->InitiPacket or IkeSa->RespPacket for following Auth Payload + // calculate. + // + if (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INIT) { + IkeHeader = AllocateZeroPool (sizeof (IKE_HEADER)); + ASSERT (IkeHeader != NULL); + CopyMem (IkeHeader, IkePacket->Header, sizeof (IKE_HEADER)); + + // + // Before store the whole packet, roll back the host order to network order, + // since the header order was changed in the IkePacketFromNetbuf. + // + IkeHdrNetToHost (IkeHeader); + IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon); + if (SessionCommon->IsInitiator) { + IkeSaSession->RespPacket = AllocateZeroPool (IkePacket->Header->Length); + IkeSaSession->RespPacketSize = IkePacket->Header->Length; + CopyMem (IkeSaSession->RespPacket, IkeHeader, sizeof (IKE_HEADER)); + CopyMem ( + IkeSaSession->RespPacket + sizeof (IKE_HEADER), + IkePacket->PayloadsBuf, + IkePacket->Header->Length - sizeof (IKE_HEADER) + ); + } else { + IkeSaSession->InitPacket = AllocateZeroPool (IkePacket->Header->Length); + IkeSaSession->InitPacketSize = IkePacket->Header->Length; + CopyMem (IkeSaSession->InitPacket, IkeHeader, sizeof (IKE_HEADER)); + CopyMem ( + IkeSaSession->InitPacket + sizeof (IKE_HEADER), + IkePacket->PayloadsBuf, + IkePacket->Header->Length - sizeof (IKE_HEADER) + ); + } + } + + // + // Point to the first Payload + // + PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePacket->PayloadsBuf; + PayloadType = IkePacket->Header->NextPayload; + + // + // Parse each payload + // + while (RemainBytes >= sizeof (IKEV2_COMMON_PAYLOAD_HEADER)) { + PayloadSize = NTOHS (PayloadHdr->PayloadLength); + + // + //Check the size of the payload is correct. + // + if (RemainBytes < PayloadSize) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // At certain states, it should save some datas before decoding. + // + if (SessionCommon->BeforeDecodePayload != NULL) { + SessionCommon->BeforeDecodePayload ( + (UINT8 *) SessionCommon, + (UINT8 *) PayloadHdr, + PayloadSize, + PayloadType + ); + } + + // + // Initial IkePayload + // + IkePayload = IkePayloadAlloc (); + ASSERT (IkePayload != NULL); + + IkePayload->PayloadType = PayloadType; + IkePayload->PayloadBuf = (UINT8 *) PayloadHdr; + IkePayload->PayloadSize = PayloadSize; + IkePayload->IsPayloadBufExt = TRUE; + + Status = Ikev2DecodePayload ((UINT8 *) SessionCommon, IkePayload); + if (EFI_ERROR (Status)) { + goto Exit; + } + + IPSEC_DUMP_BUF ("After Decoding Payload", IkePayload->PayloadBuf, IkePayload->PayloadSize); + // + // Add each payload into packet + // Notice, the IkePacket->Hdr->Lenght still recode the whole IkePacket length + // which is before the decoding. + // + IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload); + + RemainBytes -= PayloadSize; + PayloadType = PayloadHdr->NextPayload; + if (PayloadType == IKEV2_PAYLOAD_TYPE_NONE) { + break; + } + + PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) ((UINT8 *) PayloadHdr + PayloadSize); + } + + if (PayloadType != IKEV2_PAYLOAD_TYPE_NONE) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + +Exit: + if (EFI_ERROR (Status)) { + ClearAllPayloads (IkePacket); + } + + if (IkeHeader != NULL) { + FreePool (IkeHeader); + } + return Status; +} + +/** + Encode the IKE packet. + + This function puts all Payloads into one payload then encrypt it if needed. + + @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON containing + some parameter used during IKE packet encoding. + @param[in, out] IkePacket Pointer to IKE_PACKET to be encoded as input, + and the encoded result as output. + @param[in] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and + IKE_CHILD_TYPE are supportted. + + @retval EFI_SUCCESS Encode IKE packet successfully. + @retval Otherwise Encode IKE packet failed. + +**/ +EFI_STATUS +Ikev2EncodePacket ( + IN IKEV2_SESSION_COMMON *SessionCommon, + IN OUT IKE_PACKET *IkePacket, + IN UINTN IkeType + ) +{ + IKE_PAYLOAD *IkePayload; + UINTN PayloadTotalSize; + LIST_ENTRY *Entry; + EFI_STATUS Status; + IKEV2_SA_SESSION *IkeSaSession; + + PayloadTotalSize = 0; + // + // Encode each payload + // + for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) { + IkePayload = IKE_PAYLOAD_BY_PACKET (Entry); + Entry = Entry->ForwardLink; + Status = Ikev2EncodePayload ((UINT8 *) SessionCommon, IkePayload); + if (EFI_ERROR (Status)) { + return Status; + } + + if (SessionCommon->AfterEncodePayload != NULL) { + // + // For certain states, save some payload for further calculation + // + SessionCommon->AfterEncodePayload ( + (UINT8 *) SessionCommon, + IkePayload->PayloadBuf, + IkePayload->PayloadSize, + IkePayload->PayloadType + ); + } + + PayloadTotalSize += IkePayload->PayloadSize; + } + IkePacket->PayloadTotalSize = PayloadTotalSize; + + Status = EFI_SUCCESS; + if (SessionCommon->State >= IkeStateAuth) { + // + // Encrypt all payload and transfer IKE packet header from Host order to Network order. + // + Status = Ikev2EncryptPacket (SessionCommon, IkePacket); + } else { + // + // Fill in the lenght into IkePacket header and transfer Host order to Network order. + // + IkePacket->Header->Length = (UINT32) (sizeof (IKE_HEADER) + IkePacket->PayloadTotalSize); + IkeHdrHostToNet (IkePacket->Header); + } + + // + // If the packet is first message, store whole message in IkeSa->InitiPacket + // for following Auth Payload calculation. + // + if (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INIT) { + IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon); + if (SessionCommon->IsInitiator) { + IkeSaSession->InitPacketSize = IkePacket->PayloadTotalSize + sizeof (IKE_HEADER); + IkeSaSession->InitPacket = AllocateZeroPool (IkeSaSession->InitPacketSize); + ASSERT (IkeSaSession->InitPacket != NULL); + CopyMem (IkeSaSession->InitPacket, IkePacket->Header, sizeof (IKE_HEADER)); + PayloadTotalSize = 0; + for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) { + IkePayload = IKE_PAYLOAD_BY_PACKET (Entry); + Entry = Entry->ForwardLink; + CopyMem ( + IkeSaSession->InitPacket + sizeof (IKE_HEADER) + PayloadTotalSize, + IkePayload->PayloadBuf, + IkePayload->PayloadSize + ); + PayloadTotalSize = PayloadTotalSize + IkePayload->PayloadSize; + } + } else { + IkeSaSession->RespPacketSize = IkePacket->PayloadTotalSize + sizeof(IKE_HEADER); + IkeSaSession->RespPacket = AllocateZeroPool (IkeSaSession->RespPacketSize); + ASSERT (IkeSaSession->RespPacket != NULL); + CopyMem (IkeSaSession->RespPacket, IkePacket->Header, sizeof (IKE_HEADER)); + PayloadTotalSize = 0; + for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) { + IkePayload = IKE_PAYLOAD_BY_PACKET (Entry); + Entry = Entry->ForwardLink; + + CopyMem ( + IkeSaSession->RespPacket + sizeof (IKE_HEADER) + PayloadTotalSize, + IkePayload->PayloadBuf, + IkePayload->PayloadSize + ); + PayloadTotalSize = PayloadTotalSize + IkePayload->PayloadSize; + } + } + } + + return Status; +} + +/** + Decrypt IKE packet. + + This function decrypts the Encrypted IKE packet and put the result into IkePacket->PayloadBuf. + + @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON containing + some parameter used during decrypting. + @param[in, out] IkePacket Pointer to IKE_PACKET to be decrypted as input, + and the decrypted result as output. + @param[in, out] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and + IKE_CHILD_TYPE are supportted. + + @retval EFI_INVALID_PARAMETER If the IKE packet length is zero or the + IKE packet length is not aligned with Algorithm Block Size + @retval EFI_SUCCESS Decrypt IKE packet successfully. + +**/ +EFI_STATUS +Ikev2DecryptPacket ( + IN IKEV2_SESSION_COMMON *SessionCommon, + IN OUT IKE_PACKET *IkePacket, + IN OUT UINTN IkeType + ) +{ + UINT8 CryptBlockSize; // Encrypt Block Size + UINTN DecryptedSize; // Encrypted IKE Payload Size + UINT8 *DecryptedBuf; // Encrypted IKE Payload buffer + UINTN IntegritySize; + UINT8 *IntegrityBuffer; + UINTN IvSize; // Iv Size + UINT8 CheckSumSize; // Integrity Check Sum Size depends on intergrity Auth + UINT8 *CheckSumData; // Check Sum data + IKEV2_SA_SESSION *IkeSaSession; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + EFI_STATUS Status; + UINT8 PadLen; + UINTN CryptKeyLength; + HASH_DATA_FRAGMENT Fragments[1]; + + IvSize = 0; + IkeSaSession = NULL; + CryptBlockSize = 0; + CheckSumSize = 0; + CryptKeyLength = 0; + + // + // Check if the first payload is the Encrypted payload + // + if (IkePacket->Header->NextPayload != IKEV2_PAYLOAD_TYPE_ENCRYPT) { + return EFI_ACCESS_DENIED; + } + CheckSumData = NULL; + DecryptedBuf = NULL; + IntegrityBuffer = NULL; + + // + // Get the Block Size + // + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + + CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) SessionCommon->SaParams->EncAlgId); + CryptKeyLength = IpSecGetEncryptKeyLength ((UINT8) SessionCommon->SaParams->EncAlgId); + CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) SessionCommon->SaParams->IntegAlgId); + IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon); + + } else if (SessionCommon->IkeSessionType == IkeSessionTypeChildSa) { + + ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon); + IkeSaSession = ChildSaSession->IkeSaSession; + CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId); + CryptKeyLength = IpSecGetEncryptKeyLength ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId); + CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) IkeSaSession->SessionCommon.SaParams->IntegAlgId); + } else { + // + // The type of SA Session would either be IkeSa or ChildSa. + // + return EFI_INVALID_PARAMETER; + } + + CheckSumData = AllocateZeroPool (CheckSumSize); + ASSERT (CheckSumData != NULL); + + // + // Fill in the Integrity buffer + // + IntegritySize = IkePacket->PayloadTotalSize + sizeof (IKE_HEADER); + IntegrityBuffer = AllocateZeroPool (IntegritySize); + ASSERT (IntegrityBuffer != NULL); + CopyMem (IntegrityBuffer, IkePacket->Header, sizeof(IKE_HEADER)); + CopyMem (IntegrityBuffer + sizeof (IKE_HEADER), IkePacket->PayloadsBuf, IkePacket->PayloadTotalSize); + + // + // Change Host order to Network order, since the header order was changed + // in the IkePacketFromNetbuf. + // + IkeHdrHostToNet ((IKE_HEADER *)IntegrityBuffer); + + // + // Calculate the Integrity CheckSum Data + // + Fragments[0].Data = IntegrityBuffer; + Fragments[0].DataSize = IntegritySize - CheckSumSize; + + if (SessionCommon->IsInitiator) { + Status = IpSecCryptoIoHmac ( + (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId, + IkeSaSession->IkeKeys->SkArKey, + IkeSaSession->IkeKeys->SkArKeySize, + (HASH_DATA_FRAGMENT *) Fragments, + 1, + CheckSumData, + CheckSumSize + ); + } else { + Status = IpSecCryptoIoHmac ( + (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId, + IkeSaSession->IkeKeys->SkAiKey, + IkeSaSession->IkeKeys->SkAiKeySize, + (HASH_DATA_FRAGMENT *) Fragments, + 1, + CheckSumData, + CheckSumSize + ); + } + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + // + // Compare the Integrity CheckSum Data with the one in IkePacket + // + if (CompareMem ( + IkePacket->PayloadsBuf + IkePacket->PayloadTotalSize - CheckSumSize, + CheckSumData, + CheckSumSize + ) != 0) { + DEBUG ((DEBUG_ERROR, "Error auth verify payload\n")); + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } + + IvSize = CryptBlockSize; + + // + // Decrypt the payload with the key. + // + DecryptedSize = IkePacket->PayloadTotalSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER) - IvSize - CheckSumSize; + DecryptedBuf = AllocateZeroPool (DecryptedSize); + ASSERT (DecryptedBuf != NULL); + + CopyMem ( + DecryptedBuf, + IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER) + IvSize, + DecryptedSize + ); + + if (SessionCommon->IsInitiator) { + Status = IpSecCryptoIoDecrypt ( + (UINT8) SessionCommon->SaParams->EncAlgId, + IkeSaSession->IkeKeys->SkErKey, + IkeSaSession->IkeKeys->SkErKeySize << 3, + IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER), + DecryptedBuf, + DecryptedSize, + DecryptedBuf + ); + } else { + Status = IpSecCryptoIoDecrypt ( + (UINT8) SessionCommon->SaParams->EncAlgId, + IkeSaSession->IkeKeys->SkEiKey, + IkeSaSession->IkeKeys->SkEiKeySize << 3, + IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER), + DecryptedBuf, + DecryptedSize, + DecryptedBuf + ); + } + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error decrypt buffer with %r\n", Status)); + goto ON_EXIT; + } + + // + // Get the Padding length + // + // + PadLen = (UINT8) (*(DecryptedBuf + DecryptedSize - sizeof (IKEV2_PAD_LEN))); + + // + // Save the next payload of encrypted payload into IkePacket->Hdr->NextPayload + // + IkePacket->Header->NextPayload = ((IKEV2_ENCRYPTED *) IkePacket->PayloadsBuf)->Header.NextPayload; + + // + // Free old IkePacket->PayloadBuf and point it to decrypted paylaod buffer. + // + FreePool (IkePacket->PayloadsBuf); + IkePacket->PayloadsBuf = DecryptedBuf; + IkePacket->PayloadTotalSize = DecryptedSize - PadLen; + + IPSEC_DUMP_BUF ("Decrypted Buffer", DecryptedBuf, DecryptedSize); + + +ON_EXIT: + if (CheckSumData != NULL) { + FreePool (CheckSumData); + } + + if (EFI_ERROR (Status) && DecryptedBuf != NULL) { + FreePool (DecryptedBuf); + } + + if (IntegrityBuffer != NULL) { + FreePool (IntegrityBuffer); + } + + return Status; +} + +/** + Encrypt IKE packet. + + This function encrypt IKE packet before sending it. The Encrypted IKE packet + is put in to IKEV2 Encrypted Payload. + + @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the IKE packet. + @param[in, out] IkePacket Pointer to IKE packet to be encrypted. + + @retval EFI_SUCCESS Operation is successful. + @retval Others Operation is failed. + +**/ +EFI_STATUS +Ikev2EncryptPacket ( + IN IKEV2_SESSION_COMMON *SessionCommon, + IN OUT IKE_PACKET *IkePacket + ) +{ + UINT8 CryptBlockSize; // Encrypt Block Size + UINT8 CryptBlockSizeMask; // Block Mask + UINTN EncryptedSize; // Encrypted IKE Payload Size + UINT8 *EncryptedBuf; // Encrypted IKE Payload buffer + UINT8 *EncryptPayloadBuf; // Contain whole Encrypted Payload + UINTN EncryptPayloadSize; // Total size of the Encrypted payload + UINT8 *IntegrityBuf; // Buffer to be intergity + UINT32 IntegrityBufSize; // Buffer size of IntegrityBuf + UINT8 *IvBuffer; // Initialization Vector + UINT8 IvSize; // Iv Size + UINT8 CheckSumSize; // Integrity Check Sum Size depends on intergrity Auth + UINT8 *CheckSumData; // Check Sum data + UINTN Index; + IKE_PAYLOAD *EncryptPayload; + IKEV2_SA_SESSION *IkeSaSession; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + EFI_STATUS Status; + LIST_ENTRY *Entry; + IKE_PAYLOAD *IkePayload; + UINTN CryptKeyLength; + HASH_DATA_FRAGMENT Fragments[1]; + + // + // Initial all buffers to NULL. + // + EncryptedBuf = NULL; + EncryptPayloadBuf = NULL; + IvBuffer = NULL; + CheckSumData = NULL; + IkeSaSession = NULL; + CryptBlockSize = 0; + CheckSumSize = 0; + CryptKeyLength = 0; + IntegrityBuf = NULL; + // + // Get the Block Size + // + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + + CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) SessionCommon->SaParams->EncAlgId); + CryptKeyLength = IpSecGetEncryptKeyLength ((UINT8) SessionCommon->SaParams->EncAlgId); + CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) SessionCommon->SaParams->IntegAlgId); + IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon); + + } else if (SessionCommon->IkeSessionType == IkeSessionTypeChildSa) { + + ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon); + IkeSaSession = ChildSaSession->IkeSaSession; + CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId); + CryptKeyLength = IpSecGetEncryptKeyLength ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId); + CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) IkeSaSession->SessionCommon.SaParams->IntegAlgId); + } + + // + // Calcualte the EncryptPayloadSize and the PAD length + // + CryptBlockSizeMask = (UINT8) (CryptBlockSize - 1); + EncryptedSize = (IkePacket->PayloadTotalSize + sizeof (IKEV2_PAD_LEN) + CryptBlockSizeMask) & ~CryptBlockSizeMask; + EncryptedBuf = (UINT8 *) AllocateZeroPool (EncryptedSize); + ASSERT (EncryptedBuf != NULL); + + // + // Copy all payload into EncryptedIkePayload + // + Index = 0; + NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) { + IkePayload = IKE_PAYLOAD_BY_PACKET (Entry); + + CopyMem (EncryptedBuf + Index, IkePayload->PayloadBuf, IkePayload->PayloadSize); + Index += IkePayload->PayloadSize; + + }; + + // + // Fill in the Pading Length + // + *(EncryptedBuf + EncryptedSize - 1) = (UINT8)(EncryptedSize - IkePacket->PayloadTotalSize - 1); + + // + // The IV size is equal with block size + // + IvSize = CryptBlockSize; + IvBuffer = (UINT8 *) AllocateZeroPool (IvSize); + + // + // Generate IV + // + IkeGenerateIv (IvBuffer, IvSize); + + // + // Encrypt payload buf + // + if (SessionCommon->IsInitiator) { + Status = IpSecCryptoIoEncrypt ( + (UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId, + IkeSaSession->IkeKeys->SkEiKey, + IkeSaSession->IkeKeys->SkEiKeySize << 3, + IvBuffer, + EncryptedBuf, + EncryptedSize, + EncryptedBuf + ); + } else { + Status = IpSecCryptoIoEncrypt ( + (UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId, + IkeSaSession->IkeKeys->SkErKey, + IkeSaSession->IkeKeys->SkErKeySize << 3, + IvBuffer, + EncryptedBuf, + EncryptedSize, + EncryptedBuf + ); + } + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Allocate the buffer for the whole IKE payload (Encrypted Payload). + // + EncryptPayloadSize = sizeof(IKEV2_ENCRYPTED) + IvSize + EncryptedSize + CheckSumSize; + EncryptPayloadBuf = AllocateZeroPool (EncryptPayloadSize); + ASSERT (EncryptPayloadBuf != NULL); + + // + // Fill in Header of Encrypted Payload + // + ((IKEV2_ENCRYPTED *) EncryptPayloadBuf)->Header.NextPayload = IkePacket->Header->NextPayload; + ((IKEV2_ENCRYPTED *) EncryptPayloadBuf)->Header.PayloadLength = HTONS ((UINT16)EncryptPayloadSize); + + // + // Fill in Iv + // + CopyMem (EncryptPayloadBuf + sizeof (IKEV2_ENCRYPTED), IvBuffer, IvSize); + + // + // Fill in encrypted data + // + CopyMem (EncryptPayloadBuf + sizeof (IKEV2_ENCRYPTED) + IvSize, EncryptedBuf, EncryptedSize); + + // + // Fill in the IKE Packet header + // + IkePacket->PayloadTotalSize = EncryptPayloadSize; + IkePacket->Header->Length = (UINT32) (sizeof (IKE_HEADER) + IkePacket->PayloadTotalSize); + IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ENCRYPT; + + IntegrityBuf = AllocateZeroPool (IkePacket->Header->Length); + IntegrityBufSize = IkePacket->Header->Length; + IkeHdrHostToNet (IkePacket->Header); + + CopyMem (IntegrityBuf, IkePacket->Header, sizeof (IKE_HEADER)); + CopyMem (IntegrityBuf + sizeof (IKE_HEADER), EncryptPayloadBuf, EncryptPayloadSize); + + // + // Calcualte Integrity CheckSum + // + Fragments[0].Data = IntegrityBuf; + Fragments[0].DataSize = EncryptPayloadSize + sizeof (IKE_HEADER) - CheckSumSize; + + CheckSumData = AllocateZeroPool (CheckSumSize); + if (SessionCommon->IsInitiator) { + + IpSecCryptoIoHmac ( + (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId, + IkeSaSession->IkeKeys->SkAiKey, + IkeSaSession->IkeKeys->SkAiKeySize, + (HASH_DATA_FRAGMENT *) Fragments, + 1, + CheckSumData, + CheckSumSize + ); + } else { + + IpSecCryptoIoHmac ( + (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId, + IkeSaSession->IkeKeys->SkArKey, + IkeSaSession->IkeKeys->SkArKeySize, + (HASH_DATA_FRAGMENT *) Fragments, + 1, + CheckSumData, + CheckSumSize + ); + } + + // + // Copy CheckSum into Encrypted Payload + // + CopyMem (EncryptPayloadBuf + EncryptPayloadSize - CheckSumSize, CheckSumData, CheckSumSize); + + IPSEC_DUMP_BUF ("Encrypted payload buffer", EncryptPayloadBuf, EncryptPayloadSize); + IPSEC_DUMP_BUF ("Integrith CheckSum Data", CheckSumData, CheckSumSize); + + // + // Clean all payload under IkePacket->PayloadList. + // + ClearAllPayloads (IkePacket); + + // + // Create Encrypted Payload and add into IkePacket->PayloadList + // + EncryptPayload = IkePayloadAlloc (); + ASSERT (EncryptPayload != NULL); + + // + // Fill the encrypted payload into the IKE_PAYLOAD structure. + // + EncryptPayload->PayloadBuf = EncryptPayloadBuf; + EncryptPayload->PayloadSize = EncryptPayloadSize; + EncryptPayload->PayloadType = IKEV2_PAYLOAD_TYPE_ENCRYPT; + + IKE_PACKET_APPEND_PAYLOAD (IkePacket, EncryptPayload); + +ON_EXIT: + if (EncryptedBuf != NULL) { + FreePool (EncryptedBuf); + } + + if (EFI_ERROR (Status) && EncryptPayloadBuf != NULL) { + FreePool (EncryptPayloadBuf); + } + + if (IvBuffer != NULL) { + FreePool (IvBuffer); + } + + if (CheckSumData != NULL) { + FreePool (CheckSumData); + } + + if (IntegrityBuf != NULL) { + FreePool (IntegrityBuf); + } + + return Status; +} + +/** + Save some useful payloads after accepting the Packet. + + @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the operation. + @param[in] IkePacket Pointer to received IkePacet. + @param[in] IkeType The type used to indicate it is in IkeSa or ChildSa or Info + exchange. + +**/ +VOID +Ikev2OnPacketAccepted ( + IN IKEV2_SESSION_COMMON *SessionCommon, + IN IKE_PACKET *IkePacket, + IN UINT8 IkeType + ) +{ + return; +} + +/** + + The notification function. It will be called when the related UDP_TX_TOKEN's event + is signaled. + + This function frees the Net Buffer pointed to the input Packet. + + @param[in] Packet Pointer to Net buffer containing the sending IKE packet. + @param[in] EndPoint Pointer to UDP_END_POINT containing the remote and local + address information. + @param[in] IoStatus The Status of the related UDP_TX_TOKEN. + @param[in] Context Pointer to data passed from the caller. + +**/ +VOID +Ikev2OnPacketSent ( + IN NET_BUF *Packet, + IN UDP_END_POINT *EndPoint, + IN EFI_STATUS IoStatus, + IN VOID *Context + ) +{ + IKE_PACKET *IkePacket; + IKEV2_SA_SESSION *IkeSaSession; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + UINT8 Value; + IPSEC_PRIVATE_DATA *Private; + EFI_STATUS Status; + + IkePacket = (IKE_PACKET *) Context; + Private = NULL; + + if (EFI_ERROR (IoStatus)) { + DEBUG ((DEBUG_ERROR, "Error send the last packet in IkeSessionTypeIkeSa with %r\n", IoStatus)); + } + + NetbufFree (Packet); + + if (IkePacket->IsDeleteInfo) { + // + // For each RemotePeerIP, there are only one IKESA. + // + IkeSaSession = Ikev2SaSessionLookup ( + &IkePacket->Private->Ikev2EstablishedList, + &IkePacket->RemotePeerIp + ); + if (IkeSaSession == NULL) { + IkePacketFree (IkePacket); + return; + } + + Private = IkePacket->Private; + if (IkePacket->Spi != 0 ) { + // + // At that time, the established Child SA still in eht ChildSaEstablishSessionList. + // And meanwhile, if the Child SA is in the the ChildSa in Delete list, + // remove it from delete list and delete it direclty. + // + ChildSaSession = Ikev2ChildSaSessionLookupBySpi ( + &IkeSaSession->ChildSaEstablishSessionList, + IkePacket->Spi + ); + if (ChildSaSession != NULL) { + Ikev2ChildSaSessionRemove ( + &IkeSaSession->DeleteSaList, + ChildSaSession->LocalPeerSpi, + IKEV2_DELET_CHILDSA_LIST + ); + + // + // Delete the Child SA. + // + Ikev2ChildSaSilentDelete ( + IkeSaSession, + IkePacket->Spi + ); + } + + } else { + // + // Delete the IKE SA + // + DEBUG ( + (DEBUG_INFO, + "\n------ deleted Packet (cookie_i, cookie_r):(0x%lx, 0x%lx)------\n", + IkeSaSession->InitiatorCookie, + IkeSaSession->ResponderCookie) + ); + + RemoveEntryList (&IkeSaSession->BySessionTable); + Ikev2SaSessionFree (IkeSaSession); + } + } + IkePacketFree (IkePacket); + + // + // when all IKE SAs were disabled by calling "IPsecConfig -disable", the IPsec status + // should be changed. + // + if (Private != NULL && Private->IsIPsecDisabling) { + // + // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in + // IPsec status variable. + // + if (IsListEmpty (&Private->Ikev1EstablishedList) && IsListEmpty (&Private->Ikev2EstablishedList)) { + Value = IPSEC_STATUS_DISABLED; + Status = gRT->SetVariable ( + IPSECCONFIG_STATUS_NAME, + &gEfiIpSecConfigProtocolGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (Value), + &Value + ); + if (!EFI_ERROR (Status)) { + // + // Set the DisabledFlag in Private data. + // + Private->IpSec.DisabledFlag = TRUE; + Private->IsIPsecDisabling = FALSE; + } + } + } +} + +/** + Send out IKEV2 packet. + + @param[in] IkeUdpService Pointer to IKE_UDP_SERVICE used to send the IKE packet. + @param[in] SessionCommon Pointer to IKEV1_SESSION_COMMON related to the IKE packet. + @param[in] IkePacket Pointer to IKE_PACKET to be sent out. + @param[in] IkeType The type of IKE to point what's kind of the IKE + packet is to be sent out. IKE_SA_TYPE, IKE_INFO_TYPE + and IKE_CHILD_TYPE are supportted. + + @retval EFI_SUCCESS The operation complete successfully. + @retval Otherwise The operation is failed. + +**/ +EFI_STATUS +Ikev2SendIkePacket ( + IN IKE_UDP_SERVICE *IkeUdpService, + IN UINT8 *SessionCommon, + IN IKE_PACKET *IkePacket, + IN UINTN IkeType + ) +{ + EFI_STATUS Status; + NET_BUF *IkePacketNetbuf; + UDP_END_POINT EndPoint; + IKEV2_SESSION_COMMON *Common; + + Common = (IKEV2_SESSION_COMMON *) SessionCommon; + + // + // Set the resend interval + // + if (Common->TimeoutInterval == 0) { + Common->TimeoutInterval = IKE_DEFAULT_TIMEOUT_INTERVAL; + } + + // + // Retransfer the packet if it is initial packet. + // + if (IkePacket->Header->Flags == IKE_HEADER_FLAGS_INIT) { + // + // Set timer for next retry, this will cancel previous timer + // + Status = gBS->SetTimer ( + Common->TimeoutEvent, + TimerRelative, + MultU64x32 (Common->TimeoutInterval, 10000) // ms->100ns + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + IKE_PACKET_REF (IkePacket); + // + // If the last sent packet is same with this round packet, the packet is resent packet. + // + if (IkePacket != Common->LastSentPacket && Common->LastSentPacket != NULL) { + IkePacketFree (Common->LastSentPacket); + } + + Common->LastSentPacket = IkePacket; + + // + // Transform IkePacke to NetBuf + // + IkePacketNetbuf = IkeNetbufFromPacket ((UINT8 *) SessionCommon, IkePacket, IkeType); + ASSERT (IkePacketNetbuf != NULL); + + ZeroMem (&EndPoint, sizeof (UDP_END_POINT)); + EndPoint.RemotePort = IKE_DEFAULT_PORT; + CopyMem (&IkePacket->RemotePeerIp, &Common->RemotePeerIp, sizeof (EFI_IP_ADDRESS)); + CopyMem (&EndPoint.RemoteAddr, &Common->RemotePeerIp, sizeof (EFI_IP_ADDRESS)); + CopyMem (&EndPoint.LocalAddr, &Common->LocalPeerIp, sizeof (EFI_IP_ADDRESS)); + + IPSEC_DUMP_PACKET (IkePacket, EfiIPsecOutBound, IkeUdpService->IpVersion); + + if (IkeUdpService->IpVersion == IP_VERSION_4) { + EndPoint.RemoteAddr.Addr[0] = HTONL (EndPoint.RemoteAddr.Addr[0]); + EndPoint.LocalAddr.Addr[0] = HTONL (EndPoint.LocalAddr.Addr[0]); + } + + // + // Call UDPIO to send out the IKE packet. + // + Status = UdpIoSendDatagram ( + IkeUdpService->Output, + IkePacketNetbuf, + &EndPoint, + NULL, + Ikev2OnPacketSent, + (VOID*)IkePacket + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error send packet with %r\n", Status)); + } + + return Status; +} + diff --git a/NetworkPkg/IpSecDxe/Ikev2/Payload.h b/NetworkPkg/IpSecDxe/Ikev2/Payload.h new file mode 100644 index 0000000000..6096a3ba77 --- /dev/null +++ b/NetworkPkg/IpSecDxe/Ikev2/Payload.h @@ -0,0 +1,438 @@ +/** @file + The Definitions related to IKEv2 payload. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#ifndef _IKE_V2_PAYLOAD_H_ +#define _IKE_V2_PAYLOAD_H_ + +// +// Payload Type for IKEv2 +// +#define IKEV2_PAYLOAD_TYPE_NONE 0 +#define IKEV2_PAYLOAD_TYPE_SA 33 +#define IKEV2_PAYLOAD_TYPE_KE 34 +#define IKEV2_PAYLOAD_TYPE_ID_INIT 35 +#define IKEV2_PAYLOAD_TYPE_ID_RSP 36 +#define IKEV2_PAYLOAD_TYPE_CERT 37 +#define IKEV2_PAYLOAD_TYPE_CERTREQ 38 +#define IKEV2_PAYLOAD_TYPE_AUTH 39 +#define IKEV2_PAYLOAD_TYPE_NONCE 40 +#define IKEV2_PAYLOAD_TYPE_NOTIFY 41 +#define IKEV2_PAYLOAD_TYPE_DELETE 42 +#define IKEV2_PAYLOAD_TYPE_VENDOR 43 +#define IKEV2_PAYLOAD_TYPE_TS_INIT 44 +#define IKEV2_PAYLOAD_TYPE_TS_RSP 45 +#define IKEV2_PAYLOAD_TYPE_ENCRYPT 46 +#define IKEV2_PAYLOAD_TYPE_CP 47 +#define IKEV2_PAYLOAD_TYPE_EAP 48 + +// +// IKE header Flag for IKEv2 +// +#define IKE_HEADER_FLAGS_INIT 0x08 +#define IKE_HEADER_FLAGS_RESPOND 0x20 +#define IKE_HEADER_FLAGS_CHILD_INIT 0 + +// +// IKE Header Exchange Type for IKEv2 +// +#define IKEV2_EXCHANGE_TYPE_INIT 34 +#define IKEV2_EXCHANGE_TYPE_AUTH 35 +#define IKEV2_EXCHANGE_TYPE_CREATE_CHILD 36 +#define IKEV2_EXCHANGE_TYPE_INFO 37 + +#pragma pack(1) +typedef struct { + UINT8 NextPayload; + UINT8 Reserved; + UINT16 PayloadLength; +} IKEV2_COMMON_PAYLOAD_HEADER; +#pragma pack() + +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + // + // Proposals + // +} IKEV2_SA; +#pragma pack() + +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + UINT8 ProposalIndex; + UINT8 ProtocolId; + UINT8 SpiSize; + UINT8 NumTransforms; +} IKEV2_PROPOSAL; +#pragma pack() + +// +// IKEv2 Transform Type Values presented within Transform Payload +// +#define IKEV2_TRANSFORM_TYPE_ENCR 1 // Encryption Algorithm +#define IKEV2_TRANSFORM_TYPE_PRF 2 // Pseduo-Random Func +#define IKEV2_TRANSFORM_TYPE_INTEG 3 // Integrity Algorithm +#define IKEV2_TRANSFORM_TYPE_DH 4 // DH Group +#define IKEV2_TRANSFORM_TYPE_ESN 5 // Extended Sequence Number + +// +// IKEv2 Transform ID for Encrypt Algorithm (ENCR) +// +#define IKEV2_TRANSFORM_ID_ENCR_DES_IV64 1 +#define IKEV2_TRANSFORM_ID_ENCR_DES 2 +#define IKEV2_TRANSFORM_ID_ENCR_3DES 3 +#define IKEV2_TRANSFORM_ID_ENCR_RC5 4 +#define IKEV2_TRANSFORM_ID_ENCR_IDEA 5 +#define IKEV2_TRANSFORM_ID_ENCR_CAST 6 +#define IKEV2_TRANSFORM_ID_ENCR_BLOWFISH 7 +#define IKEV2_TRANSFORM_ID_ENCR_3IDEA 8 +#define IKEV2_TRANSFORM_ID_ENCR_DES_IV32 9 +#define IKEV2_TRANSFORM_ID_ENCR_NULL 11 +#define IKEV2_TRANSFORM_ID_ENCR_AES_CBC 12 +#define IKEV2_TRANSFORM_ID_ENCR_AES_CTR 13 + +// +// IKEv2 Transform ID for Pseudo-Random Function (PRF) +// +#define IKEV2_TRANSFORM_ID_PRF_HMAC_MD5 1 +#define IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1 2 +#define IKEV2_TRANSFORM_ID_PRF_HMAC_TIGER 3 +#define IKEV2_TRANSFORM_ID_PRF_AES128_XCBC 4 + +// +// IKEv2 Transform ID for Integrity Algorithm (INTEG) +// +#define IKEV2_TRANSFORM_ID_AUTH_NONE 0 +#define IKEV2_TRANSFORM_ID_AUTH_HMAC_MD5_96 1 +#define IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96 2 +#define IKEV2_TRANSFORM_ID_AUTH_HMAC_DES_MAC 3 +#define IKEV2_TRANSFORM_ID_AUTH_HMAC_KPDK_MD5 4 +#define IKEV2_TRANSFORM_ID_AUTH_HMAC_AES_XCBC_96 5 + +// +// IKEv2 Transform ID for Diffie-Hellman Group (DH) +// +#define IKEV2_TRANSFORM_ID_DH_768MODP 1 +#define IKEV2_TRANSFORM_ID_DH_1024MODP 2 +#define IKEV2_TRANSFORM_ID_DH_2048MODP 14 + +// +// IKEv2 Attribute Type Values +// +#define IKEV2_ATTRIBUTE_TYPE_KEYLEN 14 + +// +// Transform Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + UINT8 TransformType; + UINT8 Reserved; + UINT16 TransformId; + // + // SA Attributes + // +} IKEV2_TRANSFORM; +#pragma pack() + +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + UINT16 DhGroup; + UINT16 Reserved; + // + // Remaining part contains the key exchanged + // +} IKEV2_KEY_EXCHANGE; +#pragma pack() + +// +// Identification Type Values presented within Ikev2 ID payload +// +#define IKEV2_ID_TYPE_IPV4_ADDR 1 +#define IKEV2_ID_TYPE_FQDN 2 +#define IKEV2_ID_TYPE_RFC822_ADDR 3 +#define IKEV2_ID_TYPE_IPV6_ADDR 5 +#define IKEV2_ID_TYPE_DER_ASN1_DN 9 +#define IKEV2_ID_TYPE_DER_ASN1_GN 10 +#define IKEV2_ID_TYPE_KEY_ID 11 + +// +// Identification Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + UINT8 IdType; + UINT8 Reserver1; + UINT16 Reserver2; + // + // Identification Data + // +} IKEV2_ID; +#pragma pack() + +// +// Encoding Type presented in IKEV2 Cert Payload +// +#define IKEV2_CERT_ENCODEING_RESERVED 0 +#define IKEV2_CERT_ENCODEING_X509_CERT_WRAP 1 +#define IKEV2_CERT_ENCODEING_PGP_CERT 2 +#define IKEV2_CERT_ENCODEING_DNS_SIGN_KEY 3 +#define IKEV2_CERT_ENCODEING_X509_CERT_SIGN 4 +#define IKEV2_CERT_ENCODEING_KERBEROS_TOKEN 6 +#define IKEV2_CERT_ENCODEING_REVOCATION_LIST_CERT 7 +#define IKEV2_CERT_ENCODEING_AUTH_REVOCATION_LIST 8 +#define IKEV2_CERT_ENCODEING_SPKI_CERT 9 +#define IKEV2_CERT_ENCODEING_X509_CERT_ATTRIBUTE 10 +#define IKEV2_CERT_ENCODEING_RAW_RSA_KEY 11 +#define IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT 12 + +// +// IKEV2 Certificate Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + UINT8 CertEncoding; + // + // Cert Data + // +} IKEV2_CERT; +#pragma pack() + +// +// IKEV2 Certificate Request Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + UINT8 CertEncoding; + // + // Cert Authority + // +} IKEV2_CERT_REQ; +#pragma pack() + +// +// Authentication Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + UINT8 AuthMethod; + UINT8 Reserved1; + UINT16 Reserved2; + // + // Auth Data + // +} IKEV2_AUTH; +#pragma pack() + +// +// Authmethod in Authentication Payload +// +#define IKEV2_AUTH_METHOD_RSA 1; // RSA Digital Signature +#define IKEV2_AUTH_METHOD_SKMI 2; // Shared Key Message Integrity +#define IKEV2_AUTH_METHOD_DSS 3; // DSS Digital Signature + +// +// IKEv2 Nonce Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + // + // Nonce Data + // +} IKEV2_NONCE; +#pragma pack() + +// +// Notification Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + UINT8 ProtocolId; + UINT8 SpiSize; + UINT16 MessageType; + // + // SPI and Notification Data + // +} IKEV2_NOTIFY; +#pragma pack() + +// +// Notify Message Types presented within IKEv2 Notify Payload +// +#define IKEV2_NOTIFICATION_UNSUPPORT_CRITICAL_PAYLOAD 1 +#define IKEV2_NOTIFICATION_INVALID_IKE_SPI 4 +#define IKEV2_NOTIFICATION_INVALID_MAJOR_VERSION 5 +#define IKEV2_NOTIFICATION_INVALID_SYNTAX 7 +#define IKEV2_NOTIFICATION_INVALID_MESSAGE_ID 9 +#define IKEV2_NOTIFICATION_INVALID_SPI 11 +#define IKEV2_NOTIFICATION_NO_PROPOSAL_CHOSEN 14 +#define IKEV2_NOTIFICATION_INVALID_KEY_PAYLOAD 17 +#define IKEV2_NOTIFICATION_AUTHENTICATION_FAILED 24 +#define IKEV2_NOTIFICATION_SINGLE_PAIR_REQUIRED 34 +#define IKEV2_NOTIFICATION_NO_ADDITIONAL_SAS 35 +#define IKEV2_NOTIFICATION_INTERNAL_ADDRESS_FAILURE 36 +#define IKEV2_NOTIFICATION_FAILED_CP_REQUIRED 37 +#define IKEV2_NOTIFICATION_TS_UNCCEPTABLE 38 +#define IKEV2_NOTIFICATION_INVALID_SELECTORS 39 +#define IKEV2_NOTIFICATION_COOKIE 16390 +#define IKEV2_NOTIFICATION_USE_TRANSPORT_MODE 16391 +#define IKEV2_NOTIFICATION_REKEY_SA 16393 + +// +// IKEv2 Protocol ID +// +// +// IKEv2 Delete Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + UINT8 ProtocolId; + UINT8 SpiSize; + UINT16 NumSpis; + // + // SPIs + // +} IKEV2_DELETE; +#pragma pack() + +// +// Traffic Selector Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + UINT8 TSNumbers; + UINT8 Reserved1; + UINT16 Reserved2; + // + // Traffic Selector + // +} IKEV2_TS; +#pragma pack() + +// +// Traffic Selector +// +#pragma pack(1) +typedef struct { + UINT8 TSType; + UINT8 IpProtocolId; + UINT16 SelecorLen; + UINT16 StartPort; + UINT16 EndPort; + // + // Starting Address && Ending Address + // +} TRAFFIC_SELECTOR; +#pragma pack() + +// +// Ts Type in Traffic Selector +// +#define IKEV2_TS_TYPE_IPV4_ADDR_RANGE 7 +#define IKEV2_TS_TYPS_IPV6_ADDR_RANGE 8 + +// +// Vendor Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + // + // Vendor ID + // +} IKEV2_VENDOR; +#pragma pack() + +// +// Encrypted Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + // + // IV, Encrypted IKE Payloads, Padding, PAD length, Integrity CheckSum + // +} IKEV2_ENCRYPTED; +#pragma pack() + +#pragma pack(1) +typedef struct { + UINT8 PadLength; +} IKEV2_PAD_LEN; +#pragma pack() + +// +// Configuration Payload +// +#pragma pack(1) +typedef struct { + IKEV2_COMMON_PAYLOAD_HEADER Header; + UINT8 CfgType; + UINT8 Reserve1; + UINT16 Reserve2; + // + // Configuration Attributes + // +} IKEV2_CFG; +#pragma pack() + +// +// Configuration Payload CPG type +// +#define IKEV2_CFG_TYPE_REQUEST 1 +#define IKEV2_CFG_TYPE_REPLY 2 +#define IKEV2_CFG_TYPE_SET 3 +#define IKEV2_CFG_TYPE_ACK 4 + +// +// Configuration Attributes +// +#pragma pack(1) +typedef struct { + UINT16 AttritType; + UINT16 ValueLength; +} IKEV2_CFG_ATTRIBUTES; +#pragma pack() + +// +// Configuration Attributes +// +#define IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS 1 +#define IKEV2_CFG_ATTR_INTERNAL_IP4_NBTMASK 2 +#define IKEV2_CFG_ATTR_INTERNAL_IP4_DNS 3 +#define IKEV2_CFG_ATTR_INTERNAL_IP4_NBNS 4 +#define IKEV2_CFG_ATTR_INTERNA_ADDRESS_BXPIRY 5 +#define IKEV2_CFG_ATTR_INTERNAL_IP4_DHCP 6 +#define IKEV2_CFG_ATTR_APPLICATION_VERSION 7 +#define IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS 8 +#define IKEV2_CFG_ATTR_INTERNAL_IP6_DNS 10 +#define IKEV2_CFG_ATTR_INTERNAL_IP6_NBNS 11 +#define IKEV2_CFG_ATTR_INTERNAL_IP6_DHCP 12 +#define IKEV2_CFG_ATTR_INTERNAL_IP4_SUBNET 13 +#define IKEV2_CFG_ATTR_SUPPORTED_ATTRIBUTES 14 +#define IKEV2_CFG_ATTR_IP6_SUBNET 15 + +#endif + diff --git a/NetworkPkg/IpSecDxe/Ikev2/Sa.c b/NetworkPkg/IpSecDxe/Ikev2/Sa.c new file mode 100644 index 0000000000..7265ca8c6c --- /dev/null +++ b/NetworkPkg/IpSecDxe/Ikev2/Sa.c @@ -0,0 +1,1949 @@ +/** @file + The operations for IKEv2 SA. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Utility.h" +#include "IpSecDebug.h" +#include "IkeService.h" +#include "Ikev2.h" + +/** + Generates the DH Key. + + This generates the DH local public key and store it in the IKEv2 SA Session's GxBuffer. + + @param[in] IkeSaSession Pointer to related IKE SA Session. + + @retval EFI_SUCCESS The operation succeeded. + @retval Others The operation failed. + +**/ +EFI_STATUS +Ikev2GenerateSaDhPublicKey ( + IN IKEV2_SA_SESSION *IkeSaSession + ); + +/** + Generates the IKEv2 SA key for the furthure IKEv2 exchange. + + @param[in] IkeSaSession Pointer to IKEv2 SA Session. + @param[in] KePayload Pointer to Key payload used to generate the Key. + + @retval EFI_UNSUPPORTED If the Algorithm Id is not supported. + @retval EFI_SUCCESS The operation succeeded. + +**/ +EFI_STATUS +Ikev2GenerateSaKeys ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IKE_PAYLOAD *KePayload + ); + +/** + Generates the Keys for the furthure IPsec Protocol. + + @param[in] ChildSaSession Pointer to IKE Child SA Session. + @param[in] KePayload Pointer to Key payload used to generate the Key. + + @retval EFI_UNSUPPORTED If one or more Algorithm Id is unsupported. + @retval EFI_SUCCESS The operation succeeded. + +**/ +EFI_STATUS +Ikev2GenerateChildSaKeys ( + IN IKEV2_CHILD_SA_SESSION *ChildSaSession, + IN IKE_PAYLOAD *KePayload + ); + +/** + Gernerates IKEv2 packet for IKE_SA_INIT exchange. + + @param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange. + @param[in] Context Context Data passed by caller. + + @retval EFI_SUCCESS The IKEv2 packet generation succeeded. + @retval Others The IKEv2 packet generation failed. + +**/ +IKE_PACKET * +Ikev2InitPskGenerator ( + IN UINT8 *SaSession, + IN VOID *Context + ) +{ + IKE_PACKET *IkePacket; + IKEV2_SA_SESSION *IkeSaSession; + IKE_PAYLOAD *SaPayload; + IKE_PAYLOAD *KePayload; + IKE_PAYLOAD *NoncePayload; + IKE_PAYLOAD *NotifyPayload; + EFI_STATUS Status; + + SaPayload = NULL; + KePayload = NULL; + NoncePayload = NULL; + NotifyPayload = NULL; + + IkeSaSession = (IKEV2_SA_SESSION *) SaSession; + + // + // 1. Allocate IKE packet + // + IkePacket = IkePacketAlloc (); + ASSERT (IkePacket != NULL); + + // + // 1.a Fill the IkePacket->Hdr + // + IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_INIT; + IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie; + IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie; + IkePacket->Header->Version = (UINT8) (2 << 4); + IkePacket->Header->MessageId = 0; + + if (IkeSaSession->SessionCommon.IsInitiator) { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT; + } else { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND; + } + + // + // If the NCookie is not NULL, this IKE_SA_INIT packet is resent by the NCookie + // and the NCookie payload should be the first payload in this packet. + // + if (IkeSaSession->NCookie != NULL) { + IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_NOTIFY; + NotifyPayload = Ikev2GenerateNotifyPayload ( + IPSEC_PROTO_ISAKMP, + IKEV2_PAYLOAD_TYPE_SA, + 0, + IKEV2_NOTIFICATION_COOKIE, + NULL, + IkeSaSession->NCookie, + IkeSaSession->NCookieSize + ); + } else { + IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_SA; + } + + // + // 2. Generate SA Payload according to the SaData & SaParams + // + SaPayload = Ikev2GenerateSaPayload ( + IkeSaSession->SaData, + IKEV2_PAYLOAD_TYPE_KE, + IkeSessionTypeIkeSa + ); + + // + // 3. Generate DH public key. + // The DhPrivate Key has been generated in Ikev2InitPskParser, if the + // IkeSaSession is responder. If resending IKE_SA_INIT with Cookie Notify + // No need to recompute the Public key. + // + if ((IkeSaSession->SessionCommon.IsInitiator) && (IkeSaSession->NCookie == NULL)) { + Status = Ikev2GenerateSaDhPublicKey (IkeSaSession); + if (EFI_ERROR (Status)) { + goto CheckError; + } + } + + // + // 4. Generate KE Payload according to SaParams->DhGroup + // + KePayload = Ikev2GenerateKePayload ( + IkeSaSession, + IKEV2_PAYLOAD_TYPE_NONCE + ); + + // + // 5. Generate Nonce Payload + // If resending IKE_SA_INIT with Cookie Notify paylaod, no need to regenerate + // the Nonce Payload. + // + if ((IkeSaSession->SessionCommon.IsInitiator) && (IkeSaSession->NCookie == NULL)) { + IkeSaSession->NiBlkSize = IKE_NONCE_SIZE; + IkeSaSession->NiBlock = IkeGenerateNonce (IKE_NONCE_SIZE); + ASSERT (IkeSaSession->NiBlock != NULL); + } + + if (IkeSaSession->SessionCommon.IsInitiator) { + NoncePayload = Ikev2GenerateNoncePayload ( + IkeSaSession->NiBlock, + IkeSaSession->NiBlkSize, + IKEV2_PAYLOAD_TYPE_NONE + ); + } else { + // + // The Nonce Payload has been created in Ikev2PskParser if the IkeSaSession is + // responder. + // + NoncePayload = Ikev2GenerateNoncePayload ( + IkeSaSession->NrBlock, + IkeSaSession->NrBlkSize, + IKEV2_PAYLOAD_TYPE_NONE + ); + } + + if (NotifyPayload != NULL) { + IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload); + } + if (SaPayload != NULL) { + IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload); + } + if (KePayload != NULL) { + IKE_PACKET_APPEND_PAYLOAD (IkePacket, KePayload); + } + if (NoncePayload != NULL) { + IKE_PACKET_APPEND_PAYLOAD (IkePacket, NoncePayload); + } + + return IkePacket; + +CheckError: + if (IkePacket != NULL) { + IkePacketFree (IkePacket); + } + if (SaPayload != NULL) { + IkePayloadFree (SaPayload); + } + return NULL; +} + +/** + Parses the IKEv2 packet for IKE_SA_INIT exchange. + + @param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange. + @param[in] IkePacket The received IKE packet to be parsed. + + @retval EFI_SUCCESS The IKEv2 packet is acceptable and the relative data is + saved for furthure communication. + @retval EFI_INVALID_PARAMETER The IKEv2 packet is malformed or the SA proposal is unacceptable. + +**/ +EFI_STATUS +Ikev2InitPskParser ( + IN UINT8 *SaSession, + IN IKE_PACKET *IkePacket + ) +{ + IKEV2_SA_SESSION *IkeSaSession; + IKE_PAYLOAD *SaPayload; + IKE_PAYLOAD *KeyPayload; + IKE_PAYLOAD *IkePayload; + IKE_PAYLOAD *NoncePayload; + IKE_PAYLOAD *NotifyPayload; + UINT8 *NonceBuffer; + UINTN NonceSize; + LIST_ENTRY *Entry; + EFI_STATUS Status; + + IkeSaSession = (IKEV2_SA_SESSION *) SaSession; + KeyPayload = NULL; + SaPayload = NULL; + NoncePayload = NULL; + IkePayload = NULL; + NotifyPayload = NULL; + + // + // Iterate payloads to find the SaPayload and KeyPayload. + // + NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) { + IkePayload = IKE_PAYLOAD_BY_PACKET (Entry); + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) { + SaPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_KE) { + KeyPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NONCE) { + NoncePayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NOTIFY) { + NotifyPayload = IkePayload; + } + } + + // + // According to RFC 4306 - 2.6. If the responder responds with the COOKIE Notify + // payload with the cookie data, initiator MUST retry the IKE_SA_INIT with a + // Notify payload of type COOKIE containing the responder suppplied cookie data + // as first payload and all other payloads unchanged. + // + if (IkeSaSession->SessionCommon.IsInitiator) { + if (NotifyPayload != NULL) { + Status = Ikev2ParserNotifyCookiePayload (NotifyPayload, IkeSaSession); + return Status; + } + } + + if ((KeyPayload == NULL) || (SaPayload == NULL) || (NoncePayload == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Store NoncePayload for SKEYID computing. + // + NonceSize = NoncePayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER); + NonceBuffer = (UINT8 *) AllocatePool (NonceSize); + ASSERT (NonceBuffer != NULL); + CopyMem ( + NonceBuffer, + NoncePayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER), + NonceSize + ); + + // + // Check if IkePacket Header matches the state + // + if (IkeSaSession->SessionCommon.IsInitiator) { + // + // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND + // + if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) { + Status = EFI_INVALID_PARAMETER; + goto CheckError; + } + + // + // 2. Parse the SA Payload and Key Payload to find out the cryptographic + // suite and fill in the Sa paramse into CommonSession->SaParams + // + if (!Ikev2SaParseSaPayload (IkeSaSession, SaPayload, IkePacket->Header->Flags)) { + Status = EFI_INVALID_PARAMETER; + goto CheckError; + } + + // + // 3. If Initiator, the NoncePayload is Nr_b. + // + IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateAuth); + IkeSaSession->NrBlock = NonceBuffer; + IkeSaSession->NrBlkSize = NonceSize; + IkeSaSession->SessionCommon.State = IkeStateAuth; + IkeSaSession->ResponderCookie = IkePacket->Header->ResponderCookie; + + // + // 4. Change the state of IkeSaSession + // + IkeSaSession->SessionCommon.State = IkeStateAuth; + } else { + // + // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT + // + if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) { + Status = EFI_INVALID_PARAMETER; + goto CheckError; + } + + // + // 2. Parse the SA payload and find out the perfered one + // and fill in the SA parameters into CommonSession->SaParams and SaData into + // IkeSaSession for the responder SA payload generation. + // + if (!Ikev2SaParseSaPayload (IkeSaSession, SaPayload, IkePacket->Header->Flags)) { + Status = EFI_INVALID_PARAMETER; + goto CheckError; + } + + // + // 3. Generat Dh Y parivate Key + // + Status = Ikev2GenerateSaDhPublicKey (IkeSaSession); + if (EFI_ERROR (Status)) { + goto CheckError; + } + + // + // 4. If Responder, the NoncePayload is Ni_b and go to generate Nr_b. + // + IkeSaSession->NiBlock = NonceBuffer; + IkeSaSession->NiBlkSize = NonceSize; + + // + // 5. Generate Nr_b + // + IkeSaSession->NrBlock = IkeGenerateNonce (IKE_NONCE_SIZE); + ASSERT_EFI_ERROR (IkeSaSession->NrBlock != NULL); + IkeSaSession->NrBlkSize = IKE_NONCE_SIZE; + + // + // 6. Save the Cookies + // + IkeSaSession->InitiatorCookie = IkePacket->Header->InitiatorCookie; + IkeSaSession->ResponderCookie = IkeGenerateCookie (); + } + + if (IkeSaSession->SessionCommon.PreferDhGroup != ((IKEV2_KEY_EXCHANGE *)KeyPayload->PayloadBuf)->DhGroup) { + Status = EFI_INVALID_PARAMETER; + goto CheckError; + } + // + // Call Ikev2GenerateSaKeys to create SKEYID, SKEYID_d, SKEYID_a, SKEYID_e. + // + Status = Ikev2GenerateSaKeys (IkeSaSession, KeyPayload); + if (EFI_ERROR(Status)) { + goto CheckError; + } + return EFI_SUCCESS; + +CheckError: + if (NonceBuffer != NULL) { + FreePool (NonceBuffer); + } + + return Status; +} + +/** + Generates the IKEv2 packet for IKE_AUTH exchange. + + @param[in] SaSession Pointer to IKEV2_SA_SESSION. + @param[in] Context Context data passed by caller. + + @retval Pointer to IKE Packet to be sent out. + +**/ +IKE_PACKET * +Ikev2AuthPskGenerator ( + IN UINT8 *SaSession, + IN VOID *Context + ) +{ + IKE_PACKET *IkePacket; + IKEV2_SA_SESSION *IkeSaSession; + IKE_PAYLOAD *IdPayload; + IKE_PAYLOAD *AuthPayload; + IKE_PAYLOAD *SaPayload; + IKE_PAYLOAD *TsiPayload; + IKE_PAYLOAD *TsrPayload; + IKE_PAYLOAD *NotifyPayload; + IKE_PAYLOAD *CpPayload; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + + + IkeSaSession = (IKEV2_SA_SESSION *) SaSession; + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList)); + + CpPayload = NULL; + NotifyPayload = NULL; + + // + // 1. Allocate IKE Packet + // + IkePacket= IkePacketAlloc (); + ASSERT (IkePacket != NULL); + + // + // 1.a Fill the IkePacket Header. + // + IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_AUTH; + IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie; + IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie; + IkePacket->Header->Version = (UINT8)(2 << 4); + if (ChildSaSession->SessionCommon.IsInitiator) { + IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_INIT; + } else { + IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_RSP; + } + + // + // According to RFC4306_2.2, For the IKE_SA_INIT message the MessageID should + // be always number 0 and 1; + // + IkePacket->Header->MessageId = 1; + + if (IkeSaSession->SessionCommon.IsInitiator) { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT; + } else { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND; + } + + // + // 2. Generate ID Payload according to IP version and address. + // + IdPayload = Ikev2GenerateIdPayload ( + &IkeSaSession->SessionCommon, + IKEV2_PAYLOAD_TYPE_AUTH + ); + + // + // 3. Generate Auth Payload + // If it is tunnel mode, should create the configuration payload after the + // Auth payload. + // + if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) { + + AuthPayload = Ikev2PskGenerateAuthPayload ( + ChildSaSession->IkeSaSession, + IdPayload, + IKEV2_PAYLOAD_TYPE_SA, + FALSE + ); + } else { + AuthPayload = Ikev2PskGenerateAuthPayload ( + ChildSaSession->IkeSaSession, + IdPayload, + IKEV2_PAYLOAD_TYPE_CP, + FALSE + ); + if (IkeSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) { + CpPayload = Ikev2GenerateCpPayload ( + ChildSaSession->IkeSaSession, + IKEV2_PAYLOAD_TYPE_SA, + IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS + ); + } else { + CpPayload = Ikev2GenerateCpPayload ( + ChildSaSession->IkeSaSession, + IKEV2_PAYLOAD_TYPE_SA, + IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS + ); + } + } + + // + // 4. Generate SA Payload according to the SA Data in ChildSaSession + // + SaPayload = Ikev2GenerateSaPayload ( + ChildSaSession->SaData, + IKEV2_PAYLOAD_TYPE_TS_INIT, + IkeSessionTypeChildSa + ); + + if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) { + // + // Generate Tsi and Tsr. + // + TsiPayload = Ikev2GenerateTsPayload ( + ChildSaSession, + IKEV2_PAYLOAD_TYPE_TS_RSP, + FALSE + ); + + TsrPayload = Ikev2GenerateTsPayload ( + ChildSaSession, + IKEV2_PAYLOAD_TYPE_NOTIFY, + FALSE + ); + + // + // Generate Notify Payload. If transport mode, there should have Notify + // payload with TRANSPORT_MODE notification. + // + NotifyPayload = Ikev2GenerateNotifyPayload ( + 0, + IKEV2_PAYLOAD_TYPE_NONE, + 0, + IKEV2_NOTIFICATION_USE_TRANSPORT_MODE, + NULL, + NULL, + 0 + ); + } else { + // + // Generate Tsr for Tunnel mode. + // + TsiPayload = Ikev2GenerateTsPayload ( + ChildSaSession, + IKEV2_PAYLOAD_TYPE_TS_RSP, + TRUE + ); + TsrPayload = Ikev2GenerateTsPayload ( + ChildSaSession, + IKEV2_PAYLOAD_TYPE_NONE, + FALSE + ); + } + + IKE_PACKET_APPEND_PAYLOAD (IkePacket, IdPayload); + IKE_PACKET_APPEND_PAYLOAD (IkePacket, AuthPayload); + if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) { + IKE_PACKET_APPEND_PAYLOAD (IkePacket, CpPayload); + } + IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload); + IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsiPayload); + IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsrPayload); + if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) { + IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload); + } + + return IkePacket; +} + +/** + Parses IKE_AUTH packet. + + @param[in] SaSession Pointer to the IKE_SA_SESSION related to this packet. + @param[in] IkePacket Pointer to the IKE_AUTH packet to be parsered. + + @retval EFI_INVALID_PARAMETER The IKE packet is malformed or the SA + proposal is unacceptable. + @retval EFI_SUCCESS The IKE packet is acceptable and the + relative data is saved for furthure communication. + +**/ +EFI_STATUS +Ikev2AuthPskParser ( + IN UINT8 *SaSession, + IN IKE_PACKET *IkePacket + ) +{ + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SA_SESSION *IkeSaSession; + IKE_PAYLOAD *IkePayload; + IKE_PAYLOAD *SaPayload; + IKE_PAYLOAD *IdiPayload; + IKE_PAYLOAD *IdrPayload; + IKE_PAYLOAD *AuthPayload; + IKE_PAYLOAD *TsiPayload; + IKE_PAYLOAD *TsrPayload; + IKE_PAYLOAD *VerifiedAuthPayload; + LIST_ENTRY *Entry; + EFI_STATUS Status; + + IkeSaSession = (IKEV2_SA_SESSION *) SaSession; + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList)); + + SaPayload = NULL; + IdiPayload = NULL; + IdrPayload = NULL; + AuthPayload = NULL; + TsiPayload = NULL; + TsrPayload = NULL; + + // + // Iterate payloads to find the SaPayload/ID/AUTH/TS Payload. + // + NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) { + IkePayload = IKE_PAYLOAD_BY_PACKET (Entry); + + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_INIT) { + IdiPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_RSP) { + IdrPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) { + SaPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_AUTH) { + AuthPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) { + TsiPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_RSP) { + TsrPayload = IkePayload; + } + } + + if ((SaPayload == NULL) || (AuthPayload == NULL) || (TsiPayload == NULL) || (TsrPayload == NULL)) { + return EFI_INVALID_PARAMETER; + } + if ((IdiPayload == NULL) && (IdrPayload == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check IkePacket Header is match the state + // + if (IkeSaSession->SessionCommon.IsInitiator) { + + // + // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND + // + if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) || + (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH) + ) { + return EFI_INVALID_PARAMETER; + } + + } else { + // + // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT + // + if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) || + (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH) + ) { + return EFI_INVALID_PARAMETER; + } + + // + // 2. Parse the SA payload and Key Payload and find out the perferable one + // and fill in the Sa paramse into CommonSession->SaParams and SaData into + // IkeSaSession for the responder SA payload generation. + // + } + + // + // Verify the Auth Payload. + // + VerifiedAuthPayload = Ikev2PskGenerateAuthPayload ( + IkeSaSession, + IkeSaSession->SessionCommon.IsInitiator ? IdrPayload : IdiPayload, + IKEV2_PAYLOAD_TYPE_SA, + TRUE + ); + if ((VerifiedAuthPayload != NULL) && + (0 != CompareMem ( + VerifiedAuthPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER), + AuthPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER), + VerifiedAuthPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER) + ))) { + return EFI_INVALID_PARAMETER; + }; + + // + // 3. Parse the SA Payload to find out the cryptographic suite + // and fill in the Sa paramse into CommonSession->SaParams. If no acceptable + // porposal found, return EFI_INVALID_PARAMETER. + // + if (!Ikev2ChildSaParseSaPayload (ChildSaSession, SaPayload, IkePacket->Header->Flags)) { + return EFI_INVALID_PARAMETER; + } + + // + // 4. Parse TSi, TSr payloads. + // + if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != + ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId) && + (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) && + (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) + ) { + return EFI_INVALID_PARAMETER; + } + + if (!IkeSaSession->SessionCommon.IsInitiator) { + // + //TODO:check the Port range. Only support any port and one certain port here. + // + ChildSaSession->ProtoId = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId; + ChildSaSession->LocalPort = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort; + ChildSaSession->RemotePort = ((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort; + // + // Association a SPD with this SA. + // + Status = Ikev2ChildSaAssociateSpdEntry (ChildSaSession); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + // + // Associate the IkeSaSession's SPD to the first ChildSaSession's SPD. + // + if (ChildSaSession->IkeSaSession->Spd == NULL) { + ChildSaSession->IkeSaSession->Spd = ChildSaSession->Spd; + Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession); + } + } else { + // + //TODO:check the Port range. + // + if ((((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) && + (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->RemotePort) + ) { + return EFI_INVALID_PARAMETER; + } + if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) && + (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->LocalPort) + ) { + return EFI_INVALID_PARAMETER; + } + // + // For the tunnel mode, it should add the vitual IP address into the SA's SPD Selector. + // + if (ChildSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) { + if (!ChildSaSession->IkeSaSession->SessionCommon.IsInitiator) { + // + // If it is tunnel mode, the UEFI part must be the initiator. + // + return EFI_INVALID_PARAMETER; + } + // + // Get the Virtual IP address from the Tsi traffic selector. + // TODO: check the CFG reply payload + // + CopyMem ( + &ChildSaSession->SpdSelector->LocalAddress[0].Address, + TsiPayload->PayloadBuf + sizeof (IKEV2_TS) + sizeof (TRAFFIC_SELECTOR), + (ChildSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) ? + sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS) + ); + } + } + + // + // 5. Generate keymats for IPsec protocol. + // + Ikev2GenerateChildSaKeys (ChildSaSession, NULL); + if (IkeSaSession->SessionCommon.IsInitiator) { + // + // 6. Change the state of IkeSaSession + // + IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateIkeSaEstablished); + IkeSaSession->SessionCommon.State = IkeStateIkeSaEstablished; + } + + return EFI_SUCCESS; +} + +/** + Gernerates IKEv2 packet for IKE_SA_INIT exchange. + + @param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange. + @param[in] Context Context Data passed by caller. + + @retval EFI_SUCCESS The IKE packet generation succeeded. + @retval Others The IKE packet generation failed. + +**/ +IKE_PACKET* +Ikev2InitCertGenerator ( + IN UINT8 *SaSession, + IN VOID *Context + ) +{ + IKE_PACKET *IkePacket; + IKE_PAYLOAD *CertReqPayload; + LIST_ENTRY *Node; + IKE_PAYLOAD *NoncePayload; + + if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) { + return NULL; + } + + // + // The first two messages exchange is same between PSK and Cert. + // + IkePacket = Ikev2InitPskGenerator (SaSession, Context); + + if ((IkePacket != NULL) && (!((IKEV2_SA_SESSION *)SaSession)->SessionCommon.IsInitiator)) { + // + // Add the Certification Request Payload + // + CertReqPayload = Ikev2GenerateCertificatePayload ( + (IKEV2_SA_SESSION *)SaSession, + IKEV2_PAYLOAD_TYPE_NONE, + (UINT8*)PcdGetPtr(UefiCaFile), + PcdGet32(UefiCaFileSize), + IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT, + TRUE + ); + // + // Change Nonce Payload Next payload type. + // + IKE_PACKET_END_PAYLOAD (IkePacket, Node); + NoncePayload = IKE_PAYLOAD_BY_PACKET (Node); + ((IKEV2_NONCE *)NoncePayload->PayloadBuf)->Header.NextPayload = IKEV2_PAYLOAD_TYPE_CERTREQ; + + // + // Add Certification Request Payload + // + IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertReqPayload); + } + + return IkePacket; +} + +/** + Parses the IKEv2 packet for IKE_SA_INIT exchange. + + @param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange. + @param[in] IkePacket The received IKEv2 packet to be parsed. + + @retval EFI_SUCCESS The IKEv2 packet is acceptable and the relative data is + saved for furthure communication. + @retval EFI_INVALID_PARAMETER The IKE packet is malformed or the SA proposal is unacceptable. + @retval EFI_UNSUPPORTED The certificate authentication is not supported. + +**/ +EFI_STATUS +Ikev2InitCertParser ( + IN UINT8 *SaSession, + IN IKE_PACKET *IkePacket + ) +{ + if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) { + return EFI_UNSUPPORTED; + } + + // + // The first two messages exchange is same between PSK and Cert. + // Todo: Parse Certificate Request from responder Initial Exchange. + // + return Ikev2InitPskParser (SaSession, IkePacket); +} + +/** + Generates the IKEv2 packet for IKE_AUTH exchange. + + @param[in] SaSession Pointer to IKEV2_SA_SESSION. + @param[in] Context Context data passed by caller. + + @retval Pointer to IKEv2 Packet to be sent out. + +**/ +IKE_PACKET * +Ikev2AuthCertGenerator ( + IN UINT8 *SaSession, + IN VOID *Context + ) +{ + IKE_PACKET *IkePacket; + IKEV2_SA_SESSION *IkeSaSession; + IKE_PAYLOAD *IdPayload; + IKE_PAYLOAD *AuthPayload; + IKE_PAYLOAD *SaPayload; + IKE_PAYLOAD *TsiPayload; + IKE_PAYLOAD *TsrPayload; + IKE_PAYLOAD *NotifyPayload; + IKE_PAYLOAD *CpPayload; + IKE_PAYLOAD *CertPayload; + IKE_PAYLOAD *CertReqPayload; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + + if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) { + return NULL; + } + + IkeSaSession = (IKEV2_SA_SESSION *) SaSession; + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList)); + + CpPayload = NULL; + NotifyPayload = NULL; + CertPayload = NULL; + CertReqPayload = NULL; + + // + // 1. Allocate IKE Packet + // + IkePacket= IkePacketAlloc (); + ASSERT (IkePacket != NULL); + + // + // 1.a Fill the IkePacket Header. + // + IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_AUTH; + IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie; + IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie; + IkePacket->Header->Version = (UINT8)(2 << 4); + if (ChildSaSession->SessionCommon.IsInitiator) { + IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_INIT; + } else { + IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_RSP; + } + + // + // According to RFC4306_2.2, For the IKE_SA_INIT message the MessageID should + // be always number 0 and 1; + // + IkePacket->Header->MessageId = 1; + + if (IkeSaSession->SessionCommon.IsInitiator) { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT; + } else { + IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND; + } + + // + // 2. Generate ID Payload according to IP version and address. + // + IdPayload = Ikev2GenerateCertIdPayload ( + &IkeSaSession->SessionCommon, + IKEV2_PAYLOAD_TYPE_CERT, + (UINT8 *)PcdGetPtr (UefiCertificate), + PcdGet32 (UefiCertificateSize) + ); + + // + // 3. Generate Certificate Payload + // + CertPayload = Ikev2GenerateCertificatePayload ( + IkeSaSession, + (UINT8)(IkeSaSession->SessionCommon.IsInitiator ? IKEV2_PAYLOAD_TYPE_CERTREQ : IKEV2_PAYLOAD_TYPE_AUTH), + (UINT8 *)PcdGetPtr (UefiCertificate), + PcdGet32 (UefiCertificateSize), + IKEV2_CERT_ENCODEING_X509_CERT_SIGN, + FALSE + ); + if (IkeSaSession->SessionCommon.IsInitiator) { + CertReqPayload = Ikev2GenerateCertificatePayload ( + IkeSaSession, + IKEV2_PAYLOAD_TYPE_AUTH, + (UINT8 *)PcdGetPtr (UefiCertificate), + PcdGet32 (UefiCertificateSize), + IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT, + TRUE + ); + } + + // + // 4. Generate Auth Payload + // If it is tunnel mode, should create the configuration payload after the + // Auth payload. + // + if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) { + AuthPayload = Ikev2CertGenerateAuthPayload ( + ChildSaSession->IkeSaSession, + IdPayload, + IKEV2_PAYLOAD_TYPE_SA, + FALSE, + (UINT8 *)PcdGetPtr (UefiCertificateKey), + PcdGet32 (UefiCertificateKeySize), + ChildSaSession->IkeSaSession->Pad->Data->AuthData, + ChildSaSession->IkeSaSession->Pad->Data->AuthDataSize + ); + } else { + AuthPayload = Ikev2CertGenerateAuthPayload ( + ChildSaSession->IkeSaSession, + IdPayload, + IKEV2_PAYLOAD_TYPE_CP, + FALSE, + (UINT8 *)PcdGetPtr (UefiCertificateKey), + PcdGet32 (UefiCertificateKeySize), + ChildSaSession->IkeSaSession->Pad->Data->AuthData, + ChildSaSession->IkeSaSession->Pad->Data->AuthDataSize + ); + if (IkeSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) { + CpPayload = Ikev2GenerateCpPayload ( + ChildSaSession->IkeSaSession, + IKEV2_PAYLOAD_TYPE_SA, + IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS + ); + } else { + CpPayload = Ikev2GenerateCpPayload ( + ChildSaSession->IkeSaSession, + IKEV2_PAYLOAD_TYPE_SA, + IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS + ); + } + } + + // + // 5. Generate SA Payload according to the Sa Data in ChildSaSession + // + SaPayload = Ikev2GenerateSaPayload ( + ChildSaSession->SaData, + IKEV2_PAYLOAD_TYPE_TS_INIT, + IkeSessionTypeChildSa + ); + + if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) { + // + // Generate Tsi and Tsr. + // + TsiPayload = Ikev2GenerateTsPayload ( + ChildSaSession, + IKEV2_PAYLOAD_TYPE_TS_RSP, + FALSE + ); + + TsrPayload = Ikev2GenerateTsPayload ( + ChildSaSession, + IKEV2_PAYLOAD_TYPE_NOTIFY, + FALSE + ); + + // + // Generate Notify Payload. If transport mode, there should have Notify + // payload with TRANSPORT_MODE notification. + // + NotifyPayload = Ikev2GenerateNotifyPayload ( + 0, + IKEV2_PAYLOAD_TYPE_NONE, + 0, + IKEV2_NOTIFICATION_USE_TRANSPORT_MODE, + NULL, + NULL, + 0 + ); + } else { + // + // Generate Tsr for Tunnel mode. + // + TsiPayload = Ikev2GenerateTsPayload ( + ChildSaSession, + IKEV2_PAYLOAD_TYPE_TS_RSP, + TRUE + ); + TsrPayload = Ikev2GenerateTsPayload ( + ChildSaSession, + IKEV2_PAYLOAD_TYPE_NONE, + FALSE + ); + } + + IKE_PACKET_APPEND_PAYLOAD (IkePacket, IdPayload); + IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertPayload); + if (IkeSaSession->SessionCommon.IsInitiator) { + IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertReqPayload); + } + IKE_PACKET_APPEND_PAYLOAD (IkePacket, AuthPayload); + if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) { + IKE_PACKET_APPEND_PAYLOAD (IkePacket, CpPayload); + } + IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload); + IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsiPayload); + IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsrPayload); + if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) { + IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload); + } + + return IkePacket; +} + +/** + Parses IKE_AUTH packet. + + @param[in] SaSession Pointer to the IKE_SA_SESSION related to this packet. + @param[in] IkePacket Pointer to the IKE_AUTH packet to be parsered. + + @retval EFI_INVALID_PARAMETER The IKEv2 packet is malformed or the SA + proposal is unacceptable. + @retval EFI_SUCCESS The IKE packet is acceptable and the + relative data is saved for furthure communication. + @retval EFI_UNSUPPORTED The certificate authentication is not supported. + +**/ +EFI_STATUS +Ikev2AuthCertParser ( + IN UINT8 *SaSession, + IN IKE_PACKET *IkePacket + ) +{ + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SA_SESSION *IkeSaSession; + IKE_PAYLOAD *IkePayload; + IKE_PAYLOAD *SaPayload; + IKE_PAYLOAD *IdiPayload; + IKE_PAYLOAD *IdrPayload; + IKE_PAYLOAD *AuthPayload; + IKE_PAYLOAD *TsiPayload; + IKE_PAYLOAD *TsrPayload; + IKE_PAYLOAD *CertPayload; + IKE_PAYLOAD *CertReqPayload; + IKE_PAYLOAD *VerifiedAuthPayload; + LIST_ENTRY *Entry; + EFI_STATUS Status; + + if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) { + return EFI_UNSUPPORTED; + } + + IkeSaSession = (IKEV2_SA_SESSION *) SaSession; + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList)); + + SaPayload = NULL; + IdiPayload = NULL; + IdrPayload = NULL; + AuthPayload = NULL; + TsiPayload = NULL; + TsrPayload = NULL; + CertPayload = NULL; + CertReqPayload = NULL; + VerifiedAuthPayload = NULL; + Status = EFI_INVALID_PARAMETER; + + // + // Iterate payloads to find the SaPayload/ID/AUTH/TS Payload. + // + NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) { + IkePayload = IKE_PAYLOAD_BY_PACKET (Entry); + + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_INIT) { + IdiPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_RSP) { + IdrPayload = IkePayload; + } + + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) { + SaPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_AUTH) { + AuthPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) { + TsiPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_RSP) { + TsrPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_CERT) { + CertPayload = IkePayload; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_CERTREQ) { + CertReqPayload = IkePayload; + } + } + + if ((SaPayload == NULL) || (AuthPayload == NULL) || (TsiPayload == NULL) || + (TsrPayload == NULL) || (CertPayload == NULL)) { + goto Exit; + } + if ((IdiPayload == NULL) && (IdrPayload == NULL)) { + goto Exit; + } + + // + // Check IkePacket Header is match the state + // + if (IkeSaSession->SessionCommon.IsInitiator) { + + // + // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND + // + if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) || + (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)) { + goto Exit; + } + } else { + // + // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT + // + if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) || + (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)) { + goto Exit; + } + } + + // + // Verify the Auth Payload. + // + VerifiedAuthPayload = Ikev2CertGenerateAuthPayload ( + IkeSaSession, + IkeSaSession->SessionCommon.IsInitiator ? IdrPayload:IdiPayload, + IKEV2_PAYLOAD_TYPE_SA, + TRUE, + NULL, + 0, + NULL, + 0 + ); + + if ((VerifiedAuthPayload != NULL) && + (!IpSecCryptoIoVerifySignDataByCertificate ( + CertPayload->PayloadBuf + sizeof (IKEV2_CERT), + CertPayload->PayloadSize - sizeof (IKEV2_CERT), + (UINT8 *)PcdGetPtr (UefiCaFile), + PcdGet32 (UefiCaFileSize), + VerifiedAuthPayload->PayloadBuf + sizeof (IKEV2_AUTH), + VerifiedAuthPayload->PayloadSize - sizeof (IKEV2_AUTH), + AuthPayload->PayloadBuf + sizeof (IKEV2_AUTH), + AuthPayload->PayloadSize - sizeof (IKEV2_AUTH) + ))) { + goto Exit; + } + + // + // 3. Parse the SA Payload to find out the cryptographic suite + // and fill in the SA paramse into CommonSession->SaParams. If no acceptable + // porposal found, return EFI_INVALID_PARAMETER. + // + if (!Ikev2ChildSaParseSaPayload (ChildSaSession, SaPayload, IkePacket->Header->Flags)) { + goto Exit; + } + + // + // 4. Parse TSi, TSr payloads. + // + if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != + ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId) && + (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) && + (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) + ) { + goto Exit; + } + + if (!IkeSaSession->SessionCommon.IsInitiator) { + // + //Todo:check the Port range. Only support any port and one certain port here. + // + ChildSaSession->ProtoId = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId; + ChildSaSession->LocalPort = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort; + ChildSaSession->RemotePort = ((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort; + // + // Association a SPD with this SA. + // + if (EFI_ERROR (Ikev2ChildSaAssociateSpdEntry (ChildSaSession))) { + goto Exit; + } + // + // Associate the IkeSaSession's SPD to the first ChildSaSession's SPD. + // + if (ChildSaSession->IkeSaSession->Spd == NULL) { + ChildSaSession->IkeSaSession->Spd = ChildSaSession->Spd; + Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession); + } + } else { + // + // Todo:check the Port range. + // + if ((((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) && + (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->RemotePort) + ) { + goto Exit; + } + if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) && + (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->LocalPort) + ) { + goto Exit; + } + // + // For the tunnel mode, it should add the vitual IP address into the SA's SPD Selector. + // + if (ChildSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) { + if (!ChildSaSession->IkeSaSession->SessionCommon.IsInitiator) { + // + // If it is tunnel mode, the UEFI part must be the initiator. + // + goto Exit; + } + // + // Get the Virtual IP address from the Tsi traffic selector. + // TODO: check the CFG reply payload + // + CopyMem ( + &ChildSaSession->SpdSelector->LocalAddress[0].Address, + TsiPayload->PayloadBuf + sizeof (IKEV2_TS) + sizeof (TRAFFIC_SELECTOR), + (ChildSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) ? + sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS) + ); + } + } + + // + // 5. Generat keymats for IPsec protocol. + // + Ikev2GenerateChildSaKeys (ChildSaSession, NULL); + if (IkeSaSession->SessionCommon.IsInitiator) { + // + // 6. Change the state of IkeSaSession + // + IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateIkeSaEstablished); + IkeSaSession->SessionCommon.State = IkeStateIkeSaEstablished; + } + + Status = EFI_SUCCESS; + +Exit: + if (VerifiedAuthPayload != NULL) { + IkePayloadFree (VerifiedAuthPayload); + } + return Status; +} + +/** + Generates the DH Public Key. + + This generates the DH local public key and store it in the IKE SA Session's GxBuffer. + + @param[in] IkeSaSession Pointer to related IKE SA Session. + + @retval EFI_SUCCESS The operation succeeded. + @retval Others The operation failed. + +**/ +EFI_STATUS +Ikev2GenerateSaDhPublicKey ( + IN IKEV2_SA_SESSION *IkeSaSession + ) +{ + EFI_STATUS Status; + IKEV2_SESSION_KEYS *IkeKeys; + + IkeSaSession->IkeKeys = AllocateZeroPool (sizeof (IKEV2_SESSION_KEYS)); + ASSERT (IkeSaSession->IkeKeys != NULL); + IkeKeys = IkeSaSession->IkeKeys; + IkeKeys->DhBuffer = AllocateZeroPool (sizeof (IKEV2_DH_BUFFER)); + ASSERT (IkeKeys->DhBuffer != NULL); + + // + // Init DH with the certain DH Group Description. + // + IkeKeys->DhBuffer->GxSize = OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Size >> 3; + IkeKeys->DhBuffer->GxBuffer = AllocateZeroPool (IkeKeys->DhBuffer->GxSize); + ASSERT (IkeKeys->DhBuffer->GxBuffer != NULL); + + // + // Get X PublicKey + // + Status = IpSecCryptoIoDhGetPublicKey ( + &IkeKeys->DhBuffer->DhContext, + OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].GroupGenerator, + OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Size, + OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Modulus, + IkeKeys->DhBuffer->GxBuffer, + &IkeKeys->DhBuffer->GxSize + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error CPLKeyManGetKeyParam X public key error Status = %r\n", Status)); + return Status; + } + + IPSEC_DUMP_BUF ("DH Public Key (g^x) Dump", IkeKeys->DhBuffer->GxBuffer, IkeKeys->DhBuffer->GxSize); + + return EFI_SUCCESS; +} + +/** + Computes the DH Shared/Exchange Key. + + Given peer's public key, this function computes the exchanged common key and + stores it in the IKEv2 SA Session's GxyBuffer. + + @param[in] DhBuffer Pointer to buffer of peer's puliic key. + @param[in] KePayload Pointer to received key payload. + + @retval EFI_SUCCESS The operation succeeded. + @retval Otherwise The operation failed. + +**/ +EFI_STATUS +Ikev2GenerateSaDhComputeKey ( + IN IKEV2_DH_BUFFER *DhBuffer, + IN IKE_PAYLOAD *KePayload + ) +{ + EFI_STATUS Status; + IKEV2_KEY_EXCHANGE *Ke; + UINT8 *PubKey; + UINTN PubKeySize; + + Ke = (IKEV2_KEY_EXCHANGE *) KePayload->PayloadBuf; + PubKey = (UINT8 *) (Ke + 1); + PubKeySize = KePayload->PayloadSize - sizeof (IKEV2_KEY_EXCHANGE); + DhBuffer->GxySize = DhBuffer->GxSize; + DhBuffer->GxyBuffer = AllocateZeroPool (DhBuffer->GxySize); + ASSERT (DhBuffer->GxyBuffer != NULL); + + // + // Get GxyBuf + // + Status = IpSecCryptoIoDhComputeKey ( + DhBuffer->DhContext, + PubKey, + PubKeySize, + DhBuffer->GxyBuffer, + &DhBuffer->GxySize + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error CPLKeyManGetKeyParam Y session key error Status = %r\n", Status)); + return Status; + } + + // + // Create GxyBuf. + // + DhBuffer->GySize = PubKeySize; + DhBuffer->GyBuffer = AllocateZeroPool (DhBuffer->GySize); + ASSERT (DhBuffer->GyBuffer != NULL); + CopyMem (DhBuffer->GyBuffer, PubKey, DhBuffer->GySize); + + IPSEC_DUMP_BUF ("DH Public Key (g^y) Dump", DhBuffer->GyBuffer, DhBuffer->GySize); + IPSEC_DUMP_BUF ("DH Shared Key (g^xy) Dump", DhBuffer->GxyBuffer, DhBuffer->GxySize); + + return EFI_SUCCESS; +} + +/** + Generates the IKE SKEYSEED and seven other secrets. SK_d, SK_ai, SK_ar, SK_ei, SK_er, + SK_pi, SK_pr are keys for the furthure IKE exchange. + + @param[in] IkeSaSession Pointer to IKE SA Session. + @param[in] KePayload Pointer to Key payload used to generate the Key. + + @retval EFI_UNSUPPORTED If one or more Algorithm Id is not supported. + @retval EFI_OUT_OF_RESOURCES If there is no enough resource to be allocated to + meet the requirement. + @retval EFI_SUCCESS The operation succeeded. + +**/ +EFI_STATUS +Ikev2GenerateSaKeys ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IKE_PAYLOAD *KePayload + ) +{ + EFI_STATUS Status; + IKEV2_SA_PARAMS *SaParams; + IPSEC_PAD_ENTRY *Pad; + PRF_DATA_FRAGMENT Fragments[4]; + UINT64 InitiatorCookieNet; + UINT64 ResponderCookieNet; + UINT8 *KeyBuffer; + UINTN KeyBufferSize; + UINTN AuthAlgKeyLen; + UINTN EncryptAlgKeyLen; + UINTN IntegrityAlgKeyLen; + UINTN PrfAlgKeyLen; + UINT8 *OutputKey; + UINTN OutputKeyLength; + UINT8 *Digest; + UINTN DigestSize; + + Digest = NULL; + OutputKey = NULL; + KeyBuffer = NULL; + + // + // Generate Gxy + // + Ikev2GenerateSaDhComputeKey (IkeSaSession->IkeKeys->DhBuffer, KePayload); + + Pad = IkeSaSession->Pad; + + // + // Get the key length of Authenticaion, Encryption, PRF, and Integrity. + // + SaParams = IkeSaSession->SessionCommon.SaParams; + AuthAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf); + EncryptAlgKeyLen = IpSecGetEncryptKeyLength ((UINT8)SaParams->EncAlgId); + IntegrityAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->IntegAlgId); + PrfAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf); + + // + // If one or more algorithm is not support, return EFI_UNSUPPORTED. + // + if (AuthAlgKeyLen == 0 || + EncryptAlgKeyLen == 0 || + IntegrityAlgKeyLen == 0 || + PrfAlgKeyLen == 0 + ) { + Status = EFI_UNSUPPORTED; + goto Exit; + } + + // + // Compute SKEYSEED = prf(Ni | Nr, g^ir) + // + KeyBufferSize = IkeSaSession->NiBlkSize + IkeSaSession->NrBlkSize; + KeyBuffer = AllocateZeroPool (KeyBufferSize); + ASSERT (KeyBuffer != NULL); + + CopyMem (KeyBuffer, IkeSaSession->NiBlock, IkeSaSession->NiBlkSize); + CopyMem (KeyBuffer + IkeSaSession->NiBlkSize, IkeSaSession->NrBlock, IkeSaSession->NrBlkSize); + + Fragments[0].Data = IkeSaSession->IkeKeys->DhBuffer->GxyBuffer; + Fragments[0].DataSize = IkeSaSession->IkeKeys->DhBuffer->GxySize; + + DigestSize = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf); + Digest = AllocateZeroPool (DigestSize); + + if (Digest == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + IpSecCryptoIoHmac ( + (UINT8)SaParams->Prf, + KeyBuffer, + KeyBufferSize, + (HASH_DATA_FRAGMENT *) Fragments, + 1, + Digest, + DigestSize + ); + + // + // {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } = prf+ + // (SKEYSEED, Ni | Nr | SPIi | SPIr ) + // + Fragments[0].Data = IkeSaSession->NiBlock; + Fragments[0].DataSize = IkeSaSession->NiBlkSize; + Fragments[1].Data = IkeSaSession->NrBlock; + Fragments[1].DataSize = IkeSaSession->NrBlkSize; + InitiatorCookieNet = HTONLL (IkeSaSession->InitiatorCookie); + ResponderCookieNet = HTONLL (IkeSaSession->ResponderCookie); + Fragments[2].Data = (UINT8 *)(&InitiatorCookieNet); + Fragments[2].DataSize = sizeof (IkeSaSession->InitiatorCookie); + Fragments[3].Data = (UINT8 *)(&ResponderCookieNet); + Fragments[3].DataSize = sizeof (IkeSaSession->ResponderCookie); + + IPSEC_DUMP_BUF (">>> NiBlock", IkeSaSession->NiBlock, IkeSaSession->NiBlkSize); + IPSEC_DUMP_BUF (">>> NrBlock", IkeSaSession->NrBlock, IkeSaSession->NrBlkSize); + IPSEC_DUMP_BUF (">>> InitiatorCookie", (UINT8 *)&IkeSaSession->InitiatorCookie, sizeof(UINT64)); + IPSEC_DUMP_BUF (">>> ResponderCookie", (UINT8 *)&IkeSaSession->ResponderCookie, sizeof(UINT64)); + + OutputKeyLength = PrfAlgKeyLen + + 2 * EncryptAlgKeyLen + + 2 * AuthAlgKeyLen + + 2 * IntegrityAlgKeyLen; + OutputKey = AllocateZeroPool (OutputKeyLength); + + // + // Generate Seven Keymates. + // + Status = Ikev2SaGenerateKey ( + (UINT8)SaParams->Prf, + Digest, + DigestSize, + OutputKey, + OutputKeyLength, + Fragments, + 4 + ); + if (EFI_ERROR(Status)) { + goto Exit; + } + + // + // Save the seven keys into KeySession. + // First, SK_d + // + IkeSaSession->IkeKeys->SkdKey = AllocateZeroPool (PrfAlgKeyLen); + IkeSaSession->IkeKeys->SkdKeySize = PrfAlgKeyLen; + CopyMem (IkeSaSession->IkeKeys->SkdKey, OutputKey, PrfAlgKeyLen); + + IPSEC_DUMP_BUF (">>> SK_D Key", IkeSaSession->IkeKeys->SkdKey, PrfAlgKeyLen); + + // + // Second, Sk_ai + // + IkeSaSession->IkeKeys->SkAiKey = AllocateZeroPool (IntegrityAlgKeyLen); + IkeSaSession->IkeKeys->SkAiKeySize = IntegrityAlgKeyLen; + CopyMem (IkeSaSession->IkeKeys->SkAiKey, OutputKey + PrfAlgKeyLen, IntegrityAlgKeyLen); + + IPSEC_DUMP_BUF (">>> SK_Ai Key", IkeSaSession->IkeKeys->SkAiKey, IkeSaSession->IkeKeys->SkAiKeySize); + + // + // Third, Sk_ar + // + IkeSaSession->IkeKeys->SkArKey = AllocateZeroPool (IntegrityAlgKeyLen); + IkeSaSession->IkeKeys->SkArKeySize = IntegrityAlgKeyLen; + CopyMem ( + IkeSaSession->IkeKeys->SkArKey, + OutputKey + PrfAlgKeyLen + IntegrityAlgKeyLen, + IntegrityAlgKeyLen + ); + + IPSEC_DUMP_BUF (">>> SK_Ar Key", IkeSaSession->IkeKeys->SkArKey, IkeSaSession->IkeKeys->SkArKeySize); + + // + // Fourth, Sk_ei + // + IkeSaSession->IkeKeys->SkEiKey = AllocateZeroPool (EncryptAlgKeyLen); + IkeSaSession->IkeKeys->SkEiKeySize = EncryptAlgKeyLen; + + CopyMem ( + IkeSaSession->IkeKeys->SkEiKey, + OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen, + EncryptAlgKeyLen + ); + IPSEC_DUMP_BUF ( + ">>> SK_Ei Key", + OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen, + EncryptAlgKeyLen + ); + + // + // Fifth, Sk_er + // + IkeSaSession->IkeKeys->SkErKey = AllocateZeroPool (EncryptAlgKeyLen); + IkeSaSession->IkeKeys->SkErKeySize = EncryptAlgKeyLen; + + CopyMem ( + IkeSaSession->IkeKeys->SkErKey, + OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + EncryptAlgKeyLen, + EncryptAlgKeyLen + ); + IPSEC_DUMP_BUF ( + ">>> SK_Er Key", + OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + EncryptAlgKeyLen, + EncryptAlgKeyLen + ); + + // + // Sixth, Sk_pi + // + IkeSaSession->IkeKeys->SkPiKey = AllocateZeroPool (AuthAlgKeyLen); + IkeSaSession->IkeKeys->SkPiKeySize = AuthAlgKeyLen; + + CopyMem ( + IkeSaSession->IkeKeys->SkPiKey, + OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen, + AuthAlgKeyLen + ); + IPSEC_DUMP_BUF ( + ">>> SK_Pi Key", + OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen, + AuthAlgKeyLen + ); + + // + // Seventh, Sk_pr + // + IkeSaSession->IkeKeys->SkPrKey = AllocateZeroPool (AuthAlgKeyLen); + IkeSaSession->IkeKeys->SkPrKeySize = AuthAlgKeyLen; + + CopyMem ( + IkeSaSession->IkeKeys->SkPrKey, + OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen + AuthAlgKeyLen, + AuthAlgKeyLen + ); + IPSEC_DUMP_BUF ( + ">>> SK_Pr Key", + OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen + AuthAlgKeyLen, + AuthAlgKeyLen + ); + + +Exit: + if (Digest != NULL) { + FreePool (Digest); + } + if (KeyBuffer != NULL) { + FreePool (KeyBuffer); + } + if (OutputKey != NULL) { + FreePool (OutputKey); + } + + return Status; +} + +/** + Generates the Keys for the furthure IPsec Protocol. + + @param[in] ChildSaSession Pointer to IKE Child SA Session. + @param[in] KePayload Pointer to Key payload used to generate the Key. + + @retval EFI_UNSUPPORTED If one or more Algorithm Id is not supported. + @retval EFI_SUCCESS The operation succeeded. + +**/ +EFI_STATUS +Ikev2GenerateChildSaKeys ( + IN IKEV2_CHILD_SA_SESSION *ChildSaSession, + IN IKE_PAYLOAD *KePayload + ) +{ + EFI_STATUS Status; + IKEV2_SA_PARAMS *SaParams; + PRF_DATA_FRAGMENT Fragments[3]; + UINTN EncryptAlgKeyLen; + UINTN IntegrityAlgKeyLen; + UINT8* OutputKey; + UINTN OutputKeyLength; + + if (KePayload != NULL) { + // + // Generate Gxy + // + Ikev2GenerateSaDhComputeKey (ChildSaSession->DhBuffer, KePayload); + Fragments[0].Data = ChildSaSession->DhBuffer->GxyBuffer; + Fragments[0].DataSize = ChildSaSession->DhBuffer->GxySize; + } + + Fragments[1].Data = ChildSaSession->NiBlock; + Fragments[1].DataSize = ChildSaSession->NiBlkSize; + Fragments[2].Data = ChildSaSession->NrBlock; + Fragments[2].DataSize = ChildSaSession->NrBlkSize; + + // + // Get the key length of Authenticaion, Encryption, PRF, and Integrity. + // + SaParams = ChildSaSession->SessionCommon.SaParams; + EncryptAlgKeyLen = IpSecGetEncryptKeyLength ((UINT8)SaParams->EncAlgId); + IntegrityAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->IntegAlgId); + OutputKeyLength = 2 * EncryptAlgKeyLen + 2 * IntegrityAlgKeyLen; + + if ((EncryptAlgKeyLen == 0) || (IntegrityAlgKeyLen == 0)) { + return EFI_UNSUPPORTED; + } + + // + // + // If KePayload is not NULL, calculate KEYMAT = prf+(SK_d, g^ir (new) | Ni | Nr ), + // otherwise, KEYMAT = prf+(SK_d, Ni | Nr ) + // + OutputKey = AllocateZeroPool (OutputKeyLength); + + // + // Derive Key from the SkdKey Buffer. + // + Status = Ikev2SaGenerateKey ( + (UINT8)ChildSaSession->IkeSaSession->SessionCommon.SaParams->Prf, + ChildSaSession->IkeSaSession->IkeKeys->SkdKey, + ChildSaSession->IkeSaSession->IkeKeys->SkdKeySize, + OutputKey, + OutputKeyLength, + KePayload == NULL ? &Fragments[1] : Fragments, + KePayload == NULL ? 2 : 3 + ); + + if (EFI_ERROR (Status)) { + FreePool (OutputKey); + return Status; + } + + // + // Copy KEYMATE (SK_ENCRYPT_i | SK_ENCRYPT_r | SK_INTEG_i | SK_INTEG_r) to + // ChildKeyMates. + // + if (!ChildSaSession->SessionCommon.IsInitiator) { + + // + // Initiator Encryption Key + // + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId; + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen; + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen); + + CopyMem ( + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey, + OutputKey, + EncryptAlgKeyLen + ); + + // + // Initiator Authentication Key + // + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId; + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen; + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen); + + CopyMem ( + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey, + OutputKey + EncryptAlgKeyLen, + IntegrityAlgKeyLen + ); + + // + // Responder Encrypt Key + // + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId; + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen; + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen); + + CopyMem ( + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey, + OutputKey + EncryptAlgKeyLen + IntegrityAlgKeyLen, + EncryptAlgKeyLen + ); + + // + // Responder Authentication Key + // + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId; + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen; + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen); + + CopyMem ( + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey, + OutputKey + 2 * EncryptAlgKeyLen + IntegrityAlgKeyLen, + IntegrityAlgKeyLen + ); + } else { + // + // Initiator Encryption Key + // + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId; + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen; + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen); + + CopyMem ( + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey, + OutputKey, + EncryptAlgKeyLen + ); + + // + // Initiator Authentication Key + // + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId; + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen; + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen); + + CopyMem ( + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey, + OutputKey + EncryptAlgKeyLen, + IntegrityAlgKeyLen + ); + + // + // Responder Encryption Key + // + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId; + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen; + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen); + + CopyMem ( + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey, + OutputKey + EncryptAlgKeyLen + IntegrityAlgKeyLen, + EncryptAlgKeyLen + ); + + // + // Responder Authentication Key + // + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId; + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen; + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen); + + CopyMem ( + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey, + OutputKey + 2 * EncryptAlgKeyLen + IntegrityAlgKeyLen, + IntegrityAlgKeyLen + ); + } + + IPSEC_DUMP_BUF ( + " >>> Local Encryption Key", + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey, + EncryptAlgKeyLen + ); + IPSEC_DUMP_BUF ( + " >>> Remote Encryption Key", + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey, + EncryptAlgKeyLen + ); + IPSEC_DUMP_BUF ( + " >>> Local Authentication Key", + ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey, + IntegrityAlgKeyLen + ); + IPSEC_DUMP_BUF ( + " >>> Remote Authentication Key", + ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey, + IntegrityAlgKeyLen + ); + + FreePool (OutputKey); + + return EFI_SUCCESS; +} + +GLOBAL_REMOVE_IF_UNREFERENCED IKEV2_PACKET_HANDLER mIkev2Initial[][2] = { + { //PSK + { // IKEV2_INIT + Ikev2InitPskParser, + Ikev2InitPskGenerator + }, + { //IKEV2_AUTH + Ikev2AuthPskParser, + Ikev2AuthPskGenerator + } + }, + { // CERT + { // IKEV2_INIT + Ikev2InitCertParser, + Ikev2InitCertGenerator + }, + { // IKEV2_AUTH + Ikev2AuthCertParser, + Ikev2AuthCertGenerator + }, + }, +}; diff --git a/NetworkPkg/IpSecDxe/Ikev2/Utility.c b/NetworkPkg/IpSecDxe/Ikev2/Utility.c new file mode 100644 index 0000000000..4c461b3742 --- /dev/null +++ b/NetworkPkg/IpSecDxe/Ikev2/Utility.c @@ -0,0 +1,2692 @@ +/** @file + The Common operations used by IKE Exchange Process. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Utility.h" +#include "IpSecDebug.h" +#include "IkeService.h" +#include "IpSecConfigImpl.h" + +UINT16 mIkev2EncryptAlgorithmList[IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM] = { + IKEV2_TRANSFORM_ID_ENCR_3DES, + IKEV2_TRANSFORM_ID_ENCR_AES_CBC, +}; + +UINT16 mIkev2PrfAlgorithmList[IKEV2_SUPPORT_PRF_ALGORITHM_NUM] = { + IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1, +}; + +UINT16 mIkev2DhGroupAlgorithmList[IKEV2_SUPPORT_DH_ALGORITHM_NUM] = { + IKEV2_TRANSFORM_ID_DH_1024MODP, + IKEV2_TRANSFORM_ID_DH_2048MODP, +}; + +UINT16 mIkev2AuthAlgorithmList[IKEV2_SUPPORT_AUTH_ALGORITHM_NUM] = { + IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96, +}; + +/** + Allocate buffer for IKEV2_SA_SESSION and initialize it. + + @param[in] Private Pointer to IPSEC_PRIVATE_DATA. + @param[in] UdpService Pointer to IKE_UDP_SERVICE related to this IKE SA Session. + + @return Pointer to IKEV2_SA_SESSION or NULL. + +**/ +IKEV2_SA_SESSION * +Ikev2SaSessionAlloc ( + IN IPSEC_PRIVATE_DATA *Private, + IN IKE_UDP_SERVICE *UdpService + ) +{ + EFI_STATUS Status; + IKEV2_SESSION_COMMON *SessionCommon; + IKEV2_SA_SESSION *IkeSaSession; + + IkeSaSession = AllocateZeroPool (sizeof (IKEV2_SA_SESSION)); + ASSERT (IkeSaSession != NULL); + + // + // Initialize the fields of IkeSaSession and its SessionCommon. + // + IkeSaSession->NCookie = NULL; + IkeSaSession->Signature = IKEV2_SA_SESSION_SIGNATURE; + IkeSaSession->InitiatorCookie = IkeGenerateCookie (); + IkeSaSession->ResponderCookie = 0; + // + // BUGBUG: Message ID starts from 2 is to match the OpenSwan requirement, but it + // might not match the IPv6 Logo. In its test specification, it mentions that + // the Message ID should start from zero after the IKE_SA_INIT exchange. + // + IkeSaSession->MessageId = 2; + SessionCommon = &IkeSaSession->SessionCommon; + SessionCommon->UdpService = UdpService; + SessionCommon->Private = Private; + SessionCommon->IkeSessionType = IkeSessionTypeIkeSa; + SessionCommon->IkeVer = 2; + SessionCommon->AfterEncodePayload = NULL; + SessionCommon->BeforeDecodePayload = NULL; + + // + // Create a resend notfiy event for retry. + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ikev2ResendNotify, + SessionCommon, + &SessionCommon->TimeoutEvent + ); + + if (EFI_ERROR (Status)) { + FreePool (IkeSaSession); + return NULL; + } + + // + // Initialize the lists in IkeSaSession. + // + InitializeListHead (&IkeSaSession->ChildSaSessionList); + InitializeListHead (&IkeSaSession->ChildSaEstablishSessionList); + InitializeListHead (&IkeSaSession->InfoMIDList); + InitializeListHead (&IkeSaSession->DeleteSaList); + + return IkeSaSession; +} + +/** + Register the established IKEv2 SA into Private->Ikev2EstablishedList. If there is + IKEV2_SA_SESSION with same remote peer IP, remove the old one then register the + new one. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be registered. + @param[in] Private Pointer to IPSEC_PRAVATE_DATA. + +**/ +VOID +Ikev2SaSessionReg ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IPSEC_PRIVATE_DATA *Private + ) +{ + IKEV2_SESSION_COMMON *SessionCommon; + IKEV2_SA_SESSION *OldIkeSaSession; + EFI_STATUS Status; + UINT64 Lifetime; + + // + // Keep IKE SA exclusive to remote ip address. + // + SessionCommon = &IkeSaSession->SessionCommon; + OldIkeSaSession = Ikev2SaSessionRemove (&Private->Ikev2EstablishedList, &SessionCommon->RemotePeerIp); + if (OldIkeSaSession != NULL) { + // + // TODO: It should delete all child SAs if rekey the IKE SA. + // + Ikev2SaSessionFree (OldIkeSaSession); + } + + // + // Cleanup the fields of SessionCommon for processing. + // + Ikev2SessionCommonRefresh (SessionCommon); + + // + // Insert the ready IKE SA session into established list. + // + Ikev2SaSessionInsert (&Private->Ikev2EstablishedList, IkeSaSession, &SessionCommon->RemotePeerIp); + + // + // Create a notfiy event for the IKE SA life time counting. + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ikev2LifetimeNotify, + SessionCommon, + &SessionCommon->TimeoutEvent + ); + if (EFI_ERROR(Status)){ + // + // If TimerEvent creation failed, the SA will be alive untill user disable it or + // receiving a Delete Payload from peer. + // + return; + } + + // + // Start to count the lifetime of the IKE SA. + // + if (IkeSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime == 0) { + Lifetime = IKE_SA_DEFAULT_LIFETIME; + } else { + Lifetime = IkeSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime; + } + + Status = gBS->SetTimer ( + SessionCommon->TimeoutEvent, + TimerRelative, + MultU64x32(Lifetime, 10000000) // ms->100ns + ); + if (EFI_ERROR(Status)){ + // + // If SetTimer failed, the SA will be alive untill user disable it or + // receiving a Delete Payload from peer. + // + return ; + } + + DEBUG (( + DEBUG_INFO, + "\n------IkeSa established and start to count down %d seconds lifetime\n", + Lifetime + )); + + return ; +} + +/** + Find a IKEV2_SA_SESSION by the remote peer IP. + + @param[in] SaSessionList SaSession List to be searched. + @param[in] RemotePeerIp Pointer to specified IP address. + + @return Pointer to IKEV2_SA_SESSION if find one or NULL. + +**/ +IKEV2_SA_SESSION * +Ikev2SaSessionLookup ( + IN LIST_ENTRY *SaSessionList, + IN EFI_IP_ADDRESS *RemotePeerIp + ) +{ + LIST_ENTRY *Entry; + IKEV2_SA_SESSION *IkeSaSession; + + NET_LIST_FOR_EACH (Entry, SaSessionList) { + IkeSaSession = IKEV2_SA_SESSION_BY_SESSION (Entry); + + if (CompareMem ( + &IkeSaSession->SessionCommon.RemotePeerIp, + RemotePeerIp, + sizeof (EFI_IP_ADDRESS) + ) == 0) { + + return IkeSaSession; + } + } + + return NULL; +} + +/** + Insert a IKE_SA_SESSION into IkeSaSession list. The IkeSaSession list is either + Private->Ikev2SaSession list or Private->Ikev2EstablishedList list. + + @param[in] SaSessionList Pointer to list to be inserted into. + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be inserted. + @param[in] RemotePeerIp Pointer to EFI_IP_ADDRESSS to indicate the + unique IKEV2_SA_SESSION. + +**/ +VOID +Ikev2SaSessionInsert ( + IN LIST_ENTRY *SaSessionList, + IN IKEV2_SA_SESSION *IkeSaSession, + IN EFI_IP_ADDRESS *RemotePeerIp + ) +{ + Ikev2SaSessionRemove (SaSessionList, RemotePeerIp); + InsertTailList (SaSessionList, &IkeSaSession->BySessionTable); +} + +/** + Remove the SA Session by Remote Peer IP. + + @param[in] SaSessionList Pointer to list to be searched. + @param[in] RemotePeerIp Pointer to EFI_IP_ADDRESS to use for SA Session search. + + @retval Pointer to IKEV2_SA_SESSION with the specified remote IP address or NULL. + +**/ +IKEV2_SA_SESSION * +Ikev2SaSessionRemove ( + IN LIST_ENTRY *SaSessionList, + IN EFI_IP_ADDRESS *RemotePeerIp + ) +{ + LIST_ENTRY *Entry; + IKEV2_SA_SESSION *IkeSaSession; + + NET_LIST_FOR_EACH (Entry, SaSessionList) { + IkeSaSession = IKEV2_SA_SESSION_BY_SESSION (Entry); + + if (CompareMem ( + &IkeSaSession->SessionCommon.RemotePeerIp, + RemotePeerIp, + sizeof (EFI_IP_ADDRESS) + ) == 0) { + + RemoveEntryList (Entry); + return IkeSaSession; + } + } + + return NULL; +} + +/** + Marking a SA session as on deleting. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION. + + @retval EFI_SUCCESS Find the related SA session and marked it. + +**/ +EFI_STATUS +Ikev2SaSessionOnDeleting ( + IN IKEV2_SA_SESSION *IkeSaSession + ) +{ + return EFI_SUCCESS; +} + +/** + Free specified Seession Common. The session common would belong to a IKE SA or + a Child SA. + + @param[in] SessionCommon Pointer to a Session Common. + +**/ +VOID +Ikev2SaSessionCommonFree ( + IN IKEV2_SESSION_COMMON *SessionCommon + ) +{ + + ASSERT (SessionCommon != NULL); + + if (SessionCommon->LastSentPacket != NULL) { + IkePacketFree (SessionCommon->LastSentPacket); + } + + if (SessionCommon->SaParams != NULL) { + FreePool (SessionCommon->SaParams); + } + if (SessionCommon->TimeoutEvent != NULL) { + gBS->CloseEvent (SessionCommon->TimeoutEvent); + } +} + +/** + After IKE/Child SA is estiblished, close the time event and free sent packet. + + @param[in] SessionCommon Pointer to a Session Common. + +**/ +VOID +Ikev2SessionCommonRefresh ( + IN IKEV2_SESSION_COMMON *SessionCommon + ) +{ + ASSERT (SessionCommon != NULL); + + gBS->CloseEvent (SessionCommon->TimeoutEvent); + SessionCommon->TimeoutEvent = NULL; + SessionCommon->TimeoutInterval = 0; + SessionCommon->RetryCount = 0; + if (SessionCommon->LastSentPacket != NULL) { + IkePacketFree (SessionCommon->LastSentPacket); + SessionCommon->LastSentPacket = NULL; + } + + return ; +} +/** + Free specified IKEV2 SA Session. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be freed. + +**/ +VOID +Ikev2SaSessionFree ( + IN IKEV2_SA_SESSION *IkeSaSession + ) +{ + IKEV2_SESSION_KEYS *IkeKeys; + LIST_ENTRY *Entry; + IKEV2_CHILD_SA_SESSION *ChildSa; + IKEV2_DH_BUFFER *DhBuffer; + + ASSERT (IkeSaSession != NULL); + + // + // Delete Common Session + // + Ikev2SaSessionCommonFree (&IkeSaSession->SessionCommon); + + // + // Delete ChildSaEstablish List and SAD + // + for (Entry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink; + Entry != &IkeSaSession->ChildSaEstablishSessionList; + ) { + + ChildSa = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry); + Entry = Entry->ForwardLink; + Ikev2ChildSaSilentDelete (ChildSa->IkeSaSession, ChildSa->LocalPeerSpi); + + } + + // + // Delete ChildSaSessionList + // + for ( Entry = IkeSaSession->ChildSaSessionList.ForwardLink; + Entry != &IkeSaSession->ChildSaSessionList; + ){ + ChildSa = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry); + Entry = Entry->ForwardLink; + RemoveEntryList (Entry->BackLink); + Ikev2ChildSaSessionFree (ChildSa); + } + + // + // Delete DhBuffer and Keys + // + if (IkeSaSession->IkeKeys != NULL) { + IkeKeys = IkeSaSession->IkeKeys; + DhBuffer = IkeKeys->DhBuffer; + + // + // Delete DhBuffer + // + Ikev2DhBufferFree (DhBuffer); + + // + // Delete Keys + // + if (IkeKeys->SkAiKey != NULL) { + FreePool (IkeKeys->SkAiKey); + } + if (IkeKeys->SkArKey != NULL) { + FreePool (IkeKeys->SkArKey); + } + if (IkeKeys->SkdKey != NULL) { + FreePool (IkeKeys->SkdKey); + } + if (IkeKeys->SkEiKey != NULL) { + FreePool (IkeKeys->SkEiKey); + } + if (IkeKeys->SkErKey != NULL) { + FreePool (IkeKeys->SkErKey); + } + if (IkeKeys->SkPiKey != NULL) { + FreePool (IkeKeys->SkPiKey); + } + if (IkeKeys->SkPrKey != NULL) { + FreePool (IkeKeys->SkPrKey); + } + FreePool (IkeKeys); + } + + if (IkeSaSession->SaData != NULL) { + FreePool (IkeSaSession->SaData); + } + + if (IkeSaSession->NiBlock != NULL) { + FreePool (IkeSaSession->NiBlock); + } + + if (IkeSaSession->NrBlock != NULL) { + FreePool (IkeSaSession->NrBlock); + } + + if (IkeSaSession->NCookie != NULL) { + FreePool (IkeSaSession->NCookie); + } + + if (IkeSaSession->InitPacket != NULL) { + FreePool (IkeSaSession->InitPacket); + } + + if (IkeSaSession->RespPacket != NULL) { + FreePool (IkeSaSession->RespPacket); + } + + FreePool (IkeSaSession); + + return ; +} + +/** + Increase the MessageID in IkeSaSession. + + @param[in] IkeSaSession Pointer to a specified IKEV2_SA_SESSION. + +**/ +VOID +Ikev2SaSessionIncreaseMessageId ( + IN IKEV2_SA_SESSION *IkeSaSession + ) +{ + if (IkeSaSession->MessageId < 0xffffffff) { + IkeSaSession->MessageId ++; + } else { + // + // TODO: Trigger Rekey process. + // + } +} + +/** + Allocate memory for IKEV2 Child SA Session. + + @param[in] UdpService Pointer to IKE_UDP_SERVICE. + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to this Child SA + Session. + + @retval Pointer of a new created IKEV2 Child SA Session or NULL. + +**/ +IKEV2_CHILD_SA_SESSION * +Ikev2ChildSaSessionAlloc ( + IN IKE_UDP_SERVICE *UdpService, + IN IKEV2_SA_SESSION *IkeSaSession + ) +{ + EFI_STATUS Status; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SESSION_COMMON *ChildSaCommon; + IKEV2_SESSION_COMMON *SaCommon; + + ChildSaSession = AllocateZeroPool (sizeof (IKEV2_CHILD_SA_SESSION)); + if (ChildSaSession == NULL) { + return NULL; + } + + // + // Initialize the fields of ChildSaSession and its SessionCommon. + // + ChildSaSession->Signature = IKEV2_CHILD_SA_SESSION_SIGNATURE; + ChildSaSession->IkeSaSession = IkeSaSession; + ChildSaSession->MessageId = IkeSaSession->MessageId; + ChildSaSession->LocalPeerSpi = IkeGenerateSpi (); + ChildSaCommon = &ChildSaSession->SessionCommon; + ChildSaCommon->UdpService = UdpService; + ChildSaCommon->Private = IkeSaSession->SessionCommon.Private; + ChildSaCommon->IkeSessionType = IkeSessionTypeChildSa; + ChildSaCommon->IkeVer = 2; + ChildSaCommon->AfterEncodePayload = Ikev2ChildSaAfterEncodePayload; + ChildSaCommon->BeforeDecodePayload = Ikev2ChildSaBeforeDecodePayload; + SaCommon = &ChildSaSession->IkeSaSession->SessionCommon; + + // + // Create a resend notfiy event for retry. + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ikev2ResendNotify, + ChildSaCommon, + &ChildSaCommon->TimeoutEvent + ); + if (EFI_ERROR (Status)) { + FreePool (ChildSaSession); + return NULL; + } + + CopyMem (&ChildSaCommon->LocalPeerIp, &SaCommon->LocalPeerIp, sizeof (EFI_IP_ADDRESS)); + CopyMem (&ChildSaCommon->RemotePeerIp, &SaCommon->RemotePeerIp, sizeof (EFI_IP_ADDRESS)); + + return ChildSaSession; +} + +/** + Register a established IKEv2 Child SA into IkeSaSession->ChildSaEstablishSessionList. + If the there is IKEV2_CHILD_SA_SESSION with same remote peer IP, remove the old one + then register the new one. + + @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION to be registered. + @param[in] Private Pointer to IPSEC_PRAVATE_DATA. + +**/ +VOID +Ikev2ChildSaSessionReg ( + IN IKEV2_CHILD_SA_SESSION *ChildSaSession, + IN IPSEC_PRIVATE_DATA *Private + ) +{ + IKEV2_SESSION_COMMON *SessionCommon; + IKEV2_CHILD_SA_SESSION *OldChildSaSession; + IKEV2_SA_SESSION *IkeSaSession; + IKEV2_SA_PARAMS *SaParams; + EFI_STATUS Status; + UINT64 Lifetime; + + // + // Keep the IKE SA exclusive. + // + SessionCommon = &ChildSaSession->SessionCommon; + IkeSaSession = ChildSaSession->IkeSaSession; + OldChildSaSession = Ikev2ChildSaSessionRemove ( + &IkeSaSession->ChildSaEstablishSessionList, + ChildSaSession->LocalPeerSpi, + IKEV2_ESTABLISHED_CHILDSA_LIST + ); + if (OldChildSaSession != NULL) { + // + // Free the old one. + // + Ikev2ChildSaSessionFree (OldChildSaSession); + } + + // + // Store the ready child SA into SAD. + // + Ikev2StoreSaData (ChildSaSession); + + // + // Cleanup the fields of SessionCommon for processing. + // + Ikev2SessionCommonRefresh (SessionCommon); + + // + // Insert the ready child SA session into established list. + // + Ikev2ChildSaSessionInsert (&IkeSaSession->ChildSaEstablishSessionList, ChildSaSession); + + // + // Create a Notify event for the IKE SA life time counting. + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ikev2LifetimeNotify, + SessionCommon, + &SessionCommon->TimeoutEvent + ); + if (EFI_ERROR(Status)){ + return ; + } + + // + // Start to count the lifetime of the IKE SA. + // + SaParams = SessionCommon->SaParams; + if (ChildSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime != 0){ + Lifetime = ChildSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime; + } else { + Lifetime = CHILD_SA_DEFAULT_LIFETIME; + } + + Status = gBS->SetTimer ( + SessionCommon->TimeoutEvent, + TimerRelative, + MultU64x32(Lifetime, 10000000) // ms->100ns + ); + if (EFI_ERROR(Status)){ + return ; + } + + DEBUG (( + DEBUG_INFO, + "\n------ChildSa established and start to count down %d seconds lifetime\n", + Lifetime + )); + + return ; +} + +/** + Find the ChildSaSession by it's MessagId. + + @param[in] SaSessionList Pointer to a ChildSaSession List. + @param[in] Mid The messageId used to search ChildSaSession. + + @return Pointer to IKEV2_CHILD_SA_SESSION or NULL. + +**/ +IKEV2_CHILD_SA_SESSION * +Ikev2ChildSaSessionLookupByMid ( + IN LIST_ENTRY *SaSessionList, + IN UINT32 Mid + ) +{ + LIST_ENTRY *Entry; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + + NET_LIST_FOR_EACH (Entry, SaSessionList) { + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry); + + if (ChildSaSession->MessageId == Mid) { + return ChildSaSession; + } + } + return NULL; +} + +/** + This function find the Child SA by the specified SPI. + + This functin find a ChildSA session by searching the ChildSaSessionlist of + the input IKEV2_SA_SESSION by specified MessageID. + + @param[in] SaSessionList Pointer to List to be searched. + @param[in] Spi Specified SPI. + + @return Pointer to IKEV2_CHILD_SA_SESSION or NULL. + +**/ +IKEV2_CHILD_SA_SESSION * +Ikev2ChildSaSessionLookupBySpi ( + IN LIST_ENTRY *SaSessionList, + IN UINT32 Spi + ) +{ + LIST_ENTRY *Entry; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + + NET_LIST_FOR_EACH (Entry, SaSessionList) { + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry); + + if (ChildSaSession->RemotePeerSpi == Spi || ChildSaSession->LocalPeerSpi == Spi) { + return ChildSaSession; + } + } + + return NULL; +} + +/** + Insert a Child SA Session into the specified ChildSa list. + + @param[in] SaSessionList Pointer to list to be inserted in. + @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION to be inserted. + +**/ +VOID +Ikev2ChildSaSessionInsert ( + IN LIST_ENTRY *SaSessionList, + IN IKEV2_CHILD_SA_SESSION *ChildSaSession + ) +{ + InsertTailList (SaSessionList, &ChildSaSession->ByIkeSa); +} + +/** + Remove the IKEV2_CHILD_SA_SESSION from IkeSaSessionList. + + @param[in] SaSessionList The SA Session List to be iterated. + @param[in] Spi Spi used to identified the IKEV2_CHILD_SA_SESSION. + @param[in] ListType The type of the List to indicate whether it is a + Established. + + @return The point to IKEV2_CHILD_SA_SESSION or NULL. + +**/ +IKEV2_CHILD_SA_SESSION * +Ikev2ChildSaSessionRemove ( + IN LIST_ENTRY *SaSessionList, + IN UINT32 Spi, + IN UINT8 ListType + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SaSessionList) { + + if (ListType == IKEV2_ESTABLISHED_CHILDSA_LIST || ListType == IKEV2_ESTABLISHING_CHILDSA_LIST) { + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry); + } else if (ListType == IKEV2_DELET_CHILDSA_LIST) { + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_DEL_SA (Entry); + } else { + return NULL; + } + + if (ChildSaSession->RemotePeerSpi == Spi || ChildSaSession->LocalPeerSpi == Spi) { + RemoveEntryList (Entry); + return ChildSaSession; + } + } + + return NULL; +} + +/** + Mark a specified Child SA Session as on deleting. + + @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION. + + @retval EFI_SUCCESS Operation is successful. + +**/ +EFI_STATUS +Ikev2ChildSaSessionOnDeleting ( + IN IKEV2_CHILD_SA_SESSION *ChildSaSession + ) +{ + return EFI_SUCCESS; +} + +/** + Free the memory located for the specified IKEV2_CHILD_SA_SESSION. + + @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION. + +**/ +VOID +Ikev2ChildSaSessionFree ( + IN IKEV2_CHILD_SA_SESSION *ChildSaSession + ) +{ + IKEV2_SESSION_COMMON *SessionCommon; + + SessionCommon = &ChildSaSession->SessionCommon; + if (ChildSaSession->SaData != NULL) { + FreePool (ChildSaSession->SaData); + } + + if (ChildSaSession->NiBlock != NULL) { + FreePool (ChildSaSession->NiBlock); + } + + if (ChildSaSession->NrBlock != NULL) { + FreePool (ChildSaSession->NrBlock); + } + + if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey != NULL) { + FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey); + } + + if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey != NULL) { + FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey); + } + + if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey != NULL) { + FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey); + } + + if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey != NULL) { + FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey); + } + + // + // Delete DhBuffer + // + Ikev2DhBufferFree (ChildSaSession->DhBuffer); + + // + // Delete SpdSelector + // + if (ChildSaSession->SpdSelector != NULL) { + if (ChildSaSession->SpdSelector->LocalAddress != NULL) { + FreePool (ChildSaSession->SpdSelector->LocalAddress); + } + if (ChildSaSession->SpdSelector->RemoteAddress != NULL) { + FreePool (ChildSaSession->SpdSelector->RemoteAddress); + } + FreePool (ChildSaSession->SpdSelector); + } + Ikev2SaSessionCommonFree (SessionCommon); + FreePool (ChildSaSession); + + return ; +} + +/** + Delete the specified established Child SA. + + This function delete the Child SA directly and don't send the Information Packet to + remote peer. + + @param[in] IkeSaSession Pointer to a IKE SA Session used to be searched for. + @param[in] Spi SPI used to find the Child SA. + + @retval EFI_NOT_FOUND Pointer of IKE SA Session is NULL. + @retval EFI_NOT_FOUND There is no specified Child SA related with the input + SPI under this IKE SA Session. + @retval EFI_SUCCESS Delete the Child SA successfully. + +**/ +EFI_STATUS +Ikev2ChildSaSilentDelete ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN UINT32 Spi + ) +{ + EFI_STATUS Status; + EFI_IPSEC_CONFIG_SELECTOR *Selector; + UINTN SelectorSize; + BOOLEAN IsLocalFound; + BOOLEAN IsRemoteFound; + UINT32 LocalSpi; + UINT32 RemoteSpi; + IKEV2_CHILD_SA_SESSION *ChildSession; + EFI_IPSEC_CONFIG_SELECTOR *LocalSelector; + EFI_IPSEC_CONFIG_SELECTOR *RemoteSelector; + IKE_UDP_SERVICE *UdpService; + IPSEC_PRIVATE_DATA *Private; + + if (IkeSaSession == NULL) { + return EFI_NOT_FOUND; + } + + IsLocalFound = FALSE; + IsRemoteFound = FALSE; + ChildSession = NULL; + LocalSelector = NULL; + RemoteSelector = NULL; + UdpService = IkeSaSession->SessionCommon.UdpService; + + Private = (UdpService->IpVersion == IP_VERSION_4) ? + IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) : + IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead); + + // + // Remove the Established SA from ChildSaEstablishlist. + // + ChildSession = Ikev2ChildSaSessionRemove( + &(IkeSaSession->ChildSaEstablishSessionList), + Spi, + IKEV2_ESTABLISHED_CHILDSA_LIST + ); + if (ChildSession == NULL) { + return EFI_NOT_FOUND; + } + + LocalSpi = ChildSession->LocalPeerSpi; + RemoteSpi = ChildSession->RemotePeerSpi; + + SelectorSize = sizeof (EFI_IPSEC_CONFIG_SELECTOR); + Selector = AllocateZeroPool (SelectorSize); + ASSERT (Selector != NULL); + + + + while (1) { + Status = EfiIpSecConfigGetNextSelector ( + &Private->IpSecConfig, + IPsecConfigDataTypeSad, + &SelectorSize, + Selector + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + FreePool (Selector); + + Selector = AllocateZeroPool (SelectorSize); + Status = EfiIpSecConfigGetNextSelector ( + &Private->IpSecConfig, + IPsecConfigDataTypeSad, + &SelectorSize, + Selector + ); + } + + if (EFI_ERROR (Status)) { + break; + } + + if (Selector->SaId.Spi == RemoteSpi) { + // + // SPI is unique. There is only one SAD whose SPI is + // same with RemoteSpi. + // + IsRemoteFound = TRUE; + RemoteSelector = AllocateZeroPool (SelectorSize); + CopyMem (RemoteSelector, Selector, SelectorSize); + } + + if (Selector->SaId.Spi == LocalSpi) { + // + // SPI is unique. There is only one SAD whose SPI is + // same with LocalSpi. + // + IsLocalFound = TRUE; + LocalSelector = AllocateZeroPool (SelectorSize); + CopyMem (LocalSelector, Selector, SelectorSize); + } + } + // + // Delete SA from the Variable. + // + if (IsLocalFound) { + Status = EfiIpSecConfigSetData ( + &Private->IpSecConfig, + IPsecConfigDataTypeSad, + LocalSelector, + NULL, + NULL + ); + } + + if (IsRemoteFound) { + Status = EfiIpSecConfigSetData ( + &Private->IpSecConfig, + IPsecConfigDataTypeSad, + RemoteSelector, + NULL, + NULL + ); + + } + + DEBUG ( + (DEBUG_INFO, + "\n------IKEV2 deleted ChildSa(local spi, remote spi):(0x%x, 0x%x)------\n", + LocalSpi, + RemoteSpi) + ); + Ikev2ChildSaSessionFree (ChildSession); + + if (RemoteSelector != NULL) { + FreePool (RemoteSelector); + } + + if (LocalSelector != NULL) { + FreePool (LocalSelector); + } + + if (Selector != NULL) { + FreePool (Selector); + } + + return Status; +} + +/** + Free the specified DhBuffer. + + @param[in] DhBuffer Pointer to IKEV2_DH_BUFFER to be freed. + +**/ +VOID +Ikev2DhBufferFree ( + IKEV2_DH_BUFFER *DhBuffer +) +{ + if (DhBuffer != NULL) { + if (DhBuffer->GxBuffer != NULL) { + FreePool (DhBuffer->GxBuffer); + } + if (DhBuffer->GyBuffer != NULL) { + FreePool (DhBuffer->GyBuffer); + } + if (DhBuffer->GxyBuffer != NULL) { + FreePool (DhBuffer->GxyBuffer); + } + if (DhBuffer->DhContext != NULL) { + IpSecCryptoIoFreeDh (&DhBuffer->DhContext); + } + FreePool (DhBuffer); + } +} + +/** + This function is to parse a request IKE packet and return its request type. + The request type is one of IKE CHILD SA creation, IKE SA rekeying and + IKE CHILD SA rekeying. + + @param[in] IkePacket IKE packet to be prased. + + return the type of the IKE packet. + +**/ +IKEV2_CREATE_CHILD_REQUEST_TYPE +Ikev2ChildExchangeRequestType( + IN IKE_PACKET *IkePacket + ) +{ + BOOLEAN Flag; + LIST_ENTRY *Entry; + IKE_PAYLOAD *IkePayload; + + Flag = FALSE; + + NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) { + IkePayload = IKE_PAYLOAD_BY_PACKET (Entry); + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) { + // + // Packet with Ts Payload means it is for either CHILD_SA_CREATE or CHILD_SA_REKEY. + // + Flag = TRUE; + } + if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NOTIFY) { + if (((IKEV2_NOTIFY*)IkePayload)->MessageType == IKEV2_NOTIFICATION_REKEY_SA) { + // + // If notify payload with REKEY_SA message type, the IkePacket is for + // rekeying Child SA. + // + return IkeRequestTypeRekeyChildSa; + } + } + }; + + if (!Flag){ + // + // The Create Child Exchange is for IKE SA rekeying. + // + return IkeRequestTypeRekeyIkeSa; + } else { + // + // If the Notify payloaad with transport mode message type, the IkePacket is + // for create Child SA. + // + return IkeRequestTypeCreateChildSa; + } +} + +/** + Associate a SPD selector to the Child SA Session. + + This function is called when the Child SA is not the first child SA of its + IKE SA. It associate a SPD to this Child SA. + + @param[in, out] ChildSaSession Pointer to the Child SA Session to be associated to + a SPD selector. + + @retval EFI_SUCCESS Associate one SPD selector to this Child SA Session successfully. + @retval EFI_NOT_FOUND Can't find the related SPD selector. + +**/ +EFI_STATUS +Ikev2ChildSaAssociateSpdEntry ( + IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession + ) +{ + IpSecVisitConfigData (IPsecConfigDataTypeSpd, Ikev2MatchSpdEntry, ChildSaSession); + if (ChildSaSession->Spd != NULL) { + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } +} + + +/** + This function finds the SPI from Create Child SA Exchange Packet. + + @param[in] IkePacket Pointer to IKE_PACKET to be searched. + + @retval SPI number or 0 if it is not supported. + +**/ +UINT32 +Ikev2ChildExchangeRekeySpi ( + IN IKE_PACKET *IkePacket + ) +{ + // + // Not support yet. + // + return 0; +} + +/** + Validate the IKE header of received IKE packet. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to this IKE packet. + @param[in] IkeHdr Pointer to IKE header of received IKE packet. + + @retval TRUE If the IKE header is valid. + @retval FALSE If the IKE header is invalid. + +**/ +BOOLEAN +Ikev2ValidateHeader ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IKE_HEADER *IkeHdr + ) +{ + + IKEV2_SESSION_STATE State; + + State = IkeSaSession->SessionCommon.State; + if (State == IkeStateInit) { + // + // For the IKE Initial Exchange, the MessagId should be zero. + // + if (IkeHdr->MessageId != 0) { + return FALSE; + } + } else { + if (State == IkeStateAuth) { + if (IkeHdr->MessageId != 1) { + return FALSE; + } + } + if (IkeHdr->InitiatorCookie != IkeSaSession->InitiatorCookie || + IkeHdr->ResponderCookie != IkeSaSession->ResponderCookie + ) { + // + // TODO: send notification INVALID-COOKIE + // + return FALSE; + } + } + + // + // Information Exchagne and Create Child Exchange can be started from each part. + // + if (IkeHdr->ExchangeType != IKEV2_EXCHANGE_TYPE_INFO && + IkeHdr->ExchangeType != IKEV2_EXCHANGE_TYPE_CREATE_CHILD + ) { + if (IkeSaSession->SessionCommon.IsInitiator) { + if (IkeHdr->InitiatorCookie != IkeSaSession->InitiatorCookie) { + // + // TODO: send notification INVALID-COOKIE + // + return FALSE; + } + if (IkeHdr->Flags != IKE_HEADER_FLAGS_RESPOND) { + return FALSE; + } + } else { + if (IkeHdr->Flags != IKE_HEADER_FLAGS_INIT) { + return FALSE; + } + } + } + + return TRUE; +} + +/** + Create and intialize IKEV2_SA_DATA for speicifed IKEV2_SESSION_COMMON. + + This function will be only called by the initiator. The responder's IKEV2_SA_DATA + will be generated during parsed the initiator packet. + + @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to. + + @retval a Pointer to a new IKEV2_SA_DATA or NULL. + +**/ +IKEV2_SA_DATA * +Ikev2InitializeSaData ( + IN IKEV2_SESSION_COMMON *SessionCommon + ) +{ + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SA_DATA *SaData; + IKEV2_PROPOSAL_DATA *ProposalData; + IKEV2_TRANSFORM_DATA *TransformData; + IKE_SA_ATTRIBUTE *Attribute; + + ASSERT (SessionCommon != NULL); + // + // TODO: Remove the hard code of the support Alogrithm. Those data should be + // get from the SPD/PAD data. + // + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + SaData = AllocateZeroPool ( + sizeof (IKEV2_SA_DATA) + + sizeof (IKEV2_PROPOSAL_DATA) * 2 + + sizeof (IKEV2_TRANSFORM_DATA) * 4 * 2 + ); + } else { + SaData = AllocateZeroPool ( + sizeof (IKEV2_SA_DATA) + + sizeof (IKEV2_PROPOSAL_DATA) * 2 + + sizeof (IKEV2_TRANSFORM_DATA) * 3 * 2 + ); + } + if (SaData == NULL) { + return NULL; + } + + // + // First proposal payload: 3DES + SHA1 + DH + // + SaData->NumProposals = 2; + ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1); + ProposalData->ProposalIndex = 1; + + // + // If SA data for IKE_SA_INIT exchage, contains 4 transforms. If SA data for + // IKE_AUTH exchange contains 3 transforms. + // + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + ProposalData->NumTransforms = 4; + } else { + ProposalData->NumTransforms = 3; + } + + + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + ProposalData->ProtocolId = IPSEC_PROTO_ISAKMP; + } else { + ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon); + ProposalData->ProtocolId = IPSEC_PROTO_IPSEC_ESP; + ProposalData->Spi = AllocateZeroPool (sizeof (ChildSaSession->LocalPeerSpi)); + ASSERT (ProposalData->Spi != NULL); + CopyMem ( + ProposalData->Spi, + &ChildSaSession->LocalPeerSpi, + sizeof(ChildSaSession->LocalPeerSpi) + ); + } + + // + // Set transform attribute for Encryption Algorithm - 3DES + // + TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1); + TransformData->TransformIndex = 0; + TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ENCR; + TransformData->TransformId = IKEV2_TRANSFORM_ID_ENCR_3DES; + + // + // Set transform attribute for Integrity Algorithm - SHA1_96 + // + TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1); + TransformData->TransformIndex = 1; + TransformData->TransformType = IKEV2_TRANSFORM_TYPE_INTEG; + TransformData->TransformId = IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96; + + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + // + // Set transform attribute for Pseduo-Random Function - HAMC_SHA1 + // + TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1); + TransformData->TransformIndex = 2; + TransformData->TransformType = IKEV2_TRANSFORM_TYPE_PRF; + TransformData->TransformId = IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1; + } + + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + // + // Set transform attribute for DH Group - DH 1024 + // + TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1); + TransformData->TransformIndex = 3; + TransformData->TransformType = IKEV2_TRANSFORM_TYPE_DH; + TransformData->TransformId = IKEV2_TRANSFORM_ID_DH_1024MODP; + } else { + // + // Transform type for Extended Sequence Numbers. Currently not support Extended + // Sequence Number. + // + TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1); + TransformData->TransformIndex = 2; + TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ESN; + TransformData->TransformId = 0; + } + + // + // Second proposal payload: 3DES + SHA1 + DH + // + ProposalData = (IKEV2_PROPOSAL_DATA *) (TransformData + 1); + ProposalData->ProposalIndex = 2; + + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + ProposalData->ProtocolId = IPSEC_PROTO_ISAKMP; + ProposalData->NumTransforms = 4; + } else { + + ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon); + ProposalData->ProtocolId = IPSEC_PROTO_IPSEC_ESP; + ProposalData->NumTransforms = 3; + ProposalData->Spi = AllocateZeroPool (sizeof (ChildSaSession->LocalPeerSpi)); + ASSERT (ProposalData->Spi != NULL); + CopyMem ( + ProposalData->Spi, + &ChildSaSession->LocalPeerSpi, + sizeof(ChildSaSession->LocalPeerSpi) + ); + } + + // + // Set transform attribute for Encryption Algorithm - AES-CBC + // + TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1); + TransformData->TransformIndex = 0; + TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ENCR; + TransformData->TransformId = IKEV2_TRANSFORM_ID_ENCR_AES_CBC; + Attribute = &TransformData->Attribute; + Attribute->AttrType = IKEV2_ATTRIBUTE_TYPE_KEYLEN; + Attribute->Attr.AttrLength = (UINT16) (8 * IpSecGetEncryptKeyLength (IKEV2_TRANSFORM_ID_ENCR_AES_CBC)); + + // + // Set transform attribute for Integrity Algorithm - SHA1_96 + // + TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1); + TransformData->TransformIndex = 1; + TransformData->TransformType = IKEV2_TRANSFORM_TYPE_INTEG; + TransformData->TransformId = IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96; + + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + // + // Set transform attribute for Pseduo-Random Function - HAMC_SHA1 + // + TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1); + TransformData->TransformIndex = 2; + TransformData->TransformType = IKEV2_TRANSFORM_TYPE_PRF; + TransformData->TransformId = IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1; + } + + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + // + // Set transform attrbiute for DH Group - DH-1024 + // + TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1); + TransformData->TransformIndex = 3; + TransformData->TransformType = IKEV2_TRANSFORM_TYPE_DH; + TransformData->TransformId = IKEV2_TRANSFORM_ID_DH_1024MODP; + } else { + // + // Transform type for Extended Sequence Numbers. Currently not support Extended + // Sequence Number. + // + TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1); + TransformData->TransformIndex = 2; + TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ESN; + TransformData->TransformId = 0; + } + + return SaData; +} + +/** + Store the SA into SAD. + + @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION. + +**/ +VOID +Ikev2StoreSaData ( + IN IKEV2_CHILD_SA_SESSION *ChildSaSession + ) +{ + EFI_STATUS Status; + EFI_IPSEC_SA_ID SaId; + EFI_IPSEC_SA_DATA2 SaData; + IKEV2_SESSION_COMMON *SessionCommon; + IPSEC_PRIVATE_DATA *Private; + UINT32 TempAddressCount; + EFI_IP_ADDRESS_INFO *TempAddressInfo; + + SessionCommon = &ChildSaSession->SessionCommon; + Private = SessionCommon->Private; + + ZeroMem (&SaId, sizeof (EFI_IPSEC_SA_ID)); + ZeroMem (&SaData, sizeof (EFI_IPSEC_SA_DATA2)); + + // + // Create a SpdSelector. In this implementation, one SPD represents + // 2 direction traffic, so in here, there needs to reverse the local address + // and remote address for Remote Peer's SA, then reverse again for the locate + // SA. + // + TempAddressCount = ChildSaSession->SpdSelector->LocalAddressCount; + TempAddressInfo = ChildSaSession->SpdSelector->LocalAddress; + + ChildSaSession->SpdSelector->LocalAddressCount = ChildSaSession->SpdSelector->RemoteAddressCount; + ChildSaSession->SpdSelector->LocalAddress = ChildSaSession->SpdSelector->RemoteAddress; + + ChildSaSession->SpdSelector->RemoteAddress = TempAddressInfo; + ChildSaSession->SpdSelector->RemoteAddressCount= TempAddressCount; + + // + // Set the SaId and SaData. + // + SaId.Spi = ChildSaSession->LocalPeerSpi; + SaId.Proto = EfiIPsecESP; + SaData.AntiReplayWindows = 16; + SaData.SNCount = 0; + SaData.Mode = ChildSaSession->Spd->Data->ProcessingPolicy->Mode; + + // + // If it is tunnel mode, should add the TunnelDest and TunnelSource for SaData. + // + if (SaData.Mode == EfiIPsecTunnel) { + CopyMem ( + &SaData.TunnelSourceAddress, + &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress, + sizeof (EFI_IP_ADDRESS) + ); + CopyMem ( + &SaData.TunnelDestinationAddress, + &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->LocalTunnelAddress, + sizeof (EFI_IP_ADDRESS) + ); + } + + CopyMem (&SaId.DestAddress, &ChildSaSession->SessionCommon.LocalPeerIp, sizeof (EFI_IP_ADDRESS)); + CopyMem (&SaData.AlgoInfo, &ChildSaSession->ChildKeymats.LocalPeerInfo, sizeof (EFI_IPSEC_ALGO_INFO)); + SaData.SpdSelector = ChildSaSession->SpdSelector; + + // + // Store the remote SA into SAD. + // + Status = EfiIpSecConfigSetData ( + &Private->IpSecConfig, + IPsecConfigDataTypeSad, + (EFI_IPSEC_CONFIG_SELECTOR *) &SaId, + &SaData, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Store the local SA into SAD. + // + ChildSaSession->SpdSelector->RemoteAddressCount = ChildSaSession->SpdSelector->LocalAddressCount; + ChildSaSession->SpdSelector->RemoteAddress = ChildSaSession->SpdSelector->LocalAddress; + + ChildSaSession->SpdSelector->LocalAddress = TempAddressInfo; + ChildSaSession->SpdSelector->LocalAddressCount = TempAddressCount; + + SaId.Spi = ChildSaSession->RemotePeerSpi; + + CopyMem (&SaId.DestAddress, &ChildSaSession->SessionCommon.RemotePeerIp, sizeof (EFI_IP_ADDRESS)); + CopyMem (&SaData.AlgoInfo, &ChildSaSession->ChildKeymats.RemotePeerInfo, sizeof (EFI_IPSEC_ALGO_INFO)); + SaData.SpdSelector = ChildSaSession->SpdSelector; + + // + // If it is tunnel mode, should add the TunnelDest and TunnelSource for SaData. + // + if (SaData.Mode == EfiIPsecTunnel) { + CopyMem ( + &SaData.TunnelSourceAddress, + &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->LocalTunnelAddress, + sizeof (EFI_IP_ADDRESS) + ); + CopyMem ( + &SaData.TunnelDestinationAddress, + &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress, + sizeof (EFI_IP_ADDRESS) + ); + } + + Status = EfiIpSecConfigSetData ( + &Private->IpSecConfig, + IPsecConfigDataTypeSad, + (EFI_IPSEC_CONFIG_SELECTOR *) &SaId, + &SaData, + NULL + ); + + ASSERT_EFI_ERROR (Status); +} + +/** + Call back function of the IKE life time is over. + + This function will mark the related IKE SA Session as deleting and trigger a + Information negotiation. + + @param[in] Event The signaled Event. + @param[in] Context Pointer to data passed by caller. + +**/ +VOID +EFIAPI +Ikev2LifetimeNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + IKEV2_SA_SESSION *IkeSaSession; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SESSION_COMMON *SessionCommon; + + ASSERT (Context != NULL); + SessionCommon = (IKEV2_SESSION_COMMON *) Context; + + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon); + DEBUG (( + DEBUG_INFO, + "\n---IkeSa Lifetime is out(cookie_i, cookie_r):(0x%lx, 0x%lx)---\n", + IkeSaSession->InitiatorCookie, + IkeSaSession->ResponderCookie + )); + + // + // Change the IKE SA Session's State to IKE_STATE_SA_DELETING. + // + IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateSaDeleting); + IkeSaSession->SessionCommon.State = IkeStateSaDeleting; + + } else { + ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon); + IkeSaSession = ChildSaSession->IkeSaSession; + + // + // Link the timeout child SA to the DeleteSaList. + // + InsertTailList (&IkeSaSession->DeleteSaList, &ChildSaSession->ByDelete); + + // + // Change the Child SA Session's State to IKE_STATE_SA_DELETING. + // + DEBUG (( + DEBUG_INFO, + "\n------ChildSa Lifetime is out(SPI):(0x%x)------\n", + ChildSaSession->LocalPeerSpi + )); + } + + // + // TODO: Send the delete info packet or delete silently + // + mIkev2Exchange.NegotiateInfo ((UINT8 *) IkeSaSession, NULL); +} + +/** + This function will be called if the TimeOut Event is signaled. + + @param[in] Event The signaled Event. + @param[in] Context The data passed by caller. + +**/ +VOID +EFIAPI +Ikev2ResendNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + IPSEC_PRIVATE_DATA *Private; + IKEV2_SA_SESSION *IkeSaSession; + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SESSION_COMMON *SessionCommon; + LIST_ENTRY *ChildSaEntry; + UINT8 Value; + EFI_STATUS Status; + + ASSERT (Context != NULL); + IkeSaSession = NULL; + ChildSaSession = NULL; + SessionCommon = (IKEV2_SESSION_COMMON *) Context; + Private = SessionCommon->Private; + + // + // Remove the SA session from the processing list if exceed the max retry. + // + if (SessionCommon->RetryCount > IKE_MAX_RETRY) { + if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) { + IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon); + if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting) { + + // + // If the IkeSaSession is initiator, delete all its Child SAs before removing IKE SA. + // If the IkesaSession is responder, all ChildSa has been remove in Ikev2HandleInfo(); + // + for (ChildSaEntry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink; + ChildSaEntry != &IkeSaSession->ChildSaEstablishSessionList; + ) { + ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (ChildSaEntry); + // + // Move to next ChildSa Entry. + // + ChildSaEntry = ChildSaEntry->ForwardLink; + // + // Delete LocalSpi & RemoteSpi and remove the ChildSaSession from the + // EstablishedChildSaList. + // + Ikev2ChildSaSilentDelete (IkeSaSession, ChildSaSession->LocalPeerSpi); + } + + // + // If the IKE SA Delete Payload wasn't sent out successfully, Delete it from the EstablishedList. + // + Ikev2SaSessionRemove (&Private->Ikev2EstablishedList, &SessionCommon->RemotePeerIp); + + if (Private != NULL && Private->IsIPsecDisabling) { + // + // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in + // IPsec status variable. + // + if (IsListEmpty (&Private->Ikev1EstablishedList) && IsListEmpty (&Private->Ikev2EstablishedList)) { + Value = IPSEC_STATUS_DISABLED; + Status = gRT->SetVariable ( + IPSECCONFIG_STATUS_NAME, + &gEfiIpSecConfigProtocolGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (Value), + &Value + ); + if (!EFI_ERROR (Status)) { + // + // Set the Disabled Flag in Private data. + // + Private->IpSec.DisabledFlag = TRUE; + Private->IsIPsecDisabling = FALSE; + } + } + } + } else { + Ikev2SaSessionRemove (&Private->Ikev2SessionList, &SessionCommon->RemotePeerIp); + } + Ikev2SaSessionFree (IkeSaSession); + + } else { + + // + // If the packet sent by Child SA. + // + ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon); + IkeSaSession = ChildSaSession->IkeSaSession; + if (ChildSaSession->SessionCommon.State == IkeStateSaDeleting) { + + // + // Established Child SA should be remove from the SAD entry and + // DeleteList. The function of Ikev2DeleteChildSaSilent() will remove + // the childSA from the IkeSaSession->ChildSaEstablishedList. So there + // is no need to remove it here. + // + Ikev2ChildSaSilentDelete (IkeSaSession, ChildSaSession->LocalPeerSpi); + Ikev2ChildSaSessionRemove ( + &IkeSaSession->DeleteSaList, + ChildSaSession->LocalPeerSpi, + IKEV2_DELET_CHILDSA_LIST + ); + } else { + Ikev2ChildSaSessionRemove ( + &IkeSaSession->ChildSaSessionList, + ChildSaSession->LocalPeerSpi, + IKEV2_ESTABLISHING_CHILDSA_LIST + ); + } + + Ikev2ChildSaSessionFree (ChildSaSession); + } + return ; + } + + // + // Increase the retry count. + // + SessionCommon->RetryCount++; + DEBUG ((DEBUG_INFO, ">>>Resending the last packet ...\n")); + + // + // Resend the last packet. + // + Ikev2SendIkePacket ( + SessionCommon->UdpService, + (UINT8*)SessionCommon, + SessionCommon->LastSentPacket, + 0 + ); +} + +/** + Copy ChildSaSession->Spd->Selector to ChildSaSession->SpdSelector. + + ChildSaSession->SpdSelector stores the real Spdselector for its SA. Sometime, + the SpdSelector in ChildSaSession is more accurated or the scope is smaller + than the one in ChildSaSession->Spd, especially for the tunnel mode. + + @param[in, out] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION related to. + +**/ +VOID +Ikev2ChildSaSessionSpdSelectorCreate ( + IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession + ) +{ + if (ChildSaSession->Spd != NULL && ChildSaSession->Spd->Selector != NULL) { + if (ChildSaSession->SpdSelector == NULL) { + ChildSaSession->SpdSelector = AllocateZeroPool (sizeof (EFI_IPSEC_SPD_SELECTOR)); + ASSERT (ChildSaSession->SpdSelector != NULL); + } + CopyMem ( + ChildSaSession->SpdSelector, + ChildSaSession->Spd->Selector, + sizeof (EFI_IPSEC_SPD_SELECTOR) + ); + ChildSaSession->SpdSelector->RemoteAddress = AllocateCopyPool ( + ChildSaSession->Spd->Selector->RemoteAddressCount * + sizeof (EFI_IP_ADDRESS_INFO), + ChildSaSession->Spd->Selector->RemoteAddress + ); + ChildSaSession->SpdSelector->LocalAddress = AllocateCopyPool ( + ChildSaSession->Spd->Selector->LocalAddressCount * + sizeof (EFI_IP_ADDRESS_INFO), + ChildSaSession->Spd->Selector->LocalAddress + ); + + ASSERT (ChildSaSession->SpdSelector->LocalAddress != NULL); + ASSERT (ChildSaSession->SpdSelector->RemoteAddress != NULL); + + ChildSaSession->SpdSelector->RemoteAddressCount = ChildSaSession->Spd->Selector->RemoteAddressCount; + ChildSaSession->SpdSelector->LocalAddressCount = ChildSaSession->Spd->Selector->LocalAddressCount; + } +} + +/** + Generate a ChildSa Session and insert it into related IkeSaSession. + + @param[in] IkeSaSession Pointer to related IKEV2_SA_SESSION. + @param[in] UdpService Pointer to related IKE_UDP_SERVICE. + + @return pointer of IKEV2_CHILD_SA_SESSION. + +**/ +IKEV2_CHILD_SA_SESSION * +Ikev2ChildSaSessionCreate ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IKE_UDP_SERVICE *UdpService + ) +{ + IKEV2_CHILD_SA_SESSION *ChildSaSession; + IKEV2_SESSION_COMMON *ChildSaCommon; + + // + // Create a new ChildSaSession.Insert it into processing list and initiate the common parameters. + // + ChildSaSession = Ikev2ChildSaSessionAlloc (UdpService, IkeSaSession); + ASSERT (ChildSaSession != NULL); + + // + // Set the specific parameters. + // + ChildSaSession->Spd = IkeSaSession->Spd; + ChildSaCommon = &ChildSaSession->SessionCommon; + ChildSaCommon->IsInitiator = IkeSaSession->SessionCommon.IsInitiator; + if (IkeSaSession->SessionCommon.State == IkeStateAuth) { + ChildSaCommon->State = IkeStateAuth; + IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateAuth); + } else { + ChildSaCommon->State = IkeStateCreateChild; + IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateCreateChild); + } + + // + // If SPD->Selector is not NULL, copy it to the ChildSaSession->SpdSelector. + // The ChildSaSession->SpdSelector might be changed after the traffic selector + // negoniation and it will be copied into the SAData after ChildSA established. + // + Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession); + + // + // Copy first NiBlock and NrBlock to ChildSa Session + // + ChildSaSession->NiBlock = AllocateZeroPool (IkeSaSession->NiBlkSize); + ASSERT (ChildSaSession->NiBlock != NULL); + ChildSaSession->NiBlkSize = IkeSaSession->NiBlkSize; + CopyMem (ChildSaSession->NiBlock, IkeSaSession->NiBlock, IkeSaSession->NiBlkSize); + + ChildSaSession->NrBlock = AllocateZeroPool (IkeSaSession->NrBlkSize); + ASSERT (ChildSaSession->NrBlock != NULL); + ChildSaSession->NrBlkSize = IkeSaSession->NrBlkSize; + CopyMem (ChildSaSession->NrBlock, IkeSaSession->NrBlock, IkeSaSession->NrBlkSize); + + // + // Only if the Create Child SA is called for the IKE_INIT Exchange and + // IkeSaSession is initiator (Only Initiator's SPD is not NULL), Set the + // Traffic Selectors related information here. + // + if (IkeSaSession->SessionCommon.State == IkeStateAuth && IkeSaSession->Spd != NULL) { + ChildSaSession->ProtoId = IkeSaSession->Spd->Selector->NextLayerProtocol; + ChildSaSession->LocalPort = IkeSaSession->Spd->Selector->LocalPort; + ChildSaSession->RemotePort = IkeSaSession->Spd->Selector->RemotePort; + } + + // + // Insert the new ChildSaSession into processing child SA list. + // + Ikev2ChildSaSessionInsert (&IkeSaSession->ChildSaSessionList, ChildSaSession); + return ChildSaSession; +} + +/** + Check if the SPD is related to the input Child SA Session. + + This function is the subfunction of Ikev1AssociateSpdEntry(). It is the call + back function of IpSecVisitConfigData(). + + + @param[in] Type Type of the input Config Selector. + @param[in] Selector Pointer to the Configure Selector to be checked. + @param[in] Data Pointer to the Configure Selector's Data passed + from the caller. + @param[in] SelectorSize The buffer size of Selector. + @param[in] DataSize The buffer size of the Data. + @param[in] Context The data passed from the caller. It is a Child + SA Session in this context. + + @retval EFI_SUCCESS The SPD Selector is not related to the Child SA Session. + @retval EFI_ABORTED The SPD Selector is related to the Child SA session and + set the ChildSaSession->Spd to point to this SPD Selector. + +**/ +EFI_STATUS +Ikev2MatchSpdEntry ( + IN EFI_IPSEC_CONFIG_DATA_TYPE Type, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN UINTN SelectorSize, + IN UINTN DataSize, + IN VOID *Context + ) +{ + IKEV2_CHILD_SA_SESSION *ChildSaSession; + EFI_IPSEC_SPD_SELECTOR *SpdSelector; + EFI_IPSEC_SPD_DATA *SpdData; + BOOLEAN IsMatch; + UINT8 IpVersion; + + ASSERT (Type == IPsecConfigDataTypeSpd); + SpdData = (EFI_IPSEC_SPD_DATA *) Data; + // + // Bypass all non-protect SPD entry first + // + if (SpdData->Action != EfiIPsecActionProtect) { + return EFI_SUCCESS; + } + + ChildSaSession = (IKEV2_CHILD_SA_SESSION *) Context; + IpVersion = ChildSaSession->SessionCommon.UdpService->IpVersion; + SpdSelector = (EFI_IPSEC_SPD_SELECTOR *) Selector; + IsMatch = TRUE; + + if (SpdSelector->NextLayerProtocol == EFI_IP_PROTO_UDP && + SpdSelector->LocalPort == IKE_DEFAULT_PORT && + SpdSelector->LocalPortRange == 0 && + SpdSelector->RemotePort == IKE_DEFAULT_PORT && + SpdSelector->RemotePortRange == 0 + ) { + // + // TODO: Skip IKE Policy here or set a SPD entry? + // + return EFI_SUCCESS; + } + + if (SpdSelector->NextLayerProtocol != EFI_IPSEC_ANY_PROTOCOL && + SpdSelector->NextLayerProtocol != ChildSaSession->ProtoId + ) { + IsMatch = FALSE; + } + + if (SpdSelector->LocalPort != EFI_IPSEC_ANY_PORT && SpdSelector->LocalPort != ChildSaSession->LocalPort) { + IsMatch = FALSE; + } + + if (SpdSelector->RemotePort != EFI_IPSEC_ANY_PORT && SpdSelector->RemotePort != ChildSaSession->RemotePort) { + IsMatch = FALSE; + } + + IsMatch = (BOOLEAN) (IsMatch && + IpSecMatchIpAddress ( + IpVersion, + &ChildSaSession->SessionCommon.LocalPeerIp, + SpdSelector->LocalAddress, + SpdSelector->LocalAddressCount + )); + + IsMatch = (BOOLEAN) (IsMatch && + IpSecMatchIpAddress ( + IpVersion, + &ChildSaSession->SessionCommon.RemotePeerIp, + SpdSelector->RemoteAddress, + SpdSelector->RemoteAddressCount + )); + + if (IsMatch) { + ChildSaSession->Spd = IkeSearchSpdEntry (SpdSelector); + return EFI_ABORTED; + } else { + return EFI_SUCCESS; + } +} + +/** + Check if the Algorithm ID is supported. + + @param[in] AlgorithmId The specified Algorithm ID. + @param[in] Type The type used to indicate the Algorithm is for Encrypt or + Authentication. + + @retval TRUE If the Algorithm ID is supported. + @retval FALSE If the Algorithm ID is not supported. + +**/ +BOOLEAN +Ikev2IsSupportAlg ( + IN UINT16 AlgorithmId, + IN UINT8 Type + ) +{ + UINT8 Index; + switch (Type) { + case IKE_ENCRYPT_TYPE : + for (Index = 0; Index < IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM; Index++) { + if (mIkev2EncryptAlgorithmList[Index] == AlgorithmId) { + return TRUE; + } + } + break; + + case IKE_AUTH_TYPE : + for (Index = 0; Index < IKEV2_SUPPORT_AUTH_ALGORITHM_NUM; Index++) { + if (mIkev2AuthAlgorithmList[Index] == AlgorithmId) { + return TRUE; + } + } + break; + + case IKE_DH_TYPE : + for (Index = 0; Index < IKEV2_SUPPORT_DH_ALGORITHM_NUM; Index++) { + if (mIkev2DhGroupAlgorithmList[Index] == AlgorithmId) { + return TRUE; + } + } + break; + + case IKE_PRF_TYPE : + for (Index = 0; Index < IKEV2_SUPPORT_PRF_ALGORITHM_NUM; Index++) { + if (mIkev2PrfAlgorithmList[Index] == AlgorithmId) { + return TRUE; + } + } + } + return FALSE; +} + +/** + Get the preferred algorithm types from ProposalData. + + @param[in] ProposalData Pointer to related IKEV2_PROPOSAL_DATA. + @param[out] PreferEncryptAlgorithm Output of preferred encrypt algorithm. + @param[out] PreferIntegrityAlgorithm Output of preferred integrity algorithm. + @param[out] PreferPrfAlgorithm Output of preferred PRF algorithm. Only + for IKE SA. + @param[out] PreferDhGroup Output of preferred DH group. Only for + IKE SA. + @param[out] PreferEncryptKeylength Output of preferred encrypt key length + in bytes. + @param[out] IsSupportEsn Output of value about the Extented Sequence + Number is support or not. Only for Child SA. + @param[in] IsChildSa If it is ture, the ProposalData is for IKE + SA. Otherwise the proposalData is for Child SA. + +**/ +VOID +Ikev2ParseProposalData ( + IN IKEV2_PROPOSAL_DATA *ProposalData, + OUT UINT16 *PreferEncryptAlgorithm, + OUT UINT16 *PreferIntegrityAlgorithm, + OUT UINT16 *PreferPrfAlgorithm, + OUT UINT16 *PreferDhGroup, + OUT UINTN *PreferEncryptKeylength, + OUT BOOLEAN *IsSupportEsn, + IN BOOLEAN IsChildSa +) +{ + IKEV2_TRANSFORM_DATA *TransformData; + UINT8 TransformIndex; + + // + // Check input parameters. + // + if (ProposalData == NULL || + PreferEncryptAlgorithm == NULL || + PreferIntegrityAlgorithm == NULL || + PreferEncryptKeylength == NULL + ) { + return; + } + + if (IsChildSa) { + if (IsSupportEsn == NULL) { + return; + } + } else { + if (PreferPrfAlgorithm == NULL || PreferDhGroup == NULL) { + return; + } + } + + TransformData = (IKEV2_TRANSFORM_DATA *)(ProposalData + 1); + for (TransformIndex = 0; TransformIndex < ProposalData->NumTransforms; TransformIndex++) { + switch (TransformData->TransformType) { + // + // For IKE SA there are four algorithm types. Encryption Algorithm, Pseudo-random Function, + // Integrity Algorithm, Diffie-Hellman Group. For Child SA, there are three algorithm types. + // Encryption Algorithm, Integrity Algorithm, Extended Sequence Number. + // + case IKEV2_TRANSFORM_TYPE_ENCR: + if (*PreferEncryptAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_ENCRYPT_TYPE)) { + // + // Check the attribute value. According to RFC, only Keylength is support. + // + if (TransformData->Attribute.AttrType == IKEV2_ATTRIBUTE_TYPE_KEYLEN) { + // + // If the Keylength is not support, continue to check the next one. + // + if (IpSecGetEncryptKeyLength ((UINT8)TransformData->TransformId) != (UINTN)(TransformData->Attribute.Attr.AttrValue >> 3)){ + break; + } else { + *PreferEncryptKeylength = TransformData->Attribute.Attr.AttrValue; + } + } + *PreferEncryptAlgorithm = TransformData->TransformId; + } + break; + + case IKEV2_TRANSFORM_TYPE_PRF : + if (!IsChildSa) { + if (*PreferPrfAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_PRF_TYPE)) { + *PreferPrfAlgorithm = TransformData->TransformId; + } + } + break; + + case IKEV2_TRANSFORM_TYPE_INTEG : + if (*PreferIntegrityAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_AUTH_TYPE)) { + *PreferIntegrityAlgorithm = TransformData->TransformId; + } + break; + + case IKEV2_TRANSFORM_TYPE_DH : + if (!IsChildSa) { + if (*PreferDhGroup == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_DH_TYPE)) { + *PreferDhGroup = TransformData->TransformId; + } + } + break; + + case IKEV2_TRANSFORM_TYPE_ESN : + if (IsChildSa) { + if (TransformData->TransformId != 0) { + *IsSupportEsn = TRUE; + } + } + break; + + default: + break; + } + TransformData = (IKEV2_TRANSFORM_DATA *)(TransformData + 1); + } +} + +/** + Parse the received Initial Exchange Packet. + + This function parse the SA Payload and Key Payload to find out the cryptographic + suite for the further IKE negotiation and fill it into the IKE SA Session's + CommonSession->SaParams. + + @param[in, out] IkeSaSession Pointer to related IKEV2_SA_SESSION. + @param[in] SaPayload The received packet. + @param[in] Type The received packet IKE header flag. + + @retval TRUE If the SA proposal in Packet is acceptable. + @retval FALSE If the SA proposal in Packet is not acceptable. + +**/ +BOOLEAN +Ikev2SaParseSaPayload ( + IN OUT IKEV2_SA_SESSION *IkeSaSession, + IN IKE_PAYLOAD *SaPayload, + IN UINT8 Type + ) +{ + IKEV2_PROPOSAL_DATA *ProposalData; + UINT8 ProposalIndex; + UINT16 PreferEncryptAlgorithm; + UINT16 PreferIntegrityAlgorithm; + UINT16 PreferPrfAlgorithm; + UINT16 PreferDhGroup; + UINTN PreferEncryptKeylength; + UINT16 EncryptAlgorithm; + UINT16 IntegrityAlgorithm; + UINT16 PrfAlgorithm; + UINT16 DhGroup; + UINTN EncryptKeylength; + BOOLEAN IsMatch; + UINTN SaDataSize; + + PreferPrfAlgorithm = 0; + PreferIntegrityAlgorithm = 0; + PreferDhGroup = 0; + PreferEncryptAlgorithm = 0; + PreferEncryptKeylength = 0; + PrfAlgorithm = 0; + IntegrityAlgorithm = 0; + DhGroup = 0; + EncryptAlgorithm = 0; + EncryptKeylength = 0; + IsMatch = FALSE; + + if (Type == IKE_HEADER_FLAGS_INIT) { + ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1); + for (ProposalIndex = 0; ProposalIndex < ((IKEV2_SA_DATA *)SaPayload->PayloadBuf)->NumProposals; ProposalIndex++) { + // + // Iterate each proposal to find the perfered one. + // + if (ProposalData->ProtocolId == IPSEC_PROTO_ISAKMP && ProposalData->NumTransforms >= 4) { + // + // Get the preferred algorithms. + // + Ikev2ParseProposalData ( + ProposalData, + &PreferEncryptAlgorithm, + &PreferIntegrityAlgorithm, + &PreferPrfAlgorithm, + &PreferDhGroup, + &PreferEncryptKeylength, + NULL, + FALSE + ); + + if (PreferEncryptAlgorithm != 0 && + PreferIntegrityAlgorithm != 0 && + PreferPrfAlgorithm != 0 && + PreferDhGroup != 0 + ) { + // + // Find the matched one. + // + IkeSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS)); + ASSERT (IkeSaSession->SessionCommon.SaParams != NULL); + IkeSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm; + IkeSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength; + IkeSaSession->SessionCommon.SaParams->DhGroup = PreferDhGroup; + IkeSaSession->SessionCommon.SaParams->Prf = PreferPrfAlgorithm; + IkeSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm; + IkeSaSession->SessionCommon.PreferDhGroup = PreferDhGroup; + + // + // Save the matched one in IKEV2_SA_DATA for furthure calculation. + // + SaDataSize = sizeof (IKEV2_SA_DATA) + + sizeof (IKEV2_PROPOSAL_DATA) + + sizeof (IKEV2_TRANSFORM_DATA) * 4; + IkeSaSession->SaData = AllocateZeroPool (SaDataSize); + ASSERT (IkeSaSession->SaData != NULL); + + IkeSaSession->SaData->NumProposals = 1; + + // + // BUGBUG: Suppose the matched proposal only has 4 transforms. If + // The matched Proposal has more than 4 transforms means it contains + // one than one transform with same type. + // + CopyMem ( + (IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1), + ProposalData, + SaDataSize - sizeof (IKEV2_SA_DATA) + ); + + ((IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1))->ProposalIndex = 1; + return TRUE; + } else { + PreferEncryptAlgorithm = 0; + PreferIntegrityAlgorithm = 0; + PreferPrfAlgorithm = 0; + PreferDhGroup = 0; + PreferEncryptKeylength = 0; + } + } + // + // Point to next Proposal. + // + ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) + + ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA)); + } + } else if (Type == IKE_HEADER_FLAGS_RESPOND) { + // + // First check the SA proposal's ProtoctolID and Transform Numbers. Since it is + // the responded SA proposal, suppose it only has one proposal and the transform Numbers + // is 4. + // + ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *) SaPayload->PayloadBuf + 1); + if (ProposalData->ProtocolId != IPSEC_PROTO_ISAKMP || ProposalData->NumTransforms != 4) { + return FALSE; + } + // + // Get the preferred algorithms. + // + Ikev2ParseProposalData ( + ProposalData, + &PreferEncryptAlgorithm, + &PreferIntegrityAlgorithm, + &PreferPrfAlgorithm, + &PreferDhGroup, + &PreferEncryptKeylength, + NULL, + FALSE + ); + // + // Check if the Sa proposal data from received packet is in the IkeSaSession->SaData. + // + ProposalData = (IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1); + + for (ProposalIndex = 0; ProposalIndex < IkeSaSession->SaData->NumProposals && (!IsMatch); ProposalIndex++) { + Ikev2ParseProposalData ( + ProposalData, + &EncryptAlgorithm, + &IntegrityAlgorithm, + &PrfAlgorithm, + &DhGroup, + &EncryptKeylength, + NULL, + FALSE + ); + if (EncryptAlgorithm == PreferEncryptAlgorithm && + EncryptKeylength == PreferEncryptKeylength && + IntegrityAlgorithm == PreferIntegrityAlgorithm && + PrfAlgorithm == PreferPrfAlgorithm && + DhGroup == PreferDhGroup + ) { + IsMatch = TRUE; + } else { + EncryptAlgorithm = 0; + IntegrityAlgorithm = 0; + PrfAlgorithm = 0; + DhGroup = 0; + EncryptKeylength = 0; + } + + ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) + + ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA)); + } + + if (IsMatch) { + IkeSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS)); + ASSERT (IkeSaSession->SessionCommon.SaParams != NULL); + IkeSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm; + IkeSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength; + IkeSaSession->SessionCommon.SaParams->DhGroup = PreferDhGroup; + IkeSaSession->SessionCommon.SaParams->Prf = PreferPrfAlgorithm; + IkeSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm; + IkeSaSession->SessionCommon.PreferDhGroup = PreferDhGroup; + + return TRUE; + } + } + return FALSE; +} + +/** + Parse the received Authentication Exchange Packet. + + This function parse the SA Payload and Key Payload to find out the cryptographic + suite for the ESP and fill it into the Child SA Session's CommonSession->SaParams. + + @param[in, out] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION related to + this Authentication Exchange. + @param[in] SaPayload The received packet. + @param[in] Type The IKE header's flag of received packet . + + @retval TRUE If the SA proposal in Packet is acceptable. + @retval FALSE If the SA proposal in Packet is not acceptable. + +**/ +BOOLEAN +Ikev2ChildSaParseSaPayload ( + IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession, + IN IKE_PAYLOAD *SaPayload, + IN UINT8 Type + ) +{ + IKEV2_PROPOSAL_DATA *ProposalData; + UINT8 ProposalIndex; + UINT16 PreferEncryptAlgorithm; + UINT16 PreferIntegrityAlgorithm; + UINTN PreferEncryptKeylength; + BOOLEAN PreferIsSupportEsn; + UINT16 EncryptAlgorithm; + UINT16 IntegrityAlgorithm; + UINTN EncryptKeylength; + BOOLEAN IsSupportEsn; + BOOLEAN IsMatch; + UINTN SaDataSize; + + + PreferIntegrityAlgorithm = 0; + PreferEncryptAlgorithm = 0; + PreferEncryptKeylength = 0; + IntegrityAlgorithm = 0; + EncryptAlgorithm = 0; + EncryptKeylength = 0; + IsMatch = TRUE; + IsSupportEsn = FALSE; + PreferIsSupportEsn = FALSE; + + if (Type == IKE_HEADER_FLAGS_INIT) { + ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *) SaPayload->PayloadBuf + 1); + for (ProposalIndex = 0; ProposalIndex < ((IKEV2_SA_DATA *) SaPayload->PayloadBuf)->NumProposals; ProposalIndex++) { + // + // Iterate each proposal to find the preferred one. + // + if (ProposalData->ProtocolId == IPSEC_PROTO_IPSEC_ESP && ProposalData->NumTransforms >= 3) { + // + // Get the preferred algorithm. + // + Ikev2ParseProposalData ( + ProposalData, + &PreferEncryptAlgorithm, + &PreferIntegrityAlgorithm, + NULL, + NULL, + &PreferEncryptKeylength, + &IsSupportEsn, + TRUE + ); + // + // Don't support the ESN now. + // + if (PreferEncryptAlgorithm != 0 && + PreferIntegrityAlgorithm != 0 && + !IsSupportEsn + ) { + // + // Find the matched one. + // + ChildSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS)); + ASSERT (ChildSaSession->SessionCommon.SaParams != NULL); + ChildSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm; + ChildSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength; + ChildSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm; + CopyMem (&ChildSaSession->RemotePeerSpi, ProposalData->Spi, sizeof (ChildSaSession->RemotePeerSpi)); + + // + // Save the matched one in IKEV2_SA_DATA for furthure calculation. + // + SaDataSize = sizeof (IKEV2_SA_DATA) + + sizeof (IKEV2_PROPOSAL_DATA) + + sizeof (IKEV2_TRANSFORM_DATA) * 4; + + ChildSaSession->SaData = AllocateZeroPool (SaDataSize); + ASSERT (ChildSaSession->SaData != NULL); + + ChildSaSession->SaData->NumProposals = 1; + + // + // BUGBUG: Suppose there are 4 transforms in the matched proposal. If + // the matched Proposal has more than 4 transforms that means there + // are more than one transform with same type. + // + CopyMem ( + (IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1), + ProposalData, + SaDataSize - sizeof (IKEV2_SA_DATA) + ); + + ((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->ProposalIndex = 1; + + ((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->Spi = AllocateCopyPool ( + sizeof (ChildSaSession->LocalPeerSpi), + &ChildSaSession->LocalPeerSpi + ); + ASSERT (((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->Spi != NULL); + return TRUE; + + } else { + PreferEncryptAlgorithm = 0; + PreferIntegrityAlgorithm = 0; + IsSupportEsn = TRUE; + } + } + // + // Point to next Proposal + // + ProposalData = (IKEV2_PROPOSAL_DATA *)((UINT8 *)(ProposalData + 1) + + ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA)); + } + } else if (Type == IKE_HEADER_FLAGS_RESPOND) { + // + // First check the SA proposal's ProtoctolID and Transform Numbers. Since it is + // the responded SA proposal, suppose it only has one proposal and the transform Numbers + // is 3. + // + ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1); + if (ProposalData->ProtocolId != IPSEC_PROTO_IPSEC_ESP || ProposalData->NumTransforms != 3) { + return FALSE; + } + // + // Get the preferred algorithms. + // + Ikev2ParseProposalData ( + ProposalData, + &PreferEncryptAlgorithm, + &PreferIntegrityAlgorithm, + NULL, + NULL, + &PreferEncryptKeylength, + &PreferIsSupportEsn, + TRUE + ); + + ProposalData = (IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1); + + for (ProposalIndex = 0; ProposalIndex < ChildSaSession->SaData->NumProposals && (!IsMatch); ProposalIndex++) { + Ikev2ParseProposalData ( + ProposalData, + &EncryptAlgorithm, + &IntegrityAlgorithm, + NULL, + NULL, + &EncryptKeylength, + &IsSupportEsn, + TRUE + ); + if (EncryptAlgorithm == PreferEncryptAlgorithm && + EncryptKeylength == PreferEncryptKeylength && + IntegrityAlgorithm == PreferIntegrityAlgorithm && + IsSupportEsn == PreferIsSupportEsn + ) { + IsMatch = TRUE; + } else { + PreferEncryptAlgorithm = 0; + PreferIntegrityAlgorithm = 0; + IsSupportEsn = TRUE; + } + ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) + + ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA)); + } + + ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1); + if (IsMatch) { + ChildSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS)); + ASSERT (ChildSaSession->SessionCommon.SaParams != NULL); + ChildSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm; + ChildSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength; + ChildSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm; + CopyMem (&ChildSaSession->RemotePeerSpi, ProposalData->Spi, sizeof (ChildSaSession->RemotePeerSpi)); + + return TRUE; + } + } + return FALSE; +} + +/** + Generate Key buffer from fragments. + + If the digest length of specified HashAlgId is larger than or equal with the + required output key length, derive the key directly. Otherwise, Key Material + needs to be PRF-based concatenation according to 2.13 of RFC 4306: + prf+ (K,S) = T1 | T2 | T3 | T4 | ..., T1 = prf (K, S | 0x01), + T2 = prf (K, T1 | S | 0x02), T3 = prf (K, T2 | S | 0x03),T4 = prf (K, T3 | S | 0x04) + then derive the key from this key material. + + @param[in] HashAlgId The Hash Algorithm ID used to generate key. + @param[in] HashKey Pointer to a key buffer which contains hash key. + @param[in] HashKeyLength The length of HashKey in bytes. + @param[in, out] OutputKey Pointer to buffer which is used to receive the + output key. + @param[in] OutputKeyLength The length of OutPutKey buffer. + @param[in] Fragments Pointer to the data to be used to generate key. + @param[in] NumFragments The numbers of the Fragement. + + @retval EFI_SUCCESS The operation complete successfully. + @retval EFI_INVALID_PARAMETER If NumFragments is zero. + @retval EFI_OUT_OF_RESOURCES If the required resource can't be allocated. + @retval Others The operation is failed. + +**/ +EFI_STATUS +Ikev2SaGenerateKey ( + IN UINT8 HashAlgId, + IN UINT8 *HashKey, + IN UINTN HashKeyLength, + IN OUT UINT8 *OutputKey, + IN UINTN OutputKeyLength, + IN PRF_DATA_FRAGMENT *Fragments, + IN UINTN NumFragments + ) +{ + EFI_STATUS Status; + PRF_DATA_FRAGMENT LocalFragments[3]; + UINT8 *Digest; + UINTN DigestSize; + UINTN Round; + UINTN Index; + UINTN AuthKeyLength; + UINTN FragmentsSize; + UINT8 TailData; + + Status = EFI_SUCCESS; + + if (NumFragments == 0) { + return EFI_INVALID_PARAMETER; + } + + LocalFragments[0].Data = NULL; + LocalFragments[1].Data = NULL; + LocalFragments[2].Data = NULL; + + AuthKeyLength = IpSecGetHmacDigestLength (HashAlgId); + DigestSize = AuthKeyLength; + Digest = AllocateZeroPool (AuthKeyLength); + + if (Digest == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // If the required output key length is less than the digest size, + // copy the digest into OutputKey. + // + if (OutputKeyLength <= DigestSize) { + Status = IpSecCryptoIoHmac ( + HashAlgId, + HashKey, + HashKeyLength, + (HASH_DATA_FRAGMENT *) Fragments, + NumFragments, + Digest, + DigestSize + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + CopyMem (OutputKey, Digest, OutputKeyLength); + goto Exit; + } + + // + //Otherwise, Key Material need to be PRF-based concatenation according to 2.13 + //of RFC 4306: prf+ (K,S) = T1 | T2 | T3 | T4 | ..., T1 = prf (K, S | 0x01), + //T2 = prf (K, T1 | S | 0x02), T3 = prf (K, T2 | S | 0x03),T4 = prf (K, T3 | S | 0x04) + //then derive the key from this key material. + // + FragmentsSize = 0; + for (Index = 0; Index < NumFragments; Index++) { + FragmentsSize = FragmentsSize + Fragments[Index].DataSize; + } + + LocalFragments[1].Data = AllocateZeroPool (FragmentsSize); + ASSERT (LocalFragments[1].Data != NULL); + LocalFragments[1].DataSize = FragmentsSize; + + // + // Copy all input fragments into LocalFragments[1]; + // + FragmentsSize = 0; + for (Index = 0; Index < NumFragments; Index++) { + CopyMem ( + LocalFragments[1].Data + FragmentsSize, + Fragments[Index].Data, + Fragments[Index].DataSize + ); + FragmentsSize = FragmentsSize + Fragments[Index].DataSize; + } + + // + // Prepare 0x01 as the first tail data. + // + TailData = 0x01; + LocalFragments[2].Data = &TailData; + LocalFragments[2].DataSize = sizeof (TailData); + // + // Allocate buffer for the first fragment + // + LocalFragments[0].Data = AllocateZeroPool (AuthKeyLength); + ASSERT (LocalFragments[0].Data != NULL); + LocalFragments[0].DataSize = AuthKeyLength; + + Round = (OutputKeyLength - 1) / AuthKeyLength + 1; + for (Index = 0; Index < Round; Index++) { + Status = IpSecCryptoIoHmac ( + HashAlgId, + HashKey, + HashKeyLength, + (HASH_DATA_FRAGMENT *)(Index == 0 ? &LocalFragments[1] : LocalFragments), + Index == 0 ? 2 : 3, + Digest, + DigestSize + ); + if (EFI_ERROR(Status)) { + goto Exit; + } + CopyMem ( + LocalFragments[0].Data, + Digest, + DigestSize + ); + if (OutputKeyLength > DigestSize * (Index + 1)) { + CopyMem ( + OutputKey + Index * DigestSize, + Digest, + DigestSize + ); + LocalFragments[0].DataSize = DigestSize; + TailData ++; + } else { + // + // The last round + // + CopyMem ( + OutputKey + Index * DigestSize, + Digest, + OutputKeyLength - Index * DigestSize + ); + } + } + +Exit: + // + // Only First and second Framgement Data need to be freed. + // + for (Index = 0 ; Index < 2; Index++) { + if (LocalFragments[Index].Data != NULL) { + FreePool (LocalFragments[Index].Data); + } + } + if (Digest != NULL) { + FreePool (Digest); + } + return Status; +} + diff --git a/NetworkPkg/IpSecDxe/Ikev2/Utility.h b/NetworkPkg/IpSecDxe/Ikev2/Utility.h new file mode 100644 index 0000000000..ea3e5cd2b5 --- /dev/null +++ b/NetworkPkg/IpSecDxe/Ikev2/Utility.h @@ -0,0 +1,1131 @@ +/** @file + The interfaces of IKE/Child session operations and payload related operations + used by IKE Exchange Process. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _IKE_V2_UTILITY_H_ +#define _IKE_V2_UTILITY_H_ + +#include "Ikev2.h" +#include "IkeCommon.h" +#include "IpSecCryptIo.h" + +#include + +#define IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM 2 +#define IKEV2_SUPPORT_PRF_ALGORITHM_NUM 1 +#define IKEV2_SUPPORT_DH_ALGORITHM_NUM 2 +#define IKEV2_SUPPORT_AUTH_ALGORITHM_NUM 1 + +/** + Allocate buffer for IKEV2_SA_SESSION and initialize it. + + @param[in] Private Pointer to IPSEC_PRIVATE_DATA. + @param[in] UdpService Pointer to IKE_UDP_SERVICE related to this IKE SA Session. + + @return Pointer to IKEV2_SA_SESSION. + +**/ +IKEV2_SA_SESSION * +Ikev2SaSessionAlloc ( + IN IPSEC_PRIVATE_DATA *Private, + IN IKE_UDP_SERVICE *UdpService + ); + +/** + Register Establish IKEv2 SA into Private->Ikev2EstablishedList. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be registered. + @param[in] Private Pointer to IPSEC_PRAVATE_DATA. + +**/ +VOID +Ikev2SaSessionReg ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IPSEC_PRIVATE_DATA *Private + ); + +/** + Find a IKEV2_SA_SESSION by the remote peer IP. + + @param[in] SaSessionList SaSession List to be searched. + @param[in] RemotePeerIp Pointer to specified IP address. + + @return Pointer to IKEV2_SA_SESSION if find one or NULL. + +**/ +IKEV2_SA_SESSION * +Ikev2SaSessionLookup ( + IN LIST_ENTRY *SaSessionList, + IN EFI_IP_ADDRESS *RemotePeerIp + ); + +/** + Insert a IKE_SA_SESSION into IkeSaSession list. The IkeSaSession list is either + Private->Ikev2SaSession list or Private->Ikev2EstablishedList list. + + @param[in] SaSessionList Pointer to list to be inserted into. + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be inserted. + @param[in] RemotePeerIp Pointer to EFI_IP_ADDRESSS to indicate the + unique IKEV2_SA_SESSION. + +**/ +VOID +Ikev2SaSessionInsert ( + IN LIST_ENTRY *SaSessionList, + IN IKEV2_SA_SESSION *IkeSaSession, + IN EFI_IP_ADDRESS *RemotePeerIp + ); + +/** + Remove the SA Session by Remote Peer IP. + + @param[in] SaSessionList Pointer to list to be searched. + @param[in] RemotePeerIp Pointer to EFI_IP_ADDRESS to use for SA Session search. + + @retval Pointer to IKEV2_SA_SESSION with the specified remote IP address. + +**/ +IKEV2_SA_SESSION * +Ikev2SaSessionRemove ( + IN LIST_ENTRY *SaSessionList, + IN EFI_IP_ADDRESS *RemotePeerIp + ); + + +/** + Marking a SA session as on deleting. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION. + + @retval EFI_SUCCESS Find the related SA session and marked it. + +**/ +EFI_STATUS +Ikev2SaSessionOnDeleting ( + IN IKEV2_SA_SESSION *IkeSaSession + ); + +/** + After IKE/Child SA is estiblished, close the time event and free sent packet. + + @param[in] SessionCommon Pointer to a Session Common. + +**/ +VOID +Ikev2SessionCommonRefresh ( + IN IKEV2_SESSION_COMMON *SessionCommon + ); + +/** + Free specified IKEV2 SA Session. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be freed. + +**/ +VOID +Ikev2SaSessionFree ( + IN IKEV2_SA_SESSION *IkeSaSession + ); + +/** + Free specified Seession Common. The session common would belong to a IKE SA or + a Child SA. + + @param[in] SessionCommon Pointer to a Session Common. + +**/ +VOID +Ikev2SaSessionCommonFree ( + IN IKEV2_SESSION_COMMON *SessionCommon + ); + +/** + Increase the MessageID in IkeSaSession. + + @param[in] IkeSaSession Pointer to a specified IKEV2_SA_SESSION. + +**/ +VOID +Ikev2SaSessionIncreaseMessageId ( + IN IKEV2_SA_SESSION *IkeSaSession + ); + +/** + Allocate Momery for IKEV2 Child SA Session. + + @param[in] UdpService Pointer to IKE_UDP_SERVICE. + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to this Child SA + Session. + + @retval Pointer of a new created IKEV2 Child SA Session. + +**/ +IKEV2_CHILD_SA_SESSION * +Ikev2ChildSaSessionAlloc ( + IN IKE_UDP_SERVICE *UdpService, + IN IKEV2_SA_SESSION *IkeSaSession + ); + +/** + Register a established IKEv2 Child SA into IkeSaSession->ChildSaEstablishSessionList. + If the there is IKEV2_CHILD_SA_SESSION with same remote peer IP, remove the old one + then register the new one. + + @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION to be registered. + @param[in] Private Pointer to IPSEC_PRAVATE_DATA. + +**/ +VOID +Ikev2ChildSaSessionReg ( + IN IKEV2_CHILD_SA_SESSION *ChildSaSession, + IN IPSEC_PRIVATE_DATA *Private + ); + +/** + This function find the Child SA by the specified Spi. + + This functin find a ChildSA session by searching the ChildSaSessionlist of + the input IKEV2_SA_SESSION by specified MessageID. + + @param[in] SaSessionList Pointer to List to be searched. + @param[in] Spi Specified SPI. + + @return Pointer to IKEV2_CHILD_SA_SESSION. + +**/ +IKEV2_CHILD_SA_SESSION * +Ikev2ChildSaSessionLookupBySpi ( + IN LIST_ENTRY *SaSessionList, + IN UINT32 Spi + ); + +/** + Find the ChildSaSession by it's MessagId. + + @param[in] SaSessionList Pointer to a ChildSaSession List. + @param[in] Mid The messageId used to search ChildSaSession. + + @return Pointer to IKEV2_CHILD_SA_SESSION. + +**/ +IKEV2_CHILD_SA_SESSION * +Ikev2ChildSaSessionLookupByMid ( + IN LIST_ENTRY *SaSessionList, + IN UINT32 Mid + ); + +/** + Insert a Child SA Session into the specified ChildSa list.. + + @param[in] SaSessionList Pointer to list to be inserted in. + @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION to be inserted. + +**/ +VOID +Ikev2ChildSaSessionInsert ( + IN LIST_ENTRY *SaSessionList, + IN IKEV2_CHILD_SA_SESSION *ChildSaSession + ); + +/** + Remove the IKEV2_CHILD_SA_SESSION from IkeSaSessionList. + + @param[in] SaSessionList The SA Session List to be iterated. + @param[in] Spi Spi used to identify the IKEV2_CHILD_SA_SESSION. + @param[in] ListType The type of the List to indicate whether it is a + Established. + + @return The point to IKEV2_CHILD_SA_SESSION. + +**/ +IKEV2_CHILD_SA_SESSION * +Ikev2ChildSaSessionRemove ( + IN LIST_ENTRY *SaSessionList, + IN UINT32 Spi, + IN UINT8 ListType + ); + +/** + Mark a specified Child SA Session as on deleting. + + @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION. + + @retval EFI_SUCCESS Operation is successful. + +**/ +EFI_STATUS +Ikev2ChildSaSessionOnDeleting ( + IN IKEV2_CHILD_SA_SESSION *ChildSaSession + ); + +/** + Free the memory located for the specified IKEV2_CHILD_SA_SESSION. + + @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION. + +**/ +VOID +Ikev2ChildSaSessionFree ( + IN IKEV2_CHILD_SA_SESSION *ChildSaSession + ); + +/** + Free the specified DhBuffer. + + @param[in] DhBuffer Pointer to IKEV2_DH_BUFFER to be freed. + +**/ +VOID +Ikev2DhBufferFree ( + IN IKEV2_DH_BUFFER *DhBuffer + ); + +/** + Delete the specified established Child SA. + + This function delete the Child SA directly and dont send the Information Packet to + remote peer. + + @param[in] IkeSaSession Pointer to a IKE SA Session used to be searched for. + @param[in] Spi SPI used to find the Child SA. + + @retval EFI_NOT_FOUND Pointer of IKE SA Session is NULL. + @retval EFI_NOT_FOUND There is no specified Child SA related with the input + SPI under this IKE SA Session. + @retval EFI_SUCCESS Delete the Child SA successfully. + +**/ +EFI_STATUS +Ikev2ChildSaSilentDelete ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN UINT32 Spi + ); + +/** + This function is to parse a request IKE packet and return its request type. + The request type is one of IKE CHILD SA creation, IKE SA rekeying and + IKE CHILD SA rekeying. + + @param[in] IkePacket IKE packet to be prased. + + return the type of the IKE packet. + +**/ +IKEV2_CREATE_CHILD_REQUEST_TYPE +Ikev2ChildExchangeRequestType( + IN IKE_PACKET *IkePacket + ); + +/** + This function finds the SPI from Create Child Sa Exchange Packet. + + @param[in] IkePacket Pointer to IKE_PACKET to be searched. + + @retval SPI number. + +**/ +UINT32 +Ikev2ChildExchangeRekeySpi( + IN IKE_PACKET *IkePacket + ); + + +/** + Associate a SPD selector to the Child SA Session. + + This function is called when the Child SA is not the first child SA of its + IKE SA. It associate a SPD to this Child SA. + + @param[in, out] ChildSaSession Pointer to the Child SA Session to be associated to + a SPD selector. + + @retval EFI_SUCCESS Associate one SPD selector to this Child SA Session successfully. + @retval EFI_NOT_FOUND Can't find the related SPD selector. + +**/ +EFI_STATUS +Ikev2ChildSaAssociateSpdEntry ( + IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession + ); + +/** + Validate the IKE header of received IKE packet. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to this IKE packet. + @param[in] IkeHdr Pointer to IKE header of received IKE packet. + + @retval TRUE If the IKE header is valid. + @retval FALSE If the IKE header is invalid. + +**/ +BOOLEAN +Ikev2ValidateHeader ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IKE_HEADER *IkeHdr + ); + +/** + Create and intialize IKEV2_SA_DATA for speicifed IKEV2_SESSION_COMMON. + + This function will be only called by the initiator. The responder's IKEV2_SA_DATA + will be generated during parsed the initiator packet. + + @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to. + + @retval a Pointer to a new IKEV2_SA_DATA or NULL. + +**/ +IKEV2_SA_DATA * +Ikev2InitializeSaData ( + IN IKEV2_SESSION_COMMON *SessionCommon + ); + +/** + Store the SA into SAD. + + @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION. + +**/ +VOID +Ikev2StoreSaData ( + IN IKEV2_CHILD_SA_SESSION *ChildSaSession + ); + +/** + Routine process before the payload decoding. + + @param[in] SessionCommon Pointer to ChildSa SessionCommon. + @param[in] PayloadBuf Pointer to the payload. + @param[in] PayloadSize Size of PayloadBuf in byte. + @param[in] PayloadType Type of Payload. + +**/ +VOID +Ikev2ChildSaBeforeDecodePayload ( + IN UINT8 *SessionCommon, + IN UINT8 *PayloadBuf, + IN UINTN PayloadSize, + IN UINT8 PayloadType + ); + +/** + Routine Process after the encode payload. + + @param[in] SessionCommon Pointer to ChildSa SessionCommon. + @param[in] PayloadBuf Pointer to the payload. + @param[in] PayloadSize Size of PayloadBuf in byte. + @param[in] PayloadType Type of Payload. + +**/ +VOID +Ikev2ChildSaAfterEncodePayload ( + IN UINT8 *SessionCommon, + IN UINT8 *PayloadBuf, + IN UINTN PayloadSize, + IN UINT8 PayloadType + ); + +/** + Generate Ikev2 SA payload according to SessionSaData + + @param[in] SessionSaData The data used in SA payload. + @param[in] NextPayload The payload type presented in NextPayload field of + SA Payload header. + @param[in] Type The SA type. It MUST be neither (1) for IKE_SA or + (2) for CHILD_SA or (3) for INFO. + + @retval a Pointer to SA IKE payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateSaPayload ( + IN IKEV2_SA_DATA *SessionSaData, + IN UINT8 NextPayload, + IN IKE_SESSION_TYPE Type + ); + +/** + Generate a ID payload. + + @param[in] CommonSession Pointer to IKEV2_SESSION_COMMON related to ID payload. + @param[in] NextPayload The payload type presented in the NextPayload field + of ID Payload header. + + @retval Pointer to ID IKE payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateIdPayload ( + IN IKEV2_SESSION_COMMON *CommonSession, + IN UINT8 NextPayload + ); + +/** + Generate a ID payload. + + @param[in] CommonSession Pointer to IKEV2_SESSION_COMMON related to ID payload. + @param[in] NextPayload The payload type presented in the NextPayload field + of ID Payload header. + @param[in] InCert Pointer to the Certificate which distinguished name + will be added into the Id payload. + @param[in] CertSize Size of the Certificate. + + @retval Pointer to ID IKE payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateCertIdPayload ( + IN IKEV2_SESSION_COMMON *CommonSession, + IN UINT8 NextPayload, + IN UINT8 *InCert, + IN UINTN CertSize + ); + +/** + Generate a Nonce payload contenting the input parameter NonceBuf. + + @param[in] NonceBuf The nonce buffer content the whole Nonce payload block + except the payload header. + @param[in] NonceSize The buffer size of the NonceBuf + @param[in] NextPayload The payload type presented in the NextPayload field + of Nonce Payload header. + + @retval Pointer to Nonce IKE paload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateNoncePayload ( + IN UINT8 *NonceBuf, + IN UINTN NonceSize, + IN UINT8 NextPayload + ); + +/** + Generate the Notify payload. + + Since the structure of Notify payload which defined in RFC 4306 is simple, so + there is no internal data structure for Notify payload. This function generate + Notify payload defined in RFC 4306, but all the fields in this payload are still + in host order and need call Ikev2EncodePayload() to convert those fields from + the host order to network order beforing sending it. + + @param[in] ProtocolId The protocol type ID. For IKE_SA it MUST be one (1). + For IPsec SAs it MUST be neither (2) for AH or (3) + for ESP. + @param[in] NextPayload The next paylaod type in NextPayload field of + the Notify payload. + @param[in] SpiSize Size of the SPI in SPI size field of the Notify Payload. + @param[in] MessageType The message type in NotifyMessageType field of the + Notify Payload. + @param[in] SpiBuf Pointer to buffer contains the SPI value. + @param[in] NotifyData Pointer to buffer contains the notification data. + @param[in] NotifyDataSize The size of NotifyData in bytes. + + + @retval Pointer to IKE Notify Payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateNotifyPayload ( + IN UINT8 ProtocolId, + IN UINT8 NextPayload, + IN UINT8 SpiSize, + IN UINT16 MessageType, + IN UINT8 *SpiBuf, + IN UINT8 *NotifyData, + IN UINTN NotifyDataSize + ); + +/** + Generate the Delete payload. + + Since the structure of Delete payload which defined in RFC 4306 is simple, + there is no internal data structure for Delete payload. This function generate + Delete payload defined in RFC 4306, but all the fields in this payload are still + in host order and need call Ikev2EncodePayload() to convert those fields from + the host order to network order beforing sending it. + + @param[in] IkeSaSession Pointer to IKE SA Session to be used of Delete payload generation. + @param[in] NextPayload The next paylaod type in NextPayload field of + the Delete payload. + @param[in] SpiSize Size of the SPI in SPI size field of the Delete Payload. + @param[in] SpiNum Number of SPI in NumofSPIs field of the Delete Payload. + @param[in] SpiBuf Pointer to buffer contains the SPI value. + + @retval Pointer to IKE Delete Payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateDeletePayload ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN UINT8 NextPayload, + IN UINT8 SpiSize, + IN UINT16 SpiNum, + IN UINT8 *SpiBuf + ); + +/** + Generate the Configuration payload. + + This function generates a configuration payload defined in RFC 4306, but all the + fields in this payload are still in host order and need call Ikev2EncodePayload() + to convert those fields from the host order to network order beforing sending it. + + @param[in] IkeSaSession Pointer to IKE SA Session to be used for Delete payload + generation. + @param[in] NextPayload The next paylaod type in NextPayload field of + the Delete payload. + @param[in] CfgType The attribute type in the Configuration attribute. + + @retval Pointer to IKE CP Payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateCpPayload ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN UINT8 NextPayload, + IN UINT8 CfgType + ); + +/** + Generate a Authentication Payload. + + This function is used for both Authentication generation and verification. When the + IsVerify is TRUE, it create a Auth Data for verification. This function choose the + related IKE_SA_INIT Message for Auth data creation according to the IKE Session's type + and the value of IsVerify parameter. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to. + @param[in] IdPayload Pointer to the ID payload to be used for Authentication + payload generation. + @param[in] NextPayload The type filled into the Authentication Payload next + payload field. + @param[in] IsVerify If it is TURE, the Authentication payload is used for + verification. + + @return pointer to IKE Authentication payload for pre-shard key method. + +**/ +IKE_PAYLOAD * +Ikev2PskGenerateAuthPayload ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IKE_PAYLOAD *IdPayload, + IN UINT8 NextPayload, + IN BOOLEAN IsVerify + ); + +/** + Generate a Authentication Payload for Certificate Auth method. + + This function has two functions. One is creating a local Authentication + Payload for sending and other is creating the remote Authentication data + for verification when the IsVerify is TURE. + + @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to. + @param[in] IdPayload Pointer to the ID payload to be used for Authentication + payload generation. + @param[in] NextPayload The type filled into the Authentication Payload + next payload field. + @param[in] IsVerify If it is TURE, the Authentication payload is used + for verification. + @param[in] UefiPrivateKey Pointer to the UEFI private key. Ignore it when + verify the authenticate payload. + @param[in] UefiPrivateKeyLen The size of UefiPrivateKey in bytes. Ignore it + when verify the authenticate payload. + @param[in] UefiKeyPwd Pointer to the password of UEFI private key. + Ignore it when verify the authenticate payload. + @param[in] UefiKeyPwdLen The size of UefiKeyPwd in bytes.Ignore it when + verify the authenticate payload. + + @return pointer to IKE Authentication payload for certification method. + +**/ +IKE_PAYLOAD * +Ikev2CertGenerateAuthPayload ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IKE_PAYLOAD *IdPayload, + IN UINT8 NextPayload, + IN BOOLEAN IsVerify, + IN UINT8 *UefiPrivateKey, + IN UINTN UefiPrivateKeyLen, + IN UINT8 *UefiKeyPwd, + IN UINTN UefiKeyPwdLen + ); + +/** + Generate TS payload. + + This function generates TSi or TSr payload according to type of next payload. + If the next payload is Responder TS, gereate TSi Payload. Otherwise, generate + TSr payload + + @param[in] ChildSa Pointer to IKEV2_CHILD_SA_SESSION related to this TS payload. + @param[in] NextPayload The payload type presented in the NextPayload field + of ID Payload header. + @param[in] IsTunnel It indicates that if the Ts Payload is after the CP payload. + If yes, it means the Tsi and Tsr payload should be with + Max port range and address range and protocol is marked + as zero. + + @retval Pointer to Ts IKE payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateTsPayload ( + IN IKEV2_CHILD_SA_SESSION *ChildSa, + IN UINT8 NextPayload, + IN BOOLEAN IsTunnel + ); + +/** + Parser the Notify Cookie payload. + + This function parses the Notify Cookie payload.If the Notify ProtocolId is not + IPSEC_PROTO_ISAKMP or if the SpiSize is not zero or if the MessageType is not + the COOKIE, return EFI_INVALID_PARAMETER. + + @param[in] IkeNCookie Pointer to the IKE_PAYLOAD which contians the + Notify Cookie payload. + the Notify payload. + @param[in, out] IkeSaSession Pointer to the relevant IKE SA Session. + + @retval EFI_SUCCESS The Notify Cookie Payload is valid. + @retval EFI_INVALID_PARAMETER The Notify Cookie Payload is invalid. + @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated. + +**/ +EFI_STATUS +Ikev2ParserNotifyCookiePayload ( + IN IKE_PAYLOAD *IkeNCookie, + IN OUT IKEV2_SA_SESSION *IkeSaSession + ); + +/** + Generate the Certificate payload or Certificate Request Payload. + + Since the Certificate Payload structure is same with Certificate Request Payload, + the only difference is that one contains the Certificate Data, other contains + the acceptable certificateion CA. This function generate Certificate payload + or Certificate Request Payload defined in RFC 4306, but all the fields + in the payload are still in host order and need call Ikev2EncodePayload() + to convert those fields from the host order to network order beforing sending it. + + @param[in] IkeSaSession Pointer to IKE SA Session to be used of Delete payload + generation. + @param[in] NextPayload The next paylaod type in NextPayload field of + the Delete payload. + @param[in] Certificate Pointer of buffer contains the certification data. + @param[in] CertificateLen The length of Certificate in byte. + @param[in] EncodeType Specified the Certificate Encodeing which is defined + in RFC 4306. + @param[in] IsRequest To indicate create Certificate Payload or Certificate + Request Payload. If it is TURE, create Certificate + Request Payload. Otherwise, create Certificate Payload. + + @retval a Pointer to IKE Payload whose payload buffer containing the Certificate + payload or Certificated Request payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateCertificatePayload ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN UINT8 NextPayload, + IN UINT8 *Certificate, + IN UINTN CertificateLen, + IN UINT8 EncodeType, + IN BOOLEAN IsRequest + ); + +/** + General interface of payload encoding. + + This function encode the internal data structure into payload which + is defined in RFC 4306. The IkePayload->PayloadBuf used to store both the input + payload and converted payload. Only the SA payload use the interal structure + to store the attribute. Other payload use structure which is same with the RFC + defined, for this kind payloads just do host order to network order change of + some fields. + + @param[in] SessionCommon Pointer to IKE Session Common used to encode the payload. + @param[in, out] IkePayload Pointer to IKE payload to be encode as input, and + store the encoded result as output. + + @retval EFI_INVALID_PARAMETER Meet error when encode the SA payload. + @retval EFI_SUCCESS Encode successfully. + +**/ +EFI_STATUS +Ikev2EncodePayload ( + IN UINT8 *SessionCommon, + IN OUT IKE_PAYLOAD *IkePayload + ); + +/** + The general interface of decode Payload. + + This function convert the received Payload into internal structure. + + @param[in] SessionCommon Pointer to IKE Session Common to use for decoding. + @param[in, out] IkePayload Pointer to IKE payload to be decode as input, and + store the decoded result as output. + + @retval EFI_INVALID_PARAMETER Meet error when decode the SA payload. + @retval EFI_SUCCESS Decode successfully. + +**/ +EFI_STATUS +Ikev2DecodePayload ( + IN UINT8 *SessionCommon, + IN OUT IKE_PAYLOAD *IkePayload + ); + +/** + Decrypt IKE packet. + + This function decrpt the Encrypted IKE packet and put the result into IkePacket->PayloadBuf. + + @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON containing + some parameter used during decrypting. + @param[in, out] IkePacket Point to IKE_PACKET to be decrypted as input, + and the decrypted reslult as output. + @param[in, out] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and + IKE_CHILD_TYPE are supportted. + + @retval EFI_INVALID_PARAMETER If the IKE packet length is zero or the + IKE packet length is not Algorithm Block Size + alignment. + @retval EFI_SUCCESS Decrypt IKE packet successfully. + +**/ +EFI_STATUS +Ikev2DecryptPacket ( + IN IKEV2_SESSION_COMMON *SessionCommon, + IN OUT IKE_PACKET *IkePacket, + IN OUT UINTN IkeType + ); + +/** + Encrypt IKE packet. + + This function encrypt IKE packet before sending it. The Encrypted IKE packet + is put in to IKEV2 Encrypted Payload. + + @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the IKE packet. + @param[in, out] IkePacket Pointer to IKE packet to be encrypted. + + @retval EFI_SUCCESS Operation is successful. + @retval Others OPeration is failed. + +**/ +EFI_STATUS +Ikev2EncryptPacket ( + IN IKEV2_SESSION_COMMON *SessionCommon, + IN OUT IKE_PACKET *IkePacket + ); + +/** + Encode the IKE packet. + + This function put all Payloads into one payload then encrypt it if needed. + + @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON containing + some parameter used during IKE packet encoding. + @param[in, out] IkePacket Pointer to IKE_PACKET to be encoded as input, + and the encoded reslult as output. + @param[in] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and + IKE_CHILD_TYPE are supportted. + + @retval EFI_SUCCESS Encode IKE packet successfully. + @retval Otherwise Encode IKE packet failed. + +**/ +EFI_STATUS +Ikev2EncodePacket ( + IN IKEV2_SESSION_COMMON *SessionCommon, + IN OUT IKE_PACKET *IkePacket, + IN UINTN IkeType + ); + +/** + Decode the IKE packet. + + This function first decrypts the IKE packet if needed , then separats the whole + IKE packet from the IkePacket->PayloadBuf into IkePacket payload list. + + @param[in] SessionCommon Pointer to IKEV1_SESSION_COMMON containing + some parameter used by IKE packet decoding. + @param[in, out] IkePacket The IKE Packet to be decoded on input, and + the decoded result on return. + @param[in] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and + IKE_CHILD_TYPE are supportted. + + @retval EFI_SUCCESS The IKE packet is decoded successfull. + @retval Otherwise The IKE packet decoding is failed. + +**/ +EFI_STATUS +Ikev2DecodePacket ( + IN IKEV2_SESSION_COMMON *SessionCommon, + IN OUT IKE_PACKET *IkePacket, + IN UINTN IkeType + ); + +/** + Save some useful payloads after accepting the Packet. + + @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the operation. + @param[in] IkePacket Pointer to received IkePacet. + @param[in] IkeType The type used to indicate it is in IkeSa or ChildSa or Info + exchange. + +**/ +VOID +Ikev2OnPacketAccepted ( + IN IKEV2_SESSION_COMMON *SessionCommon, + IN IKE_PACKET *IkePacket, + IN UINT8 IkeType + ); + +/** + Send out IKEV2 packet. + + @param[in] IkeUdpService Pointer to IKE_UDP_SERVICE used to send the IKE packet. + @param[in] SessionCommon Pointer to IKEV1_SESSION_COMMON related to the IKE packet. + @param[in] IkePacket Pointer to IKE_PACKET to be sent out. + @param[in] IkeType The type of IKE to point what's kind of the IKE + packet is to be sent out. IKE_SA_TYPE, IKE_INFO_TYPE + and IKE_CHILD_TYPE are supportted. + + @retval EFI_SUCCESS The operation complete successfully. + @retval Otherwise The operation is failed. + +**/ +EFI_STATUS +Ikev2SendIkePacket ( + IN IKE_UDP_SERVICE *IkeUdpService, + IN UINT8 *SessionCommon, + IN IKE_PACKET *IkePacket, + IN UINTN IkeType + ); + +/** + Callback function for the IKE life time is over. + + This function will mark the related IKE SA Session as deleting and trigger a + Information negotiation. + + @param[in] Event The time out event. + @param[in] Context Pointer to data passed by caller. + +**/ +VOID +EFIAPI +Ikev2LifetimeNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + This function will be called if the TimeOut Event is signaled. + + @param[in] Event The signaled Event. + @param[in] Context The data passed by caller. + +**/ +VOID +EFIAPI +Ikev2ResendNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Generate a Key Exchange payload according to the DH group type and save the + public Key into IkeSaSession IkeKey field. + + @param[in, out] IkeSaSession Pointer of the IKE_SA_SESSION. + @param[in] NextPayload The payload type presented in the NextPayload field of Key + Exchange Payload header. + + @retval Pointer to Key IKE payload. + +**/ +IKE_PAYLOAD * +Ikev2GenerateKePayload ( + IN OUT IKEV2_SA_SESSION *IkeSaSession, + IN UINT8 NextPayload + ); + +/** + Check if the SPD is related to the input Child SA Session. + + This function is the subfunction of Ikev1AssociateSpdEntry(). It is the call + back function of IpSecVisitConfigData(). + + + @param[in] Type Type of the input Config Selector. + @param[in] Selector Pointer to the Configure Selector to be checked. + @param[in] Data Pointer to the Configure Selector's Data passed + from the caller. + @param[in] SelectorSize The buffer size of Selector. + @param[in] DataSize The buffer size of the Data. + @param[in] Context The data passed from the caller. It is a Child + SA Session in this context. + + @retval EFI_SUCCESS The SPD Selector is not related to the Child SA Session. + @retval EFI_ABORTED The SPD Selector is related to the Child SA session and + set the ChildSaSession->Spd to point to this SPD Selector. + +**/ +EFI_STATUS +Ikev2MatchSpdEntry ( + IN EFI_IPSEC_CONFIG_DATA_TYPE Type, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN UINTN SelectorSize, + IN UINTN DataSize, + IN VOID *Context + ); + +/** + Check if the Algorithm ID is supported. + + @param[in] AlgorithmId The specified Algorithm ID. + @param[in] Type The type used to indicate the Algorithm is for Encrypt or + Authentication. + + @retval TRUE If the Algorithm ID is supported. + @retval FALSE If the Algorithm ID is not supported. + +**/ +BOOLEAN +Ikev2IsSupportAlg ( + IN UINT16 AlgorithmId, + IN UINT8 Type + ); + +/** + Generate a ChildSa Session and insert it into related IkeSaSession. + + @param[in] IkeSaSession Pointer to related IKEV2_SA_SESSION. + @param[in] UdpService Pointer to related IKE_UDP_SERVICE. + + @return pointer of IKEV2_CHILD_SA_SESSION. + +**/ +IKEV2_CHILD_SA_SESSION * +Ikev2ChildSaSessionCreate ( + IN IKEV2_SA_SESSION *IkeSaSession, + IN IKE_UDP_SERVICE *UdpService + ) ; + +/** + Parse the received Initial Exchange Packet. + + This function parse the SA Payload and Key Payload to find out the cryptographic + suite for the further IKE negotiation and fill it into the IKE SA Session's + CommonSession->SaParams. + + @param[in, out] IkeSaSession Pointer to related IKEV2_SA_SESSION. + @param[in] SaPayload The received packet. + @param[in] Type The received packet IKE header flag. + + @retval TRUE If the SA proposal in Packet is acceptable. + @retval FALSE If the SA proposal in Packet is not acceptable. + +**/ +BOOLEAN +Ikev2SaParseSaPayload ( + IN OUT IKEV2_SA_SESSION *IkeSaSession, + IN IKE_PAYLOAD *SaPayload, + IN UINT8 Type + ); + +/** + Parse the received Authentication Exchange Packet. + + This function parse the SA Payload and Key Payload to find out the cryptographic + suite for the ESP and fill it into the Child SA Session's CommonSession->SaParams. + + @param[in, out] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION related to + this Authentication Exchange. + @param[in] SaPayload The received packet. + @param[in] Type The IKE header's flag of received packet . + + @retval TRUE If the SA proposal in Packet is acceptable. + @retval FALSE If the SA proposal in Packet is not acceptable. + +**/ +BOOLEAN +Ikev2ChildSaParseSaPayload ( + IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession, + IN IKE_PAYLOAD *SaPayload, + IN UINT8 Type + ); + +/** + Generate Key buffer from fragments. + + If the digest length of specified HashAlgId is larger than or equal with the + required output key length, derive the key directly. Otherwise, Key Material + needs to be PRF-based concatenation according to 2.13 of RFC 4306: + prf+ (K,S) = T1 | T2 | T3 | T4 | ..., T1 = prf (K, S | 0x01), + T2 = prf (K, T1 | S | 0x02), T3 = prf (K, T2 | S | 0x03),T4 = prf (K, T3 | S | 0x04) + then derive the key from this key material. + + @param[in] HashAlgId The Hash Algorithm ID used to generate key. + @param[in] HashKey Pointer to a key buffer which contains hash key. + @param[in] HashKeyLength The length of HashKey in bytes. + @param[in, out] OutputKey Pointer to buffer which is used to receive the + output key. + @param[in] OutputKeyLength The length of OutPutKey buffer. + @param[in] Fragments Pointer to the data to be used to generate key. + @param[in] NumFragments The numbers of the Fragement. + + @retval EFI_SUCCESS The operation complete successfully. + @retval EFI_INVALID_PARAMETER If NumFragments is zero. + @retval EFI_OUT_OF_RESOURCES If the required resource can't be allocated. + @retval Others The operation is failed. + +**/ +EFI_STATUS +Ikev2SaGenerateKey ( + IN UINT8 HashAlgId, + IN UINT8 *HashKey, + IN UINTN HashKeyLength, + IN OUT UINT8 *OutputKey, + IN UINTN OutputKeyLength, + IN PRF_DATA_FRAGMENT *Fragments, + IN UINTN NumFragments + ); + +/** + Copy ChildSaSession->Spd->Selector to ChildSaSession->SpdSelector. + + ChildSaSession->SpdSelector stores the real Spdselector for its SA. Sometime, + the SpdSelector in ChildSaSession is more accurated or the scope is smaller + than the one in ChildSaSession->Spd, especially for the tunnel mode. + + @param[in, out] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION related to. + +**/ +VOID +Ikev2ChildSaSessionSpdSelectorCreate ( + IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession + ); + +extern IKE_ALG_GUID_INFO mIPsecEncrAlgInfo[]; +#endif + diff --git a/NetworkPkg/IpSecDxe/IpSecConfigImpl.c b/NetworkPkg/IpSecDxe/IpSecConfigImpl.c index 0b52a49ae5..87f85e7ca6 100644 --- a/NetworkPkg/IpSecDxe/IpSecConfigImpl.c +++ b/NetworkPkg/IpSecDxe/IpSecConfigImpl.c @@ -20,7 +20,7 @@ LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum]; BOOLEAN mSetBySelf = FALSE; // -// Common CompareSelector routine entry for spd/sad/pad. +// Common CompareSelector routine entry for SPD/SAD/PAD. // IPSEC_COMPARE_SELECTOR mCompareSelector[] = { (IPSEC_COMPARE_SELECTOR) CompareSpdSelector, @@ -29,7 +29,7 @@ IPSEC_COMPARE_SELECTOR mCompareSelector[] = { }; // -// Common IsZeroSelector routine entry for spd/sad/pad. +// Common IsZeroSelector routine entry for SPD/SAD/PAD. // IPSEC_IS_ZERO_SELECTOR mIsZeroSelector[] = { (IPSEC_IS_ZERO_SELECTOR) IsZeroSpdSelector, @@ -38,7 +38,7 @@ IPSEC_IS_ZERO_SELECTOR mIsZeroSelector[] = { }; // -// Common DuplicateSelector routine entry for spd/sad/pad. +// Common DuplicateSelector routine entry for SPD/SAD/PAD. // IPSEC_DUPLICATE_SELECTOR mDuplicateSelector[] = { (IPSEC_DUPLICATE_SELECTOR) DuplicateSpdSelector, @@ -47,7 +47,7 @@ IPSEC_DUPLICATE_SELECTOR mDuplicateSelector[] = { }; // -// Common FixPolicyEntry routine entry for spd/sad/pad. +// Common FixPolicyEntry routine entry for SPD/SAD/PAD. // IPSEC_FIX_POLICY_ENTRY mFixPolicyEntry[] = { (IPSEC_FIX_POLICY_ENTRY) FixSpdEntry, @@ -56,7 +56,7 @@ IPSEC_FIX_POLICY_ENTRY mFixPolicyEntry[] = { }; // -// Common UnfixPolicyEntry routine entry for spd/sad/pad. +// Common UnfixPolicyEntry routine entry for SPD/SAD/PAD. // IPSEC_FIX_POLICY_ENTRY mUnfixPolicyEntry[] = { (IPSEC_FIX_POLICY_ENTRY) UnfixSpdEntry, @@ -65,7 +65,7 @@ IPSEC_FIX_POLICY_ENTRY mUnfixPolicyEntry[] = { }; // -// Common SetPolicyEntry routine entry for spd/sad/pad. +// Common SetPolicyEntry routine entry for SPD/SAD/PAD. // IPSEC_SET_POLICY_ENTRY mSetPolicyEntry[] = { (IPSEC_SET_POLICY_ENTRY) SetSpdEntry, @@ -74,7 +74,7 @@ IPSEC_SET_POLICY_ENTRY mSetPolicyEntry[] = { }; // -// Common GetPolicyEntry routine entry for spd/sad/pad. +// Common GetPolicyEntry routine entry for SPD/SAD/PAD. // IPSEC_GET_POLICY_ENTRY mGetPolicyEntry[] = { (IPSEC_GET_POLICY_ENTRY) GetSpdEntry, @@ -97,7 +97,7 @@ EFI_IPSEC_CONFIG_PROTOCOL mIpSecConfigInstance = { Get the all IPSec configuration variables and store those variables to the internal data structure. - This founction is called by IpSecConfigInitialize() that is to intialize the + This founction is called by IpSecConfigInitialize() that is to intialize the IPsecConfiguration Protocol. @param[in] Private Point to IPSEC_PRIVATE_DATA. @@ -121,7 +121,7 @@ IpSecConfigRestore ( @retval TRUE The specified AddressInfo is in the AddressInfoList. @retval FALSE The specified AddressInfo is not in the AddressInfoList. - + **/ BOOLEAN IsInAddressInfoList( @@ -130,27 +130,42 @@ IsInAddressInfoList( IN UINT32 AddressCount ) { - UINT8 Index; + UINT8 Index; + EFI_IP_ADDRESS ZeroAddress; + + ZeroMem(&ZeroAddress, sizeof (EFI_IP_ADDRESS)); + // + // Zero Address means any address is matched. + // + if (AddressCount == 1) { + if (CompareMem ( + &AddressInfoList[0].Address, + &ZeroAddress, + sizeof (EFI_IP_ADDRESS) + ) == 0) { + return TRUE; + } + } for (Index = 0; Index < AddressCount ; Index++) { if (CompareMem ( AddressInfo, &AddressInfoList[Index].Address, sizeof (EFI_IP_ADDRESS) - ) == 0 && + ) == 0 && AddressInfo->PrefixLength == AddressInfoList[Index].PrefixLength - ) { + ) { return TRUE; } } return FALSE; } - + /** Compare two SPD Selectors. Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/ - NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the + NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the Local Addresses and remote Addresses. @param[in] Selector1 Pointer of first SPD Selector. @@ -158,7 +173,7 @@ IsInAddressInfoList( @retval TRUE This two Selector have the same value in above fields. @retval FALSE Not all above fields have the same value in these two Selectors. - + **/ BOOLEAN CompareSpdSelector ( @@ -178,7 +193,7 @@ CompareSpdSelector ( // // Compare the LocalAddressCount/RemoteAddressCount/NextLayerProtocol/ // LocalPort/LocalPortRange/RemotePort/RemotePortRange fields in the - // two Spdselectors. Since the SPD supports two directions, it needs to + // two Spdselectors. Since the SPD supports two directions, it needs to // compare two directions. // if ((SpdSel1->LocalAddressCount != SpdSel2->LocalAddressCount && @@ -194,10 +209,10 @@ CompareSpdSelector ( IsMatch = FALSE; return IsMatch; } - + // // Compare the all LocalAddress fields in the two Spdselectors. - // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare + // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. If all match, return // TRUE. // @@ -248,14 +263,14 @@ CompareSpdSelector ( } } // - // Finish the one direction compare. If it is matched, return; otherwise, + // Finish the one direction compare. If it is matched, return; otherwise, // compare the other direction. // if (IsMatch) { return IsMatch; } // - // Secondly, the SpdSel1->LocalAddress doesn't equal to SpdSel2->LocalAddress and + // Secondly, the SpdSel1->LocalAddress doesn't equal to SpdSel2->LocalAddress and // SpdSel1->RemoteAddress doesn't equal to SpdSel2->RemoteAddress. Try to compare // the RemoteAddress to LocalAddress. // @@ -309,6 +324,143 @@ CompareSpdSelector ( return IsMatch; } +/** + Find if the two SPD Selectors has subordinative. + + Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/ + NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the + Local Addresses and remote Addresses. + + @param[in] Selector1 Pointer of first SPD Selector. + @param[in] Selector2 Pointer of second SPD Selector. + + @retval TRUE The first SPD Selector is subordinate Selector of second SPD Selector. + @retval FALSE The first SPD Selector is not subordinate Selector of second + SPD Selector. + +**/ +BOOLEAN +IsSubSpdSelector ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector1, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector2 + ) +{ + EFI_IPSEC_SPD_SELECTOR *SpdSel1; + EFI_IPSEC_SPD_SELECTOR *SpdSel2; + BOOLEAN IsMatch; + UINTN Index; + + SpdSel1 = &Selector1->SpdSelector; + SpdSel2 = &Selector2->SpdSelector; + IsMatch = TRUE; + + // + // Compare the LocalAddressCount/RemoteAddressCount/NextLayerProtocol/ + // LocalPort/LocalPortRange/RemotePort/RemotePortRange fields in the + // two Spdselectors. Since the SPD supports two directions, it needs to + // compare two directions. + // + if (SpdSel1->LocalAddressCount > SpdSel2->LocalAddressCount || + SpdSel1->RemoteAddressCount > SpdSel2->RemoteAddressCount || + (SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol && SpdSel2->NextLayerProtocol != 0xffff) || + (SpdSel1->LocalPort > SpdSel2->LocalPort && SpdSel2->LocalPort != 0)|| + (SpdSel1->LocalPortRange > SpdSel2->LocalPortRange && SpdSel1->LocalPort != 0)|| + (SpdSel1->RemotePort > SpdSel2->RemotePort && SpdSel2->RemotePort != 0) || + (SpdSel1->RemotePortRange > SpdSel2->RemotePortRange && SpdSel2->RemotePort != 0) + ) { + IsMatch = FALSE; + } + + // + // Compare the all LocalAddress fields in the two Spdselectors. + // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare + // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. If all match, return + // TRUE. + // + if (IsMatch) { + for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel1->LocalAddress[Index], + SpdSel2->LocalAddress, + SpdSel2->LocalAddressCount + )) { + IsMatch = FALSE; + break; + } + } + + if (IsMatch) { + for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel1->RemoteAddress[Index], + SpdSel2->RemoteAddress, + SpdSel2->RemoteAddressCount + )) { + IsMatch = FALSE; + break; + } + } + } + } + if (IsMatch) { + return IsMatch; + } + + // + // + // The SPD selector in SPD entry is two way. + // + // Compare the LocalAddressCount/RemoteAddressCount/NextLayerProtocol/ + // LocalPort/LocalPortRange/RemotePort/RemotePortRange fields in the + // two Spdselectors. Since the SPD supports two directions, it needs to + // compare two directions. + // + IsMatch = TRUE; + if (SpdSel1->LocalAddressCount > SpdSel2->RemoteAddressCount || + SpdSel1->RemoteAddressCount > SpdSel2->LocalAddressCount || + (SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol && SpdSel2->NextLayerProtocol != 0xffff) || + (SpdSel1->LocalPort > SpdSel2->RemotePort && SpdSel2->RemotePort != 0)|| + (SpdSel1->LocalPortRange > SpdSel2->RemotePortRange && SpdSel1->RemotePort != 0)|| + (SpdSel1->RemotePort > SpdSel2->LocalPort && SpdSel2->LocalPort != 0) || + (SpdSel1->RemotePortRange > SpdSel2->LocalPortRange && SpdSel2->LocalPort != 0) + ) { + IsMatch = FALSE; + return IsMatch; + } + + // + // Compare the all LocalAddress fields in the two Spdselectors. + // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare + // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. If all match, return + // TRUE. + // + for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel1->LocalAddress[Index], + SpdSel2->RemoteAddress, + SpdSel2->RemoteAddressCount + )) { + IsMatch = FALSE; + break; + } + } + + if (IsMatch) { + for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel1->RemoteAddress[Index], + SpdSel2->LocalAddress, + SpdSel2->LocalAddressCount + )) { + IsMatch = FALSE; + break; + } + } + } + return IsMatch; + +} + /** Compare two SA IDs. @@ -317,7 +469,7 @@ CompareSpdSelector ( @retval TRUE This two Selectors have the same SA ID. @retval FALSE This two Selecotrs don't have the same SA ID. - + **/ BOOLEAN CompareSaId ( @@ -348,7 +500,7 @@ CompareSaId ( @retval TRUE This two Selectors have the same PAD ID. @retval FALSE This two Selecotrs don't have the same PAD ID. - + **/ BOOLEAN ComparePadId ( @@ -435,16 +587,14 @@ IsZeroSaId ( IN EFI_IPSEC_CONFIG_SELECTOR *Selector ) { - EFI_IP_ADDRESS *DestAddr; - EFI_IP_ADDRESS ZeroAddr; - BOOLEAN IsZero; - - DestAddr = &Selector->SaId.DestAddress; + BOOLEAN IsZero; + EFI_IPSEC_CONFIG_SELECTOR ZeroSelector; + IsZero = FALSE; - ZeroMem (&ZeroAddr, sizeof (EFI_IP_ADDRESS)); + ZeroMem (&ZeroSelector, sizeof (EFI_IPSEC_CONFIG_SELECTOR)); - if (CompareMem (DestAddr, &ZeroAddr, sizeof (EFI_IP_ADDRESS)) == 0) { + if (CompareMem (&ZeroSelector, Selector, sizeof (EFI_IPSEC_CONFIG_SELECTOR)) == 0) { IsZero = TRUE; } @@ -486,14 +636,14 @@ IsZeroPadId ( @param[in, out] DstSel Pointer of Destination SPD Selector. @param[in] SrcSel Pointer of Source SPD Selector. - @param[in, out] Size The size of the Destination SPD Selector. If it - not NULL and its value less than the size of - Source SPD Selector, the value of Source SPD + @param[in, out] Size The size of the Destination SPD Selector. If it + not NULL and its value less than the size of + Source SPD Selector, the value of Source SPD Selector's size will be passed to caller by this parameter. @retval EFI_INVALID_PARAMETER If the Destination or Source SPD Selector is NULL - @retval EFI_BUFFER_TOO_SMALL If the input Size is less than size of the Source SPD Selector. + @retval EFI_BUFFER_TOO_SMALL If the input Size is less than size of the Source SPD Selector. @retval EFI_SUCCESS Copy Source SPD Selector to the Destination SPD Selector successfully. @@ -520,12 +670,12 @@ DuplicateSpdSelector ( return EFI_BUFFER_TOO_SMALL; } // - // Copy the base structure of spd selector. + // Copy the base structure of SPD selector. // CopyMem (Dst, Src, sizeof (EFI_IPSEC_SPD_SELECTOR)); // - // Copy the local address array of spd selector. + // Copy the local address array of SPD selector. // Dst->LocalAddress = (EFI_IP_ADDRESS_INFO *) (Dst + 1); CopyMem ( @@ -535,7 +685,7 @@ DuplicateSpdSelector ( ); // - // Copy the remote address array of spd selector. + // Copy the remote address array of SPD selector. // Dst->RemoteAddress = Dst->LocalAddress + Dst->LocalAddressCount; CopyMem ( @@ -552,13 +702,13 @@ DuplicateSpdSelector ( @param[in, out] DstSel Pointer of Destination SA ID. @param[in] SrcSel Pointer of Source SA ID. - @param[in, out] Size The size of the Destination SA ID. If it - not NULL and its value less than the size of - Source SA ID, the value of Source SA ID's size + @param[in, out] Size The size of the Destination SA ID. If it + not NULL and its value less than the size of + Source SA ID, the value of Source SA ID's size will be passed to caller by this parameter. @retval EFI_INVALID_PARAMETER If the Destination or Source SA ID is NULL. - @retval EFI_BUFFER_TOO_SMALL If the input Size less than size of source SA ID. + @retval EFI_BUFFER_TOO_SMALL If the input Size less than size of source SA ID. @retval EFI_SUCCESS Copy Source SA ID to the Destination SA ID successfully. **/ @@ -594,9 +744,9 @@ DuplicateSaId ( @param[in, out] DstSel Pointer of Destination PAD ID. @param[in] SrcSel Pointer of Source PAD ID. - @param[in, out] Size The size of the Destination PAD ID. If it - not NULL and its value less than the size of - Source PAD ID, the value of Source PAD ID's size + @param[in, out] Size The size of the Destination PAD ID. If it + not NULL and its value less than the size of + Source PAD ID, the value of Source PAD ID's size will be passed to caller by this parameter. @retval EFI_INVALID_PARAMETER If the Destination or Source PAD ID is NULL. @@ -632,11 +782,11 @@ DuplicatePadId ( } /** - Fix the value of some members of SPD Selector. + Fix the value of some members of SPD Selector. - This function is called by IpSecCopyPolicyEntry()which copy the Policy - Entry into the Variable. Since some members in SPD Selector are pointers, - a physical address to relative address convertion is required before copying + This function is called by IpSecCopyPolicyEntry()which copy the Policy + Entry into the Variable. Since some members in SPD Selector are pointers, + a physical address to relative address convertion is required before copying this SPD entry into the variable. @param[in] Selector Pointer of SPD Selector. @@ -650,7 +800,7 @@ FixSpdEntry ( ) { // - // It assumes that all ref buffers in spd selector and data are + // It assumes that all ref buffers in SPD selector and data are // stored in the continous memory and close to the base structure. // FIX_REF_BUF_ADDR (Selector->LocalAddress, Selector); @@ -667,11 +817,11 @@ FixSpdEntry ( } /** - Fix the value of some members of SA ID. + Fix the value of some members of SA ID. - This function is called by IpSecCopyPolicyEntry()which copy the Policy - Entry into the Variable. Since some members in SA ID are pointers, - a physical address to relative address conversion is required before copying + This function is called by IpSecCopyPolicyEntry()which copy the Policy + Entry into the Variable. Since some members in SA ID are pointers, + a physical address to relative address conversion is required before copying this SAD into the variable. @param[in] SaId Pointer of SA ID @@ -681,11 +831,11 @@ FixSpdEntry ( VOID FixSadEntry ( IN EFI_IPSEC_SA_ID *SaId, - IN OUT EFI_IPSEC_SA_DATA *Data + IN OUT EFI_IPSEC_SA_DATA2 *Data ) { // - // It assumes that all ref buffers in sad selector and data are + // It assumes that all ref buffers in SAD selector and data are // stored in the continous memory and close to the base structure. // if (Data->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { @@ -708,10 +858,10 @@ FixSadEntry ( } /** - Fix the value of some members of PAD ID. + Fix the value of some members of PAD ID. - This function is called by IpSecCopyPolicyEntry()which copy the Policy - Entry into the Variable. Since some members in PAD ID are pointers, + This function is called by IpSecCopyPolicyEntry()which copy the Policy + Entry into the Variable. Since some members in PAD ID are pointers, a physical address to relative address conversion is required before copying this PAD into the variable. @@ -740,7 +890,7 @@ FixPadEntry ( } /** - Recover the value of some members of SPD Selector. + Recover the value of some members of SPD Selector. This function is corresponding to FixSpdEntry(). It recovers the value of members of SPD Selector that are fixed by FixSpdEntry(). @@ -756,7 +906,7 @@ UnfixSpdEntry ( ) { // - // It assumes that all ref buffers in spd selector and data are + // It assumes that all ref buffers in SPD selector and data are // stored in the continous memory and close to the base structure. // UNFIX_REF_BUF_ADDR (Selector->LocalAddress, Selector); @@ -768,11 +918,11 @@ UnfixSpdEntry ( UNFIX_REF_BUF_ADDR (Data->ProcessingPolicy->TunnelOption, Data); } } - + } /** - Recover the value of some members of SA ID. + Recover the value of some members of SA ID. This function is corresponding to FixSadEntry(). It recovers the value of members of SAD ID that are fixed by FixSadEntry(). @@ -784,11 +934,11 @@ UnfixSpdEntry ( VOID UnfixSadEntry ( IN OUT EFI_IPSEC_SA_ID *SaId, - IN OUT EFI_IPSEC_SA_DATA *Data + IN OUT EFI_IPSEC_SA_DATA2 *Data ) { // - // It assumes that all ref buffers in sad selector and data are + // It assumes that all ref buffers in SAD selector and data are // stored in the continous memory and close to the base structure. // if (Data->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { @@ -811,7 +961,7 @@ UnfixSadEntry ( } /** - Recover the value of some members of PAD ID. + Recover the value of some members of PAD ID. This function is corresponding to FixPadEntry(). It recovers the value of members of PAD ID that are fixed by FixPadEntry(). @@ -843,30 +993,30 @@ UnfixPadEntry ( /** Set the security policy information for the EFI IPsec driver. - The IPsec configuration data has a unique selector/identifier separately to + The IPsec configuration data has a unique selector/identifier separately to identify a data entry. - @param[in] Selector Pointer to an entry selector on operated - configuration data specified by DataType. - A NULL Selector causes the entire specified-type + @param[in] Selector Pointer to an entry selector on operated + configuration data specified by DataType. + A NULL Selector causes the entire specified-type configuration information to be flushed. - @param[in] Data The data buffer to be set. The structure + @param[in] Data The data buffer to be set. The structure of the data buffer should be EFI_IPSEC_SPD_DATA. - @param[in] Context Pointer to one entry selector that describes - the expected position the new data entry will + @param[in] Context Pointer to one entry selector that describes + the expected position the new data entry will be added. If Context is NULL, the new entry will be appended the end of database. @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: - - Selector is not NULL and its LocalAddress + - Selector is not NULL and its LocalAddress is NULL or its RemoteAddress is NULL. - - Data is not NULL and its Action is Protected + - Data is not NULL and its Action is Protected and its plolicy is NULL. - Data is not NULL, its Action is not protected, and its policy is not NULL. - - The Action of Data is Protected, its policy + - The Action of Data is Protected, its policy mode is Tunnel, and its tunnel option is NULL. - - The Action of Data is protected and its policy + - The Action of Data is protected and its policy mode is not Tunnel and it tunnel option is not NULL. @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated. @retval EFI_SUCCESS The specified configuration data was obtained successfully. @@ -887,8 +1037,8 @@ SetSpdEntry ( LIST_ENTRY *SpdSas; LIST_ENTRY *EntryInsertBefore; LIST_ENTRY *Entry; - LIST_ENTRY *NextEntry; LIST_ENTRY *Entry2; + LIST_ENTRY *NextEntry; IPSEC_SPD_ENTRY *SpdEntry; IPSEC_SAD_ENTRY *SadEntry; UINTN SpdEntrySize; @@ -926,13 +1076,13 @@ SetSpdEntry ( EntryInsertBefore = SpdList; // - // Remove the existed spd entry. + // Remove the existed SPD entry. // NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SpdList) { SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); - if (SpdSel == NULL || + if (SpdSel == NULL || CompareSpdSelector ((EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector, (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel) ) { // @@ -942,21 +1092,26 @@ SetSpdEntry ( RemoveEntryList (&SpdEntry->List); // - // Update the reverse ref of sad entry in the spd.sas list. + // Update the reverse ref of SAD entry in the SPD.sas list. // SpdSas = &SpdEntry->Data->Sas; + + // + // TODO: Deleted the related SAs. + // NET_LIST_FOR_EACH (Entry2, SpdSas) { SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry2); SadEntry->Data->SpdEntry = NULL; } + // - // Free the existed spd entry + // Free the existed SPD entry // FreePool (SpdEntry); } } // - // Return success here if only want to remove the spd entry. + // Return success here if only want to remove the SPD entry. // if (SpdData == NULL || SpdSel == NULL) { return EFI_SUCCESS; @@ -993,7 +1148,7 @@ SetSpdEntry ( } // // Fix the address of Selector and Data buffer and copy them, which is - // continous memory and close to the base structure of spd entry. + // continous memory and close to the base structure of SPD entry. // SpdEntry->Selector = (EFI_IPSEC_SPD_SELECTOR *) ALIGN_POINTER ((SpdEntry + 1), sizeof (UINTN)); SpdEntry->Data = (IPSEC_SPD_DATA *) ALIGN_POINTER ( @@ -1017,7 +1172,7 @@ SetSpdEntry ( // // Fix the address of ProcessingPolicy and copy it if need, which is continous - // memory and close to the base structure of sad data. + // memory and close to the base structure of SAD data. // if (SpdData->Action != EfiIPsecActionProtect) { SpdEntry->Data->ProcessingPolicy = NULL; @@ -1029,7 +1184,7 @@ SetSpdEntry ( IpSecDuplicateProcessPolicy (SpdEntry->Data->ProcessingPolicy, SpdData->ProcessingPolicy); } // - // Update the sas list of the new spd entry. + // Update the sas list of the new SPD entry. // InitializeListHead (&SpdEntry->Data->Sas); @@ -1046,11 +1201,16 @@ SetSpdEntry ( )) { InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd); SadEntry->Data->SpdEntry = SpdEntry; + DuplicateSpdSelector ( + (EFI_IPSEC_CONFIG_SELECTOR *)SadEntry->Data->SpdSelector, + (EFI_IPSEC_CONFIG_SELECTOR *)SpdEntry->Selector, + NULL + ); } } } // - // Insert the new spd entry. + // Insert the new SPD entry. // InsertTailList (EntryInsertBefore, &SpdEntry->List); @@ -1060,17 +1220,17 @@ SetSpdEntry ( /** Set the security association information for the EFI IPsec driver. - The IPsec configuration data has a unique selector/identifier separately to + The IPsec configuration data has a unique selector/identifier separately to identify a data entry. - @param[in] Selector Pointer to an entry selector on operated - configuration data specified by DataType. - A NULL Selector causes the entire specified-type + @param[in] Selector Pointer to an entry selector on operated + configuration data specified by DataType. + A NULL Selector causes the entire specified-type configuration information to be flushed. - @param[in] Data The data buffer to be set. The structure + @param[in] Data The data buffer to be set. The structure of the data buffer should be EFI_IPSEC_SA_DATA. - @param[in] Context Pointer to one entry selector which describes - the expected position the new data entry will + @param[in] Context Pointer to one entry selector which describes + the expected position the new data entry will be added. If Context is NULL,the new entry will be appended the end of database. @@ -1092,13 +1252,13 @@ SetSadEntry ( LIST_ENTRY *SadList; LIST_ENTRY *SpdList; EFI_IPSEC_SA_ID *SaId; - EFI_IPSEC_SA_DATA *SaData; + EFI_IPSEC_SA_DATA2 *SaData; EFI_IPSEC_SA_ID *InsertBefore; LIST_ENTRY *EntryInsertBefore; UINTN SadEntrySize; - + SaId = (Selector == NULL) ? NULL : &Selector->SaId; - SaData = (Data == NULL) ? NULL : (EFI_IPSEC_SA_DATA *) Data; + SaData = (Data == NULL) ? NULL : (EFI_IPSEC_SA_DATA2 *) Data; InsertBefore = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SaId; SadList = &mConfigData[IPsecConfigDataTypeSad]; @@ -1108,13 +1268,13 @@ SetSadEntry ( EntryInsertBefore = SadList; // - // Remove the existed sad entry. + // Remove the existed SAD entry. // NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SadList) { SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry); - if (SaId == NULL || + if (SaId == NULL || CompareSaId ( (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id, (EFI_IPSEC_CONFIG_SELECTOR *) SaId @@ -1125,7 +1285,7 @@ SetSadEntry ( EntryInsertBefore = SadEntry->List.ForwardLink; // - // Update the related sad.byspd field. + // Update the related SAD.byspd field. // if (SadEntry->Data->SpdEntry != NULL) { RemoveEntryList (&SadEntry->BySpd); @@ -1136,7 +1296,7 @@ SetSadEntry ( } } // - // Return success here if only want to remove the sad entry + // Return success here if only want to remove the SAD entry // if (SaData == NULL || SaId == NULL) { return EFI_SUCCESS; @@ -1163,16 +1323,19 @@ SetSadEntry ( // Do Padding for different Arch. // SadEntrySize = ALIGN_VARIABLE (sizeof (IPSEC_SAD_ENTRY)); - SadEntrySize = ALIGN_VARIABLE (SadEntrySize + sizeof (EFI_IPSEC_SA_DATA)); + SadEntrySize = ALIGN_VARIABLE (SadEntrySize + sizeof (EFI_IPSEC_SA_ID)); SadEntrySize = ALIGN_VARIABLE (SadEntrySize + sizeof (IPSEC_SAD_DATA)); - + if (SaId->Proto == EfiIPsecAH) { SadEntrySize += SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength; } else { SadEntrySize = ALIGN_VARIABLE (SadEntrySize + SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength); - SadEntrySize += SaData->AlgoInfo.EspAlgoInfo.EncKeyLength; + SadEntrySize += ALIGN_VARIABLE (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength); } + if (SaData->SpdSelector != NULL) { + SadEntrySize += SadEntrySize + (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector); + } SadEntry = AllocateZeroPool (SadEntrySize); if (SadEntry == NULL) { @@ -1180,7 +1343,7 @@ SetSadEntry ( } // // Fix the address of Id and Data buffer and copy them, which is - // continous memory and close to the base structure of sad entry. + // continous memory and close to the base structure of SAD entry. // SadEntry->Id = (EFI_IPSEC_SA_ID *) ALIGN_POINTER ((SadEntry + 1), sizeof (UINTN)); SadEntry->Data = (IPSEC_SAD_DATA *) ALIGN_POINTER ((SadEntry->Id + 1), sizeof (UINTN)); @@ -1219,7 +1382,7 @@ SetSadEntry ( if (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) { SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER ( - ((UINT8 *) (SadEntry->Data + 1) + + ((UINT8 *) (SadEntry->Data + 1) + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength), sizeof (UINTN) ); @@ -1238,28 +1401,52 @@ SetSadEntry ( ); SadEntry->Data->PathMTU = SaData->PathMTU; - SadEntry->Data->SpdEntry = NULL; + SadEntry->Data->SpdSelector = NULL; SadEntry->Data->ESNEnabled = FALSE; SadEntry->Data->ManualSet = SaData->ManualSet; // - // Update the spd.sas list of the spd entry specified by sad.selector + // Copy Tunnel Source/Destination Address + // + if (SaData->Mode == EfiIPsecTunnel) { + CopyMem ( + &SadEntry->Data->TunnelDestAddress, + &SaData->TunnelDestinationAddress, + sizeof (EFI_IP_ADDRESS) + ); + CopyMem ( + &SadEntry->Data->TunnelSourceAddress, + &SaData->TunnelSourceAddress, + sizeof (EFI_IP_ADDRESS) + ); + } + // + // Update the spd.sas list of the spd entry specified by SAD selector // SpdList = &mConfigData[IPsecConfigDataTypeSpd]; for (Entry = SpdList->ForwardLink; Entry != SpdList && SaData->SpdSelector != NULL; Entry = Entry->ForwardLink) { SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); - if (CompareSpdSelector ( - (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector, - (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector + if (IsSubSpdSelector ( + (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector, + (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector ) && SpdEntry->Data->Action == EfiIPsecActionProtect) { SadEntry->Data->SpdEntry = SpdEntry; + SadEntry->Data->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *)((UINT8 *)SadEntry + + SadEntrySize - + (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector) + ); + DuplicateSpdSelector ( + (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector, + (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector, + NULL + ); InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd); } } // - // Insert the new sad entry. + // Insert the new SAD entry. // InsertTailList (EntryInsertBefore, &SadEntry->List); @@ -1269,17 +1456,17 @@ SetSadEntry ( /** Set the peer authorization configuration information for the EFI IPsec driver. - The IPsec configuration data has a unique selector/identifier separately to + The IPsec configuration data has a unique selector/identifier separately to identify a data entry. - @param[in] Selector Pointer to an entry selector on operated - configuration data specified by DataType. - A NULL Selector causes the entire specified-type + @param[in] Selector Pointer to an entry selector on operated + configuration data specified by DataType. + A NULL Selector causes the entire specified-type configuration information to be flushed. - @param[in] Data The data buffer to be set. The structure + @param[in] Data The data buffer to be set. The structure of the data buffer should be EFI_IPSEC_PAD_DATA. - @param[in] Context Pointer to one entry selector that describes - the expected position the new data entry will + @param[in] Context Pointer to one entry selector that describes + the expected position the new data entry will be added. If Context is NULL, the new entry will be appended the end of database. @@ -1303,7 +1490,7 @@ SetPadEntry ( EFI_IPSEC_PAD_ID *InsertBefore; LIST_ENTRY *EntryInsertBefore; UINTN PadEntrySize; - + PadId = (Selector == NULL) ? NULL : &Selector->PadId; PadData = (Data == NULL) ? NULL : (EFI_IPSEC_PAD_DATA *) Data; InsertBefore = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->PadId; @@ -1321,7 +1508,7 @@ SetPadEntry ( PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry); - if (PadId == NULL || + if (PadId == NULL || ComparePadId ((EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id, (EFI_IPSEC_CONFIG_SELECTOR *) PadId) ) { // @@ -1421,16 +1608,16 @@ SetPadEntry ( } /** - This function lookup the data entry from IPsec SPD. Return the configuration + This function lookup the data entry from IPsec SPD. Return the configuration value of the specified SPD Entry. - @param[in] Selector Pointer to an entry selector which is an identifier + @param[in] Selector Pointer to an entry selector which is an identifier of the SPD entry. @param[in, out] DataSize On output the size of data returned in Data. - @param[out] Data The buffer to return the contents of the IPsec - configuration data. The type of the data buffer - is associated with the DataType. - + @param[out] Data The buffer to return the contents of the IPsec + configuration data. The type of the data buffer + is associated with the DataType. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. @retval EFI_INVALID_PARAMETER Data is NULL and *DataSize is not zero. @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. @@ -1462,7 +1649,7 @@ GetSpdEntry ( SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); // - // Find the required spd entry + // Find the required SPD entry // if (CompareSpdSelector ( (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel, @@ -1482,7 +1669,7 @@ GetSpdEntry ( *DataSize = RequiredSize; // - // Extract and fill all SaId array from the spd.sas list + // Extract and fill all SaId array from the SPD.sas list // SpdSas = &SpdEntry->Data->Sas; SpdData->SaIdCount = 0; @@ -1496,7 +1683,7 @@ GetSpdEntry ( ); } // - // Fill the other fields in spd data. + // Fill the other fields in SPD data. // CopyMem (SpdData->Name, SpdEntry->Data->Name, sizeof (SpdData->Name)); @@ -1522,16 +1709,16 @@ GetSpdEntry ( } /** - This function lookup the data entry from IPsec SAD. Return the configuration + This function lookup the data entry from IPsec SAD. Return the configuration value of the specified SAD Entry. - @param[in] Selector Pointer to an entry selector which is an identifier + @param[in] Selector Pointer to an entry selector which is an identifier of the SAD entry. @param[in, out] DataSize On output, the size of data returned in Data. - @param[out] Data The buffer to return the contents of the IPsec - configuration data. The type of the data buffer - is associated with the DataType. - + @param[out] Data The buffer to return the contents of the IPsec + configuration data. The type of the data buffer + is associated with the DataType. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been @@ -1549,32 +1736,32 @@ GetSadEntry ( LIST_ENTRY *Entry; LIST_ENTRY *SadList; EFI_IPSEC_SA_ID *SaId; - EFI_IPSEC_SA_DATA *SaData; + EFI_IPSEC_SA_DATA2 *SaData; UINTN RequiredSize; SaId = &Selector->SaId; - SaData = (EFI_IPSEC_SA_DATA *) Data; + SaData = (EFI_IPSEC_SA_DATA2 *) Data; SadList = &mConfigData[IPsecConfigDataTypeSad]; NET_LIST_FOR_EACH (Entry, SadList) { SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry); // - // Find the required sad entry. + // Find the required SAD entry. // if (CompareSaId ( (EFI_IPSEC_CONFIG_SELECTOR *) SaId, (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id )) { // - // Calculate the required size of the sad entry. + // Calculate the required size of the SAD entry. // Data Layout is follows: // |EFI_IPSEC_SA_DATA // |AuthKey // |EncryptKey (Optional) - // |SpdSelector (Optional) - // - RequiredSize = ALIGN_VARIABLE (sizeof (EFI_IPSEC_SA_DATA)); + // |SpdSelector (Optional) + // + RequiredSize = ALIGN_VARIABLE (sizeof (EFI_IPSEC_SA_DATA2)); if (SaId->Proto == EfiIPsecAH) { RequiredSize = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength); @@ -1583,18 +1770,17 @@ GetSadEntry ( RequiredSize = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength); } - if (SadEntry->Data->SpdEntry != NULL) { - RequiredSize += SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdEntry->Selector); + if (SadEntry->Data->SpdSelector != NULL) { + RequiredSize += SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector); } - - - + if (*DataSize < RequiredSize) { *DataSize = RequiredSize; return EFI_BUFFER_TOO_SMALL; } + // - // Fill the data fields of sad entry. + // Fill the data fields of SAD entry. // *DataSize = RequiredSize; SaData->Mode = SadEntry->Data->Mode; @@ -1661,19 +1847,34 @@ GetSadEntry ( SaData->PathMTU = SadEntry->Data->PathMTU; // - // Fill the spd selector field of sad data + // Fill Tunnel Address if it is Tunnel Mode // - if (SadEntry->Data->SpdEntry != NULL) { + if (SadEntry->Data->Mode == EfiIPsecTunnel) { + CopyMem ( + &SaData->TunnelDestinationAddress, + &SadEntry->Data->TunnelDestAddress, + sizeof (EFI_IP_ADDRESS) + ); + CopyMem ( + &SaData->TunnelSourceAddress, + &SadEntry->Data->TunnelSourceAddress, + sizeof (EFI_IP_ADDRESS) + ); + } + // + // Fill the spd selector field of SAD data + // + if (SadEntry->Data->SpdSelector != NULL) { SaData->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *) ( (UINT8 *)SaData + RequiredSize - - SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdEntry->Selector) + SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector) ); - + DuplicateSpdSelector ( (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector, - (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdEntry->Selector, + (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector, NULL ); @@ -1692,16 +1893,16 @@ GetSadEntry ( } /** - This function lookup the data entry from IPsec PAD. Return the configuration + This function lookup the data entry from IPsec PAD. Return the configuration value of the specified PAD Entry. - @param[in] Selector Pointer to an entry selector which is an identifier + @param[in] Selector Pointer to an entry selector which is an identifier of the PAD entry. @param[in, out] DataSize On output the size of data returned in Data. - @param[out] Data The buffer to return the contents of the IPsec - configuration data. The type of the data buffer - is associated with the DataType. - + @param[out] Data The buffer to return the contents of the IPsec + configuration data. The type of the data buffer + is associated with the DataType. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been @@ -1864,7 +2065,7 @@ IpSecGetSizeOfEfiSpdData ( /** Calculate the a whole size of IPSEC_SPD_DATA which includes the buffer size pointed - to by the pointer members and the buffer size used by the Sa List. + to by the pointer members and the buffer size used by the Sa List. @param[in] SpdData Pointer to the specified IPSEC_SPD_DATA. @@ -1900,25 +2101,25 @@ IpSecGetSizeOfSpdData ( Get the IPsec Variable. Get the all variables which start with the string contained in VaraiableName. - Since all IPsec related variable store in continual space, those kinds of - variable can be searched by the EfiGetNextVariableName. Those variables also are + Since all IPsec related variable store in continual space, those kinds of + variable can be searched by the EfiGetNextVariableName. Those variables also are returned in a continual buffer. - + @param[in] VariableName Pointer to a specified Variable Name. @param[in] VendorGuid Pointer to a specified Vendor Guid. - @param[in] Attributes Point to memory location to return the attributes - of variable. If the point is NULL, the parameter + @param[in] Attributes Point to memory location to return the attributes + of variable. If the point is NULL, the parameter would be ignored. - @param[in, out] DataSize As input, point to the maximum size of return - Data-Buffer. As output, point to the actual + @param[in, out] DataSize As input, point to the maximum size of return + Data-Buffer. As output, point to the actual size of the returned Data-Buffer. @param[in] Data Point to return Data-Buffer. - + @retval EFI_ABORTED If the Variable size which contained in the variable - structure doesn't match the variable size obtained + structure doesn't match the variable size obtained from the EFIGetVariable. @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has - been updated with the size needed to complete the request. + been updated with the size needed to complete the request. @retval EFI_SUCCESS The function completed successfully. @retval others Other errors found during the variable getting. **/ @@ -1951,7 +2152,7 @@ IpSecGetVariable ( VariableNameISize = (VariableNameLength + 5) * sizeof (CHAR16); VariableNameI = AllocateZeroPool (VariableNameISize); ASSERT (VariableNameI != NULL); - + // // Construct the varible name of ipsecconfig meta data. // @@ -2084,14 +2285,14 @@ ON_EXIT: @param[in] VariableName The name of the vendor's variable. It is a Null-Terminated Unicode String. @param[in] VendorGuid Unify identifier for vendor. - @param[in] Attributes Point to memory location to return the attributes of + @param[in] Attributes Point to memory location to return the attributes of variable. If the point is NULL, the parameter would be ignored. @param[in] DataSize The size in bytes of Data-Buffer. @param[in] Data Points to the content of the variable. @retval EFI_SUCCESS The firmware successfully stored the variable and its data, as defined by the Attributes. - @retval others Storing the variables failed. + @retval others Storing the variables failed. **/ EFI_STATUS @@ -2121,7 +2322,7 @@ IpSecSetVariable ( if (EFI_ERROR (Status)) { return Status; } - + // // "VariableName + Info/0001/0002/... + NULL" // @@ -2138,7 +2339,7 @@ IpSecSetVariable ( // UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%s", VariableName, L"Info"); MaximumVariableSize -= VariableNameSize; - + IpSecVariableInfo.VariableCount = (UINT32) ((DataSize + (UINTN) MaximumVariableSize - 1) / (UINTN) MaximumVariableSize); IpSecVariableInfo.VariableSize = (UINT32) DataSize; IpSecVariableInfo.SingleVariableSize = (UINT32) MaximumVariableSize; @@ -2163,7 +2364,7 @@ IpSecSetVariable ( // Construct and set the variable of ipsecconfig data one by one. // The index of variable name begin from 0001, and the varaible name // likes "VariableName0001", "VaraiableName0002".... - // + // UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%04d", VariableName, VariableIndex + 1); Status = gRT->SetVariable ( VariableNameI, @@ -2190,20 +2391,20 @@ ON_EXIT: } /** - Return the configuration value for the EFI IPsec driver. + Return the configuration value for the EFI IPsec driver. This function lookup the data entry from IPsec database or IKEv2 configuration information. The expected data type and unique identification are described in - DataType and Selector parameters. + DataType and Selector parameters. @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. @param[in] DataType The type of data to retrieve. - @param[in] Selector Pointer to an entry selector that is an identifier of the IPsec + @param[in] Selector Pointer to an entry selector that is an identifier of the IPsec configuration data entry. @param[in, out] DataSize On output the size of data returned in Data. - @param[out] Data The buffer to return the contents of the IPsec configuration data. - The type of the data buffer associated with the DataType. - + @param[out] Data The buffer to return the contents of the IPsec configuration data. + The type of the data buffer associated with the DataType. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: - This is NULL. @@ -2243,26 +2444,26 @@ EfiIpSecConfigGetData ( /** Set the security association, security policy and peer authorization configuration - information for the EFI IPsec driver. + information for the EFI IPsec driver. This function is used to set the IPsec configuration information of type DataType for the EFI IPsec driver. The IPsec configuration data has a unique selector/identifier separately to identify a data entry. The selector structure depends on DataType's definition. Using SetData() with a Data of NULL causes the IPsec configuration data entry identified - by DataType and Selector to be deleted. + by DataType and Selector to be deleted. @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. @param[in] DataType The type of data to be set. - @param[in] Selector Pointer to an entry selector on operated configuration data - specified by DataType. A NULL Selector causes the entire + @param[in] Selector Pointer to an entry selector on operated configuration data + specified by DataType. A NULL Selector causes the entire specified-type configuration information to be flushed. - @param[in] Data The data buffer to be set. The structure of the data buffer is + @param[in] Data The data buffer to be set. The structure of the data buffer is associated with the DataType. @param[in] InsertBefore Pointer to one entry selector which describes the expected position the new data entry will be added. If InsertBefore is NULL, the new entry will be appended to the end of the database. - + @retval EFI_SUCCESS The specified configuration entry data was set successfully. @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: - This is NULL. @@ -2289,7 +2490,7 @@ EfiIpSecConfigSetData ( if (DataType >= IPsecConfigDataTypeMaximum) { return EFI_UNSUPPORTED; } - + Status = mSetPolicyEntry[DataType](Selector, Data, InsertBefore); if (!EFI_ERROR (Status) && !mSetBySelf) { @@ -2303,30 +2504,30 @@ EfiIpSecConfigSetData ( } /** - Enumerates the current selector for IPsec configuration data entry. + Enumerates the current selector for IPsec configuration data entry. This function is called multiple times to retrieve the entry Selector in IPsec - configuration database. On each call to GetNextSelector(), the next entry + configuration database. On each call to GetNextSelector(), the next entry Selector are retrieved into the output interface. - - If the entire IPsec configuration database has been iterated, the error + + If the entire IPsec configuration database has been iterated, the error EFI_NOT_FOUND is returned. - If the Selector buffer is too small for the next Selector copy, an - EFI_BUFFER_TOO_SMALL error is returned, and SelectorSize is updated to reflect + If the Selector buffer is too small for the next Selector copy, an + EFI_BUFFER_TOO_SMALL error is returned, and SelectorSize is updated to reflect the size of buffer needed. On the initial call to GetNextSelector() to start the IPsec configuration database - search, a pointer to the buffer with all zero value is passed in Selector. Calls - to SetData() between calls to GetNextSelector may produce unpredictable results. + search, a pointer to the buffer with all zero value is passed in Selector. Calls + to SetData() between calls to GetNextSelector may produce unpredictable results. @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. @param[in] DataType The type of IPsec configuration data to retrieve. @param[in, out] SelectorSize The size of the Selector buffer. - @param[in, out] Selector On input, supplies the pointer to last Selector that was + @param[in, out] Selector On input, supplies the pointer to last Selector that was returned by GetNextSelector(). On output, returns one copy of the current entry Selector - of a given DataType. - + of a given DataType. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: - This is NULL. @@ -2335,7 +2536,7 @@ EfiIpSecConfigSetData ( @retval EFI_NOT_FOUND The next configuration data entry was not found. @retval EFI_UNSUPPORTED The specified DataType is not supported. @retval EFI_BUFFER_TOO_SMALL The SelectorSize is too small for the result. This parameter - has been updated with the size needed to complete the search + has been updated with the size needed to complete the search request. **/ @@ -2384,14 +2585,14 @@ EfiIpSecConfigGetNextSelector ( /** Register an event that is to be signaled whenever a configuration process on the - specified IPsec configuration information is done. + specified IPsec configuration information is done. The register function is not surpport now and always returns EFI_UNSUPPORTED. - + @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. @param[in] DataType The type of data to be registered the event for. @param[in] Event The event to be registered. - + @retval EFI_SUCCESS The event is registered successfully. @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. @retval EFI_ACCESS_DENIED The Event is already registered for the DataType. @@ -2412,16 +2613,16 @@ EfiIpSecConfigRegisterNotify ( /** Remove the specified event that was previously registered on the specified IPsec - configuration data. + configuration data. This function is not support now and alwasy return EFI_UNSUPPORTED. @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. @param[in] DataType The configuration data type to remove the registered event for. @param[in] Event The event to be unregistered. - + @retval EFI_SUCCESS The event was removed successfully. - @retval EFI_NOT_FOUND The Event specified by DataType could not be found in the + @retval EFI_NOT_FOUND The Event specified by DataType could not be found in the database. @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. @retval EFI_UNSUPPORTED The notify registration is unsupported, or the specified @@ -2443,10 +2644,10 @@ EfiIpSecConfigUnregisterNotify ( Copy whole data in specified EFI_SIPEC_CONFIG_SELECTOR and the Data to a buffer. This function is a caller defined function, and it is called by the IpSecVisitConfigData(). - The orignal caller is IpSecConfigSave(), which calls the IpsecVisitConfigData() to + The orignal caller is IpSecConfigSave(), which calls the IpsecVisitConfigData() to copy all types of IPsec Config datas into one buffer and store this buffer into firmware in the form of several variables. - + @param[in] Type A specified IPSEC_CONFIG_DATA_TYPE. @param[in] Selector Points to a EFI_IPSEC_CONFIG_SELECTOR to be copied to the buffer. @@ -2474,12 +2675,12 @@ IpSecCopyPolicyEntry ( IPSEC_VAR_ITEM_HEADER DataHeader; UINTN EntrySize; UINT8 *TempPoint; - + if (Type == IPsecConfigDataTypeSad) { // - // Don't save automatically-generated sa entry into variable. + // Don't save automatically-generated SA entry into variable. // - if (((EFI_IPSEC_SA_DATA *) Data)->ManualSet == FALSE) { + if (((EFI_IPSEC_SA_DATA2 *) Data)->ManualSet == FALSE) { return EFI_SUCCESS; } } @@ -2490,7 +2691,7 @@ IpSecCopyPolicyEntry ( EntrySize = ALIGN_VARIABLE (EntrySize + SelectorSize); EntrySize = ALIGN_VARIABLE (EntrySize + sizeof (SelectorHeader)); EntrySize = ALIGN_VARIABLE (EntrySize + DataSize); - + //EntrySize = SelectorSize + DataSize + 2 * sizeof (SelectorHeader); if (Buffer->Capacity - Buffer->Size < EntrySize) { // @@ -2498,7 +2699,7 @@ IpSecCopyPolicyEntry ( // Buffer->Capacity += EntrySize; TempPoint = AllocatePool (Buffer->Capacity); - + if (Buffer->Ptr == NULL) { return EFI_OUT_OF_RESOURCES; } @@ -2507,8 +2708,8 @@ IpSecCopyPolicyEntry ( // CopyMem (TempPoint, Buffer->Ptr, Buffer->Size); FreePool (Buffer->Ptr); - - Buffer->Ptr = TempPoint; + + Buffer->Ptr = TempPoint; } mFixPolicyEntry[Type](Selector, Data); @@ -2525,7 +2726,7 @@ IpSecCopyPolicyEntry ( sizeof (SelectorHeader) ); Buffer->Size = ALIGN_VARIABLE (Buffer->Size + sizeof (SelectorHeader)); - + // // Copy the selector into buffer. // @@ -2557,7 +2758,7 @@ IpSecCopyPolicyEntry ( DataSize ); Buffer->Size = ALIGN_VARIABLE (Buffer->Size + DataSize); - + mUnfixPolicyEntry[Type](Selector, Data); return EFI_SUCCESS; @@ -2768,7 +2969,7 @@ IpSecConfigSave ( Get the all IPSec configuration variables and store those variables to the internal data structure. - This founction is called by IpSecConfigInitialize() which is to intialize the + This founction is called by IpSecConfigInitialize() which is to intialize the IPsecConfiguration Protocol. @param[in] Private Point to IPSEC_PRIVATE_DATA. @@ -2846,10 +3047,10 @@ IpSecConfigRestore ( Header = (IPSEC_VAR_ITEM_HEADER *) Ptr; Type = (EFI_IPSEC_CONFIG_DATA_TYPE) (Header->Type & IPSEC_VAR_ITEM_HEADER_CONTENT_BIT); ASSERT (((Header->Type & 0x80) == IPSEC_VAR_ITEM_HEADER_LOGO_BIT) && (Type < IPsecConfigDataTypeMaximum)); - + Selector = (EFI_IPSEC_CONFIG_SELECTOR *) ALIGN_POINTER (Header + 1, sizeof (UINTN)); Header = (IPSEC_VAR_ITEM_HEADER *) ALIGN_POINTER ( - (UINT8 *) Selector + Header->Size, + (UINT8 *) Selector + Header->Size, sizeof (UINTN) ); ASSERT (Header->Type == Type); diff --git a/NetworkPkg/IpSecDxe/IpSecConfigImpl.h b/NetworkPkg/IpSecDxe/IpSecConfigImpl.h index 54d43bd01c..036cd8d4e0 100644 --- a/NetworkPkg/IpSecDxe/IpSecConfigImpl.h +++ b/NetworkPkg/IpSecDxe/IpSecConfigImpl.h @@ -342,21 +342,22 @@ IpSecDuplicateProcessPolicy ( ); /** - Compare two SPD Selectors. + Find if the two SPD Selectors has subordinative. Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/ - NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the + NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the Local Addresses and remote Addresses. - @param[in] Selector1 Pointer of the first SPD Selector. - @param[in] Selector2 Pointer of the second SPD Selector. - - @retval TRUE This two Selector have the same value in above fields. - @retval FALSE Not all of the above fields have the same value in these two Selectors. + @param[in] Selector1 Pointer of first SPD Selector. + @param[in] Selector2 Pointer of second SPD Selector. + @retval TRUE The first SPD Selector is subordinate Selector of second SPD Selector. + @retval FALSE The first SPD Selector is not subordinate Selector of second + SPD Selector. + **/ BOOLEAN -CompareSpdSelector ( +IsSubSpdSelector ( IN EFI_IPSEC_CONFIG_SELECTOR *Selector1, IN EFI_IPSEC_CONFIG_SELECTOR *Selector2 ); @@ -537,7 +538,7 @@ FixSpdEntry ( VOID FixSadEntry ( IN EFI_IPSEC_SA_ID *SaId, - IN OUT EFI_IPSEC_SA_DATA *Data + IN OUT EFI_IPSEC_SA_DATA2 *Data ); /** @@ -588,7 +589,7 @@ UnfixSpdEntry ( VOID UnfixSadEntry ( IN OUT EFI_IPSEC_SA_ID *SaId, - IN OUT EFI_IPSEC_SA_DATA *Data + IN OUT EFI_IPSEC_SA_DATA2 *Data ); /** @@ -949,4 +950,6 @@ EfiIpSecConfigUnregisterNotify ( IN EFI_EVENT Event ); +extern LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum]; + #endif diff --git a/NetworkPkg/IpSecDxe/IpSecCryptIo.c b/NetworkPkg/IpSecDxe/IpSecCryptIo.c index 93b69a6682..027e078e7a 100644 --- a/NetworkPkg/IpSecDxe/IpSecCryptIo.c +++ b/NetworkPkg/IpSecDxe/IpSecCryptIo.c @@ -1,5 +1,5 @@ /** @file - Common operation for Security. + Common interfaces to call Security library. Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
@@ -15,26 +15,39 @@ #include "IpSecCryptIo.h" // -// Alogrithm's informations for the Encrypt/Decrpt Alogrithm. +// The informations for the supported Encrypt/Decrpt Alogrithm. // -ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = { +GLOBAL_REMOVE_IF_UNREFERENCED ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = { {IKE_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL}, - {(UINT8)-1, 0, 0, 0, NULL, NULL, NULL, NULL} + {IKE_EALG_NONE, 0, 0, 1, NULL, NULL, NULL, NULL}, + {IKE_EALG_3DESCBC, 24, 8, 8, TdesGetContextSize, TdesInit, TdesCbcEncrypt, TdesCbcDecrypt}, + {IKE_EALG_AESCBC, 16, 16, 16, AesGetContextSize, AesInit, AesCbcEncrypt, AesCbcDecrypt} }; + +// +// The informations for the supported Authentication algorithm +// +GLOBAL_REMOVE_IF_UNREFERENCED AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = { + {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL}, + {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL}, + {IKE_AALG_SHA1HMAC, 20, 12, 64, HmacSha1GetContextSize, HmacSha1Init, HmacSha1Update, HmacSha1Final} +}; + // -// Alogrithm's informations for the Authentication algorithm +// The information for the supported Hash aglorithm // -AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = { +GLOBAL_REMOVE_IF_UNREFERENCED HASH_ALGORITHM mIpsecHashAlgorithmList[IPSEC_HASH_ALGORITHM_LIST_SIZE] = { {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL}, {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL}, - {(UINT8)-1, 0, 0, 0, NULL, NULL, NULL, NULL} + {IKE_AALG_SHA1HMAC, 20, 12, 64, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final} }; +BOOLEAN mInitialRandomSeed = FALSE; /** - Get the block size of encrypt alogrithm. The block size is based on the algorithm used. + Get the block size of specified encryption alogrithm. - @param[in] AlgorithmId The encrypt algorithm ID. + @param[in] AlgorithmId The encryption algorithm ID. @return The value of block size. @@ -48,9 +61,6 @@ IpSecGetEncryptBlockSize ( for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) { if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) { - // - // The BlockSize is same with IvSize. - // return mIpsecEncryptAlgorithmList[Index].BlockSize; } } @@ -59,9 +69,33 @@ IpSecGetEncryptBlockSize ( } /** - Get the IV size of encrypt alogrithm. The IV size is based on the algorithm used. + Get the key length of the specified encryption alogrithm. + + @param[in] AlgorithmId The encryption algorithm ID. + + @return The value of key length. + +**/ +UINTN +IpSecGetEncryptKeyLength ( + IN UINT8 AlgorithmId + ) +{ + UINT8 Index; + + for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) { + if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) { + return mIpsecEncryptAlgorithmList[Index].KeyLength; + } + } + + return (UINTN) -1; +} + +/** + Get the IV size of the specified encryption alogrithm. - @param[in] AlgorithmId The encrypt algorithm ID. + @param[in] AlgorithmId The encryption algorithm ID. @return The value of IV size. @@ -75,9 +109,6 @@ IpSecGetEncryptIvLength ( for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) { if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) { - // - // The BlockSize is same with IvSize. - // return mIpsecEncryptAlgorithmList[Index].IvLength; } } @@ -86,24 +117,53 @@ IpSecGetEncryptIvLength ( } /** - Get the ICV size of Authenticaion alogrithm. The ICV size is based on the algorithm used. + Get the HMAC digest length by the specified Algorithm ID. + + @param[in] AlgorithmId The specified Alogrithm ID. + + @return The digest length of the specified Authentication Algorithm ID. + +**/ +UINTN +IpSecGetHmacDigestLength ( + IN UINT8 AlgorithmId + ) +{ + UINT8 Index; + + for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) { + if (mIpsecAuthAlgorithmList[Index].AlgorithmId == AlgorithmId) { + // + // Return the Digest Length of the Algorithm. + // + return mIpsecAuthAlgorithmList[Index].DigestLength; + } + } + + return 0; +} + +/** + Get the ICV size of the specified Authenticaion alogrithm. - @param[in] AuthAlgorithmId The Authentication algorithm ID. + @param[in] AlgorithmId The Authentication algorithm ID. @return The value of ICV size. **/ UINTN IpSecGetIcvLength ( - IN UINT8 AuthAlgorithmId + IN UINT8 AlgorithmId ) { UINT8 Index; + for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) { - if (AuthAlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) { + if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) { return mIpsecAuthAlgorithmList[Index].IcvLength; } } + return (UINTN) -1; } @@ -112,7 +172,7 @@ IpSecGetIcvLength ( IV and return EFI_SUCCESS. @param[in] IvBuffer The pointer of the IV buffer. - @param[in] IvSize The IV size. + @param[in] IvSize The IV size in bytes. @retval EFI_SUCCESS Create a random data for IV. @@ -124,10 +184,833 @@ IpSecGenerateIv ( ) { if (IvSize != 0) { + return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize); + } + + return EFI_SUCCESS; +} + +/** + Get index of the specified encryption alogrithm from the mIpsecEncryptAlgorithemList. + + @param[in] AlgorithmId The encryption algorithm ID. + + @return the index. + +**/ +UINTN +IpSecGetIndexFromEncList ( + IN UINT8 AlgorithmId + ) +{ + UINT8 Index; + + for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) { + if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) { + return Index; + } + } + + return (UINTN) -1; +} + +/** + Get index of the specified encryption alogrithm from the mIpsecAuthAlgorithemList. + + @param[in] AlgorithmId The encryption algorithm ID. + + @return the index. + +**/ +UINTN +IpSecGetIndexFromAuthList ( + IN UINT8 AlgorithmId + ) +{ + UINT8 Index; + + for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) { + if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) { + // + // The BlockSize is same with IvSize. + // + return Index; + } + } + + return (UINTN) -1; +} + +/** + Encrypt the buffer. + + This function calls relevant encryption interface from CryptoLib according to + the input alogrithm ID. The InData should be multiple of block size. This function + doesn't perform the padding. If it has the Ivec data, the length of it should be + same with the block size. The block size is different from the different algorithm. + + @param[in] AlgorithmId The Alogrithem identification defined in RFC. + @param[in] Key Pointer to the buffer containing encrypting key. + @param[in} KeyBits The length of the key in bits. + @param[in] Ivec Point to the buffer containning the Initializeion + Vector (IV) data. + @param[in] InData Point to the buffer containing the data to be + encrypted. + @param[in] InDataLength The length of InData in Bytes. + @param[out] OutData Point to the buffer that receives the encryption + output. + + @retval EFI_UNSUPPORTED The input Algorithm is not supported. + @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated. + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +IpSecCryptoIoEncrypt ( + IN CONST UINT8 AlgorithmId, + IN CONST UINT8 *Key, + IN CONST UINTN KeyBits, + IN CONST UINT8 *Ivec, OPTIONAL + IN UINT8 *InData, + IN UINTN InDataLength, + OUT UINT8 *OutData + ) +{ + UINTN Index; + UINTN ContextSize; + UINT8 *Context; + EFI_STATUS Status; + + Status = EFI_UNSUPPORTED; + + switch (AlgorithmId) { + + case IKE_EALG_NULL: + case IKE_EALG_NONE: + CopyMem (OutData, InData, InDataLength); + return EFI_SUCCESS; + + case IKE_EALG_3DESCBC: + case IKE_EALG_AESCBC: + Index = IpSecGetIndexFromEncList (AlgorithmId); + if (Index == -1) { + return Status; + } + // + // Get Context Size + // + ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize (); + Context = AllocateZeroPool (ContextSize); + + if (Context == NULL) { + return EFI_OUT_OF_RESOURCES; + } // - //TODO: return CryptGenerateRandom (IvBuffer, IvSize); + // Initiate Context // + if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) { + if (mIpsecEncryptAlgorithmList[Index].CipherEncrypt (Context, InData, InDataLength, Ivec, OutData)) { + Status = EFI_SUCCESS; + } + } + break; + + default: + return Status; + + } + + if (Context != NULL) { + FreePool (Context); + } + + return Status; +} + +/** + Decrypts the buffer. + + This function calls relevant Decryption interface from CryptoLib according to + the input alogrithm ID. The InData should be multiple of block size. This function + doesn't perform the padding. If it has the Ivec data, the length of it should be + same with the block size. The block size is different from the different algorithm. + + @param[in] AlgorithmId The Alogrithem identification defined in RFC. + @param[in] Key Pointer to the buffer containing encrypting key. + @param[in} KeyBits The length of the key in bits. + @param[in] Ivec Point to the buffer containning the Initializeion + Vector (IV) data. + @param[in] InData Point to the buffer containing the data to be + Decrypted. + @param[in] InDataLength The length of InData in Bytes. + @param[out] OutData Pointer to the buffer that receives the decryption + output. + + @retval EFI_UNSUPPORTED The input Algorithm is not supported. + @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated. + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +IpSecCryptoIoDecrypt ( + IN CONST UINT8 AlgorithmId, + IN CONST UINT8 *Key, + IN CONST UINTN KeyBits, + IN CONST UINT8 *Ivec, OPTIONAL + IN UINT8 *InData, + IN UINTN InDataLength, + OUT UINT8 *OutData + ) +{ + UINTN Index; + UINTN ContextSize; + UINT8 *Context; + EFI_STATUS Status; + + Status = EFI_UNSUPPORTED; + + switch (AlgorithmId) { + + case IKE_EALG_NULL: + case IKE_EALG_NONE: + CopyMem (OutData, InData, InDataLength); return EFI_SUCCESS; + + case IKE_EALG_3DESCBC: + case IKE_EALG_AESCBC: + Index = IpSecGetIndexFromEncList(AlgorithmId); + if (Index == -1) { + return Status; + } + + // + // Get Context Size + // + ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize(); + Context = AllocateZeroPool (ContextSize); + if (Context == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Initiate Context + // + if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) { + if (mIpsecEncryptAlgorithmList[Index].CipherDecrypt (Context, InData, InDataLength, Ivec, OutData)) { + Status = EFI_SUCCESS; + } + } + break; + + default: + return Status; + } + + if (Context != NULL) { + FreePool (Context); } + + return Status; +} + +/** + Digests the Payload with key and store the result into the OutData. + + This function calls relevant Hmac interface from CryptoLib according to + the input alogrithm ID. It computes all datas from InDataFragment and output + the result into the OutData buffer. If the OutDataSize is larger than the related + HMAC alogrithm output size, return EFI_INVALID_PARAMETER. + + @param[in] AlgorithmId The authentication Identification. + @param[in] Key Pointer of the authentication key. + @param[in] KeyLength The length of the Key in bytes. + @param[in] InDataFragment The list contains all data to be authenticated. + @param[in] FragmentCount The size of the InDataFragment. + @param[out] OutData For in, the buffer to receive the output data. + For out, the buffer contains the authenticated data. + @param[in] OutDataSize The size of the buffer of OutData. + + @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list. + @retval EFI_INVALID_PARAMETER The OutData buffer size is larger than algorithm digest size. + @retval EFI_SUCCESS Authenticate the payload successfully. + @retval otherwise Authentication of the payload fails. + +**/ +EFI_STATUS +IpSecCryptoIoHmac ( + IN CONST UINT8 AlgorithmId, + IN CONST UINT8 *Key, + IN UINTN KeyLength, + IN HASH_DATA_FRAGMENT *InDataFragment, + IN UINTN FragmentCount, + OUT UINT8 *OutData, + IN UINTN OutDataSize + ) +{ + UINTN ContextSize; + UINTN Index; + UINT8 FragmentIndex; + UINT8 *HashContext; + EFI_STATUS Status; + UINT8 *OutHashData; + UINTN OutHashSize; + + Status = EFI_UNSUPPORTED; + OutHashData = NULL; + + OutHashSize = IpSecGetHmacDigestLength (AlgorithmId); + // + // If the expected hash data size is larger than the related Hash algorithm + // output length, return EFI_INVALID_PARAMETER. + // + if (OutDataSize > OutHashSize) { + return EFI_INVALID_PARAMETER; + } + OutHashData = AllocatePool (OutHashSize); + + if (OutHashData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + switch (AlgorithmId) { + + case IKE_AALG_NONE : + case IKE_AALG_NULL : + return EFI_SUCCESS; + + case IKE_AALG_SHA1HMAC: + Index = IpSecGetIndexFromAuthList (AlgorithmId); + if (Index == -1) { + return Status; + } + + // + // Get Context Size + // + ContextSize = mIpsecAuthAlgorithmList[Index].HmacGetContextSize(); + HashContext = AllocateZeroPool (ContextSize); + + if (HashContext == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Initiate HMAC context and hash the input data. + // + if (mIpsecAuthAlgorithmList[Index].HmacInitiate(HashContext, Key, KeyLength)) { + for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) { + if (!mIpsecAuthAlgorithmList[Index].HmacUpdate ( + HashContext, + InDataFragment[FragmentIndex].Data, + InDataFragment[FragmentIndex].DataSize + ) + ) { + goto Exit; + } + } + if (mIpsecAuthAlgorithmList[Index].HmacFinal (HashContext, OutHashData)) { + // + // In some cases, like the Icv computing, the Icv size might be less than + // the key length size, so copy the part of hash data to the OutData. + // + CopyMem (OutData, OutHashData, OutDataSize); + Status = EFI_SUCCESS; + } + + goto Exit; + } + + default: + return Status; + } + +Exit: + if (HashContext != NULL) { + FreePool (HashContext); + } + if (OutHashData != NULL) { + FreePool (OutHashData); + } + + return Status; +} + +/** + Digests the Payload and store the result into the OutData. + + This function calls relevant Hash interface from CryptoLib according to + the input alogrithm ID. It computes all datas from InDataFragment and output + the result into the OutData buffer. If the OutDataSize is larger than the related + Hash alogrithm output size, return EFI_INVALID_PARAMETER. + + @param[in] AlgorithmId The authentication Identification. + @param[in] InDataFragment A list contains all data to be authenticated. + @param[in] FragmentCount The size of the InDataFragment. + @param[out] OutData For in, the buffer to receive the output data. + For out, the buffer contains the authenticated data. + @param[in] OutDataSize The size of the buffer of OutData. + + @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list. + @retval EFI_SUCCESS Authenticated the payload successfully. + @retval EFI_INVALID_PARAMETER If the OutDataSize is larger than the related Hash + algorithm could handle. + @retval otherwise Authentication of the payload failed. + +**/ +EFI_STATUS +IpSecCryptoIoHash ( + IN CONST UINT8 AlgorithmId, + IN HASH_DATA_FRAGMENT *InDataFragment, + IN UINTN FragmentCount, + OUT UINT8 *OutData, + IN UINTN OutDataSize + ) +{ + UINTN ContextSize; + UINTN Index; + UINT8 FragmentIndex; + UINT8 *HashContext; + EFI_STATUS Status; + UINT8 *OutHashData; + UINTN OutHashSize; + + Status = EFI_UNSUPPORTED; + OutHashData = NULL; + + OutHashSize = IpSecGetHmacDigestLength (AlgorithmId); + // + // If the expected hash data size is larger than the related Hash algorithm + // output length, return EFI_INVALID_PARAMETER. + // + if (OutDataSize > OutHashSize) { + return EFI_INVALID_PARAMETER; + } + OutHashData = AllocatePool (OutHashSize); + if (OutHashData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + switch (AlgorithmId) { + + case IKE_AALG_NONE: + case IKE_AALG_NULL: + return EFI_SUCCESS; + + case IKE_AALG_SHA1HMAC: + Index = IpSecGetIndexFromAuthList (AlgorithmId); + if (Index == -1) { + return Status; + } + // + // Get Context Size + // + ContextSize = mIpsecHashAlgorithmList[Index].HashGetContextSize(); + HashContext = AllocateZeroPool (ContextSize); + if (HashContext == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Initiate Hash context and hash the input data. + // + if (mIpsecHashAlgorithmList[Index].HashInitiate(HashContext)) { + for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) { + if (!mIpsecHashAlgorithmList[Index].HashUpdate ( + HashContext, + InDataFragment[FragmentIndex].Data, + InDataFragment[FragmentIndex].DataSize + ) + ) { + goto Exit; + } + } + if (mIpsecHashAlgorithmList[Index].HashFinal (HashContext, OutHashData)) { + // + // In some cases, like the Icv computing, the Icv size might be less than + // the key length size, so copy the part of hash data to the OutData. + // + CopyMem (OutData, OutHashData, OutDataSize); + Status = EFI_SUCCESS; + } + + goto Exit; + } + + default: + return Status; + } + +Exit: + if (HashContext != NULL) { + FreePool (HashContext); + } + if (OutHashData != NULL) { + FreePool (OutHashData); + } + + return Status; +} + +/** + Generates the Diffie-Hellman public key. + + This function first initiate a DHContext, then call the DhSetParameter() to set + the prime and primelenght, at end call the DhGenerateKey() to generates random + secret exponent, and computes the public key. The output returned via parameter + PublicKey and PublicKeySize. DH context is updated accordingly. If the PublicKey + buffer is too small to hold the public key, EFI_INVALID_PARAMETER is returned + and PublicKeySize is set to the required buffer size to obtain the public key. + + @param[in, out] DhContext Pointer to the DH context. + @param[in] Generator Vlaue of generator. + @param[in] PrimeLength Length in bits of prime to be generated. + @param[in] Prime Pointer to the buffer to receive the generated + prime number. + @param[out] PublicKey Pointer to the buffer to receive generated public key. + @param[in, out] PublicKeySize For in, the size of PublicKey buffer in bytes. + For out, the size of data returned in PublicKey + buffer in bytes. + + @retval EFI_SUCCESS The operation perfoms successfully. + @retval Otherwise The operation is failed. + +**/ +EFI_STATUS +IpSecCryptoIoDhGetPublicKey ( + IN OUT UINT8 **DhContext, + IN UINTN Generator, + IN UINTN PrimeLength, + IN CONST UINT8 *Prime, + OUT UINT8 *PublicKey, + IN OUT UINTN *PublicKeySize + ) +{ + EFI_STATUS Status; + + *DhContext = DhNew (); + ASSERT (*DhContext != NULL); + if (!DhSetParameter (*DhContext, Generator, PrimeLength, Prime)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + if (!DhGenerateKey (*DhContext, PublicKey, PublicKeySize)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + return EFI_SUCCESS; + +Exit: + if (*DhContext != NULL) { + DhFree (*DhContext); + DhContext = NULL; + } + + return Status; +} + +/** + Generates exchanged common key. + + Given peer's public key, this function computes the exchanged common key, based + on its own context including value of prime modulus and random secret exponent. + + @param[in, out] DhContext Pointer to the DH context. + @param[in] PeerPublicKey Pointer to the peer's Public Key. + @param[in] PeerPublicKeySize Size of peer's public key in bytes. + @param[out] Key Pointer to the buffer to receive generated key. + @param[in, out] KeySize For in, the size of Key buffer in bytes. + For out, the size of data returned in Key + buffer in bytes. + + @retval EFI_SUCCESS The operation perfoms successfully. + @retval Otherwise The operation is failed. + +**/ +EFI_STATUS +IpSecCryptoIoDhComputeKey ( + IN OUT UINT8 *DhContext, + IN CONST UINT8 *PeerPublicKey, + IN UINTN PeerPublicKeySize, + OUT UINT8 *Key, + IN OUT UINTN *KeySize + ) +{ + if (!DhComputeKey (DhContext, PeerPublicKey, PeerPublicKeySize, Key, KeySize)) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + Releases the DH context. If DhContext is NULL, return EFI_INVALID_PARAMETER. + + @param[in, out] DhContext Pointer to the DH context to be freed. + + @retval EFI_SUCCESS The operation perfoms successfully. + @retval EFI_INVALID_PARAMETER The DhContext is NULL. + +**/ +EFI_STATUS +IpSecCryptoIoFreeDh ( + IN OUT UINT8 **DhContext + ) +{ + if (*DhContext == NULL) { + return EFI_INVALID_PARAMETER; + } + + DhFree (*DhContext); return EFI_SUCCESS; } + +/** + Generates random numbers of specified size. + + If the Random Generator wasn't initiated, initiate it first, then call RandomBytes. + + @param[out] OutBuffer Pointer to buffer to receive random value. + @param[in] Bytes Size of randome bytes to generate. + + @retval EFI_SUCCESS The operation perfoms successfully. + @retval Otherwise The operation is failed. + +**/ +EFI_STATUS +IpSecCryptoIoGenerateRandomBytes ( + OUT UINT8* OutBuffer, + IN UINTN Bytes + ) +{ + if (!mInitialRandomSeed) { + RandomSeed (NULL, 0); + mInitialRandomSeed = TRUE; + } + if (RandomBytes (OutBuffer, Bytes)) { + return EFI_SUCCESS; + } else { + return EFI_INVALID_PARAMETER; + } +} + +/** + Authenticate data with the certificate. + + @param[in] InData Pointer to the Data to be signed. + @param[in] InDataSize InData size in bytes. + @param[in] PrivateKey Pointer to the private key. + @param[in] PrivateKeySize The size of Private Key in bytes. + @param[in] KeyPassWord Pointer to the password for retrieving private key. + @param[in] KeyPwdSize The size of Key Password in bytes. + @param[out] OutData The pointer to the signed data. + @param[in, out] OutDataSize Pointer to contain the size of out data. + +**/ +VOID +IpSecCryptoIoAuthDataWithCertificate ( + IN UINT8 *InData, + IN UINTN InDataSize, + IN UINT8 *PrivateKey, + IN UINTN PrivateKeySize, + IN UINT8 *KeyPassWord, + IN UINTN KeyPwdSize, + OUT UINT8 **OutData, + IN OUT UINTN *OutDataSize + ) +{ + UINT8 *RsaContext; + UINT8 *Signature; + UINTN SigSize; + + SigSize = 0; + // + // Retrieve RSA Private Key from password-protected PEM data + // + RsaGetPrivateKeyFromPem ( + (CONST UINT8 *)PrivateKey, + PrivateKeySize, + (CONST CHAR8 *)KeyPassWord, + (VOID **) &RsaContext + ); + if (RsaContext == NULL) { + return; + } + + // + // Sign data + // + Signature = NULL; + if (!RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize)) { + Signature = AllocateZeroPool (SigSize); + } else { + return; + } + + RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize); + + *OutData = Signature; + *OutDataSize = SigSize; + + if (RsaContext != NULL) { + RsaFree (RsaContext); + } +} + +/** + Verify the singed data with the public key which is contained in a certificate. + + @param[in] InCert Pointer to the Certificate which contains the + public key. + @param[in] InCertLen The size of Certificate in bytes. + @param[in] InCa Pointer to the CA certificate + @param[in] CaLen The size of CA certificate in bytes. + @param[in] InData Pointer to octect message hash to be checked. + @param[in] InDataSize Size of the message hash in bytes. + @param[in] Singnature The pointer to the RSA PKCS1-V1_5 signature to be verifed. + @param[in] SigSize Size of signature in bytes. + + @retval TRUE Valid signature encoded in PKCS1-v1_5. + @retval FALSE Invalid signature or invalid RSA context. + +**/ +BOOLEAN +IpSecCryptoIoVerifySignDataByCertificate ( + IN UINT8 *InCert, + IN UINTN CertLen, + IN UINT8 *InCa, + IN UINTN CaLen, + IN UINT8 *InData, + IN UINTN InDataSize, + IN UINT8 *Singnature, + IN UINTN SigSize + ) +{ + UINT8 *RsaContext; + BOOLEAN Status; + + // + // Create the RSA Context + // + RsaContext = RsaNew (); + if (RsaContext == NULL) { + return FALSE; + } + + // + // Verify the validity of X509 Certificate + // + if (!X509VerifyCert (InCert, CertLen, InCa, CaLen)) { + return FALSE; + } + + // + // Retrieve the RSA public Key from Certificate + // + RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **)&RsaContext); + + // + // Verify data + // + Status = RsaPkcs1Verify (RsaContext, InData, InDataSize, Singnature, SigSize); + + if (RsaContext != NULL) { + RsaFree (RsaContext); + } + + return Status; +} + +/** + Retrieves the RSA Public Key from one X509 certificate (DER format only). + + @param[in] InCert Pointer to the certificate. + @param[in] CertLen The size of the certificate in bytes. + @param[out] PublicKey Pointer to the retrieved public key. + @param[out] PublicKeyLen Size of Public Key in bytes. + + @retval EFI_SUCCESS Successfully get the public Key. + @retval EFI_INVALID_PARAMETER The certificate is malformed. + +**/ +EFI_STATUS +IpSecCryptoIoGetPublicKeyFromCert ( + IN UINT8 *InCert, + IN UINTN CertLen, + OUT UINT8 **PublicKey, + OUT UINTN *PublicKeyLen + ) +{ + UINT8 *RsaContext; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + // + // Create the RSA Context + // + RsaContext = RsaNew (); + + // + // Retrieve the RSA public key from CA Certificate + // + if (!RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **) &RsaContext)) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + *PublicKeyLen = 0; + + RsaGetKey (RsaContext, RsaKeyN, NULL, PublicKeyLen); + + *PublicKey = AllocateZeroPool (*PublicKeyLen); + ASSERT (*PublicKey != NULL); + + if (!RsaGetKey (RsaContext, RsaKeyN, *PublicKey, PublicKeyLen)) { + Status = EFI_INVALID_PARAMETER; + } + +EXIT: + if (RsaContext != NULL) { + RsaFree (RsaContext); + } + + return Status; +} + +/** + Retrieves the subject name from one X509 certificate (DER format only). + + @param[in] InCert Pointer to the X509 certificate. + @param[in] CertSize The size of the X509 certificate in bytes. + @param[out] CertSubject Pointer to the retrieved certificate subject. + @param[out] SubjectSize The size of Certificate Subject in bytes. + + @retval EFI_SUCCESS Retrieved the certificate subject successfully. + @retval EFI_INVALID_PARAMETER The certificate is malformed. + +**/ +EFI_STATUS +IpSecCryptoIoGetSubjectFromCert ( + IN UINT8 *InCert, + IN UINTN CertSize, + OUT UINT8 **CertSubject, + OUT UINTN *SubjectSize + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + *SubjectSize = 0; + X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize); + + *CertSubject = AllocateZeroPool (*SubjectSize); + if (!X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize)) { + Status = EFI_INVALID_PARAMETER; + } + + return Status; +} diff --git a/NetworkPkg/IpSecDxe/IpSecCryptIo.h b/NetworkPkg/IpSecDxe/IpSecCryptIo.h index ddceb12bb6..87e5a494c5 100644 --- a/NetworkPkg/IpSecDxe/IpSecCryptIo.h +++ b/NetworkPkg/IpSecDxe/IpSecCryptIo.h @@ -1,5 +1,5 @@ /** @file - Definition related to the Security operation. + Definitions related to the Cryptographic Operations in IPsec. Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
@@ -12,15 +12,21 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ - #ifndef _EFI_IPSEC_CRYPTIO_H_ #define _EFI_IPSEC_CRYPTIO_H_ #include #include +#include +#include +#include + +#include "IpSecImpl.h" +#include "IkeCommon.h" -#define IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE 2 +#define IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE 4 #define IPSEC_AUTH_ALGORITHM_LIST_SIZE 3 +#define IPSEC_HASH_ALGORITHM_LIST_SIZE 3 /// /// Authentication Algorithm Definition @@ -40,46 +46,49 @@ #define IKE_EALG_AESCBC 0x0C /** - Prototype of Hash GetContextSize. - + Prototype of HMAC GetContextSize. + Retrieves the size, in bytes, of the context buffer required. - + @return The size, in bytes, of the context buffer required. **/ typedef UINTN -(EFIAPI *CPL_HASH_GETCONTEXTSIZE) ( +(EFIAPI *CRYPTO_HMAC_GETCONTEXTSIZE) ( VOID ); /** - Prototype of Hash Operation Initiating. - + Prototype of HMAC Operation Initiating. + Initialization with a new context. - - @param[in,out] Context Input Context. - + @param[out] Context Input Context. + @param[in] Key Pointer to the key for HMAC. + @param[in] KeySize The length of the Key in bytes. + @retval TRUE Initialization Successfully. **/ typedef -EFI_STATUS -(EFIAPI *CPL_HASH_INIT) ( - IN OUT VOID *Context +BOOLEAN +(EFIAPI *CRYPTO_HMAC_INIT) ( + OUT VOID *Context, + IN CONST UINT8 *Key, + IN UINTN KeySize ); /** - Prototype of HASH update. - Hash update operation. Continue an Hash message digest operation, processing - another message block, and updating the Hash context. + Prototype of HMAC update. + HMAC update operation. Continue an HMAC message digest operation, processing + another message block, and updating the HMAC context. If Context is NULL, then ASSERT(). If Data is NULL, then ASSERT(). @param[in,out] Context The Specified Context. - @param[in,out] Data The Input Data to hash. + @param[in,out] Data The Input Data to be digested. @param[in] DataLength The length, in bytes, of Data. @retval TRUE Update data successfully. @@ -88,34 +97,34 @@ EFI_STATUS **/ typedef BOOLEAN -(EFIAPI *CPL_HASH_UPDATE) ( +(EFIAPI *CRYPTO_HMAC_UPDATE) ( IN OUT VOID *Context, IN CONST VOID *Data, IN UINTN DataLength ); /** - Prototype of Hash finallization. - Terminate a Hash message digest operation and output the message digest. + Prototype of HMAC finallization. + Terminate a HMAC message digest operation and output the message digest. If Context is NULL, then ASSERT(). If HashValue is NULL, then ASSERT(). @param[in,out] Context The specified Context. - @param[out] HashValue Pointer to a 16-byte message digest output buffer. + @param[out] HmacValue Pointer to a 16-byte message digest output buffer. @retval TRUE Finalized successfully. **/ typedef BOOLEAN -(EFIAPI *CPL_HASH_FINAL) ( +(EFIAPI *CRYPTO_HMAC_FINAL) ( IN OUT VOID *Context, - OUT UINT8 *HashValue + OUT UINT8 *HmacValue ); /** - Prototype of Cipher GetContextSize. + Prototype of Block Cipher GetContextSize. Retrieves the size, in bytes, of the context buffer required. @@ -124,12 +133,12 @@ BOOLEAN **/ typedef UINTN -(EFIAPI *CPL_CIPHER_GETCONTEXTSIZE) ( +(EFIAPI *CRYPTO_CIPHER_GETCONTEXTSIZE) ( VOID ); /** - Prototype of Cipher initiation. + Prototype of Block Cipher initiation. Intializes the user-supplied key as the specifed context (key materials) for both encryption and decryption operations. @@ -137,21 +146,20 @@ UINTN If Key is NULL, then generate random key for usage. @param[in,out] Context The specified Context. - @param[in] Key User-supplied TDES key (64/128/192 bits). + @param[in] Key User-supplied cipher key. @param[in] KeyBits Key length in bits. - @retval TRUE TDES Initialization was successful. + @retval TRUE Block Cipher Initialization was successful. **/ typedef BOOLEAN -(EFIAPI *CPL_CIPHER_INIT) ( +(EFIAPI *CRYPTO_CIPHER_INIT) ( IN OUT VOID *Context, IN CONST UINT8 *Key, - IN CONST UINTN KeyBits + IN UINTN KeyBits ); - /** Prototype of Cipher encryption. Encrypts plaintext message with the specified cipher. @@ -163,22 +171,23 @@ BOOLEAN @param[in] Context The specified Context. @param[in] InData The input plaintext data to be encrypted. + @param[in] InputSize The size of input data. + @param[in] Ivec Pointer to Initial Vector data for encryption. @param[out] OutData The resultant encrypted ciphertext. - @param[in] DataLength Length of input data in bytes. @retval TRUE Encryption successful. **/ typedef BOOLEAN -(EFIAPI *CPL_CIPHER_ENCRYPT) ( +(EFIAPI *CRYPTO_CIPHER_ENCRYPT) ( IN VOID *Context, IN CONST UINT8 *InData, - OUT UINT8 *OutData, - IN CONST UINTN DataLength + IN UINTN InputSize, + IN CONST UINT8 *Ivec, + OUT UINT8 *OutData ); - /** Prototype of Cipher decryption. Decrypts cipher message with specified cipher. @@ -189,61 +198,154 @@ BOOLEAN @param[in] Context The specified Context. @param[in] InData The input ciphertext data to be decrypted. + @param[in] InputSize The InData size. + @param[in] Ivec Pointer to the Initial Vector data for decryption. @param[out] OutData The resultant decrypted plaintext. - @param[in] DataLength Length of input data in bytes. @retval TRUE Decryption successful. **/ typedef BOOLEAN -(EFIAPI *CPL_CIPHER_DECRYPT) ( - IN CONST VOID *Context, +(EFIAPI *CRYPTO_CIPHER_DECRYPT) ( + IN VOID *Context, IN CONST UINT8 *InData, - OUT UINT8 *OutData, - IN CONST UINTN DataLength + IN UINTN InputSize, + IN CONST UINT8 *Ivec, + OUT UINT8 *OutData + ); + +/** + Prototype of Hash ContextSize. + + Retrieves the size, in bytes, of the context buffer required for specified hash operations. + + @return The size, in bytes, of the context buffer required for certain hash operations. + +**/ +typedef +UINTN +(EFIAPI *CRYPTO_HASH_GETCONTEXTSIZE) ( + VOID + ); + +/** + Prototype of Hash Initiate. + + Initializes user-supplied memory pointed by Context as specified hash context for + subsequent use. + + If Context is NULL, then ASSERT(). + + @param[out] Context Pointer to specified context being initialized. + + @retval TRUE context initialization succeeded. + @retval FALSE context initialization failed. + +**/ +typedef +BOOLEAN +(EFIAPI *CRYPTO_HASH_INIT) ( + OUT VOID *Context + ); + +/** + Prototype of Hash Update + + Digests the input data and updates hash context. + + This function performs digest on a data buffer of the specified size. + It can be called multiple times to compute the digest of long or discontinuous data streams. + Context should be already correctly intialized by HashInit(), and should not be finalized + by HashFinal(). Behavior with invalid context is undefined. + + If Context is NULL, then ASSERT(). + + @param[in, out] Context Pointer to the specified context. + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataSize Size of Data buffer in bytes. + + @retval TRUE data digest succeeded. + @retval FALSE data digest failed. + +**/ +typedef +BOOLEAN +(EFIAPI *CRYPTO_HASH_UPDATE) ( + IN OUT VOID *Context, + IN CONST VOID *Data, + IN UINTN DataSize + ); + +/** + Prototype of Hash Finalization. + + Completes computation of the digest value. + + This function completes hash computation and retrieves the digest value into + the specified memory. After this function has been called, the context cannot + be used again. + context should be already correctly intialized by HashInit(), and should not be + finalized by HashFinal(). Behavior with invalid context is undefined. + + If Context is NULL, then ASSERT(). + If HashValue is NULL, then ASSERT(). + + @param[in, out] Context Pointer to the specified context. + @param[out] HashValue Pointer to a buffer that receives the digest + value. + + @retval TRUE digest computation succeeded. + @retval FALSE digest computation failed. + +**/ +typedef +BOOLEAN +(EFIAPI *CRYPTO_HASH_FINAL) ( + IN OUT VOID *Context, + OUT UINT8 *HashValue ); // -// The struct used to store the informatino and operation of Cipher algorithm. +// The struct used to store the information and operation of Block Cipher algorithm. // typedef struct _ENCRYPT_ALGORITHM { -// -// The ID of the Algorithm -// -UINT8 AlgorithmId; -// -// The Key length of the Algorithm -// -UINTN KeyLength; -// -// Iv Size of the Algorithm -// -UINTN IvLength; -// -// The Block Size of the Algorithm -// -UINTN BlockSize; -// -// The Function pointer of GetContextSize. -// -CPL_CIPHER_GETCONTEXTSIZE CipherGetContextSize; -// -// The Function pointer of Cipher intitiaion. -// -CPL_CIPHER_INIT CipherInitiate; -// -// The Function pointer of Cipher Encryption. -// -CPL_CIPHER_ENCRYPT CipherEncrypt; -// -// The Function pointer of Cipher Decrption. -// -CPL_CIPHER_DECRYPT CipherDecrypt; + // + // The ID of the Algorithm + // + UINT8 AlgorithmId; + // + // The Key length of the Algorithm + // + UINTN KeyLength; + // + // Iv Size of the Algorithm + // + UINTN IvLength; + // + // The Block Size of the Algorithm + // + UINTN BlockSize; + // + // The Function pointer of GetContextSize. + // + CRYPTO_CIPHER_GETCONTEXTSIZE CipherGetContextSize; + // + // The Function pointer of Cipher initiation. + // + CRYPTO_CIPHER_INIT CipherInitiate; + // + // The Function pointer of Cipher Encryption. + // + CRYPTO_CIPHER_ENCRYPT CipherEncrypt; + // + // The Function pointer of Cipher Decrption. + // + CRYPTO_CIPHER_DECRYPT CipherDecrypt; } ENCRYPT_ALGORITHM; // -// The struct used to store the informatino and operation of Autahentication algorithm. +// The struct used to store the information and operation of Autahentication algorithm. // typedef struct _AUTH_ALGORITHM { // @@ -252,8 +354,8 @@ typedef struct _AUTH_ALGORITHM { UINT8 AlgorithmId; // // The Key length of the Algorithm - // - UINTN KeyLength; + // + UINTN DigestLength; // // The ICV length of the Algorithm // @@ -265,25 +367,63 @@ typedef struct _AUTH_ALGORITHM { // // The function pointer of GetContextSize. // - CPL_HASH_GETCONTEXTSIZE HashGetContextSize; + CRYPTO_HMAC_GETCONTEXTSIZE HmacGetContextSize; // - // The function pointer of Initiatoion + // The function pointer of Initiation // - CPL_HASH_INIT HashInitiate; + CRYPTO_HMAC_INIT HmacInitiate; // - // The function pointer of Hash Update. + // The function pointer of HMAC Update. // - CPL_HASH_UPDATE HashUpdate; + CRYPTO_HMAC_UPDATE HmacUpdate; // - // The fucntion pointer of Hash Final + // The fucntion pointer of HMAC Final // - CPL_HASH_FINAL HashFinal; + CRYPTO_HMAC_FINAL HmacFinal; } AUTH_ALGORITHM; +// +// The struct used to store the informatino and operation of Hash algorithm. +// +typedef struct _HASH_ALGORITHM { + // + // ID of the Algorithm + // + UINT8 AlgorithmId; + // + // The Key length of the Algorithm + // + UINTN DigestLength; + // + // The ICV length of the Algorithm + // + UINTN IcvLength; + // + // The block size of the Algorithm + // + UINTN BlockSize; + // + // The function pointer of GetContextSize + // + CRYPTO_HASH_GETCONTEXTSIZE HashGetContextSize; + // + // The function pointer of Initiation + // + CRYPTO_HASH_INIT HashInitiate; + // + // The function pointer of Hash Update + // + CRYPTO_HASH_UPDATE HashUpdate; + // + // The fucntion pointer of Hash Final + // + CRYPTO_HASH_FINAL HashFinal; +} HASH_ALGORITHM; + /** - Get the IV size of encrypt alogrithm. IV size is different from different algorithm. + Get the IV size of specified encryption alogrithm. - @param[in] AlgorithmId The encrypt algorithm ID. + @param[in] AlgorithmId The encryption algorithm ID. @return The value of IV size. @@ -294,9 +434,9 @@ IpSecGetEncryptIvLength ( ); /** - Get the block size of encrypt alogrithm. Block size is different from different algorithm. + Get the block size of specified encryption alogrithm. - @param[in] AlgorithmId The encrypt algorithm ID. + @param[in] AlgorithmId The encryption algorithm ID. @return The value of block size. @@ -307,16 +447,42 @@ IpSecGetEncryptBlockSize ( ); /** - Get the ICV size of Authenticaion alogrithm. ICV size is different from different algorithm. + Get the required key length of the specified encryption alogrithm. - @param[in] AuthAlgorithmId The Authentication algorithm ID. + @param[in] AlgorithmId The encryption algorithm ID. + + @return The value of key length. + +**/ +UINTN +IpSecGetEncryptKeyLength ( + IN UINT8 AlgorithmId + ); + +/** + Get the ICV size of the specified Authenticaion alogrithm. + + @param[in] AlgorithmId The Authentication algorithm ID. @return The value of ICV size. **/ UINTN IpSecGetIcvLength ( - IN UINT8 AuthAlgorithmId + IN UINT8 AlgorithmId + ); + +/** + Get the HMAC digest length by the specified Algorithm ID. + + @param[in] AlgorithmId The specified Alogrithm ID. + + @return The digest length of the specified Authentication Algorithm ID. + +**/ +UINTN +IpSecGetHmacDigestLength ( + IN UINT8 AlgorithmId ); /** @@ -324,7 +490,7 @@ IpSecGetIcvLength ( IV and return EFI_SUCCESS. @param[in] IvBuffer The pointer of the IV buffer. - @param[in] IvSize The IV size. + @param[in] IvSize The IV size in bytes. @retval EFI_SUCCESS Create random data for IV. @@ -335,5 +501,327 @@ IpSecGenerateIv ( IN UINTN IvSize ); +/** + Encrypt the buffer. + + This function calls relevant encryption interface from CryptoLib according to + the input alogrithm ID. The InData should be multiple of block size. This function + doesn't perform the padding. If it has the Ivec data, the length of it should be + same with the block size. The block size is different from the different algorithm. + + @param[in] AlgorithmId The Alogrithem identification defined in RFC. + @param[in] Key Pointer to the buffer containing encrypting key. + @param[in} KeyBits The length of the key in bits. + @param[in] Ivec Point to the buffer containning the Initializeion + Vector (IV) data. + @param[in] InData Point to the buffer containing the data to be + encrypted. + @param[in] InDataLength The length of InData in Bytes. + @param[out] OutData Point to the buffer that receives the encryption + output. + + @retval EFI_UNSUPPORTED The input Algorithm is not supported. + @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated. + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +IpSecCryptoIoEncrypt ( + IN CONST UINT8 AlgorithmId, + IN CONST UINT8 *Key, + IN CONST UINTN KeyBits, + IN CONST UINT8 *Ivec, OPTIONAL + IN UINT8 *InData, + IN UINTN InDataLength, + OUT UINT8 *OutData + ); + +/** + Decrypts the buffer. + + This function calls relevant Decryption interface from CryptoLib according to + the input alogrithm ID. The InData should be multiple of block size. This function + doesn't perform the padding. If it has the Ivec data, the length of it should be + same with the block size. The block size is different from the different algorithm. + + @param[in] AlgorithmId The Alogrithem identification defined in RFC. + @param[in] Key Pointer to the buffer containing encrypting key. + @param[in} KeyBits The length of the key in bits. + @param[in] Ivec Point to the buffer containning the Initializeion + Vector (IV) data. + @param[in] InData Point to the buffer containing the data to be + Decrypted. + @param[in] InDataLength The length of InData in Bytes. + @param[out] OutData Pointer to the buffer that receives the decryption + output. + + @retval EFI_UNSUPPORTED The input Algorithm is not supported. + @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated. + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +IpSecCryptoIoDecrypt ( + IN CONST UINT8 AlgorithmId, + IN CONST UINT8 *Key, + IN CONST UINTN KeyBits, + IN CONST UINT8 *Ivec, OPTIONAL + IN UINT8 *InData, + IN UINTN InDataLength, + OUT UINT8 *OutData + ); + +/** + Digests the Payload with key and store the result into the OutData. + + This function calls relevant Hmac interface from CryptoLib according to + the input alogrithm ID. It computes all datas from InDataFragment and output + the result into the OutData buffer. If the OutDataSize is larger than the related + HMAC alogrithm output size, return EFI_INVALID_PARAMETER. + + @param[in] AlgorithmId The authentication Identification. + @param[in] Key Pointer of the authentication key. + @param[in] KeyLength The length of the Key in bytes. + @param[in] InDataFragment The list contains all data to be authenticated. + @param[in] FragmentCount The size of the InDataFragment. + @param[out] OutData For in, the buffer to receive the output data. + For out, the buffer contains the authenticated data. + @param[in] OutDataSize The size of the buffer of OutData. + + @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list. + @retval EFI_INVALID_PARAMETER The OutData buffer size is larger than algorithm digest size. + @retval EFI_SUCCESS Authenticate the payload successfully. + @retval otherwise Authentication of the payload fails. + +**/ +EFI_STATUS +IpSecCryptoIoHmac ( + IN CONST UINT8 AlgorithmId, + IN CONST UINT8 *Key, + IN UINTN KeyLength, + IN HASH_DATA_FRAGMENT *InDataFragment, + IN UINTN FragmentCount, + OUT UINT8 *OutData, + IN UINTN OutDataSize + ); + +/** + Digests the Payload and store the result into the OutData. + + This function calls relevant Hash interface from CryptoLib according to + the input alogrithm ID. It computes all datas from InDataFragment and output + the result into the OutData buffer. If the OutDataSize is larger than the related + Hash alogrithm output size, return EFI_INVALID_PARAMETER. + + @param[in] AlgorithmId The authentication Identification. + @param[in] InDataFragment A list contains all data to be authenticated. + @param[in] FragmentCount The size of the InDataFragment. + @param[out] OutData For in, the buffer to receive the output data. + For out, the buffer contains the authenticated data. + @param[in] OutDataSize The size of the buffer of OutData. + + @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list. + @retval EFI_SUCCESS Authenticated the payload successfully. + @retval EFI_INVALID_PARAMETER If the OutDataSize is larger than the related Hash + algorithm could handle. + @retval otherwise Authentication of the payload failed. + +**/ +EFI_STATUS +IpSecCryptoIoHash ( + IN CONST UINT8 AlgorithmId, + IN HASH_DATA_FRAGMENT *InDataFragment, + IN UINTN FragmentCount, + OUT UINT8 *OutData, + IN UINTN OutDataSize + ); + +/** + Generates the Diffie-Hellman public key. + + This function first initiate a DHContext, then call the DhSetParameter() to set + the prime and primelenght, at end call the DhGenerateKey() to generates random + secret exponent, and computes the public key. The output returned via parameter + PublicKey and PublicKeySize. DH context is updated accordingly. If the PublicKey + buffer is too small to hold the public key, EFI_INVALID_PARAMETER is returned + and PublicKeySize is set to the required buffer size to obtain the public key. + + @param[in, out] DhContext Pointer to the DH context. + @param[in] Generator Vlaue of generator. + @param[in] PrimeLength Length in bits of prime to be generated. + @param[in] Prime Pointer to the buffer to receive the generated + prime number. + @param[out] PublicKey Pointer to the buffer to receive generated public key. + @param[in, out] PublicKeySize For in, the size of PublicKey buffer in bytes. + For out, the size of data returned in PublicKey + buffer in bytes. + + @retval EFI_SUCCESS The operation perfoms successfully. + @retval Otherwise The operation is failed. + +**/ +EFI_STATUS +IpSecCryptoIoDhGetPublicKey ( + IN OUT UINT8 **DhContext, + IN UINTN Generator, + IN UINTN PrimeLength, + IN CONST UINT8 *Prime, + OUT UINT8 *PublicKey, + IN OUT UINTN *PublicKeySize + ); + +/** + Generates exchanged common key. + + Given peer's public key, this function computes the exchanged common key, based + on its own context including value of prime modulus and random secret exponent. + + @param[in, out] DhContext Pointer to the DH context. + @param[in] PeerPublicKey Pointer to the peer's Public Key. + @param[in] PeerPublicKeySize Size of peer's public key in bytes. + @param[out] Key Pointer to the buffer to receive generated key. + @param[in, out] KeySize For in, the size of Key buffer in bytes. + For out, the size of data returned in Key + buffer in bytes. + + @retval EFI_SUCCESS The operation perfoms successfully. + @retval Otherwise The operation is failed. + +**/ +EFI_STATUS +IpSecCryptoIoDhComputeKey ( + IN OUT UINT8 *DhContext, + IN CONST UINT8 *PeerPublicKey, + IN UINTN PeerPublicKeySize, + OUT UINT8 *Key, + IN OUT UINTN *KeySize + ); + +/** + Releases the DH context. If DhContext is NULL, return EFI_INVALID_PARAMETER. + + @param[in, out] DhContext Pointer to the DH context to be freed. + + @retval EFI_SUCCESS The operation perfoms successfully. + @retval EFI_INVALID_PARAMETER The DhContext is NULL. + +**/ +EFI_STATUS +IpSecCryptoIoFreeDh ( + IN OUT UINT8 **DhContext + ); + +/** + Generates random numbers of specified size. + + If the Random Generator wasn't initiated, initiate it first, then call RandomBytes. + + @param[out] OutBuffer Pointer to buffer to receive random value. + @param[in] Bytes Size of randome bytes to generate. + + @retval EFI_SUCCESS The operation perfoms successfully. + @retval Otherwise The operation is failed. + +**/ +EFI_STATUS +IpSecCryptoIoGenerateRandomBytes ( + OUT UINT8* OutBuffer, + IN UINTN Bytes + ); + +/** + Authenticate data with the certificate. + + @param[in] InData Pointer to the Data to be signed. + @param[in] InDataSize InData size in bytes. + @param[in] PrivateKey Pointer to the private key. + @param[in] PrivateKeySize The size of Private Key in bytes. + @param[in] KeyPassWord Pointer to the password for retrieving private key. + @param[in] KeyPwdSize The size of Key Password in bytes. + @param[out] OutData The pointer to the signed data. + @param[in, out] OutDataSize Pointer to contain the size of out data. + +**/ +VOID +IpSecCryptoIoAuthDataWithCertificate ( + IN UINT8 *InData, + IN UINTN InDataSize, + IN UINT8 *PrivateKey, + IN UINTN PrivateKeySize, + IN UINT8 *KeyPassWord, + IN UINTN KeyPwdSize, + OUT UINT8 **OutData, + IN OUT UINTN *OutDataSize + ); + +/** + Verify the singed data with the public key which is contained in a certificate. + + @param[in] InCert Pointer to the Certificate which contains the + public key. + @param[in] InCertLen The size of Certificate in bytes. + @param[in] InCa Pointer to the CA certificate + @param[in] CaLen The size of CA certificate in bytes. + @param[in] InData Pointer to octect message hash to be checked. + @param[in] InDataSize Size of the message hash in bytes. + @param[in] Singnature The pointer to the RSA PKCS1-V1_5 signature to be verifed. + @param[in] SigSize Size of signature in bytes. + + @retval TRUE Valid signature encoded in PKCS1-v1_5. + @retval FALSE Invalid signature or invalid RSA context. + +**/ +BOOLEAN +IpSecCryptoIoVerifySignDataByCertificate ( + IN UINT8 *InCert, + IN UINTN CertLen, + IN UINT8 *InCa, + IN UINTN CaLen, + IN UINT8 *InData, + IN UINTN InDataSize, + IN UINT8 *Singnature, + IN UINTN SigSize + ); + +/** + Retrieves the RSA Public Key from one X509 certificate (DER format only). + + @param[in] InCert Pointer to the certificate. + @param[in] CertLen The size of the certificate in bytes. + @param[out] PublicKey Pointer to the retrieved public key. + @param[out] PublicKeyLen Size of Public Key in bytes. + + @retval EFI_SUCCESS Successfully get the public Key. + @retval EFI_INVALID_PARAMETER The CA certificate is malformed. + +**/ +EFI_STATUS +IpSecCryptoIoGetPublicKeyFromCert ( + IN UINT8 *InCert, + IN UINTN CertLen, + OUT UINT8 **PublicKey, + OUT UINTN *PublicKeyLen + ); + +/** + Retrieves the subject name from one X509 certificate (DER format only). + + @param[in] InCert Pointer to the X509 certificate. + @param[in] CertSize The size of the X509 certificate in bytes. + @param[out] CertSubject Pointer to the retrieved certificate subject. + @param[out] SubjectSize The size of Certificate Subject in bytes. + + @retval EFI_SUCCESS Retrieved the certificate subject successfully. + @retval EFI_INVALID_PARAMETER The certificate is malformed. + +**/ +EFI_STATUS +IpSecCryptoIoGetSubjectFromCert ( + IN UINT8 *InCert, + IN UINTN CertSize, + OUT UINT8 **CertSubject, + OUT UINTN *SubjectSize + ); + #endif diff --git a/NetworkPkg/IpSecDxe/IpSecDebug.c b/NetworkPkg/IpSecDxe/IpSecDebug.c index 8a5811b960..56b35a1a14 100644 --- a/NetworkPkg/IpSecDxe/IpSecDebug.c +++ b/NetworkPkg/IpSecDxe/IpSecDebug.c @@ -1,5 +1,5 @@ /** @file - Interface of IPsec printing debug information. + The Interfaces of IPsec debug information printing. Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
@@ -19,7 +19,7 @@ // // The print title for IKEv1 variety phase. // -CHAR8 *mStateStr[] = { +CHAR8 *mIkev1StateStr[] = { "IKEv1_MAIN_1", "IKEv1_MAIN_2", "IKEv1_MAIN_3", @@ -28,6 +28,20 @@ CHAR8 *mStateStr[] = { "IKEv1_QUICK_2", "IKEv1_QUICK_ESTABLISHED" }; + +// +// The print title for IKEv2 variety phase. +// +CHAR8 *mIkev2StateStr[] = { + "IKEv2_STATE_INIT", + "IKEv2_STATE_AUTH", + "IKEv2_STATE_SA_ESTABLISH", + "IKEv2_STATE_CREATE_CHILD", + "IKEv2_STATE_SA_REKEYING", + "IKEv2_STATE_CHILD_SA_ESTABLISHED", + "IKEv2_STATE_SA_DELETING" +}; + // // The print title for IKEv1 variety Exchagne. // @@ -35,13 +49,17 @@ CHAR8 *mExchangeStr[] = { "IKEv1 Main Exchange", "IKEv1 Info Exchange", "IKEv1 Quick Exchange", - "IKEv1 Unknown Exchange" + "IKEv2 Initial Exchange", + "IKEv2 Auth Exchange", + "IKEv2 Create Child Exchange", + "IKEv2 Info Exchange", + "IKE Unknow Exchange" }; // // The print title for IKEv1 variety Payload. // -CHAR8 *mPayloadStr[] = { +CHAR8 *mIkev1PayloadStr[] = { "IKEv1 None Payload", "IKEv1 SA Payload", "IKEv1 Proposal Payload", @@ -58,6 +76,28 @@ CHAR8 *mPayloadStr[] = { "IKEv1 Vendor Payload" }; +// +// The print title for IKEv2 variety Payload. +// +CHAR8* mIkev2PayloadStr[] = { + "IKEv2 SA Payload", + "IKEv2 Key Payload", + "IKEv2 Identity Initial Payload", + "IKEv2 Identity Respond Payload", + "IKEv2 Certificate Payload", + "IKEv2 Certificate Request Payload", + "IKEv2 Auth Payload", + "IKEv2 Nonce Payload", + "IKEv2 Notify Payload", + "IKEv2 Delet Payload", + "IKEv2 Vendor Payload", + "IKEv2 Traffic Selector Initiator Payload", + "IKEv2 Traffic Selector Respond Payload", + "IKEv2 Encrypt Payload", + "IKEv2 Configuration Payload", + "IKEv2 Extensible Authentication Payload" +}; + /** Print the IP address. @@ -112,24 +152,146 @@ IpSecDumpAddress ( } /** - Print IKEv1 Current states. + Print IKE Current states. - @param[in] Previous The Previous state of IKEv1. - @param[in] Current The current state of IKEv1. + @param[in] Previous The Previous state of IKE. + @param[in] Current The current state of IKE. + @param[in] IkeVersion The version of IKE. **/ VOID -IpSecDumpState ( +IkeDumpState ( IN UINT32 Previous, - IN UINT32 Current + IN UINT32 Current, + IN UINT8 IkeVersion ) { + if (Previous == Current) { - DEBUG ((DEBUG_INFO, "\n****Current state is %a\n", mStateStr[Previous])); + if (IkeVersion == 1) { + DEBUG ((DEBUG_INFO, "\n****Current state is %a\n", mIkev1StateStr[Previous])); + } else if (IkeVersion == 2) { + DEBUG ((DEBUG_INFO, "\n****Current state is %a\n", mIkev2StateStr[Previous])); + } + + } else { + if (IkeVersion == 1) { + DEBUG ((DEBUG_INFO, "\n****Change state from %a to %a\n", mIkev1StateStr[Previous], mIkev1StateStr[Current])); + } else { + DEBUG ((DEBUG_INFO, "\n****Change state from %a to %a\n", mIkev2StateStr[Previous], mIkev2StateStr[Current])); + } + + } + +} + +/** + Print the IKE Packet. + + @param[in] Packet Point to IKE packet to be printed. + @param[in] Direction Point to the IKE packet is inbound or outbound. + @param[in] IpVersion Specified IP Version. + +**/ +VOID +IpSecDumpPacket ( + IN IKE_PACKET *Packet, + IN EFI_IPSEC_TRAFFIC_DIR Direction, + IN UINT8 IpVersion + ) +{ + CHAR8 *TypeStr; + UINTN PacketSize; + UINT64 InitCookie; + UINT64 RespCookie; + + ASSERT (Packet != NULL); + + PacketSize = Packet->PayloadTotalSize + sizeof (IKE_HEADER); + InitCookie = (Direction == EfiIPsecOutBound) ? HTONLL (Packet->Header->InitiatorCookie) : Packet->Header->InitiatorCookie; + RespCookie = (Direction == EfiIPsecOutBound) ? HTONLL (Packet->Header->ResponderCookie) : Packet->Header->ResponderCookie; + + switch (Packet->Header->ExchangeType) { + case IKE_XCG_TYPE_IDENTITY_PROTECT: + TypeStr = mExchangeStr[0]; + break; + + case IKE_XCG_TYPE_INFO: + TypeStr = mExchangeStr[1]; + break; + + case IKE_XCG_TYPE_QM: + TypeStr = mExchangeStr[2]; + break; + + case IKE_XCG_TYPE_SA_INIT: + TypeStr = mExchangeStr[3]; + break; + + case IKE_XCG_TYPE_AUTH: + TypeStr = mExchangeStr[4]; + break; + + case IKE_XCG_TYPE_CREATE_CHILD_SA: + TypeStr = mExchangeStr[5]; + break; + + case IKE_XCG_TYPE_INFO2: + TypeStr = mExchangeStr[6]; + break; + + default: + TypeStr = mExchangeStr[7]; + break; + } + + if (Direction == EfiIPsecOutBound) { + DEBUG ((DEBUG_INFO, "\n>>>Sending %d bytes %a to ", PacketSize, TypeStr)); } else { - DEBUG ((DEBUG_INFO, "\n****Change state from %a to %a\n", mStateStr[Previous], mStateStr[Current])); + DEBUG ((DEBUG_INFO, "\n>>>Receiving %d bytes %a from ", PacketSize, TypeStr)); } + IpSecDumpAddress (DEBUG_INFO, &Packet->RemotePeerIp, IpVersion); + + DEBUG ((DEBUG_INFO, " InitiatorCookie:0x%lx ResponderCookie:0x%lx\n", InitCookie, RespCookie)); + DEBUG ( + (DEBUG_INFO, + " Version: 0x%x Flags:0x%x ExchangeType:0x%x\n", + Packet->Header->Version, + Packet->Header->Flags, + Packet->Header->ExchangeType) + ); + DEBUG ( + (DEBUG_INFO, + " MessageId:0x%x NextPayload:0x%x\n", + Packet->Header->MessageId, + Packet->Header->NextPayload) + ); + +} + +/** + Print the IKE Paylolad. + + @param[in] IkePayload Point to payload to be printed. + @param[in] IkeVersion The specified version of IKE. + +**/ +VOID +IpSecDumpPayload ( + IN IKE_PAYLOAD *IkePayload, + IN UINT8 IkeVersion + ) +{ + if (IkeVersion == 1) { + DEBUG ((DEBUG_INFO, "+%a\n", mIkev1PayloadStr[IkePayload->PayloadType])); + } else { + // + // For IKEV2 the first Payload type is started from 33. + // + DEBUG ((DEBUG_INFO, "+%a\n", mIkev2PayloadStr[IkePayload->PayloadType - 33])); + } + IpSecDumpBuf ("Payload data", IkePayload->PayloadBuf, IkePayload->PayloadSize); } /** diff --git a/NetworkPkg/IpSecDxe/IpSecDebug.h b/NetworkPkg/IpSecDxe/IpSecDebug.h index 0e6e6811c5..d44677f300 100644 --- a/NetworkPkg/IpSecDxe/IpSecDebug.h +++ b/NetworkPkg/IpSecDxe/IpSecDebug.h @@ -1,5 +1,5 @@ /** @file - The definition of functions and MACROs used for IPsec debug information print. + The definition of functions and MACROs used for IPsec debug information printting. Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
@@ -12,16 +12,18 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ - #ifndef _EFI_IPSEC_DEBUG_H_ #define _EFI_IPSEC_DEBUG_H_ -#include +#include "IkeCommon.h" +#include "IkePacket.h" #define IPSEC_DUMP_ADDRESS(Level, Ip, Version) IpSecDumpAddress (Level, Ip, Version) -#define IPSEC_DUMP_STATE(Previous, Current) IpSecDumpState (Previous, Current) +#define IKEV1_DUMP_STATE(Previous, Current) IkeDumpState (Previous, Current, 1) +#define IKEV2_DUMP_STATE(Previous, Current) IkeDumpState (Previous, Current, 2) #define IPSEC_DUMP_PACKET(Packet, Direction, IpVersion) IpSecDumpPacket (Packet, Direction, IpVersion) -#define IPSEC_DUMP_PAYLOAD(IkePayload) IpSecDumpPayload (IkePayload) +#define IPSEC_DUMP_PAYLOAD(IkePayload) IpSecDumpPayload (IkePayload, 1) +#define IKEV2_DUMP_PAYLOAD(IkePayload) IpSecDumpPayload (IkePayload, 2) #define IPSEC_DUMP_BUF(Title, Data, DataSize) IpSecDumpBuf (Title, Data, DataSize) #define IPSEC_DEBUG_BYTE_PER_LINE 8 @@ -43,52 +45,53 @@ IpSecDumpAddress ( ); /** - Print IKEv1 Current states. + Print IKE Current states. - @param[in] Previous The Previous state of IKEv1. - @param[in] Current The current state of IKEv1. + @param[in] Previous The Previous state of IKE. + @param[in] Current The current state of IKE. + @param[in] IkeVersion The version of IKE. **/ VOID -IpSecDumpState ( +IkeDumpState ( IN UINT32 Previous, - IN UINT32 Current + IN UINT32 Current, + IN UINT8 IkeVersion ); /** - Print the Ike Packet. + Print the IKE Packet. @param[in] Packet Point to IKE packet to be printed. @param[in] Direction Point to the IKE packet is inbound or outbound. @param[in] IpVersion Specified IP Version. **/ -/* VOID IpSecDumpPacket ( IN IKE_PACKET *Packet, IN EFI_IPSEC_TRAFFIC_DIR Direction, IN UINT8 IpVersion ); -*/ /** Print the IKE Paylolad. - @param[in] IkePayload Points to the payload to be printed. - + @param[in] IkePayload Point to payload to be printed. + @param[in] IkeVersion The specified version of IKE. + **/ -/* VOID IpSecDumpPayload ( - IN IKE_PAYLOAD *IkePayload + IN IKE_PAYLOAD *IkePayload, + IN UINT8 IkeVersion ); -*/ + /** Print the buffer in form of Hex. @param[in] Title The strings to be printed before the data of the buffer. - @param[in] Data Points to the buffer to be printed. + @param[in] Data Point to buffer to be printed. @param[in] DataSize The size of the buffer to be printed. **/ diff --git a/NetworkPkg/IpSecDxe/IpSecDriver.c b/NetworkPkg/IpSecDxe/IpSecDriver.c index 00fb26f761..7e0d1fa4ed 100644 --- a/NetworkPkg/IpSecDxe/IpSecDriver.c +++ b/NetworkPkg/IpSecDxe/IpSecDriver.c @@ -13,8 +13,10 @@ **/ -#include +#include + #include "IpSecConfigImpl.h" +#include "IkeService.h" #include "IpSecDebug.h" /** @@ -38,9 +40,34 @@ IpSecDriverBindingSupported ( IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL ) { + EFI_STATUS Udp4Status; + EFI_STATUS Udp6Status; + + Udp4Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + Udp6Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + // - //TODO: Add Udp4Protocol and Udp6Protocol testing. + // The controller with either Udp4Sb or Udp6Sb is supported. // + if (!EFI_ERROR (Udp4Status) || !EFI_ERROR (Udp6Status)) { + return EFI_SUCCESS; + } + return EFI_UNSUPPORTED; } @@ -54,7 +81,7 @@ IpSecDriverBindingSupported ( @retval EFI_SUCCES This driver is added to ControllerHandle @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle - @retval EFI_DEVICE_ERROR The device could not be started due to a device error. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error. Currently not implemented. @retval other This driver does not support this device @@ -67,10 +94,59 @@ IpSecDriverBindingStart ( IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL ) { + EFI_IPSEC_PROTOCOL *IpSec; + EFI_STATUS Status; + EFI_STATUS Udp4Status; + EFI_STATUS Udp6Status; + IPSEC_PRIVATE_DATA *Private; + // - //TODO: Add Udp4Io and Udp6Io creation for the IKE. + // Ipsec protocol should be installed when load image. // - return EFI_SUCCESS; + Status = gBS->LocateProtocol (&gEfiIpSecProtocolGuid, NULL, (VOID **) &IpSec); + + if (EFI_ERROR (Status)) { + return Status; + } + + Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (IpSec); + + // + // If udp4 sb is on the controller, try to open a udp4 io for input. + // + Udp4Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + if (!EFI_ERROR (Udp4Status)) { + Udp4Status = IkeOpenInputUdp4 (Private, ControllerHandle); + } + // + // If udp6 sb is on the controller, try to open a udp6 io for input. + // + Udp6Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + if (!EFI_ERROR (Udp6Status)) { + Udp6Status = IkeOpenInputUdp6 (Private, ControllerHandle); + } + + if (!EFI_ERROR (Udp4Status) || !EFI_ERROR (Udp6Status)) { + return EFI_SUCCESS; + } + + return EFI_DEVICE_ERROR; } /** @@ -95,10 +171,78 @@ IpSecDriverBindingStop ( IN EFI_HANDLE *ChildHandleBuffer ) { + EFI_IPSEC_PROTOCOL *IpSec; + EFI_STATUS Status; + IPSEC_PRIVATE_DATA *Private; + IKE_UDP_SERVICE *UdpSrv; + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + // - //TODO: Add UdpIo4 and UdpIo6 destruction when the Udp driver unload or stop. + // Locate ipsec protocol to get private data. // - return EFI_UNSUPPORTED; + Status = gBS->LocateProtocol (&gEfiIpSecProtocolGuid, NULL, (VOID **) &IpSec); + + if (EFI_ERROR (Status)) { + return Status; + } + + Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (IpSec); + + // + // If has udp4 io opened on the controller, close and free it. + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Udp4List) { + + UdpSrv = IPSEC_UDP_SERVICE_FROM_LIST (Entry); + // + // Find the right udp service which installed on the appointed nic handle. + // + if (UdpSrv->Input != NULL && ControllerHandle == UdpSrv->Input->UdpHandle) { + UdpIoFreeIo (UdpSrv->Input); + UdpSrv->Input = NULL; + } + + if (UdpSrv->Output != NULL && ControllerHandle == UdpSrv->Output->UdpHandle) { + UdpIoFreeIo (UdpSrv->Output); + UdpSrv->Output = NULL; + } + + if (UdpSrv->Input == NULL && UdpSrv->Output == NULL) { + RemoveEntryList (&UdpSrv->List); + FreePool (UdpSrv); + ASSERT (Private->Udp4Num > 0); + Private->Udp4Num--; + } + } + // + // If has udp6 io opened on the controller, close and free it. + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Udp6List) { + + UdpSrv = IPSEC_UDP_SERVICE_FROM_LIST (Entry); + // + // Find the right udp service which installed on the appointed nic handle. + // + if (UdpSrv->Input != NULL && ControllerHandle == UdpSrv->Input->UdpHandle) { + UdpIoFreeIo (UdpSrv->Input); + UdpSrv->Input = NULL; + } + + if (UdpSrv->Output != NULL && ControllerHandle == UdpSrv->Output->UdpHandle) { + UdpIoFreeIo (UdpSrv->Output); + UdpSrv->Output = NULL; + } + + if (UdpSrv->Input == NULL && UdpSrv->Output == NULL) { + RemoveEntryList (&UdpSrv->List); + FreePool (UdpSrv); + ASSERT (Private->Udp6Num > 0); + Private->Udp6Num--; + } + } + + return EFI_SUCCESS; } EFI_DRIVER_BINDING_PROTOCOL gIpSecDriverBinding = { @@ -112,9 +256,9 @@ EFI_DRIVER_BINDING_PROTOCOL gIpSecDriverBinding = { /** This is a callback function when the mIpSecInstance.DisabledEvent is signaled. - + @param[in] Event Event whose notification function is being invoked. - @param[in] Context Pointer to the notification function's context. + @param[in] Context Pointer to the notification function's context. **/ VOID @@ -125,34 +269,17 @@ IpSecCleanupAllSa ( ) { IPSEC_PRIVATE_DATA *Private; - UINT8 Value; - EFI_STATUS Status; - - Private = (IPSEC_PRIVATE_DATA *) Context; - - // - // Set the Status Variable - // - Value = IPSEC_STATUS_DISABLED; - Status = gRT->SetVariable ( - IPSECCONFIG_STATUS_NAME, - &gEfiIpSecConfigProtocolGuid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, - sizeof (Value), - &Value - ); - if (!EFI_ERROR (Status)) { - Private->IpSec.DisabledFlag = TRUE; - } - + Private = (IPSEC_PRIVATE_DATA *) Context; + Private->IsIPsecDisabling = TRUE; + IkeDeleteAllSas (Private); } /** This is the declaration of an EFI image entry point. This entry point is the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including both device drivers and bus drivers. - - The entry point for IPsec driver which installs the driver binding, + + The entry point for IPsec driver which installs the driver binding, component name protocol, IPsec Config protcolon, and IPsec protocol in its ImageHandle. @@ -162,7 +289,7 @@ IpSecCleanupAllSa ( @retval EFI_SUCCESS The operation completed successfully. @retval EFI_ALREADY_STARTED The IPsec driver has been already loaded. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. - @retval Others The operation is failed. + @retval Others The operation is failed. **/ EFI_STATUS @@ -174,7 +301,7 @@ IpSecDriverEntryPoint ( { EFI_STATUS Status; IPSEC_PRIVATE_DATA *Private; - EFI_IPSEC2_PROTOCOL *IpSec; + EFI_IPSEC_PROTOCOL *IpSec; // // Check whether ipsec protocol has already been installed. @@ -202,7 +329,7 @@ IpSecDriverEntryPoint ( goto ON_EXIT; } // - // Create disable event to cleanup all sa when ipsec disabled by user. + // Create disable event to cleanup all SA when ipsec disabled by user. // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, @@ -218,8 +345,8 @@ IpSecDriverEntryPoint ( Private->Signature = IPSEC_PRIVATE_DATA_SIGNATURE; Private->ImageHandle = ImageHandle; - CopyMem (&Private->IpSec, &mIpSecInstance, sizeof (EFI_IPSEC2_PROTOCOL)); - + CopyMem (&Private->IpSec, &mIpSecInstance, sizeof (EFI_IPSEC_PROTOCOL)); + // // Initilize Private's members. Thess members is used for IKE. // @@ -229,7 +356,8 @@ IpSecDriverEntryPoint ( InitializeListHead (&Private->Ikev1EstablishedList); InitializeListHead (&Private->Ikev2SessionList); InitializeListHead (&Private->Ikev2EstablishedList); - + + RandomSeed (NULL, 0); // // Initialize the ipsec config data and restore it from variable. // @@ -260,11 +388,17 @@ IpSecDriverEntryPoint ( &gIpSecComponentName2 ); if (EFI_ERROR (Status)) { - goto ON_UNINSTALL_CONFIG; + goto ON_UNINSTALL_IPSEC; } - + return Status; +ON_UNINSTALL_IPSEC: + gBS->UninstallProtocolInterface ( + Private->Handle, + &gEfiIpSecProtocolGuid, + &Private->IpSec + ); ON_UNINSTALL_CONFIG: gBS->UninstallProtocolInterface ( Private->Handle, diff --git a/NetworkPkg/IpSecDxe/IpSecDxe.inf b/NetworkPkg/IpSecDxe/IpSecDxe.inf index 250ef1cdca..9b4c7a5462 100644 --- a/NetworkPkg/IpSecDxe/IpSecDxe.inf +++ b/NetworkPkg/IpSecDxe/IpSecDxe.inf @@ -19,6 +19,7 @@ FILE_GUID = EE8367C0-A1D6-4565-8F89-EF628547B722 MODULE_TYPE = UEFI_DRIVER VERSION_STRING = 1.0 + ENTRY_POINT = IpSecDriverEntryPoint # @@ -34,15 +35,36 @@ IpSecCryptIo.c IpSecDebug.h ComponentName.c + IkeCommon.h IpSecImpl.c + IkeService.c + Ike.h + IkePacket.h + IkePacket.c IpSecDebug.c - IpSecSaEngine.c + IpSecMain.c IpSecDriver.c + IkeCommon.c + IetfConstants.c IpSecImpl.h + IkeService.h + Ikev2/Ikev2.h + Ikev2/Payload.h + Ikev2/Utility.h + Ikev2/Utility.c + Ikev2/Sa.c + Ikev2/ChildSa.c + Ikev2/Info.c + Ikev2/Payload.c + Ikev2/Exchange.c + + [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + LocalNetworkPkg/LocalNetworkPkg.dec [LibraryClasses] MemoryAllocationLib @@ -54,10 +76,30 @@ BaseMemoryLib DebugLib PrintLib + #CryptLib + BaseCryptLib DpcLib - NetLib - + UdpIoLib + NetLib + PcdLib + [Protocols] gEfiIp4ConfigProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiUdp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiUdp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiUdp6ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiUdp6ProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiIpSecConfigProtocolGuid # PROTOCOL ALWAYS_PRODUCED gEfiIpSecProtocolGuid # PROTOCOL ALWAYS_PRODUCED + +[Pcd] + gEfiNetworkPkgTokenSpaceGuid.PcdIpsecCertiifcateEnabled + gEfiMdeModulePkgTokenSpaceGuid.UefiCaFile + gEfiMdeModulePkgTokenSpaceGuid.UefiCaFileSize + gEfiMdeModulePkgTokenSpaceGuid.UefiCertificate + gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateSize + gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateKey + gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateKeySize + +[BuildOptions.common] +#DEBUG_MYTOOLS_IA32_CC_FLAGS = /Od /GL \ No newline at end of file diff --git a/NetworkPkg/IpSecDxe/IpSecImpl.c b/NetworkPkg/IpSecDxe/IpSecImpl.c index b693eb94d1..7ccbfa25ee 100644 --- a/NetworkPkg/IpSecDxe/IpSecImpl.c +++ b/NetworkPkg/IpSecDxe/IpSecImpl.c @@ -1,5 +1,5 @@ /** @file - The implementation of IPsec Protocol + The implementation of IPsec. Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
@@ -13,18 +13,19 @@ **/ +#include "IpSecImpl.h" +#include "IkeService.h" +#include "IpSecDebug.h" +#include "IpSecCryptIo.h" #include "IpSecConfigImpl.h" -EFI_IPSEC2_PROTOCOL mIpSecInstance = { IpSecProcess, NULL, TRUE }; - -extern LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum]; - /** Check if the specified Address is the Valid Address Range. This function checks if the bytes after prefixed length are all Zero in this - Address. This Address is supposed to point to a range address, meaning it only - gives the correct prefixed address. + Address. This Address is supposed to point to a range address. That means it + should gives the correct prefixed address and the bytes outside the prefixed are + zero. @param[in] IpVersion The IP version. @param[in] Address Points to EFI_IP_ADDRESS to be checked. @@ -208,7 +209,6 @@ IpSecMatchIpAddress ( break; } } - return IsMatch; } @@ -315,6 +315,7 @@ IpSecMatchNextLayerProtocol ( @param[in] SadList SAD list related to a specified SPD entry. @param[in] DestAddress The destination address used to find the SAD entry. + @param[in] IpVersion The IP version. Ip4 or Ip6. @return The pointer to a certain SAD entry. @@ -322,23 +323,25 @@ IpSecMatchNextLayerProtocol ( IPSEC_SAD_ENTRY * IpSecLookupSadBySpd ( IN LIST_ENTRY *SadList, - IN EFI_IP_ADDRESS *DestAddress + IN EFI_IP_ADDRESS *DestAddress, + IN UINT8 IpVersion ) { LIST_ENTRY *Entry; IPSEC_SAD_ENTRY *SadEntry; - - for (Entry = SadList->ForwardLink; Entry != SadList; Entry = Entry->ForwardLink) { + + NET_LIST_FOR_EACH (Entry, SadList) { SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry); // - // Find the right sad entry which contains the appointed dest address. + // Find the right SAD entry which contains the appointed dest address. // - if (CompareMem ( - &SadEntry->Id->DestAddress, + if (IpSecMatchIpAddress ( + IpVersion, DestAddress, - sizeof (EFI_IP_ADDRESS) - ) == 0) { + SadEntry->Data->SpdSelector->RemoteAddress, + SadEntry->Data->SpdSelector->RemoteAddressCount + )){ return SadEntry; } } @@ -351,6 +354,7 @@ IpSecLookupSadBySpd ( @param[in] Spi The SPI used to search the SAD entry. @param[in] DestAddress The destination used to search the SAD entry. + @param[in] IpVersion The IP version. Ip4 or Ip6. @return the pointer to a certain SAD entry. @@ -358,7 +362,8 @@ IpSecLookupSadBySpd ( IPSEC_SAD_ENTRY * IpSecLookupSadBySpi ( IN UINT32 Spi, - IN EFI_IP_ADDRESS *DestAddress + IN EFI_IP_ADDRESS *DestAddress, + IN UINT8 IpVersion ) { LIST_ENTRY *Entry; @@ -367,22 +372,36 @@ IpSecLookupSadBySpi ( SadList = &mConfigData[IPsecConfigDataTypeSad]; - for (Entry = SadList->ForwardLink; Entry != SadList; Entry = Entry->ForwardLink) { + NET_LIST_FOR_EACH (Entry, SadList) { SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry); + // - // Find the right sad entry which contain the appointed spi and dest addr. + // Find the right SAD entry which contain the appointed spi and dest addr. // - if (SadEntry->Id->Spi == Spi && CompareMem ( - &SadEntry->Id->DestAddress, - DestAddress, - sizeof (EFI_IP_ADDRESS) - ) == 0) { - - return SadEntry; + if (SadEntry->Id->Spi == Spi) { + if (SadEntry->Data->Mode == EfiIPsecTunnel) { + if (CompareMem ( + &DestAddress, + &SadEntry->Data->TunnelDestAddress, + sizeof (EFI_IP_ADDRESS) + )) { + return SadEntry; + } + } else { + if (SadEntry->Data->SpdSelector != NULL && + IpSecMatchIpAddress ( + IpVersion, + DestAddress, + SadEntry->Data->SpdSelector->RemoteAddress, + SadEntry->Data->SpdSelector->RemoteAddressCount + ) + ) { + return SadEntry; + } + } } } - return NULL; } @@ -407,7 +426,6 @@ IpSecLookupSadBySpi ( - If don't find related UDP service. - Sequence Number is used up. - Extension Sequence Number is used up. - @retval EFI_DEVICE_ERROR GC_TODO: Add description for return value. @retval EFI_NOT_READY No existing SAD entry could be used. @retval EFI_SUCCESS Find the related SAD entry. @@ -424,12 +442,18 @@ IpSecLookupSadEntry ( OUT IPSEC_SAD_ENTRY **SadEntry ) { + IKE_UDP_SERVICE *UdpService; IPSEC_SAD_ENTRY *Entry; IPSEC_SAD_DATA *Data; EFI_IP_ADDRESS DestIp; UINT32 SeqNum32; *SadEntry = NULL; + UdpService = IkeLookupUdp (Private, NicHandle, IpVersion); + + if (UdpService == NULL) { + return EFI_DEVICE_ERROR; + } // // Parse the destination address from ip header. // @@ -447,10 +471,11 @@ IpSecLookupSadEntry ( sizeof (EFI_IP_ADDRESS) ); } + // - // Find the sad entry in the spd.sas list according to the dest address. + // Find the SAD entry in the spd.sas list according to the dest address. // - Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp); + Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp, IpVersion); if (Entry == NULL) { @@ -458,9 +483,22 @@ IpSecLookupSadEntry ( (OldLastHead == IP6_ICMP && *IpPayload == ICMP_V6_ECHO_REQUEST) ) { // - // TODO: Start ike negotiation process except the request packet of ping. + // Start ike negotiation process except the request packet of ping. // - //IkeNegotiate (UdpService, SpdEntry, &DestIp); + if (SpdEntry->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) { + IkeNegotiate ( + UdpService, + SpdEntry, + &SpdEntry->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress + ); + } else { + IkeNegotiate ( + UdpService, + SpdEntry, + &DestIp + ); + } + } return EFI_NOT_READY; @@ -473,7 +511,7 @@ IpSecLookupSadEntry ( // // Validate the 64bit sn number if 64bit sn enabled. // - if (Data->SequenceNumber + 1 < Data->SequenceNumber) { + if ((UINT64) (Data->SequenceNumber + 1) == 0) { // // TODO: Re-negotiate SA // @@ -484,7 +522,7 @@ IpSecLookupSadEntry ( // Validate the 32bit sn number if 64bit sn disabled. // SeqNum32 = (UINT32) Data->SequenceNumber; - if (SeqNum32 + 1 < SeqNum32) { + if ((UINT32) (SeqNum32 + 1) == 0) { // // TODO: Re-negotiate SA // @@ -544,19 +582,21 @@ IpSecLookupPadEntry ( @param[in] IpPayload Point to IP payload. @param[in] Protocol The Last protocol of IP packet. @param[in] IsOutbound Traffic direction. + @param[out] Action The support action of SPD entry. - @retval EFI_IPSEC_ACTION The support action of SPD entry. - @retval -1 If the input packet header doesn't match the SpdEntry. + @retval EFI_SUCCESS Find the related SPD. + @retval EFI_NOT_FOUND Not find the related SPD entry; **/ -EFI_IPSEC_ACTION +EFI_STATUS IpSecLookupSpdEntry ( - IN IPSEC_SPD_ENTRY *SpdEntry, - IN UINT8 IpVersion, - IN VOID *IpHead, - IN UINT8 *IpPayload, - IN UINT8 Protocol, - IN BOOLEAN IsOutbound + IN IPSEC_SPD_ENTRY *SpdEntry, + IN UINT8 IpVersion, + IN VOID *IpHead, + IN UINT8 *IpPayload, + IN UINT8 Protocol, + IN BOOLEAN IsOutbound, + OUT EFI_IPSEC_ACTION *Action ) { EFI_IPSEC_SPD_SELECTOR *SpdSel; @@ -637,220 +677,1478 @@ IpSecLookupSpdEntry ( if (SpdMatch) { // - // Find the right spd entry if match the 5 key elements. + // Find the right SPD entry if match the 5 key elements. // - return SpdEntry->Data->Action; + *Action = SpdEntry->Data->Action; + return EFI_SUCCESS; } - return (EFI_IPSEC_ACTION) - 1; + return EFI_NOT_FOUND; } /** - Handles IPsec packet processing for inbound and outbound IP packets. - - The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet. - The behavior is that it can perform one of the following actions: - bypass the packet, discard the packet, or protect the packet. - - @param[in] This Pointer to the EFI_IPSEC_PROTOCOL instance. - @param[in] NicHandle Instance of the network interface. - @param[in] IpVersion IPV4 or IPV6. - @param[in, out] IpHead Pointer to the IP Header. - @param[in, out] LastHead The protocol of the next layer to be processed by IPsec. - @param[in, out] OptionsBuffer Pointer to the options buffer. - @param[in, out] OptionsLength Length of the options buffer. - @param[in, out] FragmentTable Pointer to a list of fragments. - @param[in, out] FragmentCount Number of fragments. - @param[in] TrafficDirection Traffic direction. - @param[out] RecycleSignal Event for recycling of resources. - - @retval EFI_SUCCESS The packet was bypassed and all buffers remain the same. - @retval EFI_SUCCESS The packet was protected. - @retval EFI_ACCESS_DENIED The packet was discarded. + The call back function of NetbufFromExt. + + @param[in] Arg The argument passed from the caller. **/ -EFI_STATUS +VOID EFIAPI -IpSecProcess ( - IN EFI_IPSEC2_PROTOCOL *This, - IN EFI_HANDLE NicHandle, - IN UINT8 IpVersion, - IN OUT VOID *IpHead, - IN OUT UINT8 *LastHead, - IN OUT VOID **OptionsBuffer, - IN OUT UINT32 *OptionsLength, - IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, - IN OUT UINT32 *FragmentCount, - IN EFI_IPSEC_TRAFFIC_DIR TrafficDirection, - OUT EFI_EVENT *RecycleSignal +IpSecOnRecyclePacket ( + IN VOID *Arg ) { - IPSEC_PRIVATE_DATA *Private; - IPSEC_SPD_ENTRY *SpdEntry; - IPSEC_SAD_ENTRY *SadEntry; - LIST_ENTRY *SpdList; - LIST_ENTRY *Entry; - EFI_IPSEC_ACTION Action; - EFI_STATUS Status; - UINT8 *IpPayload; - UINT8 OldLastHead; - BOOLEAN IsOutbound; - - Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (This); - IpPayload = (*FragmentTable)[0].FragmentBuffer; - IsOutbound = (BOOLEAN) ((TrafficDirection == EfiIPsecOutBound) ? TRUE : FALSE); - OldLastHead = *LastHead; - *RecycleSignal = NULL; - - if (!IsOutbound) { - // - // For inbound traffic, process the ipsec header of the packet. - // - Status = IpSecProtectInboundPacket ( - IpVersion, - IpHead, - LastHead, - OptionsBuffer, - OptionsLength, - FragmentTable, - FragmentCount, - &SpdEntry, - RecycleSignal - ); +} + +/** + This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP + is released. + + @param[in] Event The related event. + @param[in] Context The data passed by the caller. + +**/ +VOID +EFIAPI +IpSecRecycleCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + IPSEC_RECYCLE_CONTEXT *RecycleContext; + + RecycleContext = (IPSEC_RECYCLE_CONTEXT *) Context; + + if (RecycleContext->FragmentTable != NULL) { + FreePool (RecycleContext->FragmentTable); + } + + if (RecycleContext->PayloadBuffer != NULL) { + FreePool (RecycleContext->PayloadBuffer); + } + + FreePool (RecycleContext); + gBS->CloseEvent (Event); + +} + +/** + Calculate the extension hader of IP. The return length only doesn't contain + the fixed IP header length. + + @param[in] IpHead Points to an IP head to be calculated. + @param[in] LastHead Points to the last header of the IP header. + + @return The length of the extension header. + +**/ +UINT16 +IpSecGetPlainExtHeadSize ( + IN VOID *IpHead, + IN UINT8 *LastHead + ) +{ + UINT16 Size; + + Size = (UINT16) (LastHead - (UINT8 *) IpHead); + + if (Size > sizeof (EFI_IP6_HEADER)) { + // + // * (LastHead+1) point the last header's length but not include the first + // 8 octers, so this formluation add 8 at the end. + // + Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8); + } else { + Size = 0; + } + + return Size; +} + +/** + Verify if the Authentication payload is correct. + + @param[in] EspBuffer Points to the ESP wrapped buffer. + @param[in] EspSize The size of the ESP wrapped buffer. + @param[in] SadEntry The related SAD entry to store the authentication + algorithm key. + @param[in] IcvSize The length of ICV. + + @retval EFI_SUCCESS The authentication data is correct. + @retval EFI_ACCESS_DENIED The authentication data is not correct. + +**/ +EFI_STATUS +IpSecEspAuthVerifyPayload ( + IN UINT8 *EspBuffer, + IN UINTN EspSize, + IN IPSEC_SAD_ENTRY *SadEntry, + IN UINTN *IcvSize + ) +{ + EFI_STATUS Status; + UINTN AuthSize; + UINT8 IcvBuffer[12]; + HASH_DATA_FRAGMENT HashFragment[1]; + + // + // Calculate the size of authentication payload. + // + *IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId); + AuthSize = EspSize - *IcvSize; + + // + // Calculate the icv buffer and size of the payload. + // + HashFragment[0].Data = EspBuffer; + HashFragment[0].DataSize = AuthSize; + + Status = IpSecCryptoIoHmac ( + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId, + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey, + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength, + HashFragment, + 1, + IcvBuffer, + *IcvSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Compare the calculated icv and the appended original icv. + // + if (CompareMem (EspBuffer + AuthSize, IcvBuffer, *IcvSize) == 0) { + return EFI_SUCCESS; + } + + DEBUG ((DEBUG_ERROR, "Error auth verify payload\n")); + return EFI_ACCESS_DENIED; +} + +/** + Search the related SAD entry by the input . + + @param[in] IpHead The pointer to IP header. + @param[in] IpVersion The version of IP (IP4 or IP6). + @param[in] Spi The SPI used to search the related SAD entry. + + + @retval NULL Not find the related SAD entry. + @retval IPSEC_SAD_ENTRY Return the related SAD entry. + +**/ +IPSEC_SAD_ENTRY * +IpSecFoundSadFromInboundPacket ( + UINT8 *IpHead, + UINT8 IpVersion, + UINT32 Spi + ) +{ + EFI_IP_ADDRESS DestIp; + + // + // Parse destination address from ip header. + // + ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS)); + if (IpVersion == IP_VERSION_4) { + CopyMem ( + &DestIp, + &((IP4_HEAD *) IpHead)->Dst, + sizeof (IP4_ADDR) + ); + } else { + CopyMem ( + &DestIp, + &((EFI_IP6_HEADER *) IpHead)->DestinationAddress, + sizeof (EFI_IPv6_ADDRESS) + ); + } + + // + // Lookup SAD entry according to the spi and dest address. + // + return IpSecLookupSadBySpi (Spi, &DestIp, IpVersion); +} + +/** + Validate the IP6 extension header format for both the packets we received + and that we will transmit. + + @param[in] NextHeader The next header field in IPv6 basic header. + @param[in] ExtHdrs The first bye of the option. + @param[in] ExtHdrsLen The length of the whole option. + @param[out] LastHeader The pointer of NextHeader of the last extension + header processed by IP6. + @param[out] RealExtsLen The length of extension headers processed by IP6 layer. + This is an optional parameter that may be NULL. + + @retval TRUE The option is properly formated. + @retval FALSE The option is malformated. + +**/ +BOOLEAN +IpSecIsIp6ExtsValid ( + IN UINT8 *NextHeader, + IN UINT8 *ExtHdrs, + IN UINT32 ExtHdrsLen, + OUT UINT8 **LastHeader, + OUT UINT32 *RealExtsLen OPTIONAL + ) +{ + UINT32 Pointer; + UINT8 *Option; + UINT8 OptionLen; + BOOLEAN Flag; + UINT8 CountD; + UINT8 CountF; + UINT8 CountA; + + if (RealExtsLen != NULL) { + *RealExtsLen = 0; + } + + *LastHeader = NextHeader; - if (Status == EFI_ACCESS_DENIED) { + if (ExtHdrs == NULL && ExtHdrsLen == 0) { + return TRUE; + } + + if ((ExtHdrs == NULL && ExtHdrsLen != 0) || (ExtHdrs != NULL && ExtHdrsLen == 0)) { + return FALSE; + } + + Pointer = 0; + Flag = FALSE; + CountD = 0; + CountF = 0; + CountA = 0; + + while (Pointer <= ExtHdrsLen) { + + switch (*NextHeader) { + case IP6_HOP_BY_HOP: + if (Pointer != 0) { + return FALSE; + } + + Flag = TRUE; + + // + // Fall through + // + case IP6_DESTINATION: + if (*NextHeader == IP6_DESTINATION) { + CountD++; + } + + if (CountD > 2) { + return FALSE; + } + + NextHeader = ExtHdrs + Pointer; + + Pointer++; + Option = ExtHdrs + Pointer; + OptionLen = (UINT8) ((*Option + 1) * 8 - 2); + Option++; + Pointer++; + + Pointer = Pointer + OptionLen; + break; + + case IP6_FRAGMENT: + if (++CountF > 1) { + return FALSE; + } // - // The packet is denied to access. + // RFC2402, AH header should after fragment header. // - goto ON_EXIT; - } + if (CountA > 1) { + return FALSE; + } + + NextHeader = ExtHdrs + Pointer; + Pointer = Pointer + 8; + break; - if (Status == EFI_SUCCESS) { + case IP6_AH: + if (++CountA > 1) { + return FALSE; + } + + Option = ExtHdrs + Pointer; + NextHeader = Option; + Option++; // - // Check the spd entry if the packet is accessible. + // RFC2402, Payload length is specified in 32-bit words, minus "2". // - if (SpdEntry == NULL) { - Status = EFI_ACCESS_DENIED; - goto ON_EXIT; + OptionLen = (UINT8) ((*Option + 2) * 4); + Pointer = Pointer + OptionLen; + break; + + default: + *LastHeader = NextHeader; + if (RealExtsLen != NULL) { + *RealExtsLen = Pointer; + } + + return TRUE; + } + } + + *LastHeader = NextHeader; + + if (RealExtsLen != NULL) { + *RealExtsLen = Pointer; + } + + return TRUE; +} + +/** + The actual entry to process the tunnel header and inner header for tunnel mode + outbound traffic. + + This function is the subfunction of IpSecEspInboundPacket(). It change the destination + Ip address to the station address and recalculate the uplayyer's checksum. + + + @param[in, out] IpHead Points to the IP header containing the ESP header + to be trimed on input, and without ESP header + on return. + @param[in] IpPayload The decrypted Ip payload. It start from the inner + header. + @param[in] IpVersion The version of IP. + @param[in] SadData Pointer of the relevant SAD. + @param[in, out] LastHead The Last Header in IP header on return. + +**/ +VOID +IpSecTunnelInboundPacket ( + IN OUT UINT8 *IpHead, + IN UINT8 *IpPayload, + IN UINT8 IpVersion, + IN IPSEC_SAD_DATA *SadData, + IN OUT UINT8 *LastHead + ) +{ + EFI_UDP_HEADER *UdpHeader; + TCP_HEAD *TcpHeader; + UINT16 *Checksum; + UINT16 PseudoChecksum; + UINT16 PacketChecksum; + UINT32 OptionLen; + IP6_ICMP_HEAD *Icmp6Head; + + Checksum = NULL; + + if (IpVersion == IP_VERSION_4) { + // + // Zero OutIP header use this to indicate the input packet is under + // IPsec Tunnel protected. + // + ZeroMem ( + (IP4_HEAD *)IpHead, + sizeof (IP4_HEAD) + ); + CopyMem ( + &((IP4_HEAD *)IpPayload)->Dst, + &SadData->TunnelDestAddress.v4, + sizeof (EFI_IPv4_ADDRESS) + ); + + // + // Recalculate IpHeader Checksum + // + if (((IP4_HEAD *)(IpPayload))->Checksum != 0 ) { + ((IP4_HEAD *)(IpPayload))->Checksum = 0; + ((IP4_HEAD *)(IpPayload))->Checksum = (UINT16) (~NetblockChecksum ( + (UINT8 *)IpPayload, + ((IP4_HEAD *)IpPayload)->HeadLen << 2 + )); + + + } + + // + // Recalcualte PseudoChecksum + // + switch (((IP4_HEAD *)IpPayload)->Protocol) { + case EFI_IP_PROTO_UDP : + UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2)); + Checksum = & UdpHeader->Checksum; + *Checksum = 0; + break; + + case EFI_IP_PROTO_TCP: + TcpHeader = (TCP_HEAD *) ((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2)); + Checksum = &TcpHeader->Checksum; + *Checksum = 0; + break; + + default: + break; } - Action = IpSecLookupSpdEntry ( - SpdEntry, - IpVersion, - IpHead, - IpPayload, - *LastHead, - IsOutbound - ); - - if (Action != EfiIPsecActionProtect) { - // - // Discard the packet if the spd entry is not protect. - // - gBS->SignalEvent (*RecycleSignal); - *RecycleSignal = NULL; - Status = EFI_ACCESS_DENIED; + PacketChecksum = NetblockChecksum ( + (UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2), + NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2) + ); + PseudoChecksum = NetPseudoHeadChecksum ( + ((IP4_HEAD *)IpPayload)->Src, + ((IP4_HEAD *)IpPayload)->Dst, + ((IP4_HEAD *)IpPayload)->Protocol, + 0 + ); + + if (Checksum != NULL) { + *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum); + *Checksum = (UINT16) ~(NetAddChecksum (*Checksum, HTONS((UINT16)(NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2))))); } + }else { + // + // Zero OutIP header use this to indicate the input packet is under + // IPsec Tunnel protected. + // + ZeroMem ( + IpHead, + sizeof (EFI_IP6_HEADER) + ); + CopyMem ( + &((EFI_IP6_HEADER*)IpPayload)->DestinationAddress, + &SadData->TunnelDestAddress.v6, + sizeof (EFI_IPv6_ADDRESS) + ); + + // + // Get the Extension Header and Header length. + // + IpSecIsIp6ExtsValid ( + &((EFI_IP6_HEADER *)IpPayload)->NextHeader, + IpPayload + sizeof (EFI_IP6_HEADER), + ((EFI_IP6_HEADER *)IpPayload)->PayloadLength, + &LastHead, + &OptionLen + ); + + // + // Recalcualte PseudoChecksum + // + switch (*LastHead) { + case EFI_IP_PROTO_UDP: + UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen); + Checksum = &UdpHeader->Checksum; + *Checksum = 0; + break; - goto ON_EXIT; + case EFI_IP_PROTO_TCP: + TcpHeader = (TCP_HEAD *)(IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen); + Checksum = &TcpHeader->Checksum; + *Checksum = 0; + break; + + case IP6_ICMP: + Icmp6Head = (IP6_ICMP_HEAD *) (IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen); + Checksum = &Icmp6Head->Checksum; + *Checksum = 0; + break; + } + PacketChecksum = NetblockChecksum ( + IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen, + NTOHS(((EFI_IP6_HEADER *)IpPayload)->PayloadLength) - OptionLen + ); + PseudoChecksum = NetIp6PseudoHeadChecksum ( + &((EFI_IP6_HEADER *)IpPayload)->SourceAddress, + &((EFI_IP6_HEADER *)IpPayload)->DestinationAddress, + *LastHead, + 0 + ); + + if (Checksum != NULL) { + *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum); + *Checksum = (UINT16) ~(NetAddChecksum ( + *Checksum, + HTONS ((UINT16)((NTOHS (((EFI_IP6_HEADER *)(IpPayload))->PayloadLength)) - OptionLen)) + )); } + } +} + +/** + The actual entry to create inner header for tunnel mode inbound traffic. + + This function is the subfunction of IpSecEspOutboundPacket(). It create + the sending packet by encrypting its payload and inserting ESP header in the orginal + IP header, then return the IpHeader and IPsec protected Fragmentable. + + @param[in, out] IpHead Points to IP header containing the orginal IP header + to be processed on input, and inserted ESP header + on return. + @param[in] IpVersion The version of IP. + @param[in] SadData The related SAD data. + @param[in, out] LastHead The Last Header in IP header. + @param[in] OptionsBuffer Pointer to the options buffer. It is optional. + @param[in] OptionsLength Length of the options buffer. It is optional. + @param[in, out] FragmentTable Pointer to a list of fragments to be protected by + IPsec on input, and with IPsec protected + on return. + @param[in] FragmentCount The number of fragments. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated. + +**/ +UINT8 * +IpSecTunnelOutboundPacket ( + IN OUT UINT8 *IpHead, + IN UINT8 IpVersion, + IN IPSEC_SAD_DATA *SadData, + IN OUT UINT8 *LastHead, + IN VOID **OptionsBuffer, + IN UINT32 *OptionsLength, + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN UINT32 *FragmentCount + ) +{ + UINT8 *InnerHead; + NET_BUF *Packet; + UINT16 PacketChecksum; + UINT16 *Checksum; + UINT16 PseudoChecksum; + IP6_ICMP_HEAD *IcmpHead; + + Checksum = NULL; + if (OptionsLength == NULL) { + return NULL; } + + if (IpVersion == IP_VERSION_4) { + InnerHead = AllocateZeroPool (sizeof (IP4_HEAD) + *OptionsLength); + ASSERT (InnerHead != NULL); + CopyMem ( + InnerHead, + IpHead, + sizeof (IP4_HEAD) + ); + CopyMem ( + InnerHead + sizeof (IP4_HEAD), + *OptionsBuffer, + *OptionsLength + ); + } else { + InnerHead = AllocateZeroPool (sizeof (EFI_IP6_HEADER) + *OptionsLength); + CopyMem ( + InnerHead, + IpHead, + sizeof (EFI_IP6_HEADER) + ); + CopyMem ( + InnerHead + sizeof (EFI_IP6_HEADER), + *OptionsBuffer, + *OptionsLength + ); + } + if (OptionsBuffer != NULL) { + if (*OptionsLength != 0) { - Status = EFI_ACCESS_DENIED; - SpdList = &mConfigData[IPsecConfigDataTypeSpd]; + *OptionsBuffer = NULL; + *OptionsLength = 0; + } + } + + // + // 2. Reassamlbe Fragment into Packet + // + Packet = NetbufFromExt ( + (NET_FRAGMENT *)(*FragmentTable), + *FragmentCount, + 0, + 0, + IpSecOnRecyclePacket, + NULL + ); + ASSERT (Packet != NULL); + // + // 3. Check the Last Header, if it is TCP, UDP or ICMP recalcualate its pesudo + // CheckSum. + // + switch (*LastHead) { + case EFI_IP_PROTO_UDP: + Packet->Udp = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, 0); + ASSERT (Packet->Udp != NULL); + Checksum = &Packet->Udp->Checksum; + *Checksum = 0; + break; + + case EFI_IP_PROTO_TCP: + Packet->Tcp = (TCP_HEAD *) NetbufGetByte (Packet, 0, 0); + ASSERT (Packet->Tcp != NULL); + Checksum = &Packet->Tcp->Checksum; + *Checksum = 0; + break; + + case IP6_ICMP: + IcmpHead = (IP6_ICMP_HEAD *) NetbufGetByte (Packet, 0, NULL); + ASSERT (IcmpHead != NULL); + Checksum = &IcmpHead->Checksum; + *Checksum = 0; + break; + + default: + break; + } - for (Entry = SpdList->ForwardLink; Entry != SpdList; Entry = Entry->ForwardLink) { + PacketChecksum = NetbufChecksum (Packet); + + if (IpVersion == IP_VERSION_4) { // - // For outbound and non-ipsec Inbound traffic: check the spd entry. + // Replace the source address of Inner Header. // - SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); - Action = IpSecLookupSpdEntry ( - SpdEntry, - IpVersion, - IpHead, - IpPayload, - OldLastHead, - IsOutbound + CopyMem ( + &((IP4_HEAD *)InnerHead)->Src, + &SadData->SpdSelector->LocalAddress[0].Address.v4, + sizeof (EFI_IPv4_ADDRESS) + ); + + PacketChecksum = NetbufChecksum (Packet); + PseudoChecksum = NetPseudoHeadChecksum ( + ((IP4_HEAD *)InnerHead)->Src, + ((IP4_HEAD *)InnerHead)->Dst, + *LastHead, + 0 + ); + + } else { + // + // Replace the source address of Inner Header. + // + CopyMem ( + &((EFI_IP6_HEADER *)InnerHead)->SourceAddress, + &(SadData->SpdSelector->LocalAddress[0].Address.v6), + sizeof (EFI_IPv6_ADDRESS) + ); + PacketChecksum = NetbufChecksum (Packet); + PseudoChecksum = NetIp6PseudoHeadChecksum ( + &((EFI_IP6_HEADER *)InnerHead)->SourceAddress, + &((EFI_IP6_HEADER *)InnerHead)->DestinationAddress, + *LastHead, + 0 + ); + + } + if (Checksum != NULL) { + *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum); + *Checksum = (UINT16) ~(NetAddChecksum ((UINT16)*Checksum, HTONS ((UINT16) Packet->TotalSize))); + } + + if (Packet != NULL) { + NetbufFree (Packet); + } + return InnerHead; +} + +/** + The actual entry to relative function processes the inbound traffic of ESP header. + + This function is the subfunction of IpSecProtectInboundPacket(). It checks the + received packet security property and trim the ESP header and then returns without + an IPsec protected IP Header and FramgmentTable. + + @param[in] IpVersion The version of IP. + @param[in, out] IpHead Points to the IP header containing the ESP header + to be trimed on input, and without ESP header + on return. + @param[out] LastHead The Last Header in IP header on return. + @param[in, out] OptionsBuffer Pointer to the options buffer. It is optional. + @param[in, out] OptionsLength Length of the options buffer. It is optional. + @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec + protected on input, and without IPsec protected + on return. + @param[in, out] FragmentCount The number of fragments. + @param[out] SpdSelector Pointer to contain the address of SPD selector on return. + @param[out] RecycleEvent The event for recycling of resources. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ACCESS_DENIED One or more following conditions is TRUE: + - ESP header was not found. + - The related SAD entry was not found. + - The related SAD entry does not support the ESP protocol. + @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated. + +**/ +EFI_STATUS +IpSecEspInboundPacket ( + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + OUT UINT8 *LastHead, + IN OUT VOID **OptionsBuffer, OPTIONAL + IN OUT UINT32 *OptionsLength, OPTIONAL + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN OUT UINT32 *FragmentCount, + OUT EFI_IPSEC_SPD_SELECTOR **SpdSelector, + OUT EFI_EVENT *RecycleEvent + ) +{ + EFI_STATUS Status; + NET_BUF *Payload; + UINTN EspSize; + UINTN IvSize; + UINTN PlainPayloadSize; + UINTN PaddingSize; + UINTN IcvSize; + UINT8 *ProcessBuffer; + EFI_ESP_HEADER *EspHeader; + EFI_ESP_TAIL *EspTail; + EFI_IPSEC_SA_ID *SaId; + IPSEC_SAD_DATA *SadData; + IPSEC_SAD_ENTRY *SadEntry; + IPSEC_RECYCLE_CONTEXT *RecycleContext; + UINT8 NextHeader; + UINT16 IpSecHeadSize; + UINT8 *InnerHead; + + Status = EFI_SUCCESS; + Payload = NULL; + ProcessBuffer = NULL; + RecycleContext = NULL; + *RecycleEvent = NULL; + PlainPayloadSize = 0; + NextHeader = 0; + + // + // Build netbuf from fragment table first. + // + Payload = NetbufFromExt ( + (NET_FRAGMENT *) *FragmentTable, + *FragmentCount, + 0, + sizeof (EFI_ESP_HEADER), + IpSecOnRecyclePacket, + NULL ); + if (Payload == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Get the esp size and esp header from netbuf. + // + EspSize = Payload->TotalSize; + EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL); + + if (EspHeader == NULL) { + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } + + // + // Parse destination address from ip header and found the related SAD Entry. + // + SadEntry = IpSecFoundSadFromInboundPacket ( + IpHead, + IpVersion, + NTOHL (EspHeader->Spi) + ); + + if (SadEntry == NULL) { + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } - switch (Action) { + SaId = SadEntry->Id; + SadData = SadEntry->Data; - case EfiIPsecActionProtect: + // + // Only support esp protocol currently. + // + if (SaId->Proto != EfiIPsecESP) { + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } - if (IsOutbound) { - // - // For outbound traffic, lookup the sad entry. - // - Status = IpSecLookupSadEntry ( - Private, - NicHandle, - IpVersion, + if (!SadData->ManualSet) { + // + // TODO: Check SA lifetime and sequence number + // + } + + // + // Allocate buffer for decryption and authentication. + // + ProcessBuffer = AllocateZeroPool (EspSize); + if (ProcessBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer); + + // + // Authenticate the esp wrapped buffer by the auth keys which is from SAD entry. + // + IcvSize = 0; + if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { + Status = IpSecEspAuthVerifyPayload ( + ProcessBuffer, + EspSize, + SadEntry, + &IcvSize + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + // + // Decrypt the payload by the SAD entry if it has decrypt key. + // + IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId); + if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) { + Status = IpSecCryptoIoDecrypt ( + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId, + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey, + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3, + ProcessBuffer + sizeof (EFI_ESP_HEADER), + ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize, + EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize, + ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + + // + // Parse EspTail and compute the plain payload size. + // + EspTail = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL)); + PaddingSize = EspTail->PaddingLength; + NextHeader = EspTail->NextHeader; + PlainPayloadSize = EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize - sizeof (EFI_ESP_TAIL) - PaddingSize; + + // + // TODO: handle anti-replay window + // + // + // Decryption and authentication with esp has been done, so it's time to + // reload the new packet, create recycle event and fixup ip header. + // + RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT)); + if (RecycleContext == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + IpSecRecycleCallback, + RecycleContext, + RecycleEvent + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // The caller will take responsible to handle the original fragment table + // + *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA)); + if (*FragmentTable == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + RecycleContext->PayloadBuffer = ProcessBuffer; + RecycleContext->FragmentTable = *FragmentTable; + + // + // If Tunnel, recalculate upper-layyer PesudoCheckSum and trim the out + // + if (SadData->Mode == EfiIPsecTunnel) { + InnerHead = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize; + IpSecTunnelInboundPacket ( + IpHead, + InnerHead, + IpVersion, + SadData, + LastHead + ); + + if (IpVersion == IP_VERSION_4) { + (*FragmentTable)[0].FragmentBuffer = InnerHead ; + (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize; + + }else { + (*FragmentTable)[0].FragmentBuffer = InnerHead; + (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize; + } + } else { + (*FragmentTable)[0].FragmentBuffer = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize; + (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize; + } + + *FragmentCount = 1; + + // + // Update the total length field in ip header since processed by esp. + // + if (!SadData->Mode == EfiIPsecTunnel) { + if (IpVersion == IP_VERSION_4) { + ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) (((IP4_HEAD *) IpHead)->HeadLen + PlainPayloadSize)); + } else { + IpSecHeadSize = IpSecGetPlainExtHeadSize (IpHead, LastHead); + ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize)); + } + // + // Update the next layer field in ip header since esp header inserted. + // + *LastHead = NextHeader; + } + + + // + // Update the SPD association of the SAD entry. + // + *SpdSelector = SadData->SpdSelector; + +ON_EXIT: + if (Payload != NULL) { + NetbufFree (Payload); + } + + if (EFI_ERROR (Status)) { + if (ProcessBuffer != NULL) { + FreePool (ProcessBuffer); + } + + if (RecycleContext != NULL) { + FreePool (RecycleContext); + } + + if (*RecycleEvent != NULL) { + gBS->CloseEvent (*RecycleEvent); + } + } + + return Status; +} + +/** + The actual entry to the relative function processes the output traffic using the ESP protocol. + + This function is the subfunction of IpSecProtectOutboundPacket(). It protected + the sending packet by encrypting its payload and inserting ESP header in the orginal + IP header, then return the IpHeader and IPsec protected Fragmentable. + + @param[in] IpVersion The version of IP. + @param[in, out] IpHead Points to IP header containing the orginal IP header + to be processed on input, and inserted ESP header + on return. + @param[in, out] LastHead The Last Header in IP header. + @param[in, out] OptionsBuffer Pointer to the options buffer. It is optional. + @param[in, out] OptionsLength Length of the options buffer. It is optional. + @param[in, out] FragmentTable Pointer to a list of fragments to be protected by + IPsec on input, and with IPsec protected + on return. + @param[in, out] FragmentCount The number of fragments. + @param[in] SadEntry The related SAD entry. + @param[out] RecycleEvent The event for recycling of resources. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated. + +**/ +EFI_STATUS +IpSecEspOutboundPacket ( + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + IN OUT UINT8 *LastHead, + IN OUT VOID **OptionsBuffer, OPTIONAL + IN OUT UINT32 *OptionsLength, OPTIONAL + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN OUT UINT32 *FragmentCount, + IN IPSEC_SAD_ENTRY *SadEntry, + OUT EFI_EVENT *RecycleEvent + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_IPSEC_SA_ID *SaId; + IPSEC_SAD_DATA *SadData; + IPSEC_RECYCLE_CONTEXT *RecycleContext; + UINT8 *ProcessBuffer; + UINTN BytesCopied; + INTN EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4 + UINTN EspSize; // Total size of esp wrapped ip payload + UINTN IvSize; // Size of IV, optional, might be 0 + UINTN PlainPayloadSize;// Original IP payload size + UINTN PaddingSize; // Size of padding + UINTN EncryptSize; // Size of data to be encrypted, start after IV and + // stop before ICV + UINTN IcvSize; // Size of ICV, optional, might be 0 + UINT8 *RestOfPayload; // Start of Payload after IV + UINT8 *Padding; // Start address of padding + EFI_ESP_HEADER *EspHeader; // Start address of ESP frame + EFI_ESP_TAIL *EspTail; // Address behind padding + UINT8 *InnerHead; + HASH_DATA_FRAGMENT HashFragment[1]; + + Status = EFI_ACCESS_DENIED; + SaId = SadEntry->Id; + SadData = SadEntry->Data; + ProcessBuffer = NULL; + RecycleContext = NULL; + *RecycleEvent = NULL; + InnerHead = NULL; + + if (!SadData->ManualSet && + SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL && + SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL + ) { + // + // Invalid manual SAD entry configuration. + // + goto ON_EXIT; + } + + // + // Create OutHeader according to Inner Header + // + if (SadData->Mode == EfiIPsecTunnel) { + InnerHead = IpSecTunnelOutboundPacket ( IpHead, - IpPayload, - OldLastHead, - SpdEntry, - &SadEntry + IpVersion, + SadData, + LastHead, + OptionsBuffer, + OptionsLength, + FragmentTable, + FragmentCount ); + + if (InnerHead == NULL) { + return EFI_INVALID_PARAMETER; + } - if (SadEntry != NULL) { - // - // Process the packet by the found sad entry. - // - Status = IpSecProtectOutboundPacket ( - IpVersion, - IpHead, - LastHead, - OptionsBuffer, - OptionsLength, - FragmentTable, - FragmentCount, - SadEntry, - RecycleSignal - ); - - } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) { - // - // TODO: if no need return not ready to upper layer, change here. - // - Status = EFI_SUCCESS; - } - } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) { - // - // For inbound icmpv6 traffic except ping request, accept the packet - // although no sad entry associated with protect spd entry. - // - IpSecLookupSadEntry ( - Private, - NicHandle, - IpVersion, - IpHead, - IpPayload, - OldLastHead, - SpdEntry, - &SadEntry - ); - if (SadEntry == NULL) { - Status = EFI_SUCCESS; - } - } + } - goto ON_EXIT; + // + // Calculate enctrypt block size, need iv by default and 4 bytes alignment. + // + EncryptBlockSize = 4; + + if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) { + EncryptBlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId); - case EfiIPsecActionBypass: - Status = EFI_SUCCESS; + if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) { goto ON_EXIT; + } + } + + // + // Calculate the plain payload size accroding to the fragment table. + // + PlainPayloadSize = 0; + for (Index = 0; Index < *FragmentCount; Index++) { + PlainPayloadSize += (*FragmentTable)[Index].FragmentLength; + } + + // + // Add IPHeader size for Tunnel Mode + // + if (SadData->Mode == EfiIPsecTunnel) { + if (IpVersion == IP_VERSION_4) { + PlainPayloadSize += sizeof (IP4_HEAD); + } else { + PlainPayloadSize += sizeof (EFI_IP6_HEADER); + } + // + // OPtions should be encryption into it + // + PlainPayloadSize += *OptionsLength; + } + - case EfiIPsecActionDiscard: + // + // Calculate icv size, optional by default and 4 bytes alignment. + // + IcvSize = 0; + if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { + IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId); + if (IcvSize % 4 != 0) { goto ON_EXIT; + } + } - default: + // + // Calcuate the total size of esp wrapped ip payload. + // + IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId); + EncryptSize = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize; + PaddingSize = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL); + EspSize = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize; + + ProcessBuffer = AllocateZeroPool (EspSize); + if (ProcessBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Calculate esp header and esp tail including header, payload and padding. + // + EspHeader = (EFI_ESP_HEADER *) ProcessBuffer; + RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize; + Padding = RestOfPayload + PlainPayloadSize; + EspTail = (EFI_ESP_TAIL *) (Padding + PaddingSize); + + // + // Fill the sn and spi fields in esp header. + // + EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1); + //EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber); + EspHeader->Spi = HTONL (SaId->Spi); + + // + // Copy the rest of payload (after iv) from the original fragment buffer. + // + BytesCopied = 0; + + // + // For Tunnel Mode + // + if (SadData->Mode == EfiIPsecTunnel) { + if (IpVersion == IP_VERSION_4) { // - // Discard the packet if no spd entry match. + // HeadLen, Total Length // - break; + ((IP4_HEAD *)InnerHead)->HeadLen = (UINT8) ((sizeof (IP4_HEAD) + *OptionsLength) >> 2); + ((IP4_HEAD *)InnerHead)->TotalLen = HTONS ((UINT16) PlainPayloadSize); + ((IP4_HEAD *)InnerHead)->Checksum = 0; + ((IP4_HEAD *)InnerHead)->Checksum = (UINT16) (~NetblockChecksum ( + (UINT8 *)InnerHead, + sizeof(IP4_HEAD) + )); + CopyMem ( + RestOfPayload + BytesCopied, + InnerHead, + sizeof (IP4_HEAD) + *OptionsLength + ); + BytesCopied += sizeof (IP4_HEAD) + *OptionsLength; + + } else { + ((EFI_IP6_HEADER *)InnerHead)->PayloadLength = HTONS ((UINT16) (PlainPayloadSize - sizeof (EFI_IP6_HEADER))); + CopyMem ( + RestOfPayload + BytesCopied, + InnerHead, + sizeof (EFI_IP6_HEADER) + *OptionsLength + ); + BytesCopied += sizeof (EFI_IP6_HEADER) + *OptionsLength; } } + for (Index = 0; Index < *FragmentCount; Index++) { + CopyMem ( + (RestOfPayload + BytesCopied), + (*FragmentTable)[Index].FragmentBuffer, + (*FragmentTable)[Index].FragmentLength + ); + BytesCopied += (*FragmentTable)[Index].FragmentLength; + } + // + // Fill the padding buffer by natural number sequence. + // + for (Index = 0; Index < PaddingSize; Index++) { + Padding[Index] = (UINT8) (Index + 1); + } + // + // Fill the padding length and next header fields in esp tail. + // + EspTail->PaddingLength = (UINT8) PaddingSize; + EspTail->NextHeader = *LastHead; + + // + // Fill the next header for Tunnel mode. + // + if (SadData->Mode == EfiIPsecTunnel) { + if (IpVersion == IP_VERSION_4) { + EspTail->NextHeader = 4; + } else { + EspTail->NextHeader = 41; + } + } + + // + // Generate iv at random by crypt library. + // + Status = IpSecGenerateIv ( + (UINT8 *) (EspHeader + 1), + IvSize + ); + + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Encryption the payload (after iv) by the SAD entry if has encrypt key. + // + if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) { + Status = IpSecCryptoIoEncrypt ( + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId, + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey, + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3, + (UINT8 *)(EspHeader + 1), + RestOfPayload, + EncryptSize, + RestOfPayload + ); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + + // + // Authenticate the esp wrapped buffer by the SAD entry if it has auth key. + // + if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { + + HashFragment[0].Data = ProcessBuffer; + HashFragment[0].DataSize = EspSize - IcvSize; + Status = IpSecCryptoIoHmac ( + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId, + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey, + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength, + HashFragment, + 1, + ProcessBuffer + EspSize - IcvSize, + IcvSize + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + + // + // Encryption and authentication with esp has been done, so it's time to + // reload the new packet, create recycle event and fixup ip header. + // + RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT)); + if (RecycleContext == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + IpSecRecycleCallback, + RecycleContext, + RecycleEvent + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + // + // Caller take responsible to handle the original fragment table. + // + *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA)); + if (*FragmentTable == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + RecycleContext->FragmentTable = *FragmentTable; + RecycleContext->PayloadBuffer = ProcessBuffer; + (*FragmentTable)[0].FragmentBuffer = ProcessBuffer; + (*FragmentTable)[0].FragmentLength = (UINT32) EspSize; + *FragmentCount = 1; + + // + // Update the total length field in ip header since processed by esp. + // + if (IpVersion == IP_VERSION_4) { + ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + EspSize)); + } else { + ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize); + } + + // + // If tunnel mode, it should change the outer Ip header with tunnel source address + // and destination tunnel address. + // + if (SadData->Mode == EfiIPsecTunnel) { + if (IpVersion == IP_VERSION_4) { + CopyMem ( + &((IP4_HEAD *) IpHead)->Src, + &SadData->TunnelSourceAddress.v4, + sizeof (EFI_IPv4_ADDRESS) + ); + CopyMem ( + &((IP4_HEAD *) IpHead)->Dst, + &SadData->TunnelDestAddress.v4, + sizeof (EFI_IPv4_ADDRESS) + ); + } else { + CopyMem ( + &((EFI_IP6_HEADER *) IpHead)->SourceAddress, + &SadData->TunnelSourceAddress.v6, + sizeof (EFI_IPv6_ADDRESS) + ); + CopyMem ( + &((EFI_IP6_HEADER *) IpHead)->DestinationAddress, + &SadData->TunnelDestAddress.v6, + sizeof (EFI_IPv6_ADDRESS) + ); + } + } + + // + // Update the next layer field in ip header since esp header inserted. + // + *LastHead = IPSEC_ESP_PROTOCOL; + + // + // Increase the sn number in SAD entry according to rfc4303. + // + SadData->SequenceNumber++; + ON_EXIT: + if (EFI_ERROR (Status)) { + if (ProcessBuffer != NULL) { + FreePool (ProcessBuffer); + } + + if (RecycleContext != NULL) { + FreePool (RecycleContext); + } + + if (*RecycleEvent != NULL) { + gBS->CloseEvent (*RecycleEvent); + } + } + return Status; } +/** + This function processes the inbound traffic with IPsec. + + It checks the received packet security property, trims the ESP/AH header, and then + returns without an IPsec protected IP Header and FragmentTable. + + @param[in] IpVersion The version of IP. + @param[in, out] IpHead Points to IP header containing the ESP/AH header + to be trimed on input, and without ESP/AH header + on return. + @param[in, out] LastHead The Last Header in IP header on return. + @param[in, out] OptionsBuffer Pointer to the options buffer. It is optional. + @param[in, out] OptionsLength Length of the options buffer. It is optional. + @param[in, out] FragmentTable Pointer to a list of fragments in form of IPsec + protected on input, and without IPsec protected + on return. + @param[in, out] FragmentCount The number of fragments. + @param[out] SpdEntry Pointer to contain the address of SPD entry on return. + @param[out] RecycleEvent The event for recycling of resources. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_UNSUPPORTED The IPSEC protocol is not supported. + +**/ +EFI_STATUS +IpSecProtectInboundPacket ( + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + IN OUT UINT8 *LastHead, + IN OUT VOID **OptionsBuffer, OPTIONAL + IN OUT UINT32 *OptionsLength, OPTIONAL + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN OUT UINT32 *FragmentCount, + OUT EFI_IPSEC_SPD_SELECTOR **SpdEntry, + OUT EFI_EVENT *RecycleEvent + ) +{ + if (*LastHead == IPSEC_ESP_PROTOCOL) { + // + // Process the esp ipsec header of the inbound traffic. + // + return IpSecEspInboundPacket ( + IpVersion, + IpHead, + LastHead, + OptionsBuffer, + OptionsLength, + FragmentTable, + FragmentCount, + SpdEntry, + RecycleEvent + ); + } + // + // The other protocols are not supported. + // + return EFI_UNSUPPORTED; +} + +/** + This fucntion processes the output traffic with IPsec. + + It protected the sending packet by encrypting it payload and inserting ESP/AH header + in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable. + + @param[in] IpVersion The version of IP. + @param[in, out] IpHead Point to IP header containing the orginal IP header + to be processed on input, and inserted ESP/AH header + on return. + @param[in, out] LastHead The Last Header in IP header. + @param[in, out] OptionsBuffer Pointer to the options buffer. It is optional. + @param[in, out] OptionsLength Length of the options buffer. It is optional. + @param[in, out] FragmentTable Pointer to a list of fragments to be protected by + IPsec on input, and with IPsec protected + on return. + @param[in, out] FragmentCount Number of fragments. + @param[in] SadEntry Related SAD entry. + @param[out] RecycleEvent Event for recycling of resources. + + @retval EFI_SUCCESS The operation is successful. + @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported. + +**/ +EFI_STATUS +IpSecProtectOutboundPacket ( + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + IN OUT UINT8 *LastHead, + IN OUT VOID **OptionsBuffer, OPTIONAL + IN OUT UINT32 *OptionsLength, OPTIONAL + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN OUT UINT32 *FragmentCount, + IN IPSEC_SAD_ENTRY *SadEntry, + OUT EFI_EVENT *RecycleEvent + ) +{ + if (SadEntry->Id->Proto == EfiIPsecESP) { + // + // Process the esp ipsec header of the outbound traffic. + // + return IpSecEspOutboundPacket ( + IpVersion, + IpHead, + LastHead, + OptionsBuffer, + OptionsLength, + FragmentTable, + FragmentCount, + SadEntry, + RecycleEvent + ); + } + // + // The other protocols are not supported. + // + return EFI_UNSUPPORTED; +} diff --git a/NetworkPkg/IpSecDxe/IpSecImpl.h b/NetworkPkg/IpSecDxe/IpSecImpl.h index 84494460c4..47805f3b9f 100644 --- a/NetworkPkg/IpSecDxe/IpSecImpl.h +++ b/NetworkPkg/IpSecDxe/IpSecImpl.h @@ -121,6 +121,14 @@ typedef struct _IPSEC_RECYCLE_CONTEXT { UINT8 *PayloadBuffer; } IPSEC_RECYCLE_CONTEXT; +// +// Struct used to store the Hash and its data. +// +typedef struct { + UINTN DataSize; + UINT8 *Data; +} HASH_DATA_FRAGMENT; + struct _IPSEC_PRIVATE_DATA { UINT32 Signature; EFI_HANDLE Handle; // Virtual handle to install private prtocol @@ -142,37 +150,37 @@ struct _IPSEC_PRIVATE_DATA { /** This function processes the inbound traffic with IPsec. - It checks the received packet security property, trims the ESP/AH header, and then + It checks the received packet security property, trims the ESP/AH header, and then returns without an IPsec protected IP Header and FragmentTable. - + @param[in] IpVersion The version of IP. - @param[in, out] IpHead Points to IP header containing the ESP/AH header + @param[in, out] IpHead Points to IP header containing the ESP/AH header to be trimed on input, and without ESP/AH header on return. - @param[out] LastHead The Last Header in IP header on return. + @param[in, out] LastHead The Last Header in IP header on return. @param[in, out] OptionsBuffer Pointer to the options buffer. It is optional. @param[in, out] OptionsLength Length of the options buffer. It is optional. - @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec + @param[in, out] FragmentTable Pointer to a list of fragments in form of IPsec protected on input, and without IPsec protected on return. - @param[in, out] FragmentCount Number of fragments. + @param[in, out] FragmentCount The number of fragments. @param[out] SpdEntry Pointer to contain the address of SPD entry on return. - @param[out] RecycleEvent Event for recycling of resources. + @param[out] RecycleEvent The event for recycling of resources. - @retval EFI_SUCCESS The operation is successful. - @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported. + @retval EFI_SUCCESS The operation was successful. + @retval EFI_UNSUPPORTED The IPSEC protocol is not supported. **/ EFI_STATUS IpSecProtectInboundPacket ( IN UINT8 IpVersion, IN OUT VOID *IpHead, - OUT UINT8 *LastHead, + IN OUT UINT8 *LastHead, IN OUT VOID **OptionsBuffer, OPTIONAL IN OUT UINT32 *OptionsLength, OPTIONAL IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, IN OUT UINT32 *FragmentCount, - OUT IPSEC_SPD_ENTRY **SpdEntry, + OUT EFI_IPSEC_SPD_SELECTOR **SpdEntry, OUT EFI_EVENT *RecycleEvent ); @@ -250,11 +258,75 @@ IpSecLookupPadEntry ( IN EFI_IP_ADDRESS *IpAddr ); +/** + Check if the specified IP packet can be serviced by this SPD entry. + + @param[in] SpdEntry Point to SPD entry. + @param[in] IpVersion Version of IP. + @param[in] IpHead Point to IP header. + @param[in] IpPayload Point to IP payload. + @param[in] Protocol The Last protocol of IP packet. + @param[in] IsOutbound Traffic direction. + @param[out] Action The support action of SPD entry. + + @retval EFI_SUCCESS Find the related SPD. + @retval EFI_NOT_FOUND Not find the related SPD entry; + +**/ +EFI_STATUS +IpSecLookupSpdEntry ( + IN IPSEC_SPD_ENTRY *SpdEntry, + IN UINT8 IpVersion, + IN VOID *IpHead, + IN UINT8 *IpPayload, + IN UINT8 Protocol, + IN BOOLEAN IsOutbound, + OUT EFI_IPSEC_ACTION *Action + ); + +/** + Look up if there is existing SAD entry for specified IP packet sending. + + This function is called by the IPsecProcess when there is some IP packet needed to + send out. This function checks if there is an existing SAD entry that can be serviced + to this IP packet sending. If no existing SAD entry could be used, this + function will invoke an IPsec Key Exchange Negotiation. + + @param[in] Private Points to private data. + @param[in] NicHandle Points to a NIC handle. + @param[in] IpVersion The version of IP. + @param[in] IpHead The IP Header of packet to be sent out. + @param[in] IpPayload The IP Payload to be sent out. + @param[in] OldLastHead The Last protocol of the IP packet. + @param[in] SpdEntry Points to a related SPD entry. + @param[out] SadEntry Contains the Point of a related SAD entry. + + @retval EFI_DEVICE_ERROR One of following conditions is TRUE: + - If don't find related UDP service. + - Sequence Number is used up. + - Extension Sequence Number is used up. + @retval EFI_NOT_READY No existing SAD entry could be used. + @retval EFI_SUCCESS Find the related SAD entry. + +**/ +EFI_STATUS +IpSecLookupSadEntry ( + IN IPSEC_PRIVATE_DATA *Private, + IN EFI_HANDLE NicHandle, + IN UINT8 IpVersion, + IN VOID *IpHead, + IN UINT8 *IpPayload, + IN UINT8 OldLastHead, + IN IPSEC_SPD_ENTRY *SpdEntry, + OUT IPSEC_SAD_ENTRY **SadEntry + ); + /** Find the SAD through whole SAD list. @param[in] Spi The SPI used to search the SAD entry. @param[in] DestAddress The destination used to search the SAD entry. + @param[in] IpVersion The IP version. Ip4 or Ip6. @return The pointer to a certain SAD entry. @@ -262,7 +334,8 @@ IpSecLookupPadEntry ( IPSEC_SAD_ENTRY * IpSecLookupSadBySpi ( IN UINT32 Spi, - IN EFI_IP_ADDRESS *DestAddress + IN EFI_IP_ADDRESS *DestAddress, + IN UINT8 IpVersion ) ; diff --git a/NetworkPkg/IpSecDxe/IpSecMain.c b/NetworkPkg/IpSecDxe/IpSecMain.c new file mode 100644 index 0000000000..247dab3381 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecMain.c @@ -0,0 +1,235 @@ +/** @file + The mian interface of IPsec Protocol. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "IpSecConfigImpl.h" +#include "IpSecImpl.h" + +EFI_IPSEC2_PROTOCOL mIpSecInstance = { IpSecProcess, NULL, TRUE }; + +/** + Handles IPsec packet processing for inbound and outbound IP packets. + + The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet. + The behavior is that it can perform one of the following actions: + bypass the packet, discard the packet, or protect the packet. + + @param[in] This Pointer to the EFI_IPSEC_PROTOCOL instance. + @param[in] NicHandle Instance of the network interface. + @param[in] IpVersion IPV4 or IPV6. + @param[in, out] IpHead Pointer to the IP Header. + @param[in, out] LastHead The protocol of the next layer to be processed by IPsec. + @param[in, out] OptionsBuffer Pointer to the options buffer. + @param[in, out] OptionsLength Length of the options buffer. + @param[in, out] FragmentTable Pointer to a list of fragments. + @param[in, out] FragmentCount Number of fragments. + @param[in] TrafficDirection Traffic direction. + @param[out] RecycleSignal Event for recycling of resources. + + @retval EFI_SUCCESS The packet was bypassed and all buffers remain the same. + @retval EFI_SUCCESS The packet was protected. + @retval EFI_ACCESS_DENIED The packet was discarded. + +**/ +EFI_STATUS +EFIAPI +IpSecProcess ( + IN EFI_IPSEC2_PROTOCOL *This, + IN EFI_HANDLE NicHandle, + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + IN OUT UINT8 *LastHead, + IN OUT VOID **OptionsBuffer, + IN OUT UINT32 *OptionsLength, + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN OUT UINT32 *FragmentCount, + IN EFI_IPSEC_TRAFFIC_DIR TrafficDirection, + OUT EFI_EVENT *RecycleSignal + ) +{ + IPSEC_PRIVATE_DATA *Private; + IPSEC_SPD_ENTRY *SpdEntry; + EFI_IPSEC_SPD_SELECTOR *SpdSelector; + IPSEC_SAD_ENTRY *SadEntry; + LIST_ENTRY *SpdList; + LIST_ENTRY *Entry; + EFI_IPSEC_ACTION Action; + EFI_STATUS Status; + UINT8 *IpPayload; + UINT8 OldLastHead; + BOOLEAN IsOutbound; + + Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (This); + IpPayload = (*FragmentTable)[0].FragmentBuffer; + IsOutbound = (BOOLEAN) ((TrafficDirection == EfiIPsecOutBound) ? TRUE : FALSE); + OldLastHead = *LastHead; + *RecycleSignal = NULL; + SpdList = &mConfigData[IPsecConfigDataTypeSpd]; + + if (!IsOutbound) { + // + // For inbound traffic, process the ipsec header of the packet. + // + Status = IpSecProtectInboundPacket ( + IpVersion, + IpHead, + LastHead, + OptionsBuffer, + OptionsLength, + FragmentTable, + FragmentCount, + &SpdSelector, + RecycleSignal + ); + + if (Status == EFI_ACCESS_DENIED || Status == EFI_OUT_OF_RESOURCES) { + // + // The packet is denied to access. + // + goto ON_EXIT; + } + + if (Status == EFI_SUCCESS) { + + // + // Check the spd entry if the packet is accessible. + // + if (SpdSelector == NULL) { + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } + + Status = EFI_ACCESS_DENIED; + NET_LIST_FOR_EACH (Entry, SpdList) { + SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); + if (IsSubSpdSelector ( + (EFI_IPSEC_CONFIG_SELECTOR *) SpdSelector, + (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector + )) { + Status = EFI_SUCCESS; + } + } + goto ON_EXIT; + } + } + + Status = EFI_ACCESS_DENIED; + + NET_LIST_FOR_EACH (Entry, SpdList) { + // + // For outbound and non-ipsec Inbound traffic: check the spd entry. + // + SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); + + if (EFI_ERROR (IpSecLookupSpdEntry ( + SpdEntry, + IpVersion, + IpHead, + IpPayload, + OldLastHead, + IsOutbound, + &Action + ))) { + // + // If the related SPD not find + // + continue; + } + + switch (Action) { + + case EfiIPsecActionProtect: + + if (IsOutbound) { + // + // For outbound traffic, lookup the sad entry. + // + Status = IpSecLookupSadEntry ( + Private, + NicHandle, + IpVersion, + IpHead, + IpPayload, + OldLastHead, + SpdEntry, + &SadEntry + ); + + if (SadEntry != NULL) { + // + // Process the packet by the found sad entry. + // + Status = IpSecProtectOutboundPacket ( + IpVersion, + IpHead, + LastHead, + OptionsBuffer, + OptionsLength, + FragmentTable, + FragmentCount, + SadEntry, + RecycleSignal + ); + + } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) { + // + // TODO: if no need return not ready to upper layer, change here. + // + Status = EFI_SUCCESS; + } + } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) { + // + // For inbound icmpv6 traffic except ping request, accept the packet + // although no sad entry associated with protect spd entry. + // + Status = IpSecLookupSadEntry ( + Private, + NicHandle, + IpVersion, + IpHead, + IpPayload, + OldLastHead, + SpdEntry, + &SadEntry + ); + if (SadEntry == NULL) { + Status = EFI_SUCCESS; + } + } + + goto ON_EXIT; + + case EfiIPsecActionBypass: + Status = EFI_SUCCESS; + goto ON_EXIT; + + case EfiIPsecActionDiscard: + goto ON_EXIT; + } + } + + // + // If don't find the related SPD entry, return the EFI_ACCESS_DENIED and discard it. + // But it the packet is NS/NA, it should be by passed even not find the related SPD entry. + // + if (OldLastHead == IP6_ICMP && + (*IpPayload == ICMP_V6_NEIGHBOR_SOLICIT || *IpPayload == ICMP_V6_NEIGHBOR_ADVERTISE) + ){ + Status = EFI_SUCCESS; + } + +ON_EXIT: + return Status; +} + diff --git a/NetworkPkg/IpSecDxe/IpSecSaEngine.c b/NetworkPkg/IpSecDxe/IpSecSaEngine.c deleted file mode 100644 index b556b246a3..0000000000 --- a/NetworkPkg/IpSecDxe/IpSecSaEngine.c +++ /dev/null @@ -1,934 +0,0 @@ -/** @file - IPsec inbound and outbound traffic processing. - - Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php. - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "IpSecImpl.h" -#include "IpSecDebug.h" -#include "IpSecCryptIo.h" - -extern LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum]; - -/** - The call back function of NetbufFromExt. - - @param[in] Arg The argument passed from the caller. - -**/ -VOID -EFIAPI -IpSecOnRecyclePacket ( - IN VOID *Arg - ) -{ -} - -/** - This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP - is released. - - @param[in] Event The related event. - @param[in] Context The data passed by the caller. - -**/ -VOID -EFIAPI -IpSecRecycleCallback ( - IN EFI_EVENT Event, - IN VOID *Context - ) -{ - IPSEC_RECYCLE_CONTEXT *RecycleContext; - - RecycleContext = (IPSEC_RECYCLE_CONTEXT *) Context; - - if (RecycleContext->FragmentTable != NULL) { - FreePool (RecycleContext->FragmentTable); - } - - if (RecycleContext->PayloadBuffer != NULL) { - FreePool (RecycleContext->PayloadBuffer); - } - - FreePool (RecycleContext); - gBS->CloseEvent (Event); - -} - -/** - Calculate the extension header of IP. The return length only doesn't contain - the fixed IP header length. - - @param[in] IpHead Points to an IP head to be calculated. - @param[in] LastHead Points to the last header of the IP header. - - @return The length of the extension header. - -**/ -UINT16 -IpSecGetPlainExtHeadSize ( - IN VOID *IpHead, - IN UINT8 *LastHead - ) -{ - UINT16 Size; - - Size = (UINT16) (LastHead - (UINT8 *) IpHead); - - if (Size > sizeof (EFI_IP6_HEADER)) { - // - // * (LastHead+1) point the last header's length but not include the first - // 8 octers, so this formluation add 8 at the end. - // - Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8); - } else { - Size = 0; - } - - return Size; -} - -/** - Authenticate the IpSec Payload and store the result in the IcvBuffer. - - @param[in] BufferToAuth The buffer to be Authenticated. - @param[in] AuthSize The size of the buffer to be Authenticated. - @param[in, out] IcvBuffer The buffer to store the ICV. - @param[in] IcvSize The size of ICV. - @param[in] Key The Key passed to the CryptLib to generate a - CRYPT_HANDLE. - @param[in] AuthAlgId The Authentication Algorithm ID. - - @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list. - @retval EFI_SUCCESS Authenticated the payload successfully. - @retval otherwise Authentication of the payload failed. -**/ -EFI_STATUS -IpSecAuthPayload ( - IN UINT8 *BufferToAuth, - IN UINTN AuthSize, - IN OUT UINT8 *IcvBuffer, - IN UINTN IcvSize, - IN VOID *Key, - IN UINT8 AuthAlgId - ) -{ - switch (AuthAlgId) { - case IKE_AALG_NONE : - case IKE_AALG_NULL : - return EFI_SUCCESS; - - default: - return EFI_UNSUPPORTED; - } -} - -/** - Verify if the Authentication payload is correct. - - @param[in] EspBuffer Points to the ESP wrapped buffer. - @param[in] EspSize The size of the ESP wrapped buffer. - @param[in] SadEntry The related SAD entry to store the authentication - algorithm key. - @param[in] IcvSize The length of ICV. - - @retval EFI_SUCCESS The authentication data is correct. - @retval EFI_ACCESS_DENIED The authentication data is not correct. - -**/ -EFI_STATUS -IpSecEspAuthVerifyPayload ( - IN UINT8 *EspBuffer, - IN UINTN EspSize, - IN IPSEC_SAD_ENTRY *SadEntry, - IN UINTN *IcvSize - ) -{ - EFI_STATUS Status; - UINTN AuthSize; - UINT8 IcvBuffer[12]; - - // - // Calculate the size of authentication payload. - // - *IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId); - AuthSize = EspSize - *IcvSize; - - // - // Calculate the icv buffer and size of the payload. - // - Status = IpSecAuthPayload ( - EspBuffer, - AuthSize, - IcvBuffer, - *IcvSize, - SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey, - SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId - ); - if (EFI_ERROR (Status)) { - return Status; - } - // - // Compare the calculated icv and the appended original icv. - // - if (CompareMem (EspBuffer + AuthSize, IcvBuffer, *IcvSize) == 0) { - return EFI_SUCCESS; - } - - DEBUG ((DEBUG_ERROR, "Error auth verify payload\n")); - return EFI_ACCESS_DENIED; -} - -/** - ESP Decrypt the payload. - - @param[in, out] PayloadBuffer Pointer to the buffer containing the ESP wrapped; - to be decrypted on input, and plaintext on return. The - number of bytes of data to be decrypted is - specified by EncryptSize. - @param[in] EncryptSize The size of the PayloadBuffer as input. - @param[in] SadEntry The related SAD entry. - @param[in] IvSize The size of IV. - @param[out] PlainPayloadSize Contains the return value of decrypted size. - @param[out] PaddingSize Contains the return value of Padding size. - @param[out] NextHeader Contains the return value of the last protocol header - of the IP packet. - - @retval EFI_UNSUPPORTED The Algorithm pointed to by the SAD entry is not supported. - @retval EFI_SUCCESS The operation completed successfully. - -**/ -EFI_STATUS -IpSecEspDecryptPayload ( - IN OUT UINT8 *PayloadBuffer, - IN UINTN EncryptSize, - IN IPSEC_SAD_ENTRY *SadEntry, - IN UINTN *IvSize, - OUT UINTN *PlainPayloadSize, - OUT UINTN *PaddingSize, - OUT UINT8 *NextHeader - ) -{ - EFI_ESP_TAIL *EspTail; - - switch (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId) { - case IKE_EALG_NULL: - EspTail = (EFI_ESP_TAIL *) (PayloadBuffer + EncryptSize - sizeof (EFI_ESP_TAIL)); - *PaddingSize = EspTail->PaddingLength; - *NextHeader = EspTail->NextHeader; - *PlainPayloadSize = EncryptSize - EspTail->PaddingLength - sizeof (EFI_ESP_TAIL); - break; - - case IKE_EALG_3DESCBC: - case IKE_EALG_AESCBC: - // - // TODO: support these algorithm - // - return EFI_UNSUPPORTED; - default : - return EFI_UNSUPPORTED; - } - - return EFI_SUCCESS; -} - -/** - ESP Encrypt the payload. - - @param[in, out] BufferToEncrypt Pointer to the buffer containing plaintext to be - encrypted on input, and ciphertext on return. The - number of bytes of data to be encrypted is - specified by EncryptSize. - @param[in, out] EncryptSize The size of the plaintext on input, and the size of the - ciphertext on return. - @param[in] IvBuffer Points to IV data. - @param[in] IvSize Size of IV. - @param[in] SadEntry Related SAD entry. - - @retval EFI_UNSUPPORTED The Algorithm pointed by SAD entry is not supported. - @retval EFI_SUCCESS The operation completed successfully. - -**/ -EFI_STATUS -IpSecEspEncryptPayload ( - IN OUT UINT8 *BufferToEncrypt, - IN OUT UINTN EncryptSize, - IN UINT8 *IvBuffer, - IN UINTN IvSize, - IN IPSEC_SAD_ENTRY *SadEntry - ) -{ - switch (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId) { - case IKE_EALG_NULL: - return EFI_SUCCESS; - - case IKE_EALG_3DESCBC: - case IKE_EALG_AESCBC: - // - // TODO: support these algorithms - // - return EFI_UNSUPPORTED; - default : - return EFI_UNSUPPORTED; - - } -} - -/** - The actual entry to relative function processes the inbound traffic of ESP header. - - This function is the subfunction of IpSecProtectInboundPacket(). It checks the - received packet security property and trim the ESP header and then returns without - an IPsec protected IP Header and FramgmentTable. - - @param[in] IpVersion The version of IP. - @param[in, out] IpHead Points to the IP header containing the ESP header - to be trimed on input, and without ESP header - on return. - @param[out] LastHead The Last Header in IP header on return. - @param[in, out] OptionsBuffer Pointer to the options buffer. It is optional. - @param[in, out] OptionsLength Length of the options buffer. It is optional. - @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec - protected on input, and without IPsec protected - on return. - @param[in, out] FragmentCount The number of fragments. - @param[out] SpdEntry Pointer to contain the address of SPD entry on return. - @param[out] RecycleEvent The event for recycling of resources. - - @retval EFI_SUCCESS The operation was successful. - @retval EFI_ACCESS_DENIED One or more following conditions is TRUE: - - ESP header was not found. - - The related SAD entry was not found. - - The related SAD entry does not support the ESP protocol. - @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated. - -**/ -EFI_STATUS -IpSecEspInboundPacket ( - IN UINT8 IpVersion, - IN OUT VOID *IpHead, - OUT UINT8 *LastHead, - IN OUT VOID **OptionsBuffer, OPTIONAL - IN OUT UINT32 *OptionsLength, OPTIONAL - IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, - IN OUT UINT32 *FragmentCount, - OUT IPSEC_SPD_ENTRY **SpdEntry, - OUT EFI_EVENT *RecycleEvent - ) -{ - EFI_STATUS Status; - NET_BUF *Payload; - UINTN EspSize; - UINTN IvSize; - UINTN PlainPayloadSize; - UINTN PaddingSize; - UINTN IcvSize; - UINT8 *ProcessBuffer; - EFI_IP_ADDRESS DestIp; - EFI_ESP_HEADER *EspHeader; - EFI_ESP_TAIL *EspTail; - EFI_IPSEC_SA_ID *SaId; - IPSEC_SAD_DATA *SadData; - IPSEC_SAD_ENTRY *SadEntry; - IPSEC_RECYCLE_CONTEXT *RecycleContext; - UINT32 Spi; - UINT8 NextHeader; - UINT16 IpSecHeadSize; - - Status = EFI_SUCCESS; - Payload = NULL; - ProcessBuffer = NULL; - RecycleContext = NULL; - *RecycleEvent = NULL; - PlainPayloadSize = 0; - NextHeader = 0; - // - // Build netbuf from fragment table first. - // - Payload = NetbufFromExt ( - (NET_FRAGMENT *) *FragmentTable, - *FragmentCount, - 0, - sizeof (EFI_ESP_HEADER), - IpSecOnRecyclePacket, - NULL - ); - if (Payload == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - // - // Get the esp size and eso header from netbuf. - // - EspSize = Payload->TotalSize; - EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL); - if (EspHeader == NULL) { - Status = EFI_ACCESS_DENIED; - goto ON_EXIT; - } - // - // Parse destination address from ip header. - // - ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS)); - if (IpVersion == IP_VERSION_4) { - CopyMem ( - &DestIp, - &((IP4_HEAD *) IpHead)->Dst, - sizeof (IP4_ADDR) - ); - } else { - CopyMem ( - &DestIp, - &((EFI_IP6_HEADER *) IpHead)->DestinationAddress, - sizeof (EFI_IPv6_ADDRESS) - ); - } - // - // Lookup sad entry according to the spi and dest address. - // - Spi = NTOHL (EspHeader->Spi); - SadEntry = IpSecLookupSadBySpi (Spi, &DestIp); - if (SadEntry == NULL) { - Status = EFI_ACCESS_DENIED; - goto ON_EXIT; - } - - SaId = SadEntry->Id; - SadData = SadEntry->Data; - - // - // Only support esp protocol currently. - // - if (SaId->Proto != EfiIPsecESP) { - Status = EFI_ACCESS_DENIED; - goto ON_EXIT; - } - - if (!SadData->ManualSet) { - // - // TODO: Check sa lifetime and sequence number - // - } - // - // Allocate buffer for decryption and authentication by esp. - // - ProcessBuffer = AllocateZeroPool (EspSize); - if (ProcessBuffer == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - - NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer); - - // - // Authenticate the esp wrapped buffer by the sad entry if has auth key. - // - IcvSize = 0; - if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { - Status = IpSecEspAuthVerifyPayload ( - ProcessBuffer, - EspSize, - SadEntry, - &IcvSize - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - } - // - // Decrypt the payload by the sad entry if has decrypt key. - // - IvSize = 0; - if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) { - Status = IpSecEspDecryptPayload ( - ProcessBuffer + sizeof (EFI_ESP_HEADER), - EspSize - sizeof (EFI_ESP_HEADER) - IcvSize, - SadEntry, - &IvSize, - &PlainPayloadSize, - &PaddingSize, - &NextHeader - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - } else { - EspTail = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL)); - PaddingSize = EspTail->PaddingLength; - NextHeader = EspTail->NextHeader; - PlainPayloadSize = EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize - sizeof (EFI_ESP_TAIL) - PaddingSize; - } - // - // TODO: handle anti-replay window - // - // - // Decryption and authentication with esp has been done, so it's time to - // reload the new packet, create recycle event and fixup ip header. - // - RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT)); - if (RecycleContext == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - IpSecRecycleCallback, - RecycleContext, - RecycleEvent - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - // - // TODO: Who take responsible to handle the original fragment table? - // - *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA)); - if (*FragmentTable == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - - RecycleContext->PayloadBuffer = ProcessBuffer; - RecycleContext->FragmentTable = *FragmentTable; - (*FragmentTable)[0].FragmentBuffer = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize; - (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize; - *FragmentCount = 1; - - // - // Update the total length field in ip header since processed by esp. - // - if (IpVersion == IP_VERSION_4) { - ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) (((IP4_HEAD *) IpHead)->HeadLen + PlainPayloadSize)); - } else { - IpSecHeadSize = IpSecGetPlainExtHeadSize (IpHead, LastHead); - ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize)); - } - // - // Update the next layer field in ip header since esp header inserted. - // - *LastHead = NextHeader; - - // - // Update the spd association of the sad entry. - // - *SpdEntry = SadData->SpdEntry; - -ON_EXIT: - if (Payload != NULL) { - NetbufFree (Payload); - } - - if (EFI_ERROR (Status)) { - if (ProcessBuffer != NULL) { - FreePool (ProcessBuffer); - } - - if (RecycleContext != NULL) { - FreePool (RecycleContext); - } - - if (*RecycleEvent != NULL) { - gBS->CloseEvent (*RecycleEvent); - } - } - - return Status; -} - -/** - The actual entry to the relative function processes the output traffic using the ESP protocol. - - This function is the subfunction of IpSecProtectOutboundPacket(). It protected - the sending packet by encrypting its payload and inserting ESP header in the orginal - IP header, then return the IpHeader and IPsec protected Fragmentable. - - @param[in] IpVersion The version of IP. - @param[in, out] IpHead Points to IP header containing the orginal IP header - to be processed on input, and inserted ESP header - on return. - @param[in, out] LastHead The Last Header in IP header. - @param[in, out] OptionsBuffer Pointer to the options buffer. It is optional. - @param[in, out] OptionsLength Length of the options buffer. It is optional. - @param[in, out] FragmentTable Pointer to a list of fragments to be protected by - IPsec on input, and with IPsec protected - on return. - @param[in, out] FragmentCount The number of fragments. - @param[in] SadEntry The related SAD entry. - @param[out] RecycleEvent The event for recycling of resources. - - @retval EFI_SUCCESS The operation was successful. - @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated. - -**/ -EFI_STATUS -IpSecEspOutboundPacket ( - IN UINT8 IpVersion, - IN OUT VOID *IpHead, - IN OUT UINT8 *LastHead, - IN OUT VOID **OptionsBuffer, OPTIONAL - IN OUT UINT32 *OptionsLength, OPTIONAL - IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, - IN OUT UINT32 *FragmentCount, - IN IPSEC_SAD_ENTRY *SadEntry, - OUT EFI_EVENT *RecycleEvent - ) -{ - EFI_STATUS Status; - UINTN Index; - EFI_IPSEC_SA_ID *SaId; - IPSEC_SAD_DATA *SadData; - IPSEC_RECYCLE_CONTEXT *RecycleContext; - UINT8 *ProcessBuffer; - UINTN BytesCopied; - INTN EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4 - UINTN EspSize; // Total size of esp wrapped ip payload - UINTN IvSize; // Size of IV, optional, might be 0 - UINTN PlainPayloadSize;// Original IP payload size - UINTN PaddingSize; // Size of padding - UINTN EncryptSize; // Size of data to be encrypted, start after IV and - // stop before ICV - UINTN IcvSize; // Size of ICV, optional, might be 0 - UINT8 *RestOfPayload; // Start of Payload after IV - UINT8 *Padding; // Start address of padding - EFI_ESP_HEADER *EspHeader; // Start address of ESP frame - EFI_ESP_TAIL *EspTail; // Address behind padding - - Status = EFI_ACCESS_DENIED; - SaId = SadEntry->Id; - SadData = SadEntry->Data; - ProcessBuffer = NULL; - RecycleContext = NULL; - *RecycleEvent = NULL; - - if (!SadData->ManualSet && - SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL && - SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL - ) { - // - // Invalid manual sad entry configuration. - // - goto ON_EXIT; - } - // - // Calculate enctrypt block size, need iv by default and 4 bytes alignment. - // - EncryptBlockSize = 4; - - if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) { - EncryptBlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId); - - if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) { - goto ON_EXIT; - } - } - // - // Calculate the plain payload size accroding to the fragment table. - // - PlainPayloadSize = 0; - for (Index = 0; Index < *FragmentCount; Index++) { - PlainPayloadSize += (*FragmentTable)[Index].FragmentLength; - } - // - // Calculate icv size, optional by default and 4 bytes alignment. - // - IcvSize = 0; - if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { - IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId); - if (IcvSize % 4 != 0) { - goto ON_EXIT; - } - } - // - // Calcuate the total size of esp wrapped ip payload. - // - IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId); - EncryptSize = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize; - PaddingSize = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL); - EspSize = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize; - - ProcessBuffer = AllocateZeroPool (EspSize); - if (ProcessBuffer == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - // - // Calculate esp header and esp tail including header, payload and padding. - // - EspHeader = (EFI_ESP_HEADER *) ProcessBuffer; - RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize; - Padding = RestOfPayload + PlainPayloadSize; - EspTail = (EFI_ESP_TAIL *) (Padding + PaddingSize); - - // - // Fill the sn and spi fields in esp header. - // - EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1); - EspHeader->Spi = HTONL (SaId->Spi); - - // - // Copy the rest of payload (after iv) from the original fragment buffer. - // - BytesCopied = 0; - for (Index = 0; Index < *FragmentCount; Index++) { - CopyMem ( - (RestOfPayload + BytesCopied), - (*FragmentTable)[Index].FragmentBuffer, - (*FragmentTable)[Index].FragmentLength - ); - BytesCopied += (*FragmentTable)[Index].FragmentLength; - } - // - // Fill the padding buffer by natural number sequence. - // - for (Index = 0; Index < PaddingSize; Index++) { - Padding[Index] = (UINT8) (Index + 1); - } - // - // Fill the padding length and next header fields in esp tail. - // - EspTail->PaddingLength = (UINT8) PaddingSize; - EspTail->NextHeader = *LastHead; - - // - // Generate iv at random by crypt library. - // - Status = IpSecGenerateIv ( - (UINT8 *) (EspHeader + 1), - IvSize - ); - - - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - // - // Encrypt the payload (after iv) by the sad entry if has encrypt key. - // - if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) { - Status = IpSecEspEncryptPayload ( - RestOfPayload, - EncryptSize, - (UINT8 *) (EspHeader + 1), - IvSize, - SadEntry - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - } - // - // Authenticate the esp wrapped buffer by the sad entry if has auth key. - // - if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { - Status = IpSecAuthPayload ( - ProcessBuffer, - EspSize - IcvSize, - ProcessBuffer + EspSize - IcvSize, - IcvSize, - SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey, - SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - } - // - // Encryption and authentication with esp has been done, so it's time to - // reload the new packet, create recycle event and fixup ip header. - // - RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT)); - if (RecycleContext == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - IpSecRecycleCallback, - RecycleContext, - RecycleEvent - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - // - // TODO: Who take responsible to handle the original fragment table? - // - *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA)); - if (*FragmentTable == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - - RecycleContext->FragmentTable = *FragmentTable; - RecycleContext->PayloadBuffer = ProcessBuffer; - (*FragmentTable)[0].FragmentBuffer = ProcessBuffer; - (*FragmentTable)[0].FragmentLength = (UINT32) EspSize; - *FragmentCount = 1; - - // - // Update the total length field in ip header since processed by esp. - // - if (IpVersion == IP_VERSION_4) { - ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) (((IP4_HEAD *) IpHead)->HeadLen + EspSize)); - } else { - ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize); - } - // - // Update the next layer field in ip header since esp header inserted. - // - *LastHead = IPSEC_ESP_PROTOCOL; - - // - // Increase the sn number in sad entry according to rfc4303. - // - SadData->SequenceNumber++; - -ON_EXIT: - if (EFI_ERROR (Status)) { - if (ProcessBuffer != NULL) { - FreePool (ProcessBuffer); - } - - if (RecycleContext != NULL) { - FreePool (RecycleContext); - } - - if (*RecycleEvent != NULL) { - gBS->CloseEvent (*RecycleEvent); - } - } - - return Status; -} - -/** - This function processes the inbound traffic with IPsec. - - It checks the received packet security property, trims the ESP/AH header, and then - returns without an IPsec protected IP Header and FragmentTable. - - @param[in] IpVersion The version of IP. - @param[in, out] IpHead Points to IP header containing the ESP/AH header - to be trimed on input, and without ESP/AH header - on return. - @param[out] LastHead The Last Header in IP header on return. - @param[in, out] OptionsBuffer Pointer to the options buffer. It is optional. - @param[in, out] OptionsLength Length of the options buffer. It is optional. - @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec - protected on input, and without IPsec protected - on return. - @param[in, out] FragmentCount Number of fragments. - @param[out] SpdEntry Pointer to contain the address of SPD entry on return. - @param[out] RecycleEvent Event for recycling of resources. - - @retval EFI_SUCCESS The operation is successful. - @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported. - -**/ -EFI_STATUS -IpSecProtectInboundPacket ( - IN UINT8 IpVersion, - IN OUT VOID *IpHead, - OUT UINT8 *LastHead, - IN OUT VOID **OptionsBuffer, OPTIONAL - IN OUT UINT32 *OptionsLength, OPTIONAL - IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, - IN OUT UINT32 *FragmentCount, - OUT IPSEC_SPD_ENTRY **SpdEntry, - OUT EFI_EVENT *RecycleEvent - ) -{ - if (*LastHead == IPSEC_ESP_PROTOCOL) { - // - // Process the esp ipsec header of the inbound traffic. - // - return IpSecEspInboundPacket ( - IpVersion, - IpHead, - LastHead, - OptionsBuffer, - OptionsLength, - FragmentTable, - FragmentCount, - SpdEntry, - RecycleEvent - ); - } - // - // The other protocols are not supported. - // - return EFI_UNSUPPORTED; -} - -/** - This fucntion processes the output traffic with IPsec. - - It protected the sending packet by encrypting it payload and inserting ESP/AH header - in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable. - - @param[in] IpVersion The version of IP. - @param[in, out] IpHead Point to IP header containing the orginal IP header - to be processed on input, and inserted ESP/AH header - on return. - @param[in, out] LastHead The Last Header in IP header. - @param[in, out] OptionsBuffer Pointer to the options buffer. It is optional. - @param[in, out] OptionsLength Length of the options buffer. It is optional. - @param[in, out] FragmentTable Pointer to a list of fragments to be protected by - IPsec on input, and with IPsec protected - on return. - @param[in, out] FragmentCount Number of fragments. - @param[in] SadEntry Related SAD entry. - @param[out] RecycleEvent Event for recycling of resources. - - @retval EFI_SUCCESS The operation is successful. - @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported. - -**/ -EFI_STATUS -IpSecProtectOutboundPacket ( - IN UINT8 IpVersion, - IN OUT VOID *IpHead, - IN OUT UINT8 *LastHead, - IN OUT VOID **OptionsBuffer, OPTIONAL - IN OUT UINT32 *OptionsLength, OPTIONAL - IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, - IN OUT UINT32 *FragmentCount, - IN IPSEC_SAD_ENTRY *SadEntry, - OUT EFI_EVENT *RecycleEvent - ) -{ - if (SadEntry->Id->Proto == EfiIPsecESP) { - // - // Process the esp ipsec header of the outbound traffic. - // - return IpSecEspOutboundPacket ( - IpVersion, - IpHead, - LastHead, - OptionsBuffer, - OptionsLength, - FragmentTable, - FragmentCount, - SadEntry, - RecycleEvent - ); - } - // - // The other protocols are not supported. - // - return EFI_UNSUPPORTED; -} diff --git a/NetworkPkg/NetworkPkg.dec b/NetworkPkg/NetworkPkg.dec index 0c8df4eed8..5ac0b0ee2a 100644 --- a/NetworkPkg/NetworkPkg.dec +++ b/NetworkPkg/NetworkPkg.dec @@ -19,3 +19,19 @@ PACKAGE_NAME = NetworkPkg PACKAGE_GUID = 947988BE-8D5C-471a-893D-AD181C46BEBB PACKAGE_VERSION = 0.92 +[Guids] + ## LocalNetwork package token space guid + # Include/Guid/NetworkPkgTokenSpace.h + gEfiNetworkPkgTokenSpaceGuid = { 0x40e064b2, 0x0ae0, 0x48b1, { 0xa0, 0x7d, 0xf8, 0xcf, 0x1e, 0x1a, 0x23, 0x10}} + +[PcdsFeatureFlag] + gEfiNetworkPkgTokenSpaceGuid.PcdIpsecCertiifcateEnabled|TRUE|BOOLEAN|0x00000001 + +[PcdsFixedAtBuild] +gEfiMdeModulePkgTokenSpaceGuid.UefiCaFile|{0x30, 0x82, 0x02, 0x76, 0x30, 0x82, 0x01, 0xDF, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x80, 0x1D, 0xB9, 0x63, 0x93, 0x7C, 0x9D, 0xE0, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x30, 0x74, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0A, 0x4D, 0x79, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, 0x48, 0x5A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4E, 0x31, 0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x0D, 0x74, 0x65, 0x73, 0x74, 0x40, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x1C, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0x35, 0x33, 0x33, 0x37, 0x5A, 0x17, 0x0D, 0x31, 0x31, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0x35, 0x33, 0x33, 0x37, 0x5A, 0x30, 0x74, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0A, 0x4D, 0x79, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, 0x48, 0x5A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4E, 0x31, 0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x0D, 0x74, 0x65, 0x73, 0x74, 0x40, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x1C, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x30, 0x81, 0x9F, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8D, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xFC, 0x80, 0x5D, 0x32, 0x55, 0xC7, 0x4C, 0xC6, 0xA8, 0x2F, 0xF7, 0xEC, 0x1F, 0x75, 0x48, 0x02, 0x79, 0xEB, 0xDF, 0x17, 0x1B, 0x08, 0xBA, 0x21, 0xDD, 0xE5, 0x43, 0x06, 0xE8, 0x81, 0xC5, 0x50, 0x3C, 0x18, 0xDD, 0x53, 0xF4, 0xC9, 0xC9, 0xE1, 0x7A, 0xD3, 0xB3, 0x99, 0xA7, 0xC6, 0x43, 0x2A, 0x51, 0x65, 0x10, 0x93, 0xBA, 0x5F, 0x48, 0xAC, 0x54, 0x12, 0x70, 0x9E, 0xF2, 0x9E, 0x7D, 0xF7, 0x22, 0xAA, 0xB7, 0x19, 0xDE, 0xA9, 0x4D, 0x55, 0xAA, 0x41, 0x8F, 0x08, 0xBD, 0x74, 0xFA, 0xE5, 0x57, 0x13, 0xB4, 0x30, 0x9A, 0xBA, 0x56, 0x01, 0x55, 0x8A, 0x9B, 0x5B, 0x50, 0x29, 0x82, 0xF9, 0x00, 0x69, 0x7E, 0x7B, 0x91, 0xA7, 0x2D, 0x48, 0x1A, 0x93, 0x7C, 0xA2, 0xF9, 0x06, 0x64, 0x4B, 0x80, 0xF8, 0x47, 0x58, 0x45, 0x90, 0x09, 0xEA, 0xD6, 0x7B, 0x85, 0x49, 0x2A, 0x4E, 0xB6, 0x71, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x10, 0x30, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xEF, 0x38, 0x6A, 0x43, 0x1C, 0x1D, 0x37, 0xBD, 0xF7, 0xCF, 0x15, 0x6A, 0x99, 0x44, 0xE1, 0xFC, 0x68, 0x6E, 0x91, 0x31, 0x9C, 0x1E, 0x8C, 0x1F, 0x72, 0x4B, 0x93, 0x16, 0x1F, 0x06, 0xFE, 0x94, 0xA9, 0x41, 0x64, 0x81, 0xFD, 0xFF, 0xE7, 0x27, 0x4D, 0xE7, 0x59, 0x55, 0xE1, 0x20, 0x14, 0x07, 0x3C, 0x26, 0x78, 0xB0, 0x72, 0x48, 0x76, 0x0C, 0x8B, 0x3F, 0x08, 0xD0, 0x75, 0x7D, 0x76, 0xA4, 0xB5, 0x56, 0xA6, 0xC9, 0x88, 0x17, 0x27, 0x95, 0x85, 0xEE, 0x42, 0x1E, 0x15, 0x0B, 0x05, 0xDC, 0x2F, 0x97, 0x7B, 0x26, 0x82, 0x62, 0x23, 0xDF, 0xBF, 0x55, 0x09, 0xBF, 0x5E, 0x28, 0x1A, 0xCA, 0x1B, 0xEC, 0xA4, 0x81, 0xB7, 0x9D, 0x91, 0xC9, 0x60, 0x5B, 0x29, 0x2B, 0x4C, 0x6F, 0x8B, 0xCC, 0x17, 0xA8, 0xD6, 0x5D, 0x6B, 0xBC, 0x0D, 0x03, 0x31, 0xB0, 0x57, 0xC9, 0xF8, 0x59, 0x88, 0x3D}|VOID*|0x00000001 +gEfiMdeModulePkgTokenSpaceGuid.UefiCaFileSize|0x0000027A|UINT32|0x00000002 +gEfiMdeModulePkgTokenSpaceGuid.UefiCertificate|{0x30, 0x82, 0x02, 0x4D, 0x30, 0x82, 0x01, 0xB6, 0x02, 0x01, 0x01, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x30, 0x74, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0A, 0x4D, 0x79, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, 0x48, 0x5A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4E, 0x31, 0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x0D, 0x74, 0x65, 0x73, 0x74, 0x40, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x1C, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x32, 0x30, 0x34, 0x35, 0x39, 0x5A, 0x17, 0x0D, 0x31, 0x31, 0x31, 0x31, 0x30, 0x31, 0x30, 0x32, 0x30, 0x34, 0x35, 0x39, 0x5A, 0x30, 0x6A, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x04, 0x55, 0x45, 0x46, 0x49, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, 0x53, 0x48, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4E, 0x31, 0x23, 0x30, 0x21, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x14, 0x75, 0x65, 0x66, 0x69, 0x2E, 0x74, 0x69, 0x61, 0x6E, 0x6F, 0x40, 0x69, 0x6E, 0x74, 0x65, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x03, 0x53, 0x53, 0x47, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x03, 0x53, 0x53, 0x47, 0x30, 0x81, 0x9F, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8D, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xE9, 0x90, 0x47, 0x0D, 0x79, 0x93, 0xED, 0xF5, 0xBD, 0xC9, 0x56, 0x03, 0xDF, 0xE2, 0x71, 0xA9, 0x42, 0x3B, 0x20, 0x1E, 0xAF, 0x88, 0x9D, 0x3F, 0xE1, 0xDE, 0x61, 0xEE, 0x83, 0xC4, 0x2E, 0x48, 0x7A, 0x1F, 0x86, 0x54, 0xD2, 0xD5, 0x61, 0x94, 0xE1, 0x15, 0x79, 0x65, 0xCB, 0x39, 0xEE, 0x78, 0x68, 0x3D, 0x2C, 0xEB, 0xE4, 0x7A, 0x8D, 0x98, 0x14, 0x28, 0x7E, 0x6B, 0xFD, 0xC5, 0xF5, 0x1B, 0x62, 0xB9, 0x86, 0x7C, 0xA1, 0x7C, 0xE9, 0x8F, 0xC8, 0xF4, 0xF3, 0x95, 0x5A, 0xAF, 0x0C, 0x21, 0x39, 0xEA, 0x47, 0x5A, 0x1E, 0xBD, 0xBE, 0x7F, 0x1B, 0x0F, 0x31, 0xFB, 0xBD, 0x57, 0xAE, 0xD7, 0xCB, 0x46, 0x83, 0x8B, 0x16, 0x19, 0x74, 0xD9, 0x9E, 0x2D, 0x18, 0xE6, 0xA4, 0x5F, 0x90, 0x90, 0x54, 0xE1, 0x4B, 0x7B, 0x57, 0x76, 0xBD, 0xF4, 0xC0, 0x4D, 0x79, 0x5F, 0x64, 0x6C, 0x0D, 0x2D, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x5A, 0x80, 0x5F, 0xD3, 0x3C, 0x93, 0x81, 0xB9, 0x1B, 0xAA, 0x08, 0x1F, 0x47, 0x9C, 0x88, 0xF3, 0x1E, 0xE6, 0x6B, 0xBB, 0x99, 0xE6, 0x23, 0x1A, 0xCB, 0x25, 0x81, 0x54, 0x51, 0x88, 0xDF, 0x9B, 0xC6, 0xBF, 0x60, 0xDB, 0x6C, 0x5D, 0x69, 0xB1, 0x3A, 0xDE, 0x94, 0xEE, 0xD7, 0x6C, 0xF2, 0x2D, 0x63, 0xD3, 0xB3, 0xAB, 0xE6, 0xB5, 0x0A, 0xBF, 0xCE, 0x61, 0xC0, 0xD3, 0x73, 0x9E, 0x80, 0xB5, 0x0C, 0xC0, 0x03, 0x57, 0xA9, 0x56, 0x59, 0x1B, 0xA2, 0x99, 0x03, 0xA6, 0xA3, 0xC4, 0x59, 0xB3, 0xD9, 0x14, 0xA1, 0x34, 0x18, 0xF3, 0x73, 0xB8, 0x54, 0xAA, 0xED, 0x7D, 0x31, 0x3E, 0x23, 0xAD, 0xF1, 0x86, 0xF7, 0xE6, 0xD9, 0x01, 0x0D, 0x68, 0xC6, 0xC5, 0x95, 0x18, 0xD2, 0x89, 0xB7, 0x06, 0x96, 0xC9, 0x11, 0xB9, 0xF0, 0xDA, 0xD9, 0x02, 0x25, 0xC4, 0xB9, 0x72, 0xF8, 0x6D, 0xC5, 0x5B}|VOID*|0x00000003 +gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateSize|0x251|UINT32|0x00000004 +gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateKey|{0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x52, 0x53, 0x41, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x50, 0x72, 0x6F, 0x63, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, 0x20, 0x34, 0x2C, 0x45, 0x4E, 0x43, 0x52, 0x59, 0x50, 0x54, 0x45, 0x44, 0x0A, 0x44, 0x45, 0x4B, 0x2D, 0x49, 0x6E, 0x66, 0x6F, 0x3A, 0x20, 0x44, 0x45, 0x53, 0x2D, 0x45, 0x44, 0x45, 0x33, 0x2D, 0x43, 0x42, 0x43, 0x2C, 0x32, 0x42, 0x31, 0x46, 0x42, 0x41, 0x43, 0x41, 0x38, 0x36, 0x32, 0x36, 0x33, 0x34, 0x41, 0x37, 0x0A, 0x0A, 0x61, 0x52, 0x78, 0x49, 0x58, 0x33, 0x59, 0x4D, 0x68, 0x49, 0x50, 0x41, 0x73, 0x59, 0x79, 0x6F, 0x6A, 0x49, 0x76, 0x46, 0x7A, 0x42, 0x75, 0x6B, 0x74, 0x6B, 0x4A, 0x47, 0x5A, 0x38, 0x4D, 0x64, 0x33, 0x5A, 0x53, 0x73, 0x39, 0x41, 0x2B, 0x52, 0x2B, 0x57, 0x45, 0x59, 0x41, 0x70, 0x34, 0x63, 0x4F, 0x55, 0x43, 0x4A, 0x78, 0x51, 0x2F, 0x66, 0x4A, 0x38, 0x58, 0x4F, 0x45, 0x64, 0x58, 0x38, 0x0A, 0x31, 0x63, 0x4E, 0x66, 0x4B, 0x2B, 0x49, 0x62, 0x76, 0x4B, 0x4D, 0x68, 0x55, 0x67, 0x30, 0x4B, 0x4E, 0x35, 0x38, 0x37, 0x71, 0x66, 0x2F, 0x4C, 0x31, 0x76, 0x57, 0x58, 0x6F, 0x31, 0x74, 0x5A, 0x6B, 0x59, 0x2B, 0x5A, 0x53, 0x4E, 0x63, 0x46, 0x45, 0x41, 0x76, 0x37, 0x43, 0x43, 0x50, 0x51, 0x6B, 0x64, 0x4A, 0x42, 0x48, 0x35, 0x65, 0x6B, 0x35, 0x44, 0x51, 0x2F, 0x37, 0x6D, 0x71, 0x55, 0x0A, 0x6B, 0x76, 0x78, 0x48, 0x53, 0x50, 0x70, 0x34, 0x66, 0x41, 0x71, 0x47, 0x61, 0x68, 0x54, 0x31, 0x75, 0x37, 0x37, 0x56, 0x66, 0x4E, 0x66, 0x31, 0x53, 0x74, 0x61, 0x73, 0x31, 0x6E, 0x4F, 0x67, 0x6A, 0x50, 0x31, 0x41, 0x6C, 0x7A, 0x6E, 0x6B, 0x6A, 0x57, 0x61, 0x72, 0x6A, 0x51, 0x4F, 0x73, 0x48, 0x46, 0x33, 0x41, 0x46, 0x31, 0x62, 0x61, 0x51, 0x4A, 0x50, 0x5A, 0x31, 0x6A, 0x71, 0x4C, 0x0A, 0x61, 0x30, 0x49, 0x45, 0x6E, 0x30, 0x6C, 0x59, 0x6C, 0x78, 0x35, 0x79, 0x4D, 0x6D, 0x78, 0x54, 0x47, 0x57, 0x79, 0x52, 0x35, 0x70, 0x57, 0x51, 0x35, 0x71, 0x66, 0x78, 0x2B, 0x62, 0x37, 0x64, 0x37, 0x75, 0x71, 0x67, 0x47, 0x69, 0x66, 0x36, 0x6A, 0x44, 0x47, 0x4D, 0x37, 0x68, 0x38, 0x43, 0x78, 0x2F, 0x74, 0x67, 0x2B, 0x61, 0x62, 0x45, 0x31, 0x34, 0x30, 0x2F, 0x50, 0x66, 0x6C, 0x33, 0x0A, 0x33, 0x6A, 0x50, 0x6C, 0x52, 0x75, 0x73, 0x57, 0x6F, 0x6F, 0x63, 0x49, 0x41, 0x76, 0x49, 0x74, 0x79, 0x51, 0x6D, 0x39, 0x39, 0x71, 0x74, 0x34, 0x64, 0x6E, 0x74, 0x6E, 0x74, 0x6F, 0x4A, 0x43, 0x6D, 0x4F, 0x53, 0x79, 0x71, 0x67, 0x4D, 0x6E, 0x76, 0x2F, 0x76, 0x2B, 0x51, 0x48, 0x74, 0x79, 0x4D, 0x73, 0x42, 0x64, 0x38, 0x34, 0x78, 0x45, 0x57, 0x46, 0x36, 0x72, 0x58, 0x4D, 0x52, 0x63, 0x0A, 0x53, 0x2B, 0x66, 0x68, 0x54, 0x71, 0x58, 0x74, 0x54, 0x38, 0x44, 0x50, 0x65, 0x70, 0x2F, 0x56, 0x44, 0x66, 0x65, 0x78, 0x6B, 0x41, 0x63, 0x6D, 0x63, 0x75, 0x41, 0x69, 0x6F, 0x2B, 0x79, 0x64, 0x51, 0x75, 0x49, 0x31, 0x32, 0x7A, 0x50, 0x70, 0x45, 0x68, 0x50, 0x45, 0x68, 0x31, 0x44, 0x50, 0x58, 0x73, 0x64, 0x58, 0x67, 0x64, 0x77, 0x39, 0x75, 0x46, 0x47, 0x6D, 0x63, 0x35, 0x68, 0x52, 0x0A, 0x35, 0x31, 0x57, 0x41, 0x31, 0x65, 0x63, 0x44, 0x48, 0x6A, 0x31, 0x58, 0x32, 0x45, 0x72, 0x36, 0x39, 0x59, 0x70, 0x31, 0x50, 0x69, 0x43, 0x37, 0x49, 0x47, 0x79, 0x6F, 0x71, 0x57, 0x43, 0x37, 0x69, 0x2F, 0x71, 0x6D, 0x6D, 0x72, 0x49, 0x66, 0x6F, 0x41, 0x54, 0x74, 0x39, 0x58, 0x34, 0x30, 0x54, 0x56, 0x63, 0x37, 0x42, 0x63, 0x6A, 0x34, 0x63, 0x54, 0x31, 0x78, 0x37, 0x6B, 0x70, 0x4F, 0x0A, 0x4C, 0x71, 0x67, 0x33, 0x6C, 0x50, 0x78, 0x33, 0x2B, 0x4A, 0x63, 0x33, 0x43, 0x67, 0x34, 0x79, 0x5A, 0x54, 0x66, 0x6E, 0x4A, 0x5A, 0x37, 0x48, 0x76, 0x36, 0x64, 0x68, 0x67, 0x45, 0x6D, 0x70, 0x4D, 0x73, 0x74, 0x46, 0x65, 0x35, 0x34, 0x49, 0x53, 0x76, 0x74, 0x38, 0x37, 0x59, 0x4E, 0x77, 0x74, 0x4C, 0x65, 0x6C, 0x34, 0x67, 0x50, 0x4A, 0x79, 0x53, 0x42, 0x30, 0x4B, 0x76, 0x37, 0x69, 0x0A, 0x33, 0x32, 0x74, 0x37, 0x67, 0x4F, 0x30, 0x79, 0x6D, 0x73, 0x62, 0x71, 0x4A, 0x55, 0x75, 0x79, 0x41, 0x68, 0x47, 0x64, 0x33, 0x63, 0x2B, 0x78, 0x4C, 0x46, 0x2F, 0x63, 0x63, 0x4F, 0x57, 0x44, 0x52, 0x34, 0x79, 0x72, 0x30, 0x6A, 0x79, 0x64, 0x74, 0x70, 0x79, 0x69, 0x64, 0x52, 0x45, 0x66, 0x56, 0x46, 0x66, 0x5 +3, 0x6C, 0x39, 0x54, 0x30, 0x6D, 0x53, 0x72, 0x4E, 0x76, 0x43, 0x71, 0x45, 0x0A, 0x52, 0x52, 0x5A, 0x6E, 0x42, 0x56, 0x76, 0x37, 0x50, 0x66, 0x6C, 0x75, 0x72, 0x31, 0x59, 0x35, 0x70, 0x2F, 0x65, 0x78, 0x54, 0x63, 0x56, 0x34, 0x72, 0x4B, 0x52, 0x69, 0x6C, 0x35, 0x58, 0x6A, 0x2F, 0x39, 0x59, 0x56, 0x31, 0x4E, 0x6E, 0x6D, 0x4E, 0x2B, 0x2F, 0x31, 0x31, 0x74, 0x36, 0x58, 0x74, 0x6A, 0x72, 0x75, 0x52, 0x62, 0x33, 0x79, 0x70, 0x38, 0x76, 0x64, 0x6C, 0x61, 0x65, 0x5A, 0x0A, 0x6C, 0x67, 0x45, 0x69, 0x73, 0x30, 0x42, 0x7A, 0x4B, 0x59, 0x39, 0x59, 0x64, 0x58, 0x48, 0x64, 0x46, 0x58, 0x57, 0x59, 0x4F, 0x41, 0x71, 0x50, 0x48, 0x45, 0x65, 0x4B, 0x57, 0x79, 0x61, 0x59, 0x5A, 0x56, 0x79, 0x43, 0x70, 0x51, 0x65, 0x43, 0x53, 0x71, 0x4F, 0x71, 0x48, 0x38, 0x67, 0x42, 0x6B, 0x4F, 0x62, 0x43, 0x69, 0x72, 0x41, 0x6A, 0x65, 0x56, 0x70, 0x35, 0x7A, 0x37, 0x6B, 0x31, 0x0A, 0x64, 0x4F, 0x2F, 0x6D, 0x56, 0x74, 0x49, 0x2B, 0x57, 0x47, 0x30, 0x48, 0x72, 0x37, 0x5A, 0x4C, 0x53, 0x52, 0x78, 0x6F, 0x61, 0x44, 0x47, 0x42, 0x33, 0x4E, 0x35, 0x38, 0x4B, 0x56, 0x45, 0x4F, 0x34, 0x65, 0x46, 0x56, 0x75, 0x6E, 0x59, 0x77, 0x51, 0x42, 0x54, 0x7A, 0x4F, 0x65, 0x57, 0x39, 0x6C, 0x4B, 0x79, 0x49, 0x38, 0x67, 0x4D, 0x45, 0x57, 0x6C, 0x62, 0x4B, 0x72, 0x41, 0x45, 0x49, 0x0A, 0x46, 0x4B, 0x38, 0x7A, 0x58, 0x6F, 0x44, 0x74, 0x39, 0x6A, 0x7A, 0x54, 0x37, 0x67, 0x68, 0x6A, 0x79, 0x45, 0x54, 0x67, 0x44, 0x6C, 0x69, 0x50, 0x53, 0x49, 0x46, 0x6A, 0x79, 0x31, 0x64, 0x6B, 0x6A, 0x6D, 0x68, 0x53, 0x78, 0x79, 0x6A, 0x67, 0x62, 0x71, 0x45, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x52, 0x53, 0x41, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A}|VOID*|0x00000005 +gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateKeySize|0x3d5|UINT32|0x00000006 diff --git a/NetworkPkg/NetworkPkg.dsc b/NetworkPkg/NetworkPkg.dsc index b12d5fd04a..6de9a11415 100644 --- a/NetworkPkg/NetworkPkg.dsc +++ b/NetworkPkg/NetworkPkg.dsc @@ -42,6 +42,9 @@ NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf [LibraryClasses.common.UEFI_DRIVER] DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf -- 2.39.2