Hi,

When using OpenSSL on Windows I noticed that it's impossible to redirect
/ pipe commands directly to openssl s_client. The client apparently
keeps waiting for user input. For example, the following commands don' t
work (the connection times out or waits for user input).
echo Q | openssl s_client -connect www.google.com:443
openssl s_client -connect www.google.com:443 < file_containing_QUIT_and_EOL

In 2013 there was a discussion about this on the OpenSSL users
mailinglist (see
http://openssl.6102.n7.nabble.com/openssl-s-client-takes-over-30-seconds-to-complete-on-Windows-td45781.html
Other discussions can be found on StackOverflow, for example
http://stackoverflow.com/questions/16823068/gnuwin32-openssl-s-client-conn-to-websphere-mq-server-not-closing-at-eof-hangs
or
http://stackoverflow.com/questions/9450120/openssl-hangs-and-does-not-exit

Apparently the solution is already implemented in apps/s_client.c (line
1836-1840) with the WaitForSingleObject call.

#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS)
                        /* Under Windows/DOS we make the assumption that
we can
             * always write to the tty: therefore if we need to
             * write to the tty we just fall through. Otherwise
             * we timeout the select every second and see if there
             * are any keypresses. Note: this is a hack, in a proper
             * Windows application we wouldn't do this.
             */
            i=0;
            if(!write_tty) {
                if(read_tty) {
                    tv.tv_sec = 1;
                    tv.tv_usec = 0;
                    i=select(width,(void *)&readfds,(void *)&writefds,
                         NULL,&tv);
#if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS)
                    if(!i && (!_kbhit() || !read_tty) ) continue;
#else
                    if(!i && (!((_kbhit()) || (WAIT_OBJECT_0 ==
WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) || !read_tty) )
continue;
#endif

However the statement that fixes this (the WaitForSingleObject call )
(almost) never gets compiled on Windows, at least not when
OPENSSL_SYS_WINCE or OPENSSL_SYS_MSDOS are defined. The latter is (among
other places) defined in e_os2.h (line 119-126)

/* Anything that tries to look like Microsoft is "Windows" */
#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WINNT) ||
defined(OPENSSL_SYS_WINCE)
# undef OPENSSL_SYS_UNIX
# define OPENSSL_SYS_WINDOWS
# ifndef OPENSSL_SYS_MSDOS
#  define OPENSSL_SYS_MSDOS
# endif
#endif

This effectively means that OPENSSL_SYS_MSDOS is (almost) always defined
when compiling for Windows, rendering the solution useless.

Please find attached a patch for the OpenSSL master branch, where
apps/s_client.c is modified. It removes the OPENSSL_SYS_MSDOS requirement.
After patching, input/output isn't blocked anymore and the following
commands work:
echo Q | openssl s_client -connect www.google.com:443
openssl s_client -connect www.google.com:443 < file_containing_QUIT_and_EOL

Tested under Windows when compiling on msys with mingw / mingw64. Please
note that I haven't tested compiling on Cygwin.
The WaitForSingleObject function is supported by Windows CE 5.0 and higher.


Hope this helps someone,
thanks for your consideration,

Peter Mosmans


diff --git a/apps/s_client.c b/apps/s_client.c
index e1be6a9..f2bc1fd 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -1833,7 +1833,7 @@ SSL_set_tlsext_status_ids(con, ids);
                                        tv.tv_usec = 0;
                                        i=select(width,(void *)&readfds,(void 
*)&writefds,
                                                 NULL,&tv);
-#if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS)
+#if defined(OPENSSL_SYS_WINCE)
                                        if(!i && (!_kbhit() || !read_tty) ) 
continue;
 #else
                                        if(!i && (!((_kbhit()) || 
(WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) || 
!read_tty) ) continue;
@@ -2044,7 +2044,7 @@ printf("read=%d pending=%d 
peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240
                        }
 
 #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS)
-#if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS)
+#if defined(OPENSSL_SYS_WINCE)
                else if (_kbhit())
 #else
                else if ((_kbhit()) || (WAIT_OBJECT_0 == 
WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0)))

Reply via email to