aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssl/apps/s_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssl/apps/s_server.c')
-rw-r--r--crypto/openssl/apps/s_server.c833
1 files changed, 681 insertions, 152 deletions
diff --git a/crypto/openssl/apps/s_server.c b/crypto/openssl/apps/s_server.c
index b58e5e07c41c..f19532b75fab 100644
--- a/crypto/openssl/apps/s_server.c
+++ b/crypto/openssl/apps/s_server.c
@@ -209,14 +209,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_dh2048(void);
@@ -286,16 +289,16 @@ 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
@@ -308,14 +311,18 @@ 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;
@@ -332,6 +339,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 */
@@ -447,12 +460,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;
@@ -469,6 +483,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;
@@ -482,6 +497,12 @@ static void sv_usage(void)
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");
@@ -491,6 +512,16 @@ static void sv_usage(void)
" -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");
@@ -569,6 +600,7 @@ static void sv_usage(void)
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");
@@ -620,6 +652,12 @@ static void sv_usage(void)
" -no_ticket - disable use of RFC4507bis session tickets\n");
BIO_printf(bio_err,
" -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n");
+ BIO_printf(bio_err,
+ " -sigalgs arg - Signature algorithms to support (colon-separated list)\n");
+ BIO_printf(bio_err,
+ " -client_sigalgs arg - Signature algorithms to support for client \n");
+ BIO_printf(bio_err,
+ " certificate authentication (colon-separated list)\n");
# ifndef OPENSSL_NO_NEXTPROTONEG
BIO_printf(bio_err,
" -nextprotoneg arg - set the advertised protocols for the NPN extension (comma-separated list)\n");
@@ -628,6 +666,8 @@ static void sv_usage(void)
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");
@@ -988,12 +1028,53 @@ static int next_proto_cb(SSL *s, const unsigned char **data,
}
# endif /* ndef OPENSSL_NO_NEXTPROTONEG */
-#endif
+/* 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;
@@ -1008,18 +1089,14 @@ 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 no_tmp_rsa = 0, no_dhe = 0, nocert = 0;
-#ifndef OPENSSL_NO_ECDH
- int no_ecdhe = 0;
-#endif
+ 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;
int socket_type = SOCK_STREAM;
@@ -1030,16 +1107,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;
tlsextctx tlsextcbp = { NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING };
# ifndef OPENSSL_NO_NEXTPROTONEG
const char *next_proto_neg_in = NULL;
- tlsextnextprotoctx next_proto;
+ 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 */
@@ -1049,6 +1130,15 @@ int MAIN(int argc, char *argv[])
char *srpuserseed = NULL;
char *srp_verifier_file = NULL;
#endif
+ 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();
local_argc = argc;
@@ -1065,6 +1155,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;
@@ -1080,12 +1176,21 @@ int MAIN(int argc, char *argv[])
goto bad;
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) {
s_server_verify =
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
@@ -1093,9 +1198,10 @@ int MAIN(int argc, char *argv[])
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) {
if (--argc < 1)
goto bad;
@@ -1104,7 +1210,20 @@ int MAIN(int argc, char *argv[])
if (--argc < 1)
goto bad;
s_cert_file = *(++argv);
- } else if (strcmp(*argv, "-certform") == 0) {
+ } 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;
s_cert_format = str2fmt(*(++argv));
@@ -1120,19 +1239,15 @@ 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);
- }
-#ifndef OPENSSL_NO_ECDH
- else if (strcmp(*argv, "-named_curve") == 0) {
+ s_chain_file = *(++argv);
+ } else if (strcmp(*argv, "-dhparam") == 0) {
if (--argc < 1)
goto bad;
- named_curve = *(++argv);
- }
-#endif
- else if (strcmp(*argv, "-dcertform") == 0) {
+ dhfile = *(++argv);
+ } else if (strcmp(*argv, "-dcertform") == 0) {
if (--argc < 1)
goto bad;
s_dcert_format = str2fmt(*(++argv));
@@ -1152,32 +1267,62 @@ 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;
} else if (strcmp(*argv, "-CApath") == 0) {
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 (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) {
+ 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);
- } else if (strcmp(*argv, "-CAfile") == 0) {
+ CAfile = *(++argv);
+ } 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) {
@@ -1189,7 +1334,11 @@ int MAIN(int argc, char *argv[])
s_nbio = 1;
#endif
s_nbio_test = 1;
- } else if (strcmp(*argv, "-debug") == 0) {
+ } 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
@@ -1220,7 +1369,17 @@ int MAIN(int argc, char *argv[])
#endif
else if (strcmp(*argv, "-msg") == 0) {
s_msg = 1;
- } else if (strcmp(*argv, "-hack") == 0) {
+ } 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) {
state = 1;
@@ -1228,18 +1387,19 @@ 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;
- }
-#ifndef OPENSSL_NO_ECDH
- else if (strcmp(*argv, "-no_ecdhe") == 0) {
+ } else if (strcmp(*argv, "-no_ecdhe") == 0) {
no_ecdhe = 1;
+ } else if (strcmp(*argv, "-no_resume_ephemeral") == 0) {
+ no_resume_ephemeral = 1;
}
-#endif
#ifndef OPENSSL_NO_PSK
else if (strcmp(*argv, "-psk_hint") == 0) {
if (--argc < 1)
@@ -1272,32 +1432,18 @@ int MAIN(int argc, char *argv[])
meth = TLSv1_server_method();
}
#endif
- else if (strcmp(*argv, "-www") == 0) {
+ else if (strcmp(*argv, "-rev") == 0) {
+ rev = 1;
+ } else if (strcmp(*argv, "-www") == 0) {
www = 1;
} else if (strcmp(*argv, "-WWW") == 0) {
www = 2;
} else if (strcmp(*argv, "-HTTP") == 0) {
www = 3;
- } else if (strcmp(*argv, "-no_ssl2") == 0) {
- off |= SSL_OP_NO_SSLv2;
- } else if (strcmp(*argv, "-no_ssl3") == 0) {
- off |= SSL_OP_NO_SSLv3;
- } else if (strcmp(*argv, "-no_tls1") == 0) {
- off |= SSL_OP_NO_TLSv1;
- } else if (strcmp(*argv, "-no_tls1_1") == 0) {
- off |= SSL_OP_NO_TLSv1_1;
- } else if (strcmp(*argv, "-no_tls1_2") == 0) {
- off |= SSL_OP_NO_TLSv1_2;
- } else if (strcmp(*argv, "-no_comp") == 0) {
- off |= SSL_OP_NO_COMPRESSION;
}
-#ifndef OPENSSL_NO_TLSEXT
- else if (strcmp(*argv, "-no_ticket") == 0) {
- off |= SSL_OP_NO_TICKET;
- }
-#endif
#ifndef OPENSSL_NO_SSL2
else if (strcmp(*argv, "-ssl2") == 0) {
+ no_ecdhe = 1;
meth = SSLv2_server_method();
}
#endif
@@ -1316,9 +1462,15 @@ int MAIN(int argc, char *argv[])
}
#endif
#ifndef OPENSSL_NO_DTLS1
- else if (strcmp(*argv, "-dtls1") == 0) {
+ else if (strcmp(*argv, "-dtls") == 0) {
+ meth = DTLS_server_method();
+ socket_type = SOCK_DGRAM;
+ } else if (strcmp(*argv, "-dtls1") == 0) {
meth = DTLSv1_server_method();
socket_type = SOCK_DGRAM;
+ } else if (strcmp(*argv, "-dtls1_2") == 0) {
+ meth = DTLSv1_2_server_method();
+ socket_type = SOCK_DGRAM;
} else if (strcmp(*argv, "-timeout") == 0)
enable_timeouts = 1;
else if (strcmp(*argv, "-mtu") == 0) {
@@ -1368,6 +1520,11 @@ int MAIN(int argc, char *argv[])
next_proto_neg_in = *(++argv);
}
# endif
+ else if (strcmp(*argv, "-alpn") == 0) {
+ if (--argc < 1)
+ goto bad;
+ alpn_in = *(++argv);
+ }
#endif
#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK)
else if (strcmp(*argv, "-jpake") == 0) {
@@ -1420,11 +1577,6 @@ int MAIN(int argc, char *argv[])
goto end;
}
psk_identity = "JPAKE";
- if (cipher) {
- BIO_printf(bio_err, "JPAKE sets cipher to PSK\n");
- goto end;
- }
- cipher = "PSK";
}
#endif
@@ -1447,6 +1599,9 @@ int MAIN(int argc, char *argv[])
s_key_file2 = s_cert_file2;
#endif
+ if (!load_excert(&exc, bio_err))
+ goto end;
+
if (nocert == 0) {
s_key = load_key(bio_err, s_key_file, s_key_format, 0, pass, e,
"server certificate private key file");
@@ -1462,6 +1617,12 @@ int MAIN(int argc, char *argv[])
ERR_print_errors(bio_err);
goto end;
}
+ if (s_chain_file) {
+ s_chain = load_certs(bio_err, s_chain_file, FORMAT_PEM,
+ NULL, e, "server certificate chain");
+ if (!s_chain)
+ goto end;
+ }
#ifndef OPENSSL_NO_TLSEXT
if (tlsextcbp.servername) {
s_key2 = load_key(bio_err, s_key_file2, s_key_format, 0, pass, e,
@@ -1479,9 +1640,10 @@ int MAIN(int argc, char *argv[])
goto end;
}
}
-#endif
+#endif /* OPENSSL_NO_TLSEXT */
}
-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+#if !defined(OPENSSL_NO_TLSEXT)
+# if !defined(OPENSSL_NO_NEXTPROTONEG)
if (next_proto_neg_in) {
unsigned short len;
next_proto.data = next_protos_parse(&len, next_proto_neg_in);
@@ -1491,8 +1653,34 @@ int MAIN(int argc, char *argv[])
} else {
next_proto.data = NULL;
}
+# endif
+ alpn_ctx.data = NULL;
+ if (alpn_in) {
+ unsigned short len;
+ alpn_ctx.data = next_protos_parse(&len, alpn_in);
+ if (alpn_ctx.data == NULL)
+ goto end;
+ alpn_ctx.len = len;
+ }
#endif
+ if (crl_file) {
+ X509_CRL *crl;
+ crl = load_crl(crl_file, crl_format);
+ if (!crl) {
+ BIO_puts(bio_err, "Error loading CRL\n");
+ ERR_print_errors(bio_err);
+ goto end;
+ }
+ crls = sk_X509_CRL_new_null();
+ if (!crls || !sk_X509_CRL_push(crls, crl)) {
+ BIO_puts(bio_err, "Error adding CRL\n");
+ ERR_print_errors(bio_err);
+ X509_CRL_free(crl);
+ goto end;
+ }
+ }
+
if (s_dcert_file) {
if (s_dkey_file == NULL)
@@ -1512,6 +1700,12 @@ int MAIN(int argc, char *argv[])
ERR_print_errors(bio_err);
goto end;
}
+ if (s_dchain_file) {
+ s_dchain = load_certs(bio_err, s_dchain_file, FORMAT_PEM,
+ NULL, e, "second server certificate chain");
+ if (!s_dchain)
+ goto end;
+ }
}
@@ -1525,8 +1719,10 @@ int MAIN(int argc, char *argv[])
app_RAND_load_files(inrand));
if (bio_s_out == NULL) {
- if (s_quiet && !s_debug && !s_msg) {
+ if (s_quiet && !s_debug) {
bio_s_out = BIO_new(BIO_s_null());
+ if (s_msg && !bio_s_msg)
+ bio_s_msg = BIO_new_fp(stdout, BIO_NOCLOSE);
} else {
if (bio_s_out == NULL)
bio_s_out = BIO_new_fp(stdout, BIO_NOCLOSE);
@@ -1566,16 +1762,17 @@ int MAIN(int argc, char *argv[])
BIO_printf(bio_err, "id_prefix '%s' set.\n", session_id_prefix);
}
SSL_CTX_set_quiet_shutdown(ctx, 1);
- if (bugs)
- SSL_CTX_set_options(ctx, SSL_OP_ALL);
if (hack)
SSL_CTX_set_options(ctx, SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
- SSL_CTX_set_options(ctx, off);
+ if (exc)
+ ssl_ctx_set_excert(ctx, exc);
if (state)
SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback);
if (no_cache)
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+ else if (ext_cache)
+ init_session_cache_ctx(ctx);
else
SSL_CTX_sess_set_cache_size(ctx, 128);
@@ -1606,6 +1803,17 @@ int MAIN(int argc, char *argv[])
if (vpm)
SSL_CTX_set1_param(ctx, vpm);
+ ssl_ctx_add_crls(ctx, crls, 0);
+
+ if (!args_ssl_call(ctx, bio_err, cctx, ssl_args, no_ecdhe, no_jpake))
+ goto end;
+
+ if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile,
+ crls, crl_download)) {
+ BIO_printf(bio_err, "Error loading store locations\n");
+ ERR_print_errors(bio_err);
+ goto end;
+ }
#ifndef OPENSSL_NO_TLSEXT
if (s_cert2) {
ctx2 = SSL_CTX_new(meth);
@@ -1633,17 +1841,18 @@ int MAIN(int argc, char *argv[])
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);
+ if (exc)
+ ssl_ctx_set_excert(ctx2, exc);
if (state)
SSL_CTX_set_info_callback(ctx2, apps_ssl_info_callback);
if (no_cache)
SSL_CTX_set_session_cache_mode(ctx2, SSL_SESS_CACHE_OFF);
+ else if (ext_cache)
+ init_session_cache_ctx(ctx2);
else
SSL_CTX_sess_set_cache_size(ctx2, 128);
@@ -1653,12 +1862,20 @@ int MAIN(int argc, char *argv[])
}
if (vpm)
SSL_CTX_set1_param(ctx2, vpm);
+
+ ssl_ctx_add_crls(ctx2, crls, 0);
+
+ if (!args_ssl_call(ctx2, bio_err, cctx, ssl_args, no_ecdhe, no_jpake))
+ goto end;
+
}
# ifndef OPENSSL_NO_NEXTPROTONEG
if (next_proto.data)
SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb,
&next_proto);
# endif
+ if (alpn_ctx.data)
+ SSL_CTX_set_alpn_select_cb(ctx, alpn_cb, &alpn_ctx);
#endif
#ifndef OPENSSL_NO_DH
@@ -1702,54 +1919,21 @@ int MAIN(int argc, char *argv[])
}
#endif
-#ifndef OPENSSL_NO_ECDH
- if (!no_ecdhe) {
- EC_KEY *ecdh = NULL;
-
- if (named_curve) {
- int nid = OBJ_sn2nid(named_curve);
-
- if (nid == 0) {
- BIO_printf(bio_err, "unknown curve name (%s)\n", named_curve);
- goto end;
- }
- ecdh = EC_KEY_new_by_curve_name(nid);
- if (ecdh == NULL) {
- BIO_printf(bio_err, "unable to create curve (%s)\n",
- named_curve);
- goto end;
- }
- }
-
- 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 = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
- if (ecdh == NULL) {
- 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);
+ if (!set_cert_key_stuff(ctx, s_cert, s_key, s_chain, build_chain))
+ goto end;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s_serverinfo_file != NULL
+ && !SSL_CTX_use_serverinfo_file(ctx, s_serverinfo_file)) {
+ ERR_print_errors(bio_err);
+ goto end;
}
#endif
-
- if (!set_cert_key_stuff(ctx, s_cert, s_key))
- goto end;
#ifndef OPENSSL_NO_TLSEXT
- if (ctx2 && !set_cert_key_stuff(ctx2, s_cert2, s_key2))
+ if (ctx2 && !set_cert_key_stuff(ctx2, s_cert2, s_key2, NULL, build_chain))
goto end;
#endif
if (s_dcert != NULL) {
- if (!set_cert_key_stuff(ctx, s_dcert, s_dkey))
+ if (!set_cert_key_stuff(ctx, s_dcert, s_dkey, s_dchain, build_chain))
goto end;
}
#ifndef OPENSSL_NO_RSA
@@ -1808,20 +1992,6 @@ int MAIN(int argc, char *argv[])
}
#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);
@@ -1873,10 +2043,15 @@ int MAIN(int argc, char *argv[])
BIO_printf(bio_s_out, "ACCEPT\n");
(void)BIO_flush(bio_s_out);
- if (www)
- do_server(port, socket_type, &accept_socket, www_body, context);
+ if (rev)
+ do_server(port, socket_type, &accept_socket, rev_body, context,
+ naccept);
+ else if (www)
+ do_server(port, socket_type, &accept_socket, www_body, context,
+ naccept);
else
- do_server(port, socket_type, &accept_socket, sv_body, context);
+ do_server(port, socket_type, &accept_socket, sv_body, context,
+ naccept);
print_stats(bio_s_out, ctx);
ret = 0;
end:
@@ -1884,18 +2059,25 @@ int MAIN(int argc, char *argv[])
SSL_CTX_free(ctx);
if (s_cert)
X509_free(s_cert);
+ if (crls)
+ sk_X509_CRL_pop_free(crls, X509_CRL_free);
if (s_dcert)
X509_free(s_dcert);
if (s_key)
EVP_PKEY_free(s_key);
if (s_dkey)
EVP_PKEY_free(s_dkey);
+ if (s_chain)
+ sk_X509_pop_free(s_chain, X509_free);
+ if (s_dchain)
+ sk_X509_pop_free(s_dchain, X509_free);
if (pass)
OPENSSL_free(pass);
if (dpass)
OPENSSL_free(dpass);
if (vpm)
X509_VERIFY_PARAM_free(vpm);
+ free_sessions();
#ifndef OPENSSL_NO_TLSEXT
if (tlscstatp.host)
OPENSSL_free(tlscstatp.host);
@@ -1909,11 +2091,32 @@ int MAIN(int argc, char *argv[])
X509_free(s_cert2);
if (s_key2)
EVP_PKEY_free(s_key2);
+ if (serverinfo_in != NULL)
+ BIO_free(serverinfo_in);
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ if (next_proto.data)
+ OPENSSL_free(next_proto.data);
+# endif
+ if (alpn_ctx.data)
+ OPENSSL_free(alpn_ctx.data);
+#endif
+ ssl_excert_free(exc);
+ if (ssl_args)
+ sk_OPENSSL_STRING_free(ssl_args);
+ if (cctx)
+ SSL_CONF_CTX_free(cctx);
+#ifndef OPENSSL_NO_JPAKE
+ if (jpake_secret && psk_key)
+ OPENSSL_free(psk_key);
#endif
if (bio_s_out != NULL) {
BIO_free(bio_s_out);
bio_s_out = NULL;
}
+ if (bio_s_msg != NULL) {
+ BIO_free(bio_s_msg);
+ bio_s_msg = NULL;
+ }
apps_shutdown();
OPENSSL_EXIT(ret);
}
@@ -1946,7 +2149,7 @@ static void print_stats(BIO *bio, SSL_CTX *ssl_ctx)
SSL_CTX_sess_get_cache_size(ssl_ctx));
}
-static int sv_body(char *hostname, int s, unsigned char *context)
+static int sv_body(char *hostname, int s, int stype, unsigned char *context)
{
char *buf = NULL;
fd_set readfds;
@@ -2010,7 +2213,7 @@ static int sv_body(char *hostname, int s, unsigned char *context)
# endif
#endif
- if (SSL_version(con) == DTLS1_VERSION) {
+ if (stype == SOCK_DGRAM) {
sbio = BIO_new_dgram(s, BIO_NOCLOSE);
@@ -2069,8 +2272,13 @@ static int sv_body(char *hostname, int s, unsigned char *context)
BIO_set_callback_arg(SSL_get_rbio(con), (char *)bio_s_out);
}
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) {
@@ -2168,7 +2376,7 @@ static int sv_body(char *hostname, int s, unsigned char *context)
assert(lf_num == 0);
} else
i = raw_read_stdin(buf, bufsize);
- if (!s_quiet) {
+ if (!s_quiet && !s_brief) {
if ((i <= 0) || (buf[0] == 'Q')) {
BIO_printf(bio_s_out, "DONE\n");
SHUTDOWN(s);
@@ -2383,6 +2591,16 @@ static int init_ssl_connection(SSL *con)
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",
@@ -2398,6 +2616,7 @@ static int init_ssl_connection(SSL *con)
i = SSL_accept(con);
}
#endif
+
if (i <= 0) {
if (BIO_sock_should_retry(i)) {
BIO_printf(bio_s_out, "DELAY\n");
@@ -2409,11 +2628,15 @@ static int init_ssl_connection(SSL *con)
if (verify_error != X509_V_OK) {
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);
@@ -2430,6 +2653,11 @@ 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)
@@ -2529,7 +2757,7 @@ static int load_CA(SSL_CTX *ctx, char *file)
}
#endif
-static int www_body(char *hostname, int s, unsigned char *context)
+static int www_body(char *hostname, int s, int stype, unsigned char *context)
{
char *buf = NULL;
int ret = 1;
@@ -2604,8 +2832,13 @@ static int www_body(char *hostname, int s, unsigned char *context)
BIO_set_callback_arg(SSL_get_rbio(con), (char *)bio_s_out);
}
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);
}
for (;;) {
@@ -2654,6 +2887,21 @@ static int www_body(char *hostname, int s, unsigned char *context)
goto err;
} else {
BIO_printf(bio_s_out, "read R BLOCK\n");
+#ifndef OPENSSL_NO_SRP
+ if (BIO_should_io_special(io)
+ && BIO_get_retry_reason(io) == BIO_RR_SSL_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");
+ continue;
+ }
+#endif
#if defined(OPENSSL_SYS_NETWARE)
delay(1000);
#elif !defined(OPENSSL_SYS_MSDOS) && !defined(__DJGPP__)
@@ -2724,6 +2972,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, "));
c = SSL_get_current_cipher(con);
@@ -2906,6 +3158,170 @@ static int www_body(char *hostname, int s, unsigned char *context)
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;
+ }
+#ifndef OPENSSL_NO_SRP
+ if (BIO_should_io_special(io)
+ && BIO_get_retry_reason(io) == BIO_RR_SSL_X509_LOOKUP) {
+ BIO_printf(bio_s_out, "LOOKUP renego during accept\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");
+ continue;
+ }
+#endif
+ }
+ 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");
+#ifndef OPENSSL_NO_SRP
+ if (BIO_should_io_special(io)
+ && BIO_get_retry_reason(io) == BIO_RR_SSL_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");
+ continue;
+ }
+#endif
+#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)
{
@@ -2961,3 +3377,116 @@ 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));
+ if (!sess) {
+ BIO_printf(bio_err, "Out of memory adding session to external cache\n");
+ return 0;
+ }
+
+ 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);
+ if (!sess->id || !sess->der) {
+ BIO_printf(bio_err, "Out of memory adding session to external cache\n");
+
+ if (sess->id)
+ OPENSSL_free(sess->id);
+ if (sess->der)
+ OPENSSL_free(sess->der);
+ OPENSSL_free(sess);
+ return 0;
+ }
+ 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;
+}