For better forward-security support, add functions
SSL_[CTX_]set_not_resumable_session_callback.

Submitted by: Emilia Kasper (Google)

[A part of this change affecting ssl/s3_lib.c was accidentally commited
separately, together with a compilation fix for that file;
see s3_lib.c CVS revision 1.133 (http://cvs.openssl.org/chngview?cn=19855).]
diff --git a/CHANGES b/CHANGES
index 8c6cfbe..114f339 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,24 @@
 
  Changes between 1.0.0 and 1.1.0  [xx XXX xxxx]
 
+  *) Improve forward-security support: add functions
+
+       void SSL_CTX_set_not_resumable_session_callback(SSL_CTX *ctx, int (*cb)(SSL *ssl, int is_forward_secure))
+       void SSL_set_not_resumable_session_callback(SSL *ssl, int (*cb)(SSL *ssl, int is_forward_secure))
+
+     for use by SSL/TLS servers; the callback function will be called whenever a
+     new session is created, and gets to decide whether the session may be
+     cached to make it resumable (return 0) or not (return 1).  (As by the
+     SSL/TLS protocol specifications, the session_id sent by the server will be
+     empty to indicate that the session is not resumable; also, the server will
+     not generate RFC 4507 (RFC 5077) session tickets.)
+
+     A simple reasonable callback implementation is to return is_forward_secure.
+     This parameter will be set to 1 or 0 depending on the ciphersuite selected
+     by the SSL/TLS server library, indicating whether it can provide forward
+     security.
+     [Emilia Käsper <emilia.kasper@esat.kuleuven.be> (Google)]
+
   *) Add Next Protocol Negotiation,
      http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-00. Can be
      disabled with a no-npn flag to config or Configure. Code donated
diff --git a/apps/s_server.c b/apps/s_server.c
index d339968..29c737c 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -201,6 +201,7 @@
 #ifndef OPENSSL_NO_RSA
 static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export, int keylength);
 #endif
+static int not_resumable_sess_cb(SSL *s, int is_forward_secure);
 static int sv_body(char *hostname, int s, unsigned char *context);
 static int www_body(char *hostname, int s, unsigned char *context);
 static void close_accept_socket(void );
@@ -289,6 +290,7 @@
 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;
 
@@ -476,6 +478,7 @@
 #ifndef OPENSSL_NO_ECDH
 	BIO_printf(bio_err," -no_ecdhe     - Disable ephemeral ECDH\n");
 #endif
+	BIO_printf(bio_err, "-no_resume_ephemeral - Disable caching and tickets if ephemeral (EC)DH is used\n");
 	BIO_printf(bio_err," -bugs         - Turn on SSL bug compatibility\n");
 	BIO_printf(bio_err," -www          - Respond to a 'GET /' with a status page\n");
 	BIO_printf(bio_err," -WWW          - Respond to a 'GET /<path> HTTP/1.0' with file ./<path>\n");
@@ -853,6 +856,12 @@
 # endif  /* ndef OPENSSL_NO_NPN */
 #endif
 
+static int not_resumable_sess_cb(SSL *s, int is_forward_secure)
+	{
+	/* disable resumption for sessions with forward secure ciphers */
+	return is_forward_secure;
+	}
+
 int MAIN(int, char **);
 
 #ifndef OPENSSL_NO_JPAKE
@@ -1120,6 +1129,8 @@
 			{ 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)
 			{
@@ -1689,6 +1700,15 @@
 #endif
 #endif
 
+	if (no_resume_ephemeral)
+		{
+		SSL_CTX_set_not_resumable_session_callback(ctx, not_resumable_sess_cb);
+#ifndef OPENSSL_NO_TLSEXT
+		if (ctx2)
+			SSL_CTX_set_not_resumable_session_callback(ctx2, not_resumable_sess_cb);
+#endif
+		}
+
 #ifndef OPENSSL_NO_PSK
 #ifdef OPENSSL_NO_JPAKE
 	if (psk_key != NULL)
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index c2874e7..bc6ece4 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -1251,6 +1251,13 @@
 			goto f_err;
 			}
 		s->s3->tmp.new_cipher=c;
+		/* check whether we should disable session resumption */
+		if (s->not_resumable_session_cb != NULL)
+			s->session->not_resumable=s->not_resumable_session_cb(s,
+				((c->algorithm_mkey & (SSL_kEDH | SSL_kEECDH)) != 0));
+		if (s->session->not_resumable)
+			/* do not send a session ticket */
+			s->tlsext_ticket_expected = 0;
 		}
 	else
 		{
@@ -1354,8 +1361,9 @@
 		 * if session caching is disabled so existing functionality
 		 * is unaffected.
 		 */
-		if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
-			&& !s->hit)
+		if (s->session->not_resumable ||
+			(!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
+				&& !s->hit))
 			s->session->session_id_length=0;
 
 		sl=s->session->session_id_length;
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 5a35c67..20e49ec 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -468,6 +468,9 @@
 	char *psk_identity_hint;
 	char *psk_identity;
 #endif
+	/* Used to indicate that session resumption is not allowed.
+	 * Applications can also set this bit for a new session via
+	 * not_resumable_session_cb to disable session caching and tickets. */
 	int not_resumable;
 
 	/* The cert is the certificate used to establish this connection */
@@ -811,6 +814,10 @@
 
 	X509_VERIFY_PARAM *param;
 
+	/* Callback for disabling session caching and ticket support
+	 * on a session basis, depending on the chosen cipher. */
+	int (*not_resumable_session_cb)(SSL *ssl, int is_forward_secure);
+
 #if 0
 	int purpose;		/* Purpose setting */
 	int trust;		/* Trust setting */
@@ -1088,6 +1095,10 @@
 
 	X509_VERIFY_PARAM *param;
 
+	/* Callback for disabling session caching and ticket support
+	 * on a session basis, depending on the chosen cipher. */
+	int (*not_resumable_session_cb)(SSL *ssl, int is_forward_secure);
+
 #if 0
 	int purpose;		/* Purpose setting */
 	int trust;		/* Trust setting */
@@ -1477,6 +1488,7 @@
 #define SSL_CTRL_GET_RI_SUPPORT			76
 #define SSL_CTRL_CLEAR_OPTIONS			77
 #define SSL_CTRL_CLEAR_MODE			78
+#define SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB	79
 
 #define DTLSv1_get_timeout(ssl, arg) \
 	SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
@@ -1875,6 +1887,12 @@
                            unsigned char *context, int context_len,
                            unsigned char *out, int olen);
 
+void SSL_CTX_set_not_resumable_session_callback(SSL_CTX *ctx,
+	int (*cb)(SSL *ssl, int is_forward_secure));
+
+void SSL_set_not_resumable_session_callback(SSL *ssl,
+	int (*cb)(SSL *ssl, int is_forward_secure));
+
 /* BEGIN ERROR CODES */
 /* The following lines are auto generated by the script mkerr.pl. Any changes
  * made after this point may be overwritten when the script is next run.
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index ff71004..9dfa3aa 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -319,6 +319,7 @@
 	s->msg_callback=ctx->msg_callback;
 	s->msg_callback_arg=ctx->msg_callback_arg;
 	s->verify_mode=ctx->verify_mode;
+	s->not_resumable_session_cb=ctx->not_resumable_session_cb;
 #if 0
 	s->verify_depth=ctx->verify_depth;
 #endif
@@ -3164,6 +3165,19 @@
 	SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
 	}
 
+void SSL_CTX_set_not_resumable_session_callback(SSL_CTX *ctx,
+	int (*cb)(SSL *ssl, int is_forward_secure))
+	{
+	SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB,
+		(void (*)(void))cb);
+	}
+void SSL_set_not_resumable_session_callback(SSL *ssl,
+	int (*cb)(SSL *ssl, int is_forward_secure))
+	{
+	SSL_callback_ctrl(ssl, SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB,
+		(void (*)(void))cb);
+	}
+
 /* Allocates new EVP_MD_CTX and sets pointer to it into given pointer
  * vairable, freeing  EVP_MD_CTX previously stored in that variable, if
  * any. If EVP_MD pointer is passed, initializes ctx with this md