X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_server.c;h=9982d6ac7e29d8ec4ba5fafc2093437f2d641584;hp=cc2c10d10cfbcde754bb4f97ab1ae445dc50dd38;hb=bcbe37b716780763ee66c839618bd76eda2b507c;hpb=bcfea9fb25738b007cfef48d5070376c4398675a diff --git a/apps/s_server.c b/apps/s_server.c index cc2c10d10c..9982d6ac7e 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -56,7 +56,7 @@ * [including the GNU Public Licence.] */ /* ==================================================================== - * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -113,6 +113,32 @@ * ECC cipher suite support in OpenSSL originally developed by * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ /* Until the key-gen callbacks are modified to use newer prototypes, we allow * deprecated functions for openssl-internal code */ @@ -121,11 +147,11 @@ #endif #include +#include #include #include #include -#include #include #ifdef OPENSSL_NO_STDIO #define APPS_WIN16 @@ -153,15 +179,14 @@ typedef unsigned int u_int; #include #include #include -#include "s_apps.h" - -#ifdef OPENSSL_SYS_WINCE -/* Windows CE incorrectly defines fileno as returning void*, so to avoid problems below... */ -#ifdef fileno -#undef fileno +#ifndef OPENSSL_NO_DH +#include #endif -#define fileno(a) (int)_fileno(a) +#ifndef OPENSSL_NO_RSA +#include #endif +#include "s_apps.h" +#include "timeouts.h" #if (defined(OPENSSL_SYS_VMS) && __VMS_VER < 70000000) /* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */ @@ -180,7 +205,7 @@ static void print_stats(BIO *bp,SSL_CTX *ctx); static int generate_session_id(const SSL *ssl, unsigned char *id, unsigned int *id_len); #ifndef OPENSSL_NO_DH -static DH *load_dh_param(char *dhfile); +static DH *load_dh_param(const char *dhfile); static DH *get_dh512(void); #endif @@ -188,14 +213,6 @@ static DH *get_dh512(void); static void s_server_init(void); #endif -#ifndef S_ISDIR -# 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 OPENSSL_NO_DH static unsigned char dh512_p[]={ 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75, @@ -231,6 +248,9 @@ static int bufsize=BUFSIZZ; static int accept_socket= -1; #define TEST_CERT "server.pem" +#ifndef OPENSSL_NO_TLSEXT +#define TEST_CERT2 "server2.pem" +#endif #undef PROG #define PROG s_server_main @@ -239,7 +259,10 @@ 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 const char *s_cert_file=TEST_CERT,*s_key_file=NULL; +#ifndef OPENSSL_NO_TLSEXT +static const char *s_cert_file2=TEST_CERT2,*s_key_file2=NULL; +#endif static char *s_dcert_file=NULL,*s_dkey_file=NULL; #ifdef FIONBIO static int s_nbio=0; @@ -247,6 +270,9 @@ static int s_nbio=0; static int s_nbio_test=0; int s_crlf=0; static SSL_CTX *ctx=NULL; +#ifndef OPENSSL_NO_TLSEXT +static SSL_CTX *ctx2=NULL; +#endif static int www=0; static BIO *bio_s_out=NULL; @@ -260,6 +286,75 @@ static char *engine_id=NULL; #endif static const char *session_id_prefix=NULL; +static int enable_timeouts = 0; +static long socket_mtu; +static int cert_chain = 0; + +#ifndef OPENSSL_NO_PSK +static char *psk_identity="Client_identity"; +static char *psk_key=NULL; /* by default PSK is not used */ + +static unsigned int psk_server_cb(SSL *ssl, const char *identity, + unsigned char *psk, unsigned int max_psk_len) + { + unsigned int psk_len = 0; + int ret; + BIGNUM *bn = NULL; + + if (s_debug) + BIO_printf(bio_s_out,"psk_server_cb\n"); + if (!identity) + { + BIO_printf(bio_err,"Error: client did not send PSK identity\n"); + goto out_err; + } + if (s_debug) + BIO_printf(bio_s_out,"identity_len=%d identity=%s\n", + identity ? strlen(identity) : 0, identity); + + /* here we could lookup the given identity e.g. from a database */ + if (strcmp(identity, psk_identity) != 0) + { + BIO_printf(bio_s_out, "PSK error: client identity not found\n"); + goto out_err; + } + if (s_debug) + BIO_printf(bio_s_out, "PSK client identity found\n"); + + /* convert the PSK key to binary */ + ret = BN_hex2bn(&bn, psk_key); + if (!ret) + { + BIO_printf(bio_err,"Could not convert PSK key '%s' to BIGNUM\n", psk_key); + if (bn) + BN_free(bn); + return 0; + } + if (BN_num_bytes(bn) > (int)max_psk_len) + { + BIO_printf(bio_err,"psk buffer of callback is too small (%d) for key (%d)\n", + max_psk_len, BN_num_bytes(bn)); + BN_free(bn); + return 0; + } + + ret = BN_bn2bin(bn, psk); + BN_free(bn); + + if (ret < 0) + goto out_err; + psk_len = (unsigned int)ret; + + if (s_debug) + BIO_printf(bio_s_out, "fetched PSK len=%d\n", psk_len); + return psk_len; + out_err: + if (s_debug) + BIO_printf(bio_err, "Error in PSK server callback\n"); + return 0; + } +#endif + #ifdef MONOLITH static void s_server_init(void) { @@ -270,6 +365,11 @@ static void s_server_init(void) s_dkey_file=NULL; s_cert_file=TEST_CERT; s_key_file=NULL; +#ifndef OPENSSL_NO_TLSEXT + s_cert_file2=TEST_CERT2; + s_key_file2=NULL; + ctx2=NULL; +#endif #ifdef FIONBIO s_nbio=0; #endif @@ -296,18 +396,24 @@ static void sv_usage(void) BIO_printf(bio_err," -context arg - set session ID context\n"); BIO_printf(bio_err," -verify arg - turn on peer certificate verification\n"); 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," -cert arg - certificate file to use\n"); BIO_printf(bio_err," (default is %s)\n",TEST_CERT); - BIO_printf(bio_err," -key arg - Private Key file to use, PEM format assumed, in cert file if\n"); + BIO_printf(bio_err," -certform arg - certificate format (PEM or DER) PEM default\n"); + BIO_printf(bio_err," -key arg - Private Key file to use, in cert file if\n"); BIO_printf(bio_err," not specified (default is %s)\n",TEST_CERT); + BIO_printf(bio_err," -keyform arg - key format (PEM, DER or ENGINE) PEM default\n"); + BIO_printf(bio_err," -pass arg - private key file pass phrase source\n"); BIO_printf(bio_err," -dcert arg - second certificate file to use (usually for DSA)\n"); + BIO_printf(bio_err," -dcertform x - second certificate format (PEM or DER) PEM default\n"); BIO_printf(bio_err," -dkey arg - second private key file to use (usually for DSA)\n"); + BIO_printf(bio_err," -dkeyform arg - second key format (PEM, DER or ENGINE) PEM default\n"); + BIO_printf(bio_err," -dpass arg - second private key file pass phrase source\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"); #ifndef OPENSSL_NO_ECDH BIO_printf(bio_err," -named_curve arg - Elliptic curve name to use for ephemeral ECDH keys.\n" \ " Use \"openssl ecparam -list_curves\" for all names\n" \ - " (default is sect163r2).\n"); + " (default is nistp256).\n"); #endif #ifdef FIONBIO BIO_printf(bio_err," -nbio - Run with non-blocking IO\n"); @@ -324,9 +430,17 @@ static void sv_usage(void) BIO_printf(bio_err," -serverpref - Use server's cipher preferences\n"); BIO_printf(bio_err," -quiet - No server output\n"); BIO_printf(bio_err," -no_tmp_rsa - Do not generate a tmp RSA key\n"); +#ifndef OPENSSL_NO_PSK + BIO_printf(bio_err," -psk_hint arg - PSK identity hint to use\n"); + BIO_printf(bio_err," -psk arg - PSK in hex (without 0x)\n"); +#endif BIO_printf(bio_err," -ssl2 - Just talk SSLv2\n"); BIO_printf(bio_err," -ssl3 - Just talk SSLv3\n"); BIO_printf(bio_err," -tls1 - Just talk TLSv1\n"); + BIO_printf(bio_err," -dtls1 - Just talk DTLSv1\n"); + BIO_printf(bio_err," -timeout - Enable timeouts\n"); + BIO_printf(bio_err," -mtu - Set MTU\n"); + BIO_printf(bio_err," -chain - Read a certificate chain\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"); @@ -346,6 +460,14 @@ static void sv_usage(void) #endif BIO_printf(bio_err," -id_prefix arg - Generate SSL/TLS session IDs prefixed by 'arg'\n"); BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR); +#ifndef OPENSSL_NO_TLSEXT + BIO_printf(bio_err," -servername host - servername for HostName TLS extension\n"); + BIO_printf(bio_err," -servername_fatal - on mismatch send fatal alert (default warning alert)\n"); + BIO_printf(bio_err," -cert2 arg - certificate file to use for servername\n"); + BIO_printf(bio_err," (default is %s)\n",TEST_CERT2); + BIO_printf(bio_err," -key2 arg - Private Key file to use for servername, in cert file if\n"); + BIO_printf(bio_err," not specified (default is %s)\n",TEST_CERT2); +#endif } static int local_argc=0; @@ -501,6 +623,40 @@ static int ebcdic_puts(BIO *bp, const char *str) } #endif +#ifndef OPENSSL_NO_TLSEXT + +/* This is a context that we pass to callbacks */ +typedef struct tlsextctx_st { + char * servername; + BIO * biodebug; + int extension_error; +} tlsextctx; + + +static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg) + { + tlsextctx * p = (tlsextctx *) arg; + const char * servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); + if (servername && p->biodebug) + BIO_printf(p->biodebug,"Hostname in TLS extension: \"%s\"\n",servername); + + if (!p->servername) + return SSL_TLSEXT_ERR_NOACK; + + if (servername) + { + if (strcmp(servername,p->servername)) + return p->extension_error; + if (ctx2) + { + BIO_printf(p->biodebug,"Swiching server context.\n"); + SSL_set_SSL_CTX(s,ctx2); + } + } + return SSL_TLSEXT_ERR_OK; +} +#endif + int MAIN(int, char **); int MAIN(int argc, char *argv[]) @@ -509,20 +665,40 @@ int MAIN(int argc, char *argv[]) int vflags = 0; short port=PORT; char *CApath=NULL,*CAfile=NULL; - char *context = NULL; + unsigned char *context = NULL; char *dhfile = NULL; +#ifndef OPENSSL_NO_ECDH char *named_curve = NULL; +#endif int badop=0,bugs=0; int ret=1; int off=0; int no_tmp_rsa=0,no_dhe=0,no_ecdhe=0,nocert=0; int state=0; - SSL_METHOD *meth=NULL; + const SSL_METHOD *meth=NULL; + int socket_type=SOCK_STREAM; #ifndef OPENSSL_NO_ENGINE ENGINE *e=NULL; #endif char *inrand=NULL; + int s_cert_format = FORMAT_PEM, s_key_format = FORMAT_PEM; + char *passarg = NULL, *pass = NULL; + char *dpassarg = NULL, *dpass = NULL; + int s_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM; + X509 *s_cert = NULL, *s_dcert = NULL; + EVP_PKEY *s_key = NULL, *s_dkey = NULL; +#ifndef OPENSSL_NO_TLSEXT + EVP_PKEY *s_key2 = NULL; + X509 *s_cert2 = NULL; +#endif +#ifndef OPENSSL_NO_TLSEXT + tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING}; +#endif +#ifndef OPENSSL_NO_PSK + /* by default do not send a PSK identity hint */ + static char *psk_identity_hint=NULL; +#endif #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) meth=SSLv23_server_method(); #elif !defined(OPENSSL_NO_SSL3) @@ -581,18 +757,33 @@ int MAIN(int argc, char *argv[]) else if (strcmp(*argv,"-context") == 0) { if (--argc < 1) goto bad; - context= *(++argv); + context= (unsigned char *)*(++argv); } else if (strcmp(*argv,"-cert") == 0) { if (--argc < 1) goto bad; s_cert_file= *(++argv); } + else if (strcmp(*argv,"-certform") == 0) + { + if (--argc < 1) goto bad; + s_cert_format = str2fmt(*(++argv)); + } else if (strcmp(*argv,"-key") == 0) { if (--argc < 1) goto bad; s_key_file= *(++argv); } + else if (strcmp(*argv,"-keyform") == 0) + { + if (--argc < 1) goto bad; + s_key_format = str2fmt(*(++argv)); + } + else if (strcmp(*argv,"-pass") == 0) + { + if (--argc < 1) goto bad; + passarg = *(++argv); + } else if (strcmp(*argv,"-dhparam") == 0) { if (--argc < 1) goto bad; @@ -605,11 +796,26 @@ int MAIN(int argc, char *argv[]) named_curve = *(++argv); } #endif + else if (strcmp(*argv,"-dcertform") == 0) + { + if (--argc < 1) goto bad; + s_dcert_format = str2fmt(*(++argv)); + } else if (strcmp(*argv,"-dcert") == 0) { if (--argc < 1) goto bad; s_dcert_file= *(++argv); } + else if (strcmp(*argv,"-dkeyform") == 0) + { + if (--argc < 1) goto bad; + s_dkey_format = str2fmt(*(++argv)); + } + else if (strcmp(*argv,"-dpass") == 0) + { + if (--argc < 1) goto bad; + dpassarg = *(++argv); + } else if (strcmp(*argv,"-dkey") == 0) { if (--argc < 1) goto bad; @@ -675,6 +881,27 @@ int MAIN(int argc, char *argv[]) { no_dhe=1; } else if (strcmp(*argv,"-no_ecdhe") == 0) { no_ecdhe=1; } +#ifndef OPENSSL_NO_PSK + else if (strcmp(*argv,"-psk_hint") == 0) + { + if (--argc < 1) goto bad; + psk_identity_hint= *(++argv); + } + else if (strcmp(*argv,"-psk") == 0) + { + size_t i; + + if (--argc < 1) goto bad; + psk_key=*(++argv); + for (i=0; i= 32) + BIO_printf(bio_err, + "warning: id_prefix is too long, only one new session will be possible\n"); + else if(strlen(session_id_prefix) >= 16) + BIO_printf(bio_err, + "warning: id_prefix is too long if you use SSLv2\n"); + if(!SSL_CTX_set_generate_session_id(ctx2, generate_session_id)) + { + BIO_printf(bio_err,"error setting 'id_prefix'\n"); + ERR_print_errors(bio_err); + goto end; + } + BIO_printf(bio_err,"id_prefix '%s' set.\n", session_id_prefix); + } + SSL_CTX_set_quiet_shutdown(ctx2,1); + if (bugs) SSL_CTX_set_options(ctx2,SSL_OP_ALL); + if (hack) SSL_CTX_set_options(ctx2,SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG); + SSL_CTX_set_options(ctx2,off); + /* DTLS: partial reads end up discarding unread UDP bytes :-( + * Setting read ahead solves this problem. + */ + if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx2, 1); + + if (state) SSL_CTX_set_info_callback(ctx2,apps_ssl_info_callback); + + SSL_CTX_sess_set_cache_size(ctx2,128); + + if ((!SSL_CTX_load_verify_locations(ctx2,CAfile,CApath)) || + (!SSL_CTX_set_default_verify_paths(ctx2))) + { + ERR_print_errors(bio_err); + } + store = SSL_CTX_get_cert_store(ctx2); + X509_STORE_set_flags(store, vflags); + } +#endif + #ifndef OPENSSL_NO_DH if (!no_dhe) { @@ -846,6 +1255,24 @@ bad: (void)BIO_flush(bio_s_out); SSL_CTX_set_tmp_dh(ctx,dh); +#ifndef OPENSSL_NO_TLSEXT + if (ctx2) + { + if (!dhfile) + { + DH *dh2=load_dh_param(s_cert_file2); + if (dh2 != NULL) + { + BIO_printf(bio_s_out,"Setting temp DH parameters\n"); + (void)BIO_flush(bio_s_out); + + DH_free(dh); + dh = dh2; + } + } + SSL_CTX_set_tmp_dh(ctx2,dh); + } +#endif DH_free(dh); } #endif @@ -855,13 +1282,6 @@ bad: { EC_KEY *ecdh=NULL; - ecdh = EC_KEY_new(); - if (ecdh == NULL) - { - BIO_printf(bio_err,"Could not create ECDH struct.\n"); - goto end; - } - if (named_curve) { int nid = OBJ_sn2nid(named_curve); @@ -872,9 +1292,8 @@ bad: named_curve); goto end; } - - ecdh->group = EC_GROUP_new_by_nid(nid); - if (ecdh->group == NULL) + ecdh = EC_KEY_new_by_curve_name(nid); + if (ecdh == NULL) { BIO_printf(bio_err, "unable to create curve (%s)\n", named_curve); @@ -882,39 +1301,53 @@ bad: } } - if (ecdh->group != NULL) + if (ecdh != NULL) { BIO_printf(bio_s_out,"Setting temp ECDH parameters\n"); } else { BIO_printf(bio_s_out,"Using default temp ECDH parameters\n"); - ecdh->group=EC_GROUP_new_by_nid(NID_sect163r2); - if (ecdh->group == NULL) + ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (ecdh == NULL) { - BIO_printf(bio_err, "unable to create curve (sect163r2)\n"); + BIO_printf(bio_err, "unable to create curve (nistp256)\n"); goto end; } } (void)BIO_flush(bio_s_out); SSL_CTX_set_tmp_ecdh(ctx,ecdh); +#ifndef OPENSSL_NO_TLSEXT + if (ctx2) + SSL_CTX_set_tmp_ecdh(ctx2,ecdh); +#endif EC_KEY_free(ecdh); } #endif - if (!set_cert_stuff(ctx,s_cert_file,s_key_file)) + if (!set_cert_key_stuff(ctx,s_cert,s_key)) goto end; - if (s_dcert_file != NULL) +#ifndef OPENSSL_NO_TLSEXT + if (ctx2 && !set_cert_key_stuff(ctx2,s_cert2,s_key2)) + goto end; +#endif + if (s_dcert != NULL) { - if (!set_cert_stuff(ctx,s_dcert_file,s_dkey_file)) + if (!set_cert_key_stuff(ctx,s_dcert,s_dkey)) goto end; } #ifndef OPENSSL_NO_RSA #if 1 if (!no_tmp_rsa) + { SSL_CTX_set_tmp_rsa_callback(ctx,tmp_rsa_cb); +#ifndef OPENSSL_NO_TLSEXT + if (ctx2) + SSL_CTX_set_tmp_rsa_callback(ctx2,tmp_rsa_cb); +#endif + } #else if (!no_tmp_rsa && SSL_CTX_need_tmp_RSA(ctx)) { @@ -930,37 +1363,114 @@ bad: ERR_print_errors(bio_err); goto end; } +#ifndef OPENSSL_NO_TLSEXT + if (ctx2) + { + if (!SSL_CTX_set_tmp_rsa(ctx2,rsa)) + { + ERR_print_errors(bio_err); + goto end; + } + } +#endif RSA_free(rsa); BIO_printf(bio_s_out,"\n"); } #endif #endif - if (cipher != NULL) - if(!SSL_CTX_set_cipher_list(ctx,cipher)) { - BIO_printf(bio_err,"error setting cipher list\n"); +#ifndef OPENSSL_NO_PSK + if (psk_key != NULL) + { + if (s_debug) + BIO_printf(bio_s_out, "PSK key given, setting server callback\n"); + SSL_CTX_set_psk_server_callback(ctx, psk_server_cb); + } + + if (!SSL_CTX_use_psk_identity_hint(ctx, psk_identity_hint)) + { + BIO_printf(bio_err,"error setting PSK identity hint to context\n"); ERR_print_errors(bio_err); goto end; - } + } +#endif + + if (cipher != NULL) + { + if(!SSL_CTX_set_cipher_list(ctx,cipher)) + { + BIO_printf(bio_err,"error setting cipher list\n"); + ERR_print_errors(bio_err); + goto end; + } +#ifndef OPENSSL_NO_TLSEXT + if (ctx2 && !SSL_CTX_set_cipher_list(ctx2,cipher)) + { + BIO_printf(bio_err,"error setting cipher list\n"); + ERR_print_errors(bio_err); + goto end; + } +#endif + } 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); +#ifndef OPENSSL_NO_TLSEXT + if (ctx2) + { + SSL_CTX_set_verify(ctx2,s_server_verify,verify_callback); + SSL_CTX_set_session_id_context(ctx2,(void*)&s_server_session_id_context, + sizeof s_server_session_id_context); + + tlsextcbp.biodebug = bio_s_out; + SSL_CTX_set_tlsext_servername_callback(ctx2, ssl_servername_cb); + SSL_CTX_set_tlsext_servername_arg(ctx2, &tlsextcbp); + SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); + SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); + } +#endif + if (CAfile != NULL) - SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile)); + { + SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile)); +#ifndef OPENSSL_NO_TLSEXT + if (ctx2) + SSL_CTX_set_client_CA_list(ctx2,SSL_load_client_CA_file(CAfile)); +#endif + } BIO_printf(bio_s_out,"ACCEPT\n"); if (www) - do_server(port,&accept_socket,www_body, context); + do_server(port,socket_type,&accept_socket,www_body, context); else - do_server(port,&accept_socket,sv_body, context); + do_server(port,socket_type,&accept_socket,sv_body, context); print_stats(bio_s_out,ctx); ret=0; end: if (ctx != NULL) SSL_CTX_free(ctx); + if (s_cert) + X509_free(s_cert); + if (s_dcert) + X509_free(s_dcert); + if (s_key) + EVP_PKEY_free(s_key); + if (s_dkey) + EVP_PKEY_free(s_dkey); + if (pass) + OPENSSL_free(pass); + if (dpass) + OPENSSL_free(dpass); +#ifndef OPENSSL_NO_TLSEXT + if (ctx2 != NULL) SSL_CTX_free(ctx2); + if (s_cert2) + X509_free(s_cert2); + if (s_key2) + EVP_PKEY_free(s_key2); +#endif if (bio_s_out != NULL) { - BIO_free(bio_s_out); + BIO_free(bio_s_out); bio_s_out=NULL; } apps_shutdown(); @@ -1039,7 +1549,38 @@ static int sv_body(char *hostname, int s, unsigned char *context) } SSL_clear(con); - sbio=BIO_new_socket(s,BIO_NOCLOSE); + if (SSL_version(con) == DTLS1_VERSION) + { + struct timeval timeout; + + sbio=BIO_new_dgram(s,BIO_NOCLOSE); + + if (enable_timeouts) + { + timeout.tv_sec = 0; + timeout.tv_usec = DGRAM_RCV_TIMEOUT; + BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); + + timeout.tv_sec = 0; + timeout.tv_usec = DGRAM_SND_TIMEOUT; + BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); + } + + if (socket_mtu > 0) + { + SSL_set_options(con, SSL_OP_NO_QUERY_MTU); + SSL_set_mtu(con, socket_mtu); + } + else + /* want to do MTU discovery */ + BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); + + /* turn on cookie exchange */ + SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE); + } + else + sbio=BIO_new_socket(s,BIO_NOCLOSE); + if (s_nbio_test) { BIO *test; @@ -1054,7 +1595,7 @@ static int sv_body(char *hostname, int s, unsigned char *context) if (s_debug) { con->debug=1; - BIO_set_callback(SSL_get_rbio(con),bio_dump_cb); + BIO_set_callback(SSL_get_rbio(con),bio_dump_callback); BIO_set_callback_arg(SSL_get_rbio(con),bio_s_out); } if (s_msg) @@ -1112,7 +1653,7 @@ static int sv_body(char *hostname, int s, unsigned char *context) { int j, lf_num; - i=read(fileno(stdin), buf, bufsize/2); + i=raw_read_stdin(buf, bufsize/2); lf_num = 0; /* both loops are skipped when i <= 0 */ for (j = 0; j < i; j++) @@ -1131,7 +1672,7 @@ static int sv_body(char *hostname, int s, unsigned char *context) assert(lf_num == 0); } else - i=read(fileno(stdin),buf,bufsize); + i=raw_read_stdin(buf,bufsize); if (!s_quiet) { if ((i <= 0) || (buf[0] == 'Q')) @@ -1145,11 +1686,13 @@ static int sv_body(char *hostname, int s, unsigned char *context) if ((i <= 0) || (buf[0] == 'q')) { BIO_printf(bio_s_out,"DONE\n"); - SHUTDOWN(s); + if (SSL_version(con) != DTLS1_VERSION) + SHUTDOWN(s); /* close_accept_socket(); ret= -11;*/ goto err; } + if ((buf[0] == 'r') && ((buf[1] == '\n') || (buf[1] == '\r'))) { @@ -1174,7 +1717,7 @@ static int sv_body(char *hostname, int s, unsigned char *context) } if (buf[0] == 'P') { - static char *str="Lets print some clear text\n"; + static const char *str="Lets print some clear text\n"; BIO_write(SSL_get_wbio(con),str,strlen(str)); } if (buf[0] == 'S') @@ -1246,7 +1789,7 @@ again: #ifdef CHARSET_EBCDIC ascii2ebcdic(buf,buf,i); #endif - write(fileno(stdout),buf, + raw_write_stdout(buf, (unsigned int)i); if (SSL_pending(con)) goto again; break; @@ -1270,13 +1813,16 @@ again: } } err: - BIO_printf(bio_s_out,"shutting down SSL\n"); + if (con != NULL) + { + BIO_printf(bio_s_out,"shutting down SSL\n"); #if 1 - SSL_set_shutdown(con,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); + SSL_set_shutdown(con,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); #else - SSL_shutdown(con); + SSL_shutdown(con); #endif - if (con != NULL) SSL_free(con); + SSL_free(con); + } BIO_printf(bio_s_out,"CONNECTION CLOSED\n"); if (buf != NULL) { @@ -1358,7 +1904,7 @@ static int init_ssl_connection(SSL *con) } #ifndef OPENSSL_NO_DH -static DH *load_dh_param(char *dhfile) +static DH *load_dh_param(const char *dhfile) { DH *ret=NULL; BIO *bio; @@ -1398,7 +1944,6 @@ static int www_body(char *hostname, int s, unsigned char *context) char *buf=NULL; int ret=1; int i,j,k,blank,dot; - struct stat st_buf; SSL *con; SSL_CIPHER *c; BIO *io,*ssl_bio,*sbio; @@ -1457,7 +2002,7 @@ static int www_body(char *hostname, int s, unsigned char *context) if (s_debug) { con->debug=1; - BIO_set_callback(SSL_get_rbio(con),bio_dump_cb); + BIO_set_callback(SSL_get_rbio(con),bio_dump_callback); BIO_set_callback_arg(SSL_get_rbio(con),bio_s_out); } if (s_msg) @@ -1526,7 +2071,7 @@ static int www_body(char *hostname, int s, unsigned char *context) char *p; X509 *peer; STACK_OF(SSL_CIPHER) *sk; - static char *space=" "; + static const char *space=" "; BIO_puts(io,"HTTP/1.0 200 ok\r\nContent-type: text/html\r\n\r\n"); BIO_puts(io,"\n"); @@ -1606,7 +2151,7 @@ static int www_body(char *hostname, int s, unsigned char *context) { BIO *file; char *p,*e; - static char *text="HTTP/1.0 200 ok\r\nContent-type: text/plain\r\n\r\n"; + static const char *text="HTTP/1.0 200 ok\r\nContent-type: text/plain\r\n\r\n"; /* skip the '/' */ p= &(buf[5]); @@ -1663,14 +2208,7 @@ static int www_body(char *hostname, int s, unsigned char *context) #endif /* if a directory, do the index thang */ - if (stat(p,&st_buf) < 0) - { - BIO_puts(io,text); - BIO_printf(io,"Error accessing '%s'\r\n",p); - ERR_print_errors(io); - break; - } - if (S_ISDIR(st_buf.st_mode)) + if (app_isdir(p)>0) { #if 0 /* must check buffer size */ strcat(p,"/index.html");