diff --git a/trunk/tinyIPSec/src/tipsec_xp.c b/trunk/tinyIPSec/src/tipsec_xp.c index e69de29b..0519879f 100644 --- a/trunk/tinyIPSec/src/tipsec_xp.c +++ b/trunk/tinyIPSec/src/tipsec_xp.c @@ -0,0 +1,604 @@ +/* +* Copyright (C) 2009 Mamadou Diop. +* +* Contact: Mamadou Diop +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + +/**@file tipsec_xp.c + * @brief Windows XP/2003 IPsec implementation using ipsec6 tool. + * + * @author Mamadou Diop + * + * @date Created: Sat Nov 8 16:54:58 2009 mdiop + */ +#include "tipsec_common.h" + +#if HAVE_IPSEC_XP + +#include "tsk_debug.h" +#include "tsk_memory.h" + +#define TINYIPSEC_XP_GET_ALGO(algo) ((algo == algo_hmac_md5_96) ? "HMAC-MD5-96" : "HMAC-SHA1") +#define TINYIPSEC_XP_GET_MODE(mode) ((mode == mode_tun) ? "TUNNEL" : "TRANSPORT") +#define TINYIPSEC_XP_GET_PROTO(proto) ((proto == proto_ah) ? "AH" : "ESP") +#define TINYIPSEC_XP_GET_IPPROTO(ipproto) ((ipproto == ipproto_tcp) ? "TCP" : "UDP") + +#define TINYIPSEC_IPSEC6_FILE "tinyIPSec" +#define TINYIPSEC_IPSEC6_FILE_KEY TINYIPSEC_IPSEC6_FILE".key" +#define TINYIPSEC_IPSEC6_FILE_SAD TINYIPSEC_IPSEC6_FILE".sad" +#define TINYIPSEC_IPSEC6_FILE_SPD TINYIPSEC_IPSEC6_FILE".spd" + +#define TINYIPSEC_IPSEC6_TEMPLATE_POLICY "\n"\ +"Security Policy List\n"\ +"\n"\ +"Policy RemoteIPAddr LocalIPAddr Protocol RemotePort LocalPort IPSecProtocol IPSecMode RemoteGWIPAddr SABundleIndex Direction Action InterfaceIndex \n"\ +"_________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________\n"\ +"%s - %s - %s - %s - %u - %u %s %s %s %s %s %s %s ;\n"\ +"%s - %s - %s - %s - %u - %u %s %s %s %s %s %s %s ;\n"\ +"_________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________\n"\ +"\n"\ +"- = Take selector from policy.\n"\ +"+ = Take selector from packet.\n" +#define TINYIPSEC_IPSEC6_TEMPLATE_SA "\n"\ +"Security Association List\n"\ +"\n"\ +"SAEntry SPI SADestIPAddr DestIPAddr SrcIPAddr Protocol DestPort SrcPort AuthAlg KeyFile Direction SecPolicyIndex \n"\ +"___________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________\n"\ +"%s %u %s %s %s %s %s %s %s %s %s %s ;\n"\ +"%s %u %s %s %s %s %s %s %s %s %s %s ;\n"\ +"%s %u %s %s %s %s %s %s %s %s %s %s ;\n"\ +"%s %u %s %s %s %s %s %s %s %s %s %s ;\n"\ +"___________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________\n" + +#define TINYIPSEC_IPSEC6_UCPS_POLICY "11111983" +#define TINYIPSEC_IPSEC6_USPC_POLICY "22221983" + +typedef struct tipsec_context_xp_s +{ + TINYIPSEC_DECLARE_CONTEXT; + +} +tipsec_context_xp_t; + +#define TIPSEC_CONTEXT_XP(ctx) ((tipsec_context_xp_t*)(ctx)) + +int tipsec_set_IKey(tipsec_context_xp_t* ctx_xp); +int tipsec_set_SPDs(tipsec_context_xp_t* ctx_xp); +int tipsec_set_SAs(tipsec_context_xp_t* ctx_xp); + +struct handleInfo{ + HANDLE process; + HANDLE pipe; +}; + +int tipsec_run_command(TCHAR *args); +DWORD WINAPI tipsec_waitForExit(void *arg); + +int tipsec_start(tipsec_context_t* ctx) +{ + tipsec_context_xp_t* ctx_xp = TIPSEC_CONTEXT_XP(ctx); + int ret = -1; + + if(!ctx_xp){ + ret = -1; + goto bail; + } + + if(TIPSEC_CONTEXT(ctx_xp)->started){ + TSK_DEBUG_WARN("The IPSec context already started."); + ret = -2; + goto bail; + } + + if(TIPSEC_CONTEXT(ctx_xp)->state != state_full){ + TSK_DEBUG_ERROR("IPSec context is in the wrong state."); + ret = -3; + goto bail; + } + + if((ret = tipsec_set_IKey(ctx_xp))){ + TSK_DEBUG_ERROR("Failed to set IKey."); + goto bail; + } + + if((ret = tipsec_set_SPDs(ctx_xp))){ + TSK_DEBUG_ERROR("Failed to set SPDs."); + goto bail; + } + + if((ret = tipsec_set_SAs(ctx_xp))){ + TSK_DEBUG_ERROR("Failed to set SAs."); + goto bail; + } + + /* Load previous Policies */ + tipsec_run_command(TEXT("d sp "TEXT(TINYIPSEC_IPSEC6_UCPS_POLICY))); + tipsec_run_command(TEXT("d sp "TEXT(TINYIPSEC_IPSEC6_USPC_POLICY))); + + /* Load new policies */ + ret = tipsec_run_command(TEXT("l "TEXT(TINYIPSEC_IPSEC6_FILE))); + +bail: + /* Remove files */ + remove(TINYIPSEC_IPSEC6_FILE_SPD); + remove(TINYIPSEC_IPSEC6_FILE_SAD); + remove(TINYIPSEC_IPSEC6_FILE_KEY); + + return ret; +} + +int tipsec_set_local(tipsec_context_t* ctx, const char* addr_local, const char* addr_remote, tipsec_port_t port_uc, tipsec_port_t port_us) +{ + tipsec_context_xp_t* ctx_xp = TIPSEC_CONTEXT_XP(ctx); + int ret = -1; + + if(!ctx_xp){ + ret = -1; + goto bail; + } + + if(!addr_local || !port_uc || !port_us){ + ret = -2; + goto bail; + } + + if(!TIPSEC_CONTEXT(ctx_xp)->initialized){ + TSK_DEBUG_ERROR("IPSec engine not initialized."); + ret = -3; + goto bail; + } + + if(TIPSEC_CONTEXT(ctx_xp)->state != state_initial){ + TSK_DEBUG_ERROR("IPSec context is in the wrong state."); + ret = -4; + goto bail; + } + + /* Set local/remote IPv6 addresses*/ + tsk_strupdate((char**)&TIPSEC_CONTEXT(ctx_xp)->addr_local, addr_local); + tsk_strupdate((char**)&TIPSEC_CONTEXT(ctx_xp)->addr_remote, addr_remote); + + /* Set ports */ + TIPSEC_CONTEXT(ctx_xp)->port_uc = port_uc; + TIPSEC_CONTEXT(ctx_xp)->port_us = port_us; + + /* Set SPIs */ + TIPSEC_CONTEXT(ctx_xp)->spi_uc = abs(rand() ^ rand()); + TIPSEC_CONTEXT(ctx_xp)->spi_us = abs(rand() ^ rand()); + + TIPSEC_CONTEXT(ctx_xp)->state = state_inbound; + + ret = 0; + +bail: + return ret; +} + +int tipsec_set_remote(tipsec_context_t* ctx, tipsec_spi_t spi_pc, tipsec_spi_t spi_ps, tipsec_port_t port_pc, tipsec_port_t port_ps, tipsec_lifetime_t lifetime) +{ + tipsec_context_xp_t* ctx_xp = TIPSEC_CONTEXT_XP(ctx); + int ret = -1; + + if(!ctx_xp){ + ret = -1; + goto bail; + } + + if(!lifetime || !port_pc || !port_ps){ + ret = -2; + goto bail; + } + + if(TIPSEC_CONTEXT(ctx_xp)->state != state_inbound){ + TSK_DEBUG_ERROR("IPSec context is in the wrong state."); + ret = -3; + goto bail; + } + + /* Set Lifetime */ + TIPSEC_CONTEXT(ctx_xp)->lifetime = lifetime; + + /* Set ports */ + TIPSEC_CONTEXT(ctx_xp)->port_ps = port_ps; + TIPSEC_CONTEXT(ctx_xp)->port_pc = port_pc; + + /* Set spis */ + TIPSEC_CONTEXT(ctx_xp)->spi_ps = spi_ps; + TIPSEC_CONTEXT(ctx_xp)->spi_pc = spi_pc; + + TIPSEC_CONTEXT(ctx_xp)->state = state_full; + + ret = 0; + +bail: + return ret; +} + +int tipsec_stop(tipsec_context_t* ctx) +{ + tipsec_context_xp_t* ctx_xp = TIPSEC_CONTEXT_XP(ctx); + int ret = -1; + + /* Load previous Policies */ + ret = tipsec_run_command(TEXT("d sp "TEXT(TINYIPSEC_IPSEC6_UCPS_POLICY))); + ret = tipsec_run_command(TEXT("d sp "TEXT(TINYIPSEC_IPSEC6_USPC_POLICY))); + + return ret; +} + + +int tipsec_set_IKey(tipsec_context_xp_t* ctx_xp) +{ + int ret = -1; + FILE* file = NULL; + + if(!ctx_xp){ + goto bail; + } + + if(TIPSEC_CONTEXT(ctx_xp)->state != state_full){ + TSK_DEBUG_ERROR("IPSec context is in the wrong state."); + ret = -3; + goto bail; + } + + if(!(file = fopen(TINYIPSEC_IPSEC6_FILE_KEY, "wb+"))){ + TSK_DEBUG_ERROR("Failed to open file [%s].", TINYIPSEC_IPSEC6_FILE_KEY); + ret = -4; + goto bail; + } + + fwrite(TIPSEC_CONTEXT(ctx_xp)->ik, TIPSEC_KEY_LEN, sizeof(uint8_t), file); + + if(TIPSEC_CONTEXT(ctx_xp)->alg == algo_hmac_md5_96){ /* Pad if HMAC-MD5-96 */ + uint8_t zeros[4]; + memset(zeros, 0, 4); + fwrite(zeros, 4, sizeof(uint8_t), file); + } + + ret = 0; + +bail: + if(file){ + fclose(file); + } + + return ret; +} + +int tipsec_set_SPDs(tipsec_context_xp_t* ctx_xp) +{ + int ret = -1; + FILE* file = NULL; + char* str = NULL; + + if(!ctx_xp){ + goto bail; + } + + if(TIPSEC_CONTEXT(ctx_xp)->state != state_full){ + TSK_DEBUG_ERROR("IPSec context is in the wrong state."); + ret = -3; + goto bail; + } + + if(!(file = fopen(TINYIPSEC_IPSEC6_FILE_SPD, "wb+"))){ + TSK_DEBUG_ERROR("Failed to open file [%s].", TINYIPSEC_IPSEC6_FILE_SPD); + ret = -4; + goto bail; + } + + tsk_sprintf(&str, TINYIPSEC_IPSEC6_TEMPLATE_POLICY, + /* UC -> PS */ + TINYIPSEC_IPSEC6_UCPS_POLICY, + TIPSEC_CONTEXT(ctx_xp)->addr_remote, + TIPSEC_CONTEXT(ctx_xp)->addr_local, + TINYIPSEC_XP_GET_IPPROTO(TIPSEC_CONTEXT(ctx_xp)->ipproto), + TIPSEC_CONTEXT(ctx_xp)->port_ps, + TIPSEC_CONTEXT(ctx_xp)->port_uc, + TINYIPSEC_XP_GET_PROTO(TIPSEC_CONTEXT(ctx_xp)->protocol), + TINYIPSEC_XP_GET_MODE(TIPSEC_CONTEXT(ctx_xp)->mode), + "*", /* RemoteGWIPAddr */ + "NONE", /* SABundleIndex */ + "BIDIRECT", /* Direction */ + "APPLY", /* Action */ + "0", /* InterfaceIndex */ + + /* US -> PC */ + TINYIPSEC_IPSEC6_USPC_POLICY, + TIPSEC_CONTEXT(ctx_xp)->addr_remote, + TIPSEC_CONTEXT(ctx_xp)->addr_local, + TINYIPSEC_XP_GET_IPPROTO(TIPSEC_CONTEXT(ctx_xp)->ipproto), + TIPSEC_CONTEXT(ctx_xp)->port_pc, + TIPSEC_CONTEXT(ctx_xp)->port_us, + TINYIPSEC_XP_GET_PROTO(TIPSEC_CONTEXT(ctx_xp)->protocol), + TINYIPSEC_XP_GET_MODE(TIPSEC_CONTEXT(ctx_xp)->mode), + "*", /* RemoteGWIPAddr */ + "NONE", /* SABundleIndex */ + "BIDIRECT", /* Direction */ + "APPLY", /* Action */ + "0" /* InterfaceIndex */ + ); + + fwrite(str, strlen(str), sizeof(uint8_t), file); + ret = 0; + +bail: + if(file){ + fclose(file); + } + if(str){ + TSK_FREE(str); + } + return ret; +} + +int tipsec_set_SAs(tipsec_context_xp_t* ctx_xp) +{ + + int ret = -1; + FILE* file = NULL; + char* str = NULL; + + if(!ctx_xp){ + goto bail; + } + + if(TIPSEC_CONTEXT(ctx_xp)->state != state_full){ + TSK_DEBUG_ERROR("IPSec context is in the wrong state."); + ret = -3; + goto bail; + } + + if(!(file = fopen(TINYIPSEC_IPSEC6_FILE_SAD, "wb+"))){ + TSK_DEBUG_ERROR("Failed to open file [%s].", TINYIPSEC_IPSEC6_FILE_SAD); + ret = -4; + goto bail; + } + + tsk_sprintf(&str, TINYIPSEC_IPSEC6_TEMPLATE_SA, + /* PC -> US */ + "1", // SAEntry + TIPSEC_CONTEXT(ctx_xp)->spi_us, // SPI + TIPSEC_CONTEXT(ctx_xp)->addr_local, // SADestIPAddr + "POLICY", // DestIPAddr + "POLICY", // SrcIPAddr + "POLICY", // Protocol + "POLICY", // DestPort + "POLICY", // SrcPort + TINYIPSEC_XP_GET_ALGO(TIPSEC_CONTEXT(ctx_xp)->alg), // AuthAlg + TINYIPSEC_IPSEC6_FILE_KEY, // KeyFile + "INBOUND", // Direction + "0", /* SecPolicyIndex */ + + /* US -> PC */ + "2", // SAEntry + TIPSEC_CONTEXT(ctx_xp)->spi_pc, // SPI + TIPSEC_CONTEXT(ctx_xp)->addr_remote, // SADestIPAddr + "POLICY", // DestIPAddr + "POLICY", // SrcIPAddr + "POLICY", // Protocol + "POLICY", // DestPort + "POLICY", // SrcPort + TINYIPSEC_XP_GET_ALGO(TIPSEC_CONTEXT(ctx_xp)->alg), // AuthAlg + TINYIPSEC_IPSEC6_FILE_KEY, // KeyFile + "OUTBOUND", // Direction + "0", /* SecPolicyIndex */ + + /* PS -> UC */ + "3", // SAEntry + TIPSEC_CONTEXT(ctx_xp)->spi_uc, // SPI + TIPSEC_CONTEXT(ctx_xp)->addr_local, // SADestIPAddr + "POLICY", // DestIPAddr + "POLICY", // SrcIPAddr + "POLICY", // Protocol + "POLICY", // DestPort + "POLICY", // SrcPort + TINYIPSEC_XP_GET_ALGO(TIPSEC_CONTEXT(ctx_xp)->alg), // AuthAlg + TINYIPSEC_IPSEC6_FILE_KEY, // KeyFile + "INBOUND", // Direction + "0", /* SecPolicyIndex */ + + /* UC -> PS */ + "4", // SAEntry + TIPSEC_CONTEXT(ctx_xp)->spi_ps, // SPI + TIPSEC_CONTEXT(ctx_xp)->addr_remote, // SADestIPAddr + "POLICY", // DestIPAddr + "POLICY", // SrcIPAddr + "POLICY", // Protocol + "POLICY", // DestPort + "POLICY", // SrcPort + TINYIPSEC_XP_GET_ALGO(TIPSEC_CONTEXT(ctx_xp)->alg), // AuthAlg + TINYIPSEC_IPSEC6_FILE_KEY, // KeyFile + "OUTBOUND", // Direction + "0" /* SecPolicyIndex */ + ); + + fwrite(str, strlen(str), sizeof(uint8_t), file); + ret = 0; + +bail: + if(file){ + fclose(file); + } + if(str){ + TSK_FREE(str); + } + return ret; +} + +int tipsec_run_command(TCHAR *args) +{ +#define TIPSEC_PIPE_BUFFER 1024 + + DWORD bread=0,tid=0; + int ret = -1; + struct handleInfo hInfo; + TCHAR _args[MAX_PATH]; + HANDLE writePipe, readPipe, hThread; + SECURITY_ATTRIBUTES secAttr = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; + + STARTUPINFO si = {0}; + PROCESS_INFORMATION pi = {0}; + + char buffer[TIPSEC_PIPE_BUFFER]; + + /* Create pipes */ + if((ret = CreatePipe(&readPipe, &writePipe, &secAttr, 0)) == 0) { + TSK_DEBUG_ERROR("CreatePipe failed with error code [%d].", GetLastError()); + ret = -5; + goto bail; + } + + wsprintf(_args, TEXT("\"%s\" %s"), TEXT("ipsec6.exe"), args ); + + memset(buffer, 0, TIPSEC_PIPE_BUFFER); + + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = NULL; + si.hStdOutput = writePipe; + si.hStdError = NULL; + + + /* Create process */ + if (CreateProcess(NULL, _args, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi) == 0){ + TSK_DEBUG_ERROR("CreateProcess failed with error code [%d].", GetLastError()); + ret = -3; + goto bail; + } + + hInfo.process = pi.hProcess; + hInfo.pipe = writePipe; + + /* Create thread */ + if((hThread = CreateThread(NULL, 0, tipsec_waitForExit, &hInfo, 0, &tid)) == NULL) { + TSK_DEBUG_ERROR("CreateThread failed with error code [%d].", GetLastError()); + ret = -4; + goto bail; + } + + /* For debugging */ +#if defined(DEBUG) || defined(_DEBUG) + while (ReadFile(readPipe, buffer, TIPSEC_PIPE_BUFFER-2, &bread, NULL)) + { + if(bread > 0){ + TSK_DEBUG_INFO("IPSEC6 ==> %s\n-------------\n", buffer); + memset(buffer, 0, TIPSEC_PIPE_BUFFER); /* reset the buffer. */ + } + } +#endif + + ret = 0; + +bail: + return ret; +} + +DWORD WINAPI tipsec_waitForExit(void *arg) +{ + struct handleInfo *info = (struct handleInfo *)arg; + WaitForSingleObject(&(info->process),INFINITE); + CloseHandle(info->pipe); + return 0; +} + + + + + + + +//================================================================================================= +// IPSec context object definition +// +static void* tipsec_context_create(void * self, va_list * app) +{ + tipsec_context_xp_t *context = self; + if(context) + { + const tipsec_key_t *ik; + const tipsec_key_t *ck; + + TIPSEC_CONTEXT(context)->ipproto = va_arg(*app, tipsec_ipproto_t); + TIPSEC_CONTEXT(context)->use_ipv6 = va_arg(*app, int); + TIPSEC_CONTEXT(context)->mode = va_arg(*app, tipsec_mode_t); + TIPSEC_CONTEXT(context)->ealg = va_arg(*app, tipsec_ealgorithm_t); + TIPSEC_CONTEXT(context)->alg = va_arg(*app, tipsec_algorithm_t); + TIPSEC_CONTEXT(context)->protocol = va_arg(*app, tipsec_protocol_t); + + ik = va_arg(*app, const tipsec_key_t*); + ck = va_arg(*app, const tipsec_key_t*); + + /* Open engine */ + if(!TIPSEC_CONTEXT(context)->use_ipv6){ + TSK_DEBUG_ERROR("IPSec/IPv4 is not supported on Windows XP."); + + TIPSEC_CONTEXT(context)->initialized = 0; + goto bail; + } + else{ + TIPSEC_CONTEXT(context)->initialized = 1; + } + + /* Compute ik and ck */ + TIPSEC_CONTEXT(context)->ik = tsk_strndup(ik, TIPSEC_KEY_LEN); + TIPSEC_CONTEXT(context)->ck = tsk_strndup(ck, TIPSEC_KEY_LEN); /* XP version of IPSec do not support encryption key but we copy ck (Who know?). */ + + TIPSEC_CONTEXT(context)->state = state_initial; + } +bail: + return self; +} + +static void* tipsec_context_destroy(void * self) +{ + tipsec_context_xp_t *context = self; + if(context) + { + if(TIPSEC_CONTEXT(context)->started){ + tipsec_stop(TIPSEC_CONTEXT(context)); + } + + TSK_FREE(TIPSEC_CONTEXT(context)->addr_local); + TSK_FREE(TIPSEC_CONTEXT(context)->addr_remote); + + TSK_FREE(TIPSEC_CONTEXT(context)->ik); + TSK_FREE(TIPSEC_CONTEXT(context)->ck); + } + + return self; +} + +static int tipsec_context_cmp(const void *obj1, const void *obj2) +{ + return-1; +} + +static const tsk_object_def_t tipsec_context_def_s = +{ + sizeof(tipsec_context_xp_t), + tipsec_context_create, + tipsec_context_destroy, + tipsec_context_cmp, +}; +const void *tipsec_context_def_t = &tipsec_context_def_s; + + +#endif /* HAVE_IPSEC_XP */