* [including the GNU Public Licence.]
*/
-/* With IPv6, it looks like Digital has mixed up the proper order of
- recursive header file inclusion, resulting in the compiler complaining
- that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which
- is needed to have fileno() declared correctly... So let's define u_int */
-#if defined(__DECC) && !defined(__U_INT)
-#define __U_INT
-typedef unsigned int u_int;
-#endif
-
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef NO_STDIO
#define APPS_WIN16
#endif
+
+/* With IPv6, it looks like Digital has mixed up the proper order of
+ recursive header file inclusion, resulting in the compiler complaining
+ that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which
+ is needed to have fileno() declared correctly... So let's define u_int */
+#if defined(VMS) && defined(__DECC) && !defined(__U_INT)
+#define __U_INT
+typedef unsigned int u_int;
+#endif
+
#include <openssl/lhash.h>
#include <openssl/bn.h>
#define USE_SOCKETS
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>
+#include <openssl/engine.h>
#include "s_apps.h"
+#ifdef WINDOWS
+#include <conio.h>
+#endif
+
#if (defined(VMS) && __VMS_VER < 70000000)
/* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */
#undef FIONBIO
#endif
-#if defined(NO_RSA) && !defined(NO_SSL2)
-#define NO_SSL2
-#endif
-
#ifndef NO_RSA
-static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int export,int keylength);
+static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export, int keylength);
#endif
static int sv_body(char *hostname, int s, unsigned char *context);
static int www_body(char *hostname, int s, unsigned char *context);
static int init_ssl_connection(SSL *s);
static void print_stats(BIO *bp,SSL_CTX *ctx);
#ifndef NO_DH
-static DH *load_dh_param(void );
+static DH *load_dh_param(char *dhfile);
static DH *get_dh512(void);
#endif
-/* static void s_server_init(void);*/
+#ifdef MONOLITH
+static void s_server_init(void);
+#endif
#ifndef S_ISDIR
-#if defined(VMS) && !defined(__DECC)
-#define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR)
-#else
-#define S_ISDIR(a) (((a) & _S_IFMT) == _S_IFDIR)
-#endif
+# if defined(_S_IFMT) && defined(_S_IFDIR)
+# define S_ISDIR(a) (((a) & _S_IFMT) == _S_IFDIR)
+# else
+# define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR)
+# endif
#endif
#ifndef NO_DH
#undef BUFSIZZ
#define BUFSIZZ 16*1024
-static int bufsize=32;
+static int bufsize=BUFSIZZ;
static int accept_socket= -1;
#define TEST_CERT "server.pem"
#undef PROG
#define PROG s_server_main
-#define DH_PARAM "server.pem"
-
extern int verify_depth;
static char *cipher=NULL;
static int s_server_verify=SSL_VERIFY_NONE;
+static int s_server_session_id_context = 1; /* anything will do */
static char *s_cert_file=TEST_CERT,*s_key_file=NULL;
static char *s_dcert_file=NULL,*s_dkey_file=NULL;
#ifdef FIONBIO
static int s_nbio=0;
#endif
static int s_nbio_test=0;
+int s_crlf=0;
static SSL_CTX *ctx=NULL;
static int www=0;
static int s_debug=0;
static int s_quiet=0;
-#if 0
+static int hack=0;
+static char *engine_id=NULL;
+
+#ifdef MONOLITH
static void s_server_init(void)
{
+ accept_socket=-1;
cipher=NULL;
s_server_verify=SSL_VERIFY_NONE;
s_dcert_file=NULL;
bio_s_out=NULL;
s_debug=0;
s_quiet=0;
+ hack=0;
+ engine_id=NULL;
}
#endif
BIO_printf(bio_err," -Verify arg - turn on peer certificate verification, must have a cert.\n");
BIO_printf(bio_err," -cert arg - certificate file to use, PEM format assumed\n");
BIO_printf(bio_err," (default is %s)\n",TEST_CERT);
- BIO_printf(bio_err," -key arg - RSA file to use, PEM format assumed, in cert file if\n");
+ BIO_printf(bio_err," -key arg - Private Key file to use, PEM format assumed, in cert file if\n");
BIO_printf(bio_err," not specified (default is %s)\n",TEST_CERT);
BIO_printf(bio_err," -dcert arg - second certificate file to use (usually for DSA)\n");
BIO_printf(bio_err," -dkey arg - second private key file to use (usually for DSA)\n");
+ BIO_printf(bio_err," -dhparam arg - DH parameter file to use, in cert file if not specified\n");
+ BIO_printf(bio_err," or a default set of parameters is used\n");
#ifdef FIONBIO
BIO_printf(bio_err," -nbio - Run with non-blocking IO\n");
#endif
BIO_printf(bio_err," -nbio_test - test with the non-blocking test bio\n");
+ BIO_printf(bio_err," -crlf - convert LF from terminal into CRLF\n");
BIO_printf(bio_err," -debug - Print more output\n");
BIO_printf(bio_err," -state - Print the SSL states\n");
BIO_printf(bio_err," -CApath arg - PEM format directory of CA's\n");
BIO_printf(bio_err," -no_ssl2 - Just disable SSLv2\n");
BIO_printf(bio_err," -no_ssl3 - Just disable SSLv3\n");
BIO_printf(bio_err," -no_tls1 - Just disable TLSv1\n");
- BIO_printf(bio_err," -bugs - Turn on SSL bug compatability\n");
+#ifndef NO_DH
+ BIO_printf(bio_err," -no_dhe - Disable ephemeral DH\n");
+#endif
+ BIO_printf(bio_err," -bugs - Turn on SSL bug compatibility\n");
BIO_printf(bio_err," -www - Respond to a 'GET /' with a status page\n");
BIO_printf(bio_err," -WWW - Respond to a 'GET /<path> HTTP/1.0' with file ./<path>\n");
+ BIO_printf(bio_err," -engine id - Initialise and use the specified engine\n");
}
static int local_argc=0;
static char **local_argv;
-static int hack=0;
+
+#ifdef CHARSET_EBCDIC
+static int ebcdic_new(BIO *bi);
+static int ebcdic_free(BIO *a);
+static int ebcdic_read(BIO *b, char *out, int outl);
+static int ebcdic_write(BIO *b, char *in, int inl);
+static long ebcdic_ctrl(BIO *b, int cmd, long num, char *ptr);
+static int ebcdic_gets(BIO *bp, char *buf, int size);
+static int ebcdic_puts(BIO *bp, char *str);
+
+#define BIO_TYPE_EBCDIC_FILTER (18|0x0200)
+static BIO_METHOD methods_ebcdic=
+ {
+ BIO_TYPE_EBCDIC_FILTER,
+ "EBCDIC/ASCII filter",
+ ebcdic_write,
+ ebcdic_read,
+ ebcdic_puts,
+ ebcdic_gets,
+ ebcdic_ctrl,
+ ebcdic_new,
+ ebcdic_free,
+ };
+
+typedef struct
+{
+ size_t alloced;
+ char buff[1];
+} EBCDIC_OUTBUFF;
+
+BIO_METHOD *BIO_f_ebcdic_filter()
+{
+ return(&methods_ebcdic);
+}
+
+static int ebcdic_new(BIO *bi)
+{
+ EBCDIC_OUTBUFF *wbuf;
+
+ wbuf = (EBCDIC_OUTBUFF *)OPENSSL_malloc(sizeof(EBCDIC_OUTBUFF) + 1024);
+ wbuf->alloced = 1024;
+ wbuf->buff[0] = '\0';
+
+ bi->ptr=(char *)wbuf;
+ bi->init=1;
+ bi->flags=0;
+ return(1);
+}
+
+static int ebcdic_free(BIO *a)
+{
+ if (a == NULL) return(0);
+ if (a->ptr != NULL)
+ OPENSSL_free(a->ptr);
+ a->ptr=NULL;
+ a->init=0;
+ a->flags=0;
+ return(1);
+}
+
+static int ebcdic_read(BIO *b, char *out, int outl)
+{
+ int ret=0;
+
+ if (out == NULL || outl == 0) return(0);
+ if (b->next_bio == NULL) return(0);
+
+ ret=BIO_read(b->next_bio,out,outl);
+ if (ret > 0)
+ ascii2ebcdic(out,out,ret);
+ return(ret);
+}
+
+static int ebcdic_write(BIO *b, char *in, int inl)
+{
+ EBCDIC_OUTBUFF *wbuf;
+ int ret=0;
+ int num;
+ unsigned char n;
+
+ if ((in == NULL) || (inl <= 0)) return(0);
+ if (b->next_bio == NULL) return(0);
+
+ wbuf=(EBCDIC_OUTBUFF *)b->ptr;
+
+ if (inl > (num = wbuf->alloced))
+ {
+ num = num + num; /* double the size */
+ if (num < inl)
+ num = inl;
+ OPENSSL_free(wbuf);
+ wbuf=(EBCDIC_OUTBUFF *)OPENSSL_malloc(sizeof(EBCDIC_OUTBUFF) + num);
+
+ wbuf->alloced = num;
+ wbuf->buff[0] = '\0';
+
+ b->ptr=(char *)wbuf;
+ }
+
+ ebcdic2ascii(wbuf->buff, in, inl);
+
+ ret=BIO_write(b->next_bio, wbuf->buff, inl);
+
+ return(ret);
+}
+
+static long ebcdic_ctrl(BIO *b, int cmd, long num, char *ptr)
+{
+ long ret;
+
+ if (b->next_bio == NULL) return(0);
+ switch (cmd)
+ {
+ case BIO_CTRL_DUP:
+ ret=0L;
+ break;
+ default:
+ ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
+ break;
+ }
+ return(ret);
+}
+
+static int ebcdic_gets(BIO *bp, char *buf, int size)
+{
+ int i, ret;
+ if (bp->next_bio == NULL) return(0);
+/* return(BIO_gets(bp->next_bio,buf,size));*/
+ for (i=0; i<size-1; ++i)
+ {
+ ret = ebcdic_read(bp,&buf[i],1);
+ if (ret <= 0)
+ break;
+ else if (buf[i] == '\n')
+ {
+ ++i;
+ break;
+ }
+ }
+ if (i < size)
+ buf[i] = '\0';
+ return (ret < 0 && i == 0) ? ret : i;
+}
+
+static int ebcdic_puts(BIO *bp, char *str)
+{
+ if (bp->next_bio == NULL) return(0);
+ return ebcdic_write(bp, str, strlen(str));
+}
+#endif
+
+int MAIN(int, char **);
int MAIN(int argc, char *argv[])
{
short port=PORT;
char *CApath=NULL,*CAfile=NULL;
char *context = NULL;
+ char *dhfile = NULL;
int badop=0,bugs=0;
int ret=1;
int off=0;
- int no_tmp_rsa=0,nocert=0;
+ int no_tmp_rsa=0,no_dhe=0,nocert=0;
int state=0;
SSL_METHOD *meth=NULL;
-#ifndef NO_DH
- DH *dh=NULL;
-#endif
+ ENGINE *e=NULL;
#if !defined(NO_SSL2) && !defined(NO_SSL3)
meth=SSLv23_server_method();
local_argv=argv;
apps_startup();
- s_quiet=0;
- s_debug=0;
+#ifdef MONOLITH
+ s_server_init();
+#endif
if (bio_err == NULL)
bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
if (--argc < 1) goto bad;
s_key_file= *(++argv);
}
+ else if (strcmp(*argv,"-dhparam") == 0)
+ {
+ if (--argc < 1) goto bad;
+ dhfile = *(++argv);
+ }
else if (strcmp(*argv,"-dcert") == 0)
{
if (--argc < 1) goto bad;
{ hack=1; }
else if (strcmp(*argv,"-state") == 0)
{ state=1; }
+ else if (strcmp(*argv,"-crlf") == 0)
+ { s_crlf=1; }
else if (strcmp(*argv,"-quiet") == 0)
{ s_quiet=1; }
else if (strcmp(*argv,"-bugs") == 0)
{ bugs=1; }
else if (strcmp(*argv,"-no_tmp_rsa") == 0)
{ no_tmp_rsa=1; }
+ else if (strcmp(*argv,"-no_dhe") == 0)
+ { no_dhe=1; }
else if (strcmp(*argv,"-www") == 0)
{ www=1; }
else if (strcmp(*argv,"-WWW") == 0)
else if (strcmp(*argv,"-tls1") == 0)
{ meth=TLSv1_server_method(); }
#endif
+ else if (strcmp(*argv,"-engine") == 0)
+ {
+ if (--argc < 1) goto bad;
+ engine_id= *(++argv);
+ }
else
{
BIO_printf(bio_err,"unknown option %s\n",*argv);
goto end;
}
+ app_RAND_load_file(NULL, bio_err, 0);
+
if (bio_s_out == NULL)
{
if (s_quiet && !s_debug)
}
SSL_load_error_strings();
- SSLeay_add_ssl_algorithms();
+ OpenSSL_add_ssl_algorithms();
+
+ if (engine_id != NULL)
+ {
+ if((e = ENGINE_by_id(engine_id)) == NULL)
+ {
+ BIO_printf(bio_err,"invalid engine\n");
+ ERR_print_errors(bio_err);
+ goto end;
+ }
+ if (s_debug)
+ {
+ ENGINE_ctrl(e, ENGINE_CTRL_SET_LOGSTREAM,
+ 0, bio_err, 0);
+ }
+ if(!ENGINE_set_default(e, ENGINE_METHOD_ALL))
+ {
+ BIO_printf(bio_err,"can't use that engine\n");
+ ERR_print_errors(bio_err);
+ goto end;
+ }
+ BIO_printf(bio_err,"engine \"%s\" set.\n", engine_id);
+ ENGINE_free(e);
+ }
ctx=SSL_CTX_new(meth);
if (ctx == NULL)
}
#ifndef NO_DH
- /* EAY EAY EAY evil hack */
- dh=load_dh_param();
- if (dh != NULL)
- {
- BIO_printf(bio_s_out,"Setting temp DH parameters\n");
- }
- else
+ if (!no_dhe)
{
- BIO_printf(bio_s_out,"Using default temp DH parameters\n");
- dh=get_dh512();
- }
- BIO_flush(bio_s_out);
+ DH *dh=NULL;
+
+ if (dhfile)
+ dh = load_dh_param(dhfile);
+ else if (s_cert_file)
+ dh = load_dh_param(s_cert_file);
+
+ if (dh != NULL)
+ {
+ BIO_printf(bio_s_out,"Setting temp DH parameters\n");
+ }
+ else
+ {
+ BIO_printf(bio_s_out,"Using default temp DH parameters\n");
+ dh=get_dh512();
+ }
+ (void)BIO_flush(bio_s_out);
- SSL_CTX_set_tmp_dh(ctx,dh);
- DH_free(dh);
+ SSL_CTX_set_tmp_dh(ctx,dh);
+ DH_free(dh);
+ }
#endif
if (!set_cert_stuff(ctx,s_cert_file,s_key_file))
#endif
if (cipher != NULL)
- SSL_CTX_set_cipher_list(ctx,cipher);
+ if(!SSL_CTX_set_cipher_list(ctx,cipher)) {
+ BIO_printf(bio_err,"error setting cipher list\n");
+ ERR_print_errors(bio_err);
+ goto end;
+ }
SSL_CTX_set_verify(ctx,s_server_verify,verify_callback);
+ SSL_CTX_set_session_id_context(ctx,(void*)&s_server_session_id_context,
+ sizeof s_server_session_id_context);
- SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
+ if (CAfile != NULL)
+ SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
BIO_printf(bio_s_out,"ACCEPT\n");
if (www)
unsigned long l;
SSL *con=NULL;
BIO *sbio;
+#ifdef WINDOWS
+ struct timeval tv;
+#endif
- if ((buf=Malloc(bufsize)) == NULL)
+ if ((buf=OPENSSL_malloc(bufsize)) == NULL)
{
BIO_printf(bio_err,"out of memory\n");
goto err;
#endif
if (con == NULL) {
- con=(SSL *)SSL_new(ctx);
+ con=SSL_new(ctx);
if(context)
SSL_set_session_id_context(con, context,
strlen((char *)context));
width=s+1;
for (;;)
{
- FD_ZERO(&readfds);
+ int read_from_terminal;
+ int read_from_sslcon;
+
+ read_from_terminal = 0;
+ read_from_sslcon = SSL_pending(con);
+
+ if (!read_from_sslcon)
+ {
+ FD_ZERO(&readfds);
#ifndef WINDOWS
- FD_SET(fileno(stdin),&readfds);
+ FD_SET(fileno(stdin),&readfds);
+#endif
+ FD_SET(s,&readfds);
+ /* Note: under VMS with SOCKETSHR the second parameter is
+ * currently of type (int *) whereas under other systems
+ * it is (void *) if you don't have a cast it will choke
+ * the compiler: if you do have a cast then you can either
+ * go for (int *) or (void *).
+ */
+#ifdef WINDOWS
+ /* Under Windows we can't select on stdin: only
+ * on sockets. As a workaround we timeout the select every
+ * second and check for any keypress. In a proper Windows
+ * application we wouldn't do this because it is inefficient.
+ */
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ i=select(width,(void *)&readfds,NULL,NULL,&tv);
+ if((i < 0) || (!i && !_kbhit() ) )continue;
+ if(_kbhit())
+ read_from_terminal = 1;
+#else
+ i=select(width,(void *)&readfds,NULL,NULL,NULL);
+ if (i <= 0) continue;
+ if (FD_ISSET(fileno(stdin),&readfds))
+ read_from_terminal = 1;
#endif
- FD_SET(s,&readfds);
- /* Note: under VMS with SOCKETSHR the second parameter is
- * currently of type (int *) whereas under other systems
- * it is (void *) if you don't have a cast it will choke
- * the compiler: if you do have a cast then you can either
- * go for (int *) or (void *).
- */
- i=select(width,(void *)&readfds,NULL,NULL,NULL);
- if (i <= 0) continue;
- if (FD_ISSET(fileno(stdin),&readfds))
+ if (FD_ISSET(s,&readfds))
+ read_from_sslcon = 1;
+ }
+ if (read_from_terminal)
{
- i=read(fileno(stdin),buf,bufsize);
+ if (s_crlf)
+ {
+ int j, lf_num;
+
+ i=read(fileno(stdin), buf, bufsize/2);
+ lf_num = 0;
+ /* both loops are skipped when i <= 0 */
+ for (j = 0; j < i; j++)
+ if (buf[j] == '\n')
+ lf_num++;
+ for (j = i-1; j >= 0; j--)
+ {
+ buf[j+lf_num] = buf[j];
+ if (buf[j] == '\n')
+ {
+ lf_num--;
+ i++;
+ buf[j+lf_num] = '\r';
+ }
+ }
+ assert(lf_num == 0);
+ }
+ else
+ i=read(fileno(stdin),buf,bufsize);
if (!s_quiet)
{
if ((i <= 0) || (buf[0] == 'Q'))
print_stats(bio_s_out,SSL_get_SSL_CTX(con));
}
}
+#ifdef CHARSET_EBCDIC
+ ebcdic2ascii(buf,buf,i);
+#endif
l=k=0;
for (;;)
{
if (i <= 0) break;
}
}
- if (FD_ISSET(s,&readfds))
+ if (read_from_sslcon)
{
if (!SSL_is_init_finished(con))
{
switch (SSL_get_error(con,i))
{
case SSL_ERROR_NONE:
+#ifdef CHARSET_EBCDIC
+ ascii2ebcdic(buf,buf,i);
+#endif
write(fileno(stdout),buf,
(unsigned int)i);
if (SSL_pending(con)) goto again;
if (buf != NULL)
{
memset(buf,0,bufsize);
- Free(buf);
+ OPENSSL_free(buf);
}
if (ret >= 0)
BIO_printf(bio_s_out,"ACCEPT\n");
}
#ifndef NO_DH
-static DH *load_dh_param(void)
+static DH *load_dh_param(char *dhfile)
{
DH *ret=NULL;
BIO *bio;
- if ((bio=BIO_new_file(DH_PARAM,"r")) == NULL)
+ if ((bio=BIO_new_file(dhfile,"r")) == NULL)
goto err;
- ret=PEM_read_bio_DHparams(bio,NULL,NULL);
+ ret=PEM_read_bio_DHparams(bio,NULL,NULL,NULL);
err:
if (bio != NULL) BIO_free(bio);
return(ret);
BIO *io,*ssl_bio,*sbio;
long total_bytes;
- buf=Malloc(bufsize);
+ buf=OPENSSL_malloc(bufsize);
if (buf == NULL) return(0);
io=BIO_new(BIO_f_buffer());
ssl_bio=BIO_new(BIO_f_ssl());
/* lets make the output buffer a reasonable size */
if (!BIO_set_write_buffer_size(io,bufsize)) goto err;
- if ((con=(SSL *)SSL_new(ctx)) == NULL) goto err;
+ if ((con=SSL_new(ctx)) == NULL) goto err;
if(context) SSL_set_session_id_context(con, context,
strlen((char *)context));
/* SSL_set_fd(con,s); */
BIO_set_ssl(ssl_bio,con,BIO_CLOSE);
BIO_push(io,ssl_bio);
+#ifdef CHARSET_EBCDIC
+ io = BIO_push(BIO_new(BIO_f_ebcdic_filter()),io);
+#endif
if (s_debug)
{
static char *space=" ";
BIO_puts(io,"HTTP/1.0 200 ok\r\nContent-type: text/html\r\n\r\n");
- BIO_puts(io,"<HTML><BODY BGCOLOR=ffffff>\n");
+ BIO_puts(io,"<HTML><BODY BGCOLOR=\"#ffffff\">\n");
BIO_puts(io,"<pre>\n");
/* BIO_puts(io,SSLeay_version(SSLEAY_VERSION));*/
BIO_puts(io,"\n");
BIO_puts(io,"</BODY></HTML>\r\n\r\n");
break;
}
- else if ((www == 2) && (strncmp("GET ",buf,4) == 0))
+ else if ((www == 2) && (strncmp("GET /",buf,5) == 0))
{
BIO *file;
char *p,*e;
/* make sure we re-use sessions */
SSL_set_shutdown(con,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
#else
- /* This kills performace */
+ /* This kills performance */
/* SSL_shutdown(con); A shutdown gets sent in the
* BIO_free_all(io) procession */
#endif
if (ret >= 0)
BIO_printf(bio_s_out,"ACCEPT\n");
- if (buf != NULL) Free(buf);
+ if (buf != NULL) OPENSSL_free(buf);
if (io != NULL) BIO_free_all(io);
/* if (ssl_bio != NULL) BIO_free(ssl_bio);*/
return(ret);
}
#ifndef NO_RSA
-static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int export, int keylength)
+static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export, int keylength)
{
static RSA *rsa_tmp=NULL;
if (!s_quiet)
{
BIO_printf(bio_err,"Generating temp (%d bit) RSA key...",keylength);
- BIO_flush(bio_err);
+ (void)BIO_flush(bio_err);
}
rsa_tmp=RSA_generate_key(keylength,RSA_F4,NULL,NULL);
if (!s_quiet)
{
BIO_printf(bio_err,"\n");
- BIO_flush(bio_err);
+ (void)BIO_flush(bio_err);
}
}
return(rsa_tmp);