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);
#endif
BIO_printf(bio_err," -ssl2 - Just talk SSLv2\n");
BIO_printf(bio_err," -ssl3 - Just talk SSLv3\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," -timeout - Enable timeouts\n");
BIO_printf(bio_err," -no_ssl2 - Just disable SSLv2\n");
BIO_printf(bio_err," -no_ssl3 - Just disable SSLv3\n");
BIO_printf(bio_err," -no_tls1 - Just disable TLSv1\n");
+ BIO_printf(bio_err," -no_tls1_1 - Just disable TLSv1.1\n");
#ifndef OPENSSL_NO_DH
BIO_printf(bio_err," -no_dhe - Disable ephemeral DH\n");
#endif
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;
- int no_cache = 0;
+ int no_cache = 0, ext_cache = 0;
#ifndef OPENSSL_NO_TLSEXT
EVP_PKEY *s_key2 = NULL;
X509 *s_cert2 = NULL;
}
else if (strcmp(*argv,"-no_cache") == 0)
no_cache = 1;
+ else if (strcmp(*argv,"-ext_cache") == 0)
+ ext_cache = 1;
else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm))
{
if (badarg)
{ off|=SSL_OP_NO_SSLv2; }
else if (strcmp(*argv,"-no_ssl3") == 0)
{ off|=SSL_OP_NO_SSLv3; }
+ else if (strcmp(*argv,"-no_tls1_1") == 0)
+ { off|=SSL_OP_NO_TLSv1_1; }
else if (strcmp(*argv,"-no_tls1") == 0)
{ off|=SSL_OP_NO_TLSv1; }
else if (strcmp(*argv,"-no_comp") == 0)
{ meth=SSLv3_server_method(); }
#endif
#ifndef OPENSSL_NO_TLS1
+ else if (strcmp(*argv,"-tls1_1") == 0)
+ { meth=TLSv1_1_server_method(); }
else if (strcmp(*argv,"-tls1") == 0)
{ meth=TLSv1_server_method(); }
#endif
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);
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);
OPENSSL_free(pass);
if (dpass)
OPENSSL_free(dpass);
+ free_sessions();
#ifndef OPENSSL_NO_TLSEXT
if (ctx2 != NULL) SSL_CTX_free(ctx2);
if (s_cert2)
con->kssl_ctx->client_princ);
}
#endif /* OPENSSL_NO_KRB5 */
+ BIO_printf(bio_s_out, "Secure Renegotiation IS%s supported\n",
+ SSL_get_secure_renegotiation_support(con) ? "" : " NOT");
return(1);
}
}
SSL_set_bio(con,sbio,sbio);
SSL_set_accept_state(con);
-
/* SSL_set_fd(con,s); */
BIO_set_ssl(ssl_bio,con,BIO_CLOSE);
BIO_push(io,ssl_bio);
STACK_OF(SSL_CIPHER) *sk;
static const char *space=" ";
+ if (www == 1 && strncmp("GET /reneg", buf, 10) == 0)
+ {
+ if (strncmp("GET /renegcert", buf, 14) == 0)
+ SSL_set_verify(con,
+ SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,NULL);
+ i=SSL_renegotiate(con);
+ BIO_printf(bio_s_out, "SSL_renegotiate -> %d\n",i);
+ i=SSL_do_handshake(con);
+ if (i <= 0)
+ {
+ BIO_printf(bio_s_out, "SSL_do_handshake() Retval %d\n", SSL_get_error(con, i));
+ ERR_print_errors(bio_err);
+ goto err;
+ }
+ /* EVIL HACK! */
+ con->state = SSL_ST_ACCEPT;
+ i=SSL_do_handshake(con);
+ BIO_printf(bio_s_out, "SSL_do_handshake -> %d\n",i);
+ if (i <= 0)
+ {
+ BIO_printf(bio_s_out, "SSL_do_handshake() Retval %d\n", SSL_get_error(con, i));
+ ERR_print_errors(bio_err);
+ goto err;
+ }
+ }
+
BIO_puts(io,"HTTP/1.0 200 ok\r\nContent-type: text/html\r\n\r\n");
BIO_puts(io,"<HTML><BODY BGCOLOR=\"#ffffff\">\n");
BIO_puts(io,"<pre>\n");
}
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");
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;
+ 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));
+
+ sess->idlen = session->session_id_length;
+ sess->derlen = i2d_SSL_SESSION(session, NULL);
+
+ sess->id = BUF_memdup(session->session_id, 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 == 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;
+ unsigned char *id = session->session_id;
+ int idlen = session->session_id_length;
+ 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;
+ }
+
+
+
+
+
+
+
+
+
+