Dear Sir, Please find enclosed a patch in "diff -cr orig work" format, applying to stunnel4.27b1 as found here ftp://stunnel.mirt.net/stunnel/. This patch maily addresses compilation and unicode issues for Windows CE targets. I use MS EVC 4sp2 compiler with WCE 420 SDK, on a vista host platform. Once debugged the code works fine on WM5 and WM6 HTC smartphones. It needs a windows CE openssl lib (I logged a patch to openssl snap 20090102 because it has some compilation issues on windows CE platform).
* For the sake of completeness openssl 098i and 098j (latest) must be ALSO patched to compile for wince, with this patch I submitted to openssl team : http://marc.info/?l=openssl-dev&m=123099015013538&w=2
The present stunnel patch addresses the following issues :
1/ COMPILATION FAILURE : on common.h "EINVAL redefinition" : in fact the compile options WX (see evc.mak) does not tolerate any warning : to avoid a warning on EINVAL redef, we must protect this undef by ifdef. Note that there is still a problem : if the symbol is NOT defined at all, it will NEVER be defined by that revised code : this is because the compiler always generate an error if it sees something like : #ifdef EINVAL #undef EINVAL #define EINVAL WSAEINVAL #else #define EINVAL WSAEINVAL #endif because it seems to not like two defines even separated by a else. Just putting the #define outside of a block dealing with undef, does not solve the compilation issue.
2/ COMPILATION FAILURE : related to wcecompat/setjmp.h SOLUTION : in evc.mak, needed /D ARM to compile with wcecompat/setjmp.h. This symbol is not documented in MSDN but clearly present is header files. Moreover It is consistent with other processor symbols described in the sdk.
3/ COMPILATION FAILURE : related to gui.c pb with undeclared hmainmenu identifier, because "endif use_win32" misplaced.
3/ RC COMPILATION FAILURE : related to resources.rc CAUSE : "VERSION" unknown SOLUTION : /dversion in rflags in evc.mak
4/ LINK ERROR : fatal error LNK1181: cannot open input file 'libeay32.lib' cause : bad path name in evc.mak for openssl lib. since openssl >> 098a (eg 098h) "out32dll" folder is named "out32dll_targetCPU".
5/ LINK ERROR on gui.obj : error LNK2001: unresolved external symbol _beginthread _$(TARGETCPU) Cause : in sthreads.c, misplaced "#endif os2" Note : corrected various erroneous comments on #if endif in sthreads.c
************* OPERATIONAL ERRORS (at run-time)
using stunnel to enable certificate based authentication for POPS/SMPTPS between a smartphone and a linux server, I faced this problems :
When first trying to authenticate a dlgbox is displayed on the smartphone to input the password of the private key protecting the client certificate:
6/ RUN-TIME ERROR : "squares" displayed instead of chars in "password input dialog box" titlebar Well, this is only a cosmetic issue, but this is still an issue.
Cause : this is a typical unicode issue in gui.c pass_proc/wm_initdialog : the sendmessage to display the title uses a concatenation of two strings : a constant extracted from the resource file, and converted to wchar by TEXT macro in unicode context, and a key file name given by ui_data->section->key. The problem is that the file name is always of type 8bit char, leading to concatenation "scrambling" when concatenated with a unicode string. SOLUTION : it seems not possible to change the type of ui_data->section->key to tchar/wchar because it is used in various ansi code. So the simplest way to correct this pb is just to make a local conversion from ansi to tchar in gui.c/pass_proc/initdialog
7/ RUN-TIME ERROR : It is impossible to validate a password on a private key protecting a certificate: The password is ALWAYS rejected (after many tests with 3 retries). Cause : the password is input as unicode (because the message EM_GETLINE on the control IDE_PASSEDIT is unicode ready) but stored and managed as an ansi string so the password can never be validated. NOTE : contrary to the documentation of windows CE sdk, the EM_GETLINE msg IS REALLY unicode ready. Indeed this is also the case in classic win32 sdk for PC platform (described in the msdn library). SOLUTION : the input password must be converted to ansi before being validated vs openssl
2009.01.05 13:00:01 LOG3[4849170:5712826]: Wrong pass phrase: retrying 2009.01.05 13:00:05 LOG3[4849170:5712826]: error stack: 140B3009 : error:140B3009:SSL routines:SSL_CTX_use_RSAPrivateKey_file:PEM lib 2009.01.05 13:00:05 LOG3[4849170:5712826]: error stack: 906A065 : error:0906A065:PEM routines:PEM_do_header:bad decrypt 2009.01.05 13:00:05 LOG3[4849170:5712826]: SSL_CTX_use_RSAPrivateKey_file: 6065064: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
2009.01.05 13:00:05 LOG3[4849170:5712826]: Server is down
I hope you will find this patch useful. Thank you for your excellent work, Yours sincerely and happy new year,
Pierre Delaage
Note : I use stunnel to establish a simple "vpn" between smartphones and a corporate linux server mainly for HTTPS/POPS/SMTPS support. Stunnel is very relevant in that matter, over solutions based on SSH (although we use also ssh), from a communication cost point of view : ssh establishes permanent socket between client and server, so that the communication is charged by the mobile network provider : and these charges are very expensive. On the contrary stunnel only establishes ssl sockets on demand so that financial charges are limited to strict necessary. Please note that stunnel brings "client based certificate authentication" to POP/SMTP mobile mail user agents which only supports SSL with server authentication, but NO client authentication, such as mobile outlook.Here again stunnel is very relevant.
Note 2 : the unicode bug fixes should benefit also to the win32 stunnel version for PC.
Note 3 : this mail has also been sent to webmaster@stunnel.org, but with no response at all.
Only in work/src: client.obj diff -cr orig/src/common.h work/src/common.h *** orig/src/common.h 2008-09-01 08:06:24.000000000 +0200 --- work/src/common.h 2009-01-05 23:16:03.052680000 +0100 *************** *** 187,198 **** #define EINPROGRESS WSAEINPROGRESS #define EWOULDBLOCK WSAEWOULDBLOCK #define EISCONN WSAEISCONN ! #undef EINVAL #define EINVAL WSAEINVAL
#include <process.h> /* _beginthread */ #include <tchar.h>
#define NO_IDEA #define OPENSSL_NO_IDEA
--- 187,204 ---- #define EINPROGRESS WSAEINPROGRESS #define EWOULDBLOCK WSAEWOULDBLOCK #define EISCONN WSAEISCONN ! ! #ifdef EINVAL // pdelaage, required to avoid compilation "error", see WX option in evc.mak and ms-evc420 compiler ! #undef EINVAL // TODO : if einval is not defined, this code does not define it; but putting a #define in an #else leads again to compilation error! #define EINVAL WSAEINVAL + #endif +
#include <process.h> /* _beginthread */ #include <tchar.h>
+ + #define NO_IDEA #define OPENSSL_NO_IDEA
Only in work/src: ctx.obj diff -cr orig/src/evc.mak work/src/evc.mak *** orig/src/evc.mak 2008-09-20 22:23:21.000000000 +0200 --- work/src/evc.mak 2009-01-04 10:09:32.439894500 +0100 *************** *** 1,23 **** # wce.mak for stunnel.exe by Michal Trojnara 2006 #
! WCEVER=300
# Modify this to point to your actual openssl compile directory # (You did already compile openssl, didn't you???) ! SSLDIR=....\build\openssl-0.9.8i ! COMPATDIR=....\build\wcecompat CEUTILSDIR=....\ceutils DSTDIR=ce:\stunnel - SDKDIR=C:\Windows CE Tools\wce$(WCEVER)\Pocket PC 2002
! INCLUDES=-I$(SSLDIR)/inc32 -I$(COMPATDIR)\include -I"$(SDKDIR)\include" LIBS=libeay32.lib ssleay32.lib wcecompatex.lib winsock.lib
! CC=CL$(TARGETCPU) ! CFLAGS=/nologo /MC /O1i /W3 /WX /GF /Gy /DHOST="$(TARGETCPU)-WCE-eVC-$(WCEVER)" /D$(TARGETCPU) /DUNDER_CE=$(WCEVER) /D_WIN32_WCE=$(WCEVER) /DUNICODE -D_UNICODE $(INCLUDES) ! RFLAGS=$(INCLUDES) ! LDFLAGS=/nologo /subsystem:windowsce,3.00 /machine:ARM /libpath:"$(SDKDIR)\lib$(TARGETCPU)" /libpath:"$(COMPATDIR)\lib" /libpath:"$(SSLDIR)\out32dll"
OBJS=stunnel.obj ssl.obj ctx.obj verify.obj file.obj client.obj protocol.obj sthreads.obj log.obj options.obj network.obj resolver.obj GUIOBJS=gui.obj resources.res --- 1,35 ---- # wce.mak for stunnel.exe by Michal Trojnara 2006 #
! WCEVER=420 ! # pdelaage : following flag required by (eg) winnt.h, and is different from targetcpu (armV4) ! WCETARGETCPU=ARM
# Modify this to point to your actual openssl compile directory # (You did already compile openssl, didn't you???) ! SSLDIR=C:\Users\standard\Documents\Dvts\Contrib\openssl\openssl-0.9.8-stable-SNAP-20090102\openssl-0.9.8-stable-SNAP-20090102 ! COMPATDIR=C:\Users\standard\Documents\Dvts\openssl\build\wcecompat ! # pdelaage : ceutilsdir probably useless CEUTILSDIR=....\ceutils + # pdelaage "ce:" is not a correct location , but we never "make install" DSTDIR=ce:\stunnel
! SDKDIR="C:\Progra~1\Micros~2\wce$(WCEVER)\standardsdk" ! ! # pdelaage eroneous path for sdkdir INCLUDES=-I$(SSLDIR)/inc32 -I$(COMPATDIR)\include -I"$(SDKDIR)\include" ! INCLUDES=-I$(SSLDIR)\inc32 -I$(COMPATDIR)\include -I"$(SDKDIR)\include$(TARGETCPU)" LIBS=libeay32.lib ssleay32.lib wcecompatex.lib winsock.lib
! # not correct because for armv4 cc is just clarm.exe. Moreover cc is already set in the ms wce$TARGETCPU.bat script, so it is not necessary to set it up here ! # CC=CL$(TARGETCPU) ! ! VERSION=4.27 ! DEFINES=/DVERSION="$(VERSION)" ! # pdelaage added wcetargetcpu to cflags ! CFLAGS=/nologo /MC /O1i /W3 /WX /GF /Gy $(DEFINES) /DHOST="$(TARGETCPU)-WCE-eVC-$(WCEVER)" /D$(WCETARGETCPU) /D$(TARGETCPU) /DUNDER_CE=$(WCEVER) /D_WIN32_WCE=$(WCEVER) /DUNICODE -D_UNICODE $(INCLUDES) ! RFLAGS=/DVERSION="$(VERSION)" $(INCLUDES) ! # pdelaage : LDFLAGS: since openssl >> 098a (eg 098h) out32dll is out32dll_targetCPU ! LDFLAGS=/nologo /subsystem:windowsce,3.00 /machine:ARM /libpath:"$(SDKDIR)\lib$(TARGETCPU)" /libpath:"$(COMPATDIR)\lib" /libpath:"$(SSLDIR)\out32dll_$(TARGETCPU)"
OBJS=stunnel.obj ssl.obj ctx.obj verify.obj file.obj client.obj protocol.obj sthreads.obj log.obj options.obj network.obj resolver.obj GUIOBJS=gui.obj resources.res Only in work/src: file.obj diff -cr orig/src/gui.c work/src/gui.c *** orig/src/gui.c 2008-05-02 08:23:03.000000000 +0200 --- work/src/gui.c 2009-01-04 23:45:07.451820500 +0100 *************** *** 320,329 **** hwnd=CreateWindow(classname, win32_name, WS_TILEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, hmainmenu, hInstance, NULL); ! #endif
if(cmdline.service) /* do not allow to save file in the service mode */ EnableMenuItem(hmainmenu, IDM_SAVEAS, MF_GRAYED);
if(error_mode) /* log window is hidden by default */ set_visible(1); --- 320,330 ---- hwnd=CreateWindow(classname, win32_name, WS_TILEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, hmainmenu, hInstance, NULL); ! // commented by pdelaage on 20090104 #endif
if(cmdline.service) /* do not allow to save file in the service mode */ EnableMenuItem(hmainmenu, IDM_SAVEAS, MF_GRAYED); + #endif // added by pdelaage on 20090104
if(error_mode) /* log window is hidden by default */ set_visible(1); *************** *** 523,536 **** WPARAM wParam, LPARAM lParam) { TCHAR titlebar[STRLEN]; WORD cchPassword;
switch (message) { case WM_INITDIALOG: /* Set the default push button to "Cancel." */ SendMessage(hDlg, DM_SETDEFID, (WPARAM) IDCANCEL, (LPARAM) 0);
_sntprintf(titlebar, STRLEN, TEXT("Private key: %s"), ! ui_data->section->key); SetWindowText(hDlg, titlebar); return TRUE;
--- 524,548 ---- WPARAM wParam, LPARAM lParam) { TCHAR titlebar[STRLEN]; WORD cchPassword; + LPTSTR keyFileName;// added by pdelaage on 20090104 + TCHAR sPassword[PEM_BUFSIZE];// added by pdelaage on 20090104 + char* cPassword;// added by pdelaage on 20090104
switch (message) { case WM_INITDIALOG: /* Set the default push button to "Cancel." */ SendMessage(hDlg, DM_SETDEFID, (WPARAM) IDCANCEL, (LPARAM) 0);
+ // pdelaage on 20090104: here was a bug : _sntprintf is unicode ready but ui_data->section->key is always char. + // commented by pdelaage on 20090104 _sntprintf(titlebar, STRLEN, TEXT("Private key: %s"), + // ui_data->section->key); + + keyFileName = str2tstr(ui_data->section->key); _sntprintf(titlebar, STRLEN, TEXT("Private key: %s"), ! keyFileName); ! free(keyFileName); ! ! SetWindowText(hDlg, titlebar); return TRUE;
*************** *** 549,561 **** }
/* Put the number of characters into first word of buffer. */ ! *((LPWORD)ui_data->pass) = cchPassword;
/* Get the characters. */ SendDlgItemMessage(hDlg, IDE_PASSEDIT, EM_GETLINE, ! (WPARAM) 0, /* line 0 */ (LPARAM) ui_data->pass);
! ui_data->pass[cchPassword] = 0; /* Null-terminate the string. */ EndDialog(hDlg, TRUE); return TRUE;
--- 561,580 ---- }
/* Put the number of characters into first word of buffer. */ ! *((LPWORD) sPassword) = cchPassword;
/* Get the characters. */ SendDlgItemMessage(hDlg, IDE_PASSEDIT, EM_GETLINE, ! (WPARAM) 0, /* line 0 */ (LPARAM) sPassword);// pdelaage ui_data->pass); !
! sPassword[cchPassword] = 0; /* Null-terminate the string. */ ! ! // convert input password to ANSI string (as ui_data->pass) ! cPassword = tstr2str(sPassword); ! strcpy(ui_data->pass, cPassword); ! free(cPassword); ! EndDialog(hDlg, TRUE); return TRUE;
Only in work/src: gui.obj Only in work/src: log.obj diff -cr orig/src/makece.bat work/src/makece.bat *** orig/src/makece.bat 2005-12-23 20:57:24.000000000 +0100 --- work/src/makece.bat 2009-01-03 19:31:34.507379500 +0100 *************** *** 1,3 **** @echo off ! call "C:\Program Files\Microsoft eMbedded Tools\EVC\WCE300\BIN\WCEARM.BAT" nmake /NOLOGO -f evc.mak %1 %2 %3 %4 %5 %6 %7 %8 %9 --- 1,4 ---- @echo off ! ::call "C:\Program Files\Microsoft eMbedded Tools\EVC\WCE300\BIN\WCEARM.BAT" ! call "C:\Progra~1\MSEVC4\EVC\WCE420\BIN\WCEARMV4.BAT" nmake /NOLOGO -f evc.mak %1 %2 %3 %4 %5 %6 %7 %8 %9 Only in work/src: network.obj Only in work/src: nogui.obj Only in work/src: options.obj Only in work/src: protocol.obj Only in work/src: resolver.obj Only in work/src: resources.RES Only in work/src: ssl.obj diff -cr orig/src/sthreads.c work/src/sthreads.c *** orig/src/sthreads.c 2008-09-21 21:44:06.000000000 +0200 --- work/src/sthreads.c 2009-01-04 10:46:46.285200500 +0100 *************** *** 400,406 **** return 0; }
! #endif
#ifdef USE_OS2
--- 400,406 ---- return 0; }
! #endif /* cmt added by pdelaage on 20090104 : USE_WIN32 */
#ifdef USE_OS2
*************** *** 437,442 **** --- 437,444 ---- return 0; }
+ #endif /* USE_OS2 */ // added by pdelaage on 20090104 + #ifdef _WIN32_WCE
int _beginthread(void (*start_address)(void *), *************** *** 456,464 **** ExitThread(0); }
! #endif /* !defined(_WIN32_WCE) */
! #endif /* USE_WIN32 */
#ifdef DEBUG_STACK_SIZE
--- 458,467 ---- ExitThread(0); }
! #endif /* _WIN32_WCE */ /* pdelaage 20090104, following cmt is improper: !defined(_WIN32_WCE) */
! // pdelaage 20090104 : following endif is misplaced, the endif usewin32 is already placed upper, but this endif relates ! // to os2, and is misplaced because it "squeezes" winCE code #endif /* USE_WIN32 */
#ifdef DEBUG_STACK_SIZE
Only in work/src: sthreads.obj Files orig/src/stunnel.exe and work/src/stunnel.exe differ Only in work/src: stunnel.obj Only in work/src: tstunnel.exe Only in work/src: verify.obj