X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=apps%2Fs_server.c;h=d824a838d48d4e1b70e9ba20738e9552d09dfa05;hb=65a6a1ff452ab7d72becfe9322d1e4bdc1786c44;hp=0137b31cd11daba9a17c897cccf610041e96f532;hpb=6bd173fced6935db65756ecd0678e8666c53284e;p=oweals%2Fopenssl.git diff --git a/apps/s_server.c b/apps/s_server.c index 0137b31cd1..d824a838d4 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -204,14 +204,17 @@ typedef unsigned int u_int; #ifndef OPENSSL_NO_RSA 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 sv_body(char *hostname, int s, int stype, unsigned char *context); +static int www_body(char *hostname, int s, int stype, unsigned char *context); +static int rev_body(char *hostname, int s, int stype, unsigned char *context); static void close_accept_socket(void ); static void sv_usage(void); static int init_ssl_connection(SSL *s); static void print_stats(BIO *bp,SSL_CTX *ctx); static int generate_session_id(const SSL *ssl, unsigned char *id, unsigned int *id_len); +static void init_session_cache_ctx(SSL_CTX *sctx); +static void free_sessions(void); #ifndef OPENSSL_NO_DH static DH *load_dh_param(const char *dhfile); static DH *get_dh512(void); @@ -262,16 +265,15 @@ static int accept_socket= -1; #undef PROG #define PROG s_server_main -extern int verify_depth, verify_return_error; +extern int verify_depth, verify_return_error, verify_quiet; -static char *cipher=NULL; static int s_server_verify=SSL_VERIFY_NONE; static int s_server_session_id_context = 1; /* anything will do */ -static const char *s_cert_file=TEST_CERT,*s_key_file=NULL; +static const char *s_cert_file=TEST_CERT,*s_key_file=NULL, *s_chain_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; +static char *s_dcert_file=NULL,*s_dkey_file=NULL, *s_dchain_file=NULL; #ifdef FIONBIO static int s_nbio=0; #endif @@ -284,14 +286,21 @@ static SSL_CTX *ctx2=NULL; static int www=0; static BIO *bio_s_out=NULL; +static BIO *bio_s_msg = NULL; static int s_debug=0; #ifndef OPENSSL_NO_TLSEXT static int s_tlsextdebug=0; static int s_tlsextstatus=0; static int cert_status_cb(SSL *s, void *arg); #endif +static int no_resume_ephemeral = 0; static int s_msg=0; static int s_quiet=0; +static int s_ign_eof=0; +static int s_brief=0; + +static char *keymatexportlabel=NULL; +static int keymatexportlen=20; static int hack=0; #ifndef OPENSSL_NO_ENGINE @@ -305,6 +314,12 @@ static long socket_mtu; static int cert_chain = 0; #endif +#ifndef OPENSSL_NO_TLSEXT +static BIO *serverinfo_in = NULL; +static const char *s_serverinfo_file = NULL; + +#endif + #ifndef OPENSSL_NO_PSK static char *psk_identity="Client_identity"; char *psk_key=NULL; /* by default PSK is not used */ @@ -376,31 +391,43 @@ static unsigned int psk_server_cb(SSL *ssl, const char *identity, /* This is a context that we pass to callbacks */ typedef struct srpsrvparm_st { - int verbose; char *login; SRP_VBASE *vb; + SRP_user_pwd *user; } srpsrvparm; +/* This callback pretends to require some asynchronous logic in order to obtain + a verifier. When the callback is called for a new connection we return + with a negative value. This will provoke the accept etc to return with + an LOOKUP_X509. The main logic of the reinvokes the suspended call + (which would normally occur after a worker has finished) and we + set the user parameters. +*/ static int MS_CALLBACK ssl_srp_server_param_cb(SSL *s, int *ad, void *arg) { - srpsrvparm *p = (srpsrvparm *) arg; - SRP_user_pwd *user; - - p->login = BUF_strdup(SSL_get_srp_username(s)); - BIO_printf(bio_err, "SRP username = \"%s\"\n", p->login); + srpsrvparm *p = (srpsrvparm *)arg; + if (p->login == NULL && p->user == NULL ) + { + p->login = SSL_get_srp_username(s); + BIO_printf(bio_err, "SRP username = \"%s\"\n", p->login); + return (-1) ; + } - user = SRP_VBASE_get_by_user(p->vb, p->login); - if (user == NULL) + if (p->user == NULL) { BIO_printf(bio_err, "User %s doesn't exist\n", p->login); return SSL3_AL_FATAL; } - if (SSL_set_srp_server_param(s, user->N, user->g, user->s, user->v, - user->info) < 0) + if (SSL_set_srp_server_param(s, p->user->N, p->user->g, p->user->s, p->user->v, + p->user->info) < 0) { *ad = SSL_AD_INTERNAL_ERROR; return SSL3_AL_FATAL; } + BIO_printf(bio_err, "SRP parameters set: username = \"%s\" info=\"%s\" \n", p->login,p->user->info); + /* need to check whether there are memory leaks */ + p->user = NULL; + p->login = NULL; return SSL_ERROR_NONE; } @@ -410,12 +437,13 @@ static int MS_CALLBACK ssl_srp_server_param_cb(SSL *s, int *ad, void *arg) static void s_server_init(void) { accept_socket=-1; - cipher=NULL; s_server_verify=SSL_VERIFY_NONE; s_dcert_file=NULL; s_dkey_file=NULL; + s_dchain_file=NULL; s_cert_file=TEST_CERT; s_key_file=NULL; + s_chain_file=NULL; #ifndef OPENSSL_NO_TLSEXT s_cert_file2=TEST_CERT2; s_key_file2=NULL; @@ -432,6 +460,7 @@ static void s_server_init(void) s_debug=0; s_msg=0; s_quiet=0; + s_brief=0; hack=0; #ifndef OPENSSL_NO_ENGINE engine_id=NULL; @@ -444,11 +473,21 @@ static void sv_usage(void) BIO_printf(bio_err,"usage: s_server [args ...]\n"); BIO_printf(bio_err,"\n"); BIO_printf(bio_err," -accept arg - port to accept on (default is %d)\n",PORT); + BIO_printf(bio_err," -verify_host host - check peer certificate matches \"host\"\n"); + BIO_printf(bio_err," -verify_email email - check peer certificate matches \"email\"\n"); + BIO_printf(bio_err," -verify_ip ipaddr - check peer certificate matches \"ipaddr\"\n"); 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," -verify_return_error - return verification errors\n"); BIO_printf(bio_err," -cert arg - certificate file to use\n"); BIO_printf(bio_err," (default is %s)\n",TEST_CERT); +#ifndef OPENSSL_NO_TLSEXT + BIO_printf(bio_err," -serverinfo arg - PEM serverinfo file for certificate\n"); + BIO_printf(bio_err," -auth - send and receive RFC 5878 TLS auth extensions and supplemental data\n"); + BIO_printf(bio_err," -auth_require_reneg - Do not send TLS auth extensions until renegotiation\n"); +#endif + BIO_printf(bio_err," -no_resumption_on_reneg - set SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION flag\n"); BIO_printf(bio_err," -crl_check - check the peer certificate has not been revoked by its CA.\n" \ " The CRL(s) are appended to the certificate file\n"); BIO_printf(bio_err," -crl_check_all - check the peer certificate has not been revoked by its CA\n" \ @@ -498,11 +537,14 @@ static void sv_usage(void) BIO_printf(bio_err," -srpuserseed string - A seed string for a default user salt.\n"); #endif BIO_printf(bio_err," -ssl2 - Just talk SSLv2\n"); +#ifndef OPENSSL_NO_SSL3_METHOD BIO_printf(bio_err," -ssl3 - Just talk SSLv3\n"); +#endif BIO_printf(bio_err," -tls1_2 - Just talk TLSv1.2\n"); BIO_printf(bio_err," -tls1_1 - Just talk TLSv1.1\n"); BIO_printf(bio_err," -tls1 - Just talk TLSv1\n"); BIO_printf(bio_err," -dtls1 - Just talk DTLSv1\n"); + BIO_printf(bio_err," -dtls1_2 - Just talk DTLSv1.2\n"); BIO_printf(bio_err," -timeout - Enable timeouts\n"); BIO_printf(bio_err," -mtu - Set link layer MTU\n"); BIO_printf(bio_err," -chain - Read a certificate chain\n"); @@ -518,6 +560,7 @@ static void sv_usage(void) BIO_printf(bio_err," -no_ecdhe - Disable ephemeral ECDH\n"); #endif BIO_printf(bio_err," -bugs - Turn on SSL bug compatibility\n"); + BIO_printf(bio_err," -hack - workaround for early Netscape code\n"); BIO_printf(bio_err," -www - Respond to a 'GET /' with a status page\n"); BIO_printf(bio_err," -WWW - Respond to a 'GET / HTTP/1.0' with file ./\n"); BIO_printf(bio_err," -HTTP - Respond to a 'GET / HTTP/1.0' with file ./\n"); @@ -537,7 +580,20 @@ static void sv_usage(void) BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions received\n"); BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n"); BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); -#endif +# ifndef OPENSSL_NO_NEXTPROTONEG + BIO_printf(bio_err," -nextprotoneg arg - set the advertised protocols for the NPN extension (comma-separated list)\n"); +# endif +# ifndef OPENSSL_NO_SRTP + BIO_printf(bio_err," -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); +# endif + BIO_printf(bio_err," -alpn arg - set the advertised protocols for the ALPN extension (comma-separated list)\n"); +#endif + BIO_printf(bio_err," -keymatexport label - Export keying material using label\n"); + BIO_printf(bio_err," -keymatexportlen len - Export len bytes of keying material (default 20)\n"); + BIO_printf(bio_err," -status - respond to certificate status requests\n"); + BIO_printf(bio_err," -status_verbose - enable status request verbose printout\n"); + BIO_printf(bio_err," -status_timeout n - status request responder timeout\n"); + BIO_printf(bio_err," -status_url URL - status request fallback URL\n"); } static int local_argc=0; @@ -715,7 +771,7 @@ static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg) if (servername) { - if (strcmp(servername,p->servername)) + if (strcasecmp(servername,p->servername)) return p->extension_error; if (ctx2) { @@ -871,12 +927,80 @@ BIO_printf(err, "cert_status: received %d ids\n", sk_OCSP_RESPID_num(ids)); ret = SSL_TLSEXT_ERR_ALERT_FATAL; goto done; } -#endif + +# ifndef OPENSSL_NO_NEXTPROTONEG +/* This is the context that we pass to next_proto_cb */ +typedef struct tlsextnextprotoctx_st { + unsigned char *data; + unsigned int len; +} tlsextnextprotoctx; + +static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len, void *arg) + { + tlsextnextprotoctx *next_proto = arg; + + *data = next_proto->data; + *len = next_proto->len; + + return SSL_TLSEXT_ERR_OK; + } +# endif /* ndef OPENSSL_NO_NEXTPROTONEG */ + +/* This the context that we pass to alpn_cb */ +typedef struct tlsextalpnctx_st { + unsigned char *data; + unsigned short len; +} tlsextalpnctx; + +static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) + { + tlsextalpnctx *alpn_ctx = arg; + + if (!s_quiet) + { + /* We can assume that |in| is syntactically valid. */ + unsigned i; + BIO_printf(bio_s_out, "ALPN protocols advertised by the client: "); + for (i = 0; i < inlen; ) + { + if (i) + BIO_write(bio_s_out, ", ", 2); + BIO_write(bio_s_out, &in[i + 1], in[i]); + i += in[i] + 1; + } + BIO_write(bio_s_out, "\n", 1); + } + + if (SSL_select_next_proto((unsigned char**) out, outlen, alpn_ctx->data, alpn_ctx->len, in, inlen) != + OPENSSL_NPN_NEGOTIATED) + { + return SSL_TLSEXT_ERR_NOACK; + } + + if (!s_quiet) + { + BIO_printf(bio_s_out, "ALPN protocols selected: "); + BIO_write(bio_s_out, *out, *outlen); + BIO_write(bio_s_out, "\n", 1); + } + + return SSL_TLSEXT_ERR_OK; + } +#endif /* ndef OPENSSL_NO_TLSEXT */ int MAIN(int, char **); #ifndef OPENSSL_NO_JPAKE static char *jpake_secret = NULL; +#define no_jpake !jpake_secret +#else +#define no_jpake 1 +#endif +#ifndef OPENSSL_NO_SRP + static srpsrvparm srp_callback_parm; +#endif +#ifndef OPENSSL_NO_SRTP +static char *srtp_profiles = NULL; #endif int MAIN(int argc, char *argv[]) @@ -885,14 +1009,13 @@ int MAIN(int argc, char *argv[]) int badarg = 0; short port=PORT; char *CApath=NULL,*CAfile=NULL; + char *chCApath=NULL,*chCAfile=NULL; + char *vfyCApath=NULL,*vfyCAfile=NULL; unsigned char *context = NULL; char *dhfile = NULL; -#ifndef OPENSSL_NO_ECDH - char *named_curve = NULL; -#endif - int badop=0,bugs=0; + int badop=0; int ret=1; - int off=0; + int build_chain = 0; int no_tmp_rsa=0,no_dhe=0,no_ecdhe=0,nocert=0; int state=0; const SSL_METHOD *meth=NULL; @@ -904,14 +1027,20 @@ int MAIN(int argc, char *argv[]) char *dpassarg = NULL, *dpass = NULL; int s_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM; X509 *s_cert = NULL, *s_dcert = NULL; + STACK_OF(X509) *s_chain = NULL, *s_dchain = NULL; EVP_PKEY *s_key = NULL, *s_dkey = NULL; - int no_cache = 0; + int no_cache = 0, ext_cache = 0; + int rev = 0, naccept = -1; #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}; +# ifndef OPENSSL_NO_NEXTPROTONEG + const char *next_proto_neg_in = NULL; + tlsextnextprotoctx next_proto = { NULL, 0}; +# endif + const char *alpn_in = NULL; + tlsextalpnctx alpn_ctx = { NULL, 0}; #endif #ifndef OPENSSL_NO_PSK /* by default do not send a PSK identity hint */ @@ -920,19 +1049,17 @@ int MAIN(int argc, char *argv[]) #ifndef OPENSSL_NO_SRP char *srpuserseed = NULL; char *srp_verifier_file = NULL; - srpsrvparm p; #endif -#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) + SSL_EXCERT *exc = NULL; + SSL_CONF_CTX *cctx = NULL; + STACK_OF(OPENSSL_STRING) *ssl_args = NULL; + + char *crl_file = NULL; + int crl_format = FORMAT_PEM; + int crl_download = 0; + STACK_OF(X509_CRL) *crls = NULL; + meth=SSLv23_server_method(); -#elif !defined(OPENSSL_NO_SSL3) - meth=SSLv3_server_method(); -#elif !defined(OPENSSL_NO_SSL2) - meth=SSLv2_server_method(); -#elif !defined(OPENSSL_NO_TLS1) - meth=TLSv1_server_method(); -#else - /* #error no SSL version enabled */ -#endif local_argc=argc; local_argv=argv; @@ -948,6 +1075,12 @@ int MAIN(int argc, char *argv[]) if (!load_config(bio_err, NULL)) goto end; + cctx = SSL_CONF_CTX_new(); + if (!cctx) + goto end; + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CMDLINE); + verify_depth=0; #ifdef FIONBIO s_nbio=0; @@ -966,12 +1099,24 @@ int MAIN(int argc, char *argv[]) if (!extract_port(*(++argv),&port)) goto bad; } + else if (strcmp(*argv,"-naccept") == 0) + { + if (--argc < 1) goto bad; + naccept = atol(*(++argv)); + if (naccept <= 0) + { + BIO_printf(bio_err, "bad accept value %s\n", + *argv); + goto bad; + } + } else if (strcmp(*argv,"-verify") == 0) { s_server_verify=SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE; if (--argc < 1) goto bad; verify_depth=atoi(*(++argv)); - BIO_printf(bio_err,"verify depth is %d\n",verify_depth); + if (!s_quiet) + BIO_printf(bio_err,"verify depth is %d\n",verify_depth); } else if (strcmp(*argv,"-Verify") == 0) { @@ -979,7 +1124,8 @@ int MAIN(int argc, char *argv[]) SSL_VERIFY_CLIENT_ONCE; if (--argc < 1) goto bad; verify_depth=atoi(*(++argv)); - BIO_printf(bio_err,"verify depth is %d, must return a certificate\n",verify_depth); + if (!s_quiet) + BIO_printf(bio_err,"verify depth is %d, must return a certificate\n",verify_depth); } else if (strcmp(*argv,"-context") == 0) { @@ -991,6 +1137,20 @@ int MAIN(int argc, char *argv[]) if (--argc < 1) goto bad; s_cert_file= *(++argv); } + else if (strcmp(*argv,"-CRL") == 0) + { + if (--argc < 1) goto bad; + crl_file= *(++argv); + } + else if (strcmp(*argv,"-crl_download") == 0) + crl_download = 1; +#ifndef OPENSSL_NO_TLSEXT + else if (strcmp(*argv,"-serverinfo") == 0) + { + if (--argc < 1) goto bad; + s_serverinfo_file = *(++argv); + } +#endif else if (strcmp(*argv,"-certform") == 0) { if (--argc < 1) goto bad; @@ -1011,18 +1171,16 @@ int MAIN(int argc, char *argv[]) if (--argc < 1) goto bad; passarg = *(++argv); } - else if (strcmp(*argv,"-dhparam") == 0) + else if (strcmp(*argv,"-cert_chain") == 0) { if (--argc < 1) goto bad; - dhfile = *(++argv); + s_chain_file= *(++argv); } -#ifndef OPENSSL_NO_ECDH - else if (strcmp(*argv,"-named_curve") == 0) + else if (strcmp(*argv,"-dhparam") == 0) { if (--argc < 1) goto bad; - named_curve = *(++argv); + dhfile = *(++argv); } -#endif else if (strcmp(*argv,"-dcertform") == 0) { if (--argc < 1) goto bad; @@ -1048,6 +1206,11 @@ int MAIN(int argc, char *argv[]) if (--argc < 1) goto bad; s_dkey_file= *(++argv); } + else if (strcmp(*argv,"-dcert_chain") == 0) + { + if (--argc < 1) goto bad; + s_dchain_file= *(++argv); + } else if (strcmp(*argv,"-nocert") == 0) { nocert=1; @@ -1057,29 +1220,63 @@ int MAIN(int argc, char *argv[]) if (--argc < 1) goto bad; CApath= *(++argv); } + else if (strcmp(*argv,"-chainCApath") == 0) + { + if (--argc < 1) goto bad; + chCApath= *(++argv); + } + else if (strcmp(*argv,"-verifyCApath") == 0) + { + if (--argc < 1) goto bad; + vfyCApath= *(++argv); + } else if (strcmp(*argv,"-no_cache") == 0) no_cache = 1; + else if (strcmp(*argv,"-ext_cache") == 0) + ext_cache = 1; + else if (strcmp(*argv,"-CRLform") == 0) + { + if (--argc < 1) goto bad; + crl_format = str2fmt(*(++argv)); + } else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) { if (badarg) goto bad; continue; } + else if (args_excert(&argv, &argc, &badarg, bio_err, &exc)) + { + if (badarg) + goto bad; + continue; + } + else if (args_ssl(&argv, &argc, cctx, &badarg, bio_err, &ssl_args)) + { + if (badarg) + goto bad; + continue; + } else if (strcmp(*argv,"-verify_return_error") == 0) verify_return_error = 1; - else if (strcmp(*argv,"-serverpref") == 0) - { off|=SSL_OP_CIPHER_SERVER_PREFERENCE; } - else if (strcmp(*argv,"-legacy_renegotiation") == 0) - off|=SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; - else if (strcmp(*argv,"-cipher") == 0) + else if (strcmp(*argv,"-verify_quiet") == 0) + verify_quiet = 1; + else if (strcmp(*argv,"-build_chain") == 0) + build_chain = 1; + else if (strcmp(*argv,"-CAfile") == 0) { if (--argc < 1) goto bad; - cipher= *(++argv); + CAfile= *(++argv); } - else if (strcmp(*argv,"-CAfile") == 0) + else if (strcmp(*argv,"-chainCAfile") == 0) { if (--argc < 1) goto bad; - CAfile= *(++argv); + chCAfile= *(++argv); + } + else if (strcmp(*argv,"-verifyCAfile") == 0) + { + if (--argc < 1) goto bad; + vfyCAfile= *(++argv); } #ifdef FIONBIO else if (strcmp(*argv,"-nbio") == 0) @@ -1092,6 +1289,10 @@ int MAIN(int argc, char *argv[]) #endif s_nbio_test=1; } + else if (strcmp(*argv,"-ign_eof") == 0) + s_ign_eof=1; + else if (strcmp(*argv,"-no_ign_eof") == 0) + s_ign_eof=0; else if (strcmp(*argv,"-debug") == 0) { s_debug=1; } #ifndef OPENSSL_NO_TLSEXT @@ -1127,6 +1328,15 @@ int MAIN(int argc, char *argv[]) #endif else if (strcmp(*argv,"-msg") == 0) { s_msg=1; } + else if (strcmp(*argv,"-msgfile") == 0) + { + if (--argc < 1) goto bad; + bio_s_msg = BIO_new_file(*(++argv), "w"); + } +#ifndef OPENSSL_NO_SSL_TRACE + else if (strcmp(*argv,"-trace") == 0) + { s_msg=2; } +#endif else if (strcmp(*argv,"-hack") == 0) { hack=1; } else if (strcmp(*argv,"-state") == 0) @@ -1135,14 +1345,20 @@ int MAIN(int argc, char *argv[]) { s_crlf=1; } else if (strcmp(*argv,"-quiet") == 0) { s_quiet=1; } - else if (strcmp(*argv,"-bugs") == 0) - { bugs=1; } + else if (strcmp(*argv,"-brief") == 0) + { + s_quiet=1; + s_brief=1; + verify_quiet=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,"-no_ecdhe") == 0) { no_ecdhe=1; } + else if (strcmp(*argv,"-no_resume_ephemeral") == 0) + { no_resume_ephemeral = 1; } #ifndef OPENSSL_NO_PSK else if (strcmp(*argv,"-psk_hint") == 0) { @@ -1157,7 +1373,7 @@ int MAIN(int argc, char *argv[]) psk_key=*(++argv); for (i=0; i 28) + if (socket_mtu) { + if(socket_mtu < DTLS_get_link_min_mtu(con)) + { + BIO_printf(bio_err,"MTU too small. Must be at least %ld\n", + DTLS_get_link_min_mtu(con)); + ret = -1; + BIO_free(sbio); + goto err; + } SSL_set_options(con, SSL_OP_NO_QUERY_MTU); - SSL_set_mtu(con, socket_mtu - 28); + if(!DTLS_set_link_mtu(con, socket_mtu)) + { + BIO_printf(bio_err, "Failed to set MTU\n"); + ret = -1; + BIO_free(sbio); + goto err; + } } else /* want to do MTU discovery */ @@ -1974,8 +2314,13 @@ static int sv_body(char *hostname, int s, unsigned char *context) } if (s_msg) { - SSL_set_msg_callback(con, msg_cb); - SSL_set_msg_callback_arg(con, bio_s_out); +#ifndef OPENSSL_NO_SSL_TRACE + if (s_msg == 2) + SSL_set_msg_callback(con, SSL_trace); + else +#endif + SSL_set_msg_callback(con, msg_cb); + SSL_set_msg_callback_arg(con, bio_s_msg ? bio_s_msg : bio_s_out); } #ifndef OPENSSL_NO_TLSEXT if (s_tlsextdebug) @@ -2077,7 +2422,7 @@ static int sv_body(char *hostname, int s, unsigned char *context) } else i=raw_read_stdin(buf,bufsize); - if (!s_quiet) + if (!s_quiet && !s_brief) { if ((i <= 0) || (buf[0] == 'Q')) { @@ -2097,6 +2442,16 @@ static int sv_body(char *hostname, int s, unsigned char *context) goto err; } +#ifndef OPENSSL_NO_HEARTBEATS + if ((buf[0] == 'B') && + ((buf[1] == '\n') || (buf[1] == '\r'))) + { + BIO_printf(bio_err,"HEARTBEATING\n"); + SSL_heartbeat(con); + i=0; + continue; + } +#endif if ((buf[0] == 'r') && ((buf[1] == '\n') || (buf[1] == '\r'))) { @@ -2140,6 +2495,18 @@ static int sv_body(char *hostname, int s, unsigned char *context) { static count=0; if (++count == 100) { count=0; SSL_renegotiate(con); } } #endif k=SSL_write(con,&(buf[l]),(unsigned int)i); +#ifndef OPENSSL_NO_SRP + while (SSL_get_error(con,k) == SSL_ERROR_WANT_X509_LOOKUP) + { + BIO_printf(bio_s_out,"LOOKUP renego during write\n"); + srp_callback_parm.user = SRP_VBASE_get_by_user(srp_callback_parm.vb, srp_callback_parm.login); + if (srp_callback_parm.user) + BIO_printf(bio_s_out,"LOOKUP done %s\n",srp_callback_parm.user->info); + else + BIO_printf(bio_s_out,"LOOKUP not successful\n"); + k=SSL_write(con,&(buf[l]),(unsigned int)i); + } +#endif switch (SSL_get_error(con,k)) { case SSL_ERROR_NONE: @@ -2187,6 +2554,18 @@ static int sv_body(char *hostname, int s, unsigned char *context) { again: i=SSL_read(con,(char *)buf,bufsize); +#ifndef OPENSSL_NO_SRP + while (SSL_get_error(con,i) == SSL_ERROR_WANT_X509_LOOKUP) + { + BIO_printf(bio_s_out,"LOOKUP renego during read\n"); + srp_callback_parm.user = SRP_VBASE_get_by_user(srp_callback_parm.vb, srp_callback_parm.login); + if (srp_callback_parm.user) + BIO_printf(bio_s_out,"LOOKUP done %s\n",srp_callback_parm.user->info); + else + BIO_printf(bio_s_out,"LOOKUP not successful\n"); + i=SSL_read(con,(char *)buf,bufsize); + } +#endif switch (SSL_get_error(con,i)) { case SSL_ERROR_NONE: @@ -2199,7 +2578,6 @@ again: break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_s_out,"Read BLOCK\n"); break; case SSL_ERROR_SYSCALL: @@ -2257,8 +2635,37 @@ static int init_ssl_connection(SSL *con) #ifndef OPENSSL_NO_KRB5 char *client_princ; #endif +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + const unsigned char *next_proto_neg; + unsigned next_proto_neg_len; +#endif + unsigned char *exportedkeymat; + + + i=SSL_accept(con); +#ifdef CERT_CB_TEST_RETRY + { + while (i <= 0 && SSL_get_error(con,i) == SSL_ERROR_WANT_X509_LOOKUP && SSL_state(con) == SSL3_ST_SR_CLNT_HELLO_C) + { + fprintf(stderr, "LOOKUP from certificate callback during accept\n"); + i=SSL_accept(con); + } + } +#endif +#ifndef OPENSSL_NO_SRP + while (i <= 0 && SSL_get_error(con,i) == SSL_ERROR_WANT_X509_LOOKUP) + { + BIO_printf(bio_s_out,"LOOKUP during accept %s\n",srp_callback_parm.login); + srp_callback_parm.user = SRP_VBASE_get_by_user(srp_callback_parm.vb, srp_callback_parm.login); + if (srp_callback_parm.user) + BIO_printf(bio_s_out,"LOOKUP done %s\n",srp_callback_parm.user->info); + else + BIO_printf(bio_s_out,"LOOKUP not successful\n"); + i=SSL_accept(con); + } +#endif - if ((i=SSL_accept(con)) <= 0) + if (i <= 0) { if (BIO_sock_should_retry(i)) { @@ -2273,11 +2680,14 @@ static int init_ssl_connection(SSL *con) BIO_printf(bio_err,"verify error:%s\n", X509_verify_cert_error_string(verify_error)); } - else - ERR_print_errors(bio_err); + /* Always print any error messages */ + ERR_print_errors(bio_err); return(0); } + if (s_brief) + print_ssl_summary(bio_err, con); + PEM_write_bio_SSL_SESSION(bio_s_out,SSL_get_session(con)); peer=SSL_get_peer_certificate(con); @@ -2295,11 +2705,37 @@ static int init_ssl_connection(SSL *con) if (SSL_get_shared_ciphers(con,buf,sizeof buf) != NULL) BIO_printf(bio_s_out,"Shared ciphers:%s\n",buf); str=SSL_CIPHER_get_name(SSL_get_current_cipher(con)); + ssl_print_sigalgs(bio_s_out, con); +#ifndef OPENSSL_NO_EC + ssl_print_point_formats(bio_s_out, con); + ssl_print_curves(bio_s_out, con, 0); +#endif BIO_printf(bio_s_out,"CIPHER is %s\n",(str != NULL)?str:"(NONE)"); + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + SSL_get0_next_proto_negotiated(con, &next_proto_neg, &next_proto_neg_len); + if (next_proto_neg) + { + BIO_printf(bio_s_out,"NEXTPROTO is "); + BIO_write(bio_s_out, next_proto_neg, next_proto_neg_len); + BIO_printf(bio_s_out, "\n"); + } +#endif +#ifndef OPENSSL_NO_SRTP + { + SRTP_PROTECTION_PROFILE *srtp_profile + = SSL_get_selected_srtp_profile(con); + + if(srtp_profile) + BIO_printf(bio_s_out,"SRTP Extension negotiated, profile=%s\n", + srtp_profile->name); + } +#endif if (SSL_cache_hit(con)) BIO_printf(bio_s_out,"Reused session-id\n"); if (SSL_ctrl(con,SSL_CTRL_GET_FLAGS,0,NULL) & TLS1_FLAGS_TLS_PADDING_BUG) - BIO_printf(bio_s_out,"Peer has incorrect TLSv1 block padding\n"); + BIO_printf(bio_s_out, + "Peer has incorrect TLSv1 block padding\n"); #ifndef OPENSSL_NO_KRB5 client_princ = kssl_ctx_get0_client_princ(SSL_get0_kssl_ctx(con)); if (client_princ != NULL) @@ -2310,6 +2746,35 @@ static int init_ssl_connection(SSL *con) #endif /* OPENSSL_NO_KRB5 */ BIO_printf(bio_s_out, "Secure Renegotiation IS%s supported\n", SSL_get_secure_renegotiation_support(con) ? "" : " NOT"); + if (keymatexportlabel != NULL) + { + BIO_printf(bio_s_out, "Keying material exporter:\n"); + BIO_printf(bio_s_out, " Label: '%s'\n", keymatexportlabel); + BIO_printf(bio_s_out, " Length: %i bytes\n", + keymatexportlen); + exportedkeymat = OPENSSL_malloc(keymatexportlen); + if (exportedkeymat != NULL) + { + if (!SSL_export_keying_material(con, exportedkeymat, + keymatexportlen, + keymatexportlabel, + strlen(keymatexportlabel), + NULL, 0, 0)) + { + BIO_printf(bio_s_out, " Error\n"); + } + else + { + BIO_printf(bio_s_out, " Keying material: "); + for (i=0; iinfo); + else + BIO_printf(bio_s_out,"LOOKUP not successful\n"); + i=SSL_accept(con); + } +#endif switch (SSL_get_error(con,i)) { case SSL_ERROR_NONE: @@ -2506,6 +2987,11 @@ static int www_body(char *hostname, int s, unsigned char *context) } BIO_puts(io,"\n"); + BIO_printf(io, + "Secure Renegotiation IS%s supported\n", + SSL_get_secure_renegotiation_support(con) ? + "" : " NOT"); + /* The following is evil and should not really * be done */ BIO_printf(io,"Ciphers supported in s_server binary\n"); @@ -2544,6 +3030,10 @@ static int www_body(char *hostname, int s, unsigned char *context) } BIO_puts(io,"\n"); } + ssl_print_sigalgs(io, con); +#ifndef OPENSSL_NO_EC + ssl_print_curves(io, con, 0); +#endif BIO_printf(io,(SSL_cache_hit(con) ?"---\nReused, " :"---\nNew, ")); @@ -2737,6 +3227,152 @@ err: return(ret); } +static int rev_body(char *hostname, int s, int stype, unsigned char *context) + { + char *buf=NULL; + int i; + int ret=1; + SSL *con; + BIO *io,*ssl_bio,*sbio; +#ifndef OPENSSL_NO_KRB5 + KSSL_CTX *kctx; +#endif + + buf=OPENSSL_malloc(bufsize); + if (buf == NULL) return(0); + io=BIO_new(BIO_f_buffer()); + ssl_bio=BIO_new(BIO_f_ssl()); + if ((io == NULL) || (ssl_bio == NULL)) goto err; + + /* lets make the output buffer a reasonable size */ + if (!BIO_set_write_buffer_size(io,bufsize)) goto err; + + if ((con=SSL_new(ctx)) == NULL) goto err; +#ifndef OPENSSL_NO_TLSEXT + if (s_tlsextdebug) + { + SSL_set_tlsext_debug_callback(con, tlsext_cb); + SSL_set_tlsext_debug_arg(con, bio_s_out); + } +#endif +#ifndef OPENSSL_NO_KRB5 + if ((kctx = kssl_ctx_new()) != NULL) + { + kssl_ctx_setstring(kctx, KSSL_SERVICE, KRB5SVC); + kssl_ctx_setstring(kctx, KSSL_KEYTAB, KRB5KEYTAB); + } +#endif /* OPENSSL_NO_KRB5 */ + if(context) SSL_set_session_id_context(con, context, + strlen((char *)context)); + + sbio=BIO_new_socket(s,BIO_NOCLOSE); + SSL_set_bio(con,sbio,sbio); + SSL_set_accept_state(con); + + 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) + { + SSL_set_debug(con, 1); + BIO_set_callback(SSL_get_rbio(con),bio_dump_callback); + BIO_set_callback_arg(SSL_get_rbio(con),(char *)bio_s_out); + } + if (s_msg) + { +#ifndef OPENSSL_NO_SSL_TRACE + if (s_msg == 2) + SSL_set_msg_callback(con, SSL_trace); + else +#endif + SSL_set_msg_callback(con, msg_cb); + SSL_set_msg_callback_arg(con, bio_s_msg ? bio_s_msg : bio_s_out); + } + + for (;;) + { + i = BIO_do_handshake(io); + if (i > 0) + break; + if (!BIO_should_retry(io)) + { + BIO_puts(bio_err, "CONNECTION FAILURE\n"); + ERR_print_errors(bio_err); + goto end; + } + } + BIO_printf(bio_err, "CONNECTION ESTABLISHED\n"); + print_ssl_summary(bio_err, con); + + for (;;) + { + i=BIO_gets(io,buf,bufsize-1); + if (i < 0) /* error */ + { + if (!BIO_should_retry(io)) + { + if (!s_quiet) + ERR_print_errors(bio_err); + goto err; + } + else + { + BIO_printf(bio_s_out,"read R BLOCK\n"); +#if defined(OPENSSL_SYS_NETWARE) + delay(1000); +#elif !defined(OPENSSL_SYS_MSDOS) && !defined(__DJGPP__) + sleep(1); +#endif + continue; + } + } + else if (i == 0) /* end of input */ + { + ret=1; + BIO_printf(bio_err, "CONNECTION CLOSED\n"); + goto end; + } + else + { + char *p = buf + i - 1; + while(i && (*p == '\n' || *p == '\r')) + { + p--; + i--; + } + if (!s_ign_eof && i == 5 && !strncmp(buf, "CLOSE", 5)) + { + ret = 1; + BIO_printf(bio_err, "CONNECTION CLOSED\n"); + goto end; + } + BUF_reverse((unsigned char *)buf, NULL, i); + buf[i] = '\n'; + BIO_write(io, buf, i + 1); + for (;;) + { + i = BIO_flush(io); + if (i > 0) + break; + if (!BIO_should_retry(io)) + goto end; + } + } + } +end: + /* make sure we re-use sessions */ + SSL_set_shutdown(con,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); + +err: + + if (buf != NULL) OPENSSL_free(buf); + if (io != NULL) BIO_free_all(io); + return(ret); + } + #ifndef OPENSSL_NO_RSA static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export, int keylength) { @@ -2791,3 +3427,107 @@ static int generate_session_id(const SSL *ssl, unsigned char *id, return 0; return 1; } + +/* By default s_server uses an in-memory cache which caches SSL_SESSION + * structures without any serialisation. This hides some bugs which only + * become apparent in deployed servers. By implementing a basic external + * session cache some issues can be debugged using s_server. + */ + +typedef struct simple_ssl_session_st + { + unsigned char *id; + unsigned int idlen; + unsigned char *der; + int derlen; + struct simple_ssl_session_st *next; + } simple_ssl_session; + +static simple_ssl_session *first = NULL; + +static int add_session(SSL *ssl, SSL_SESSION *session) + { + simple_ssl_session *sess; + unsigned char *p; + + sess = OPENSSL_malloc(sizeof(simple_ssl_session)); + + SSL_SESSION_get_id(session, &sess->idlen); + sess->derlen = i2d_SSL_SESSION(session, NULL); + + sess->id = BUF_memdup(SSL_SESSION_get_id(session, NULL), sess->idlen); + + sess->der = OPENSSL_malloc(sess->derlen); + p = sess->der; + i2d_SSL_SESSION(session, &p); + + sess->next = first; + first = sess; + BIO_printf(bio_err, "New session added to external cache\n"); + return 0; + } + +static SSL_SESSION *get_session(SSL *ssl, unsigned char *id, int idlen, + int *do_copy) + { + simple_ssl_session *sess; + *do_copy = 0; + for (sess = first; sess; sess = sess->next) + { + if (idlen == (int)sess->idlen && !memcmp(sess->id, id, idlen)) + { + const unsigned char *p = sess->der; + BIO_printf(bio_err, "Lookup session: cache hit\n"); + return d2i_SSL_SESSION(NULL, &p, sess->derlen); + } + } + BIO_printf(bio_err, "Lookup session: cache miss\n"); + return NULL; + } + +static void del_session(SSL_CTX *sctx, SSL_SESSION *session) + { + simple_ssl_session *sess, *prev = NULL; + const unsigned char *id; + unsigned int idlen; + id = SSL_SESSION_get_id(session, &idlen); + for (sess = first; sess; sess = sess->next) + { + if (idlen == sess->idlen && !memcmp(sess->id, id, idlen)) + { + if(prev) + prev->next = sess->next; + else + first = sess->next; + OPENSSL_free(sess->id); + OPENSSL_free(sess->der); + OPENSSL_free(sess); + return; + } + prev = sess; + } + } + +static void init_session_cache_ctx(SSL_CTX *sctx) + { + SSL_CTX_set_session_cache_mode(sctx, + SSL_SESS_CACHE_NO_INTERNAL|SSL_SESS_CACHE_SERVER); + SSL_CTX_sess_set_new_cb(sctx, add_session); + SSL_CTX_sess_set_get_cb(sctx, get_session); + SSL_CTX_sess_set_remove_cb(sctx, del_session); + } + +static void free_sessions(void) + { + simple_ssl_session *sess, *tsess; + for (sess = first; sess;) + { + OPENSSL_free(sess->id); + OPENSSL_free(sess->der); + tsess = sess; + sess = sess->next; + OPENSSL_free(tsess); + } + first = NULL; + } +