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);
static int enable_timeouts = 0;
static long socket_mtu;
+#ifndef OPENSSL_NO_DTLS1
static int cert_chain = 0;
+#endif
#ifndef OPENSSL_NO_PSK
static char *psk_identity="Client_identity";
#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");
-# ifdef OPENSSL_EXPERIMENTAL_JPAKE
+# ifndef OPENSSL_NO_JPAKE
BIO_printf(bio_err," -jpake arg - JPAKE secret to use\n");
# endif
#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," -mtu - Set MTU\n");
+ BIO_printf(bio_err," -mtu - Set link layer 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");
+ 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
BIO_printf(bio_err," not specified (default is %s)\n",TEST_CERT2);
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
}
return p->extension_error;
if (ctx2)
{
- BIO_printf(p->biodebug,"Swiching server context.\n");
+ BIO_printf(p->biodebug,"Switching server context.\n");
SSL_set_SSL_CTX(s,ctx2);
}
}
int use_ssl;
unsigned char *rspder = NULL;
int rspderlen;
- STACK_OF(STRING) *aia = NULL;
+ STACK_OF(OPENSSL_STRING) *aia = NULL;
X509 *x = NULL;
X509_STORE_CTX inctx;
X509_OBJECT obj;
aia = X509_get1_ocsp(x);
if (aia)
{
- if (!OCSP_parse_url(sk_STRING_value(aia, 0),
+ if (!OCSP_parse_url(sk_OPENSSL_STRING_value(aia, 0),
&host, &port, &path, &use_ssl))
{
BIO_puts(err, "cert_status: can't parse AIA URL\n");
}
if (srctx->verbose)
BIO_printf(err, "cert_status: AIA URL: %s\n",
- sk_STRING_value(aia, 0));
+ sk_OPENSSL_STRING_value(aia, 0));
}
else
{
if (!OCSP_REQUEST_add_ext(req, ext, -1))
goto err;
}
- resp = process_responder(err, req, host, path, port, use_ssl,
+ resp = process_responder(err, req, host, path, port, use_ssl, NULL,
srctx->timeout);
if (!resp)
{
int MAIN(int, char **);
-#ifdef OPENSSL_EXPERIMENTAL_JPAKE
+#ifndef OPENSSL_NO_JPAKE
static char *jpake_secret = NULL;
#endif
int MAIN(int argc, char *argv[])
{
- X509_STORE *store = NULL;
- int vflags = 0;
+ X509_VERIFY_PARAM *vpm = NULL;
+ int badarg = 0;
short port=PORT;
char *CApath=NULL,*CAfile=NULL;
unsigned char *context = NULL;
int state=0;
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;
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, ext_cache = 0;
#ifndef OPENSSL_NO_TLSEXT
EVP_PKEY *s_key2 = NULL;
X509 *s_cert2 = NULL;
if (--argc < 1) goto bad;
CApath= *(++argv);
}
- else if (strcmp(*argv,"-crl_check") == 0)
- {
- vflags |= X509_V_FLAG_CRL_CHECK;
- }
- else if (strcmp(*argv,"-crl_check_all") == 0)
+ 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))
{
- vflags |= X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
+ 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)
{
if (--argc < 1) goto bad;
{ 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
}
#endif
-#if defined(OPENSSL_EXPERIMENTAL_JPAKE) && !defined(OPENSSL_NO_PSK)
+#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK)
else if (strcmp(*argv,"-jpake") == 0)
{
if (--argc < 1) goto bad;
goto end;
}
-#if defined(OPENSSL_EXPERIMENTAL_JPAKE) && !defined(OPENSSL_NO_PSK)
+#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK)
if (jpake_secret)
{
if (psk_key)
goto end;
}
psk_identity = "JPAKE";
+ if (cipher)
+ {
+ BIO_printf(bio_err, "JPAKE sets cipher to PSK\n");
+ goto end;
+ }
+ cipher = "PSK";
}
- if (cipher)
- {
- BIO_printf(bio_err, "JPAKE sets cipher to PSK\n");
- goto end;
- }
- cipher = "PSK";
#endif
-
+
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
-
- SSL_CTX_sess_set_cache_size(ctx,128);
+ 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 0
if (cipher == NULL) cipher=getenv("SSL_CIPHER");
ERR_print_errors(bio_err);
/* goto end; */
}
- store = SSL_CTX_get_cert_store(ctx);
- X509_STORE_set_flags(store, vflags);
+ if (vpm)
+ SSL_CTX_set1_param(ctx, vpm);
#ifndef OPENSSL_NO_TLSEXT
if (s_cert2)
if (state) SSL_CTX_set_info_callback(ctx2,apps_ssl_info_callback);
- SSL_CTX_sess_set_cache_size(ctx2,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);
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);
+ if (vpm)
+ SSL_CTX_set1_param(ctx2, vpm);
}
#endif
#endif
#ifndef OPENSSL_NO_PSK
+#ifdef OPENSSL_NO_JPAKE
+ if (psk_key != NULL)
+#else
if (psk_key != NULL || jpake_secret)
+#endif
{
if (s_debug)
BIO_printf(bio_s_out, "PSK key given or JPAKE in use, setting server callback\n");
SSL_CTX_set_session_id_context(ctx,(void*)&s_server_session_id_context,
sizeof s_server_session_id_context);
+ /* Set DTLS cookie generation and verification callbacks */
+ SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie_callback);
+ SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie_callback);
+
#ifndef OPENSSL_NO_TLSEXT
if (ctx2)
{
OPENSSL_free(pass);
if (dpass)
OPENSSL_free(dpass);
+ free_sessions();
#ifndef OPENSSL_NO_TLSEXT
if (ctx2 != NULL) SSL_CTX_free(ctx2);
if (s_cert2)
unsigned long l;
SSL *con=NULL;
BIO *sbio;
+ struct timeval timeout;
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_BEOS_R5)
struct timeval tv;
+#else
+ struct timeval *timeoutp;
#endif
if ((buf=OPENSSL_malloc(bufsize)) == NULL)
if (SSL_version(con) == DTLS1_VERSION)
{
- struct timeval timeout;
sbio=BIO_new_dgram(s,BIO_NOCLOSE);
BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout);
}
- if (socket_mtu > 0)
+ if (socket_mtu > 28)
{
SSL_set_options(con, SSL_OP_NO_QUERY_MTU);
- SSL_set_mtu(con, socket_mtu);
+ SSL_set_mtu(con, socket_mtu - 28);
}
else
/* want to do MTU discovery */
test=BIO_new(BIO_f_nbio_test());
sbio=BIO_push(test,sbio);
}
-#ifdef OPENSSL_EXPERIMENTAL_JPAKE
+#ifndef OPENSSL_NO_JPAKE
if(jpake_secret)
jpake_server_auth(bio_s_out, sbio, jpake_secret);
#endif
read_from_terminal = 1;
(void)fcntl(fileno(stdin), F_SETFL, 0);
#else
- i=select(width,(void *)&readfds,NULL,NULL,NULL);
+ if ((SSL_version(con) == DTLS1_VERSION) &&
+ DTLSv1_get_timeout(con, &timeout))
+ timeoutp = &timeout;
+ else
+ timeoutp = NULL;
+
+ i=select(width,(void *)&readfds,NULL,NULL,timeoutp);
+
+ if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_handle_timeout(con) > 0)
+ {
+ BIO_printf(bio_err,"TIMEOUT occured\n");
+ }
+
if (i <= 0) continue;
if (FD_ISSET(fileno(stdin),&readfds))
read_from_terminal = 1;
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;
+ }
+
+
+
+
+
+
+
+
+
+