New functions SSL[_CTX]_set_msg_callback().
New macros SSL[_CTX]_set_msg_callback_arg().

Message callback imlementation for SSL 3.0/TLS 1.0 (no SSL 2.0 yet).

New '-msg' option for 'openssl s_client' and 'openssl s_server'
that enable a message callback that displays all protocol messages.


In ssl3_get_client_hello (ssl/s3_srvr.c), generate a fatal alert if
client_version is smaller than the protocol version in use.
Also change ssl23_get_client_hello (ssl/s23_srvr.c) to select TLS 1.0
if the client demanded SSL 3.0 but only TLS 1.0 is enabled; then the
client will at least see that alert.

Fix SSL[_CTX]_ctrl prototype (void * instead of char * for generic
pointer).

Add/update some OpenSSL copyright notices.
diff --git a/ssl/s23_srvr.c b/ssl/s23_srvr.c
index 563531f..8c41e1f 100644
--- a/ssl/s23_srvr.c
+++ b/ssl/s23_srvr.c
@@ -55,6 +55,59 @@
  * copied and put under another distribution licence
  * [including the GNU Public Licence.]
  */
+/* ====================================================================
+ * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
 
 #include <stdio.h>
 #include <openssl/buffer.h>
@@ -310,10 +363,21 @@
 					type=3;
 					}
 				}
-			else if (!(s->options & SSL_OP_NO_SSLv3))
+			else
 				{
-				s->version=SSL3_VERSION;
-				type=3;
+				/* client requests SSL 3.0 */
+				if (!(s->options & SSL_OP_NO_SSLv3))
+					{
+					s->version=SSL3_VERSION;
+					type=3;
+					}
+				else if (!(s->options & SSL_OP_NO_TLSv1))
+					{
+					/* we won't be able to use TLS of course,
+					 * but this will send an appropriate alert */
+					s->version=TLS1_VERSION;
+					type=3;
+					}
 				}
 			}
 		else if ((strncmp("GET ", (char *)p,4) == 0) ||
diff --git a/ssl/s2_lib.c b/ssl/s2_lib.c
index f231e07..aaca270 100644
--- a/ssl/s2_lib.c
+++ b/ssl/s2_lib.c
@@ -330,7 +330,7 @@
 	s->packet_length=0;
 	}
 
-long ssl2_ctrl(SSL *s, int cmd, long larg, char *parg)
+long ssl2_ctrl(SSL *s, int cmd, long larg, void *parg)
 	{
 	int ret=0;
 
@@ -350,7 +350,7 @@
 	return(0);
 	}
 
-long ssl2_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, char *parg)
+long ssl2_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
 	{
 	return(0);
 	}
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index dd860a6..fa84077 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -119,7 +119,7 @@
 #include <openssl/x509.h>
 #include "ssl_locl.h"
 
-/* send s->init_buf in records of type 'type' */
+/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
 int ssl3_do_write(SSL *s, int type)
 	{
 	int ret;
@@ -133,7 +133,11 @@
 		ssl3_finish_mac(s,(unsigned char *)&s->init_buf->data[s->init_off],ret);
 	
 	if (ret == s->init_num)
+		{
+		if (s->msg_callback)
+			s->msg_callback(1, s->version, type, s->init_buf->data, (size_t)s->init_num, s, s->msg_callback_arg);
 		return(1);
+		}
 	s->init_off+=ret;
 	s->init_num-=ret;
 	return(0);
@@ -393,8 +397,10 @@
 						{
 						s->init_num = 0;
 						skip_message = 1;
+
+						if (s->msg_callback)
+							s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, p, 4, s, s->msg_callback_arg);
 						}
-			
 			}
 		while (skip_message);
 
@@ -461,6 +467,8 @@
 		n -= i;
 		}
 	ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, s->init_num + 4);
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, (size_t)s->init_num + 4, s, s->msg_callback_arg);
 	*ok=1;
 	return s->init_num;
 f_err:
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 4575eee..9a8cf10 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -56,7 +56,7 @@
  * [including the GNU Public Licence.]
  */
 /* ====================================================================
- * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1026,7 +1026,7 @@
 	s->version=SSL3_VERSION;
 	}
 
-long ssl3_ctrl(SSL *s, int cmd, long larg, char *parg)
+long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
 	{
 	int ret=0;
 
@@ -1189,7 +1189,7 @@
 	return(ret);
 	}
 
-long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, char *parg)
+long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
 	{
 	CERT *cert;
 
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
index b76aabe..3baf6c5 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -911,6 +911,9 @@
 			goto err;
 			}
 
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->s3->handshake_fragment, 4, s, s->msg_callback_arg);
+
 		if (SSL_is_init_finished(s) &&
 			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
 			!s->s3->renegotiate)
@@ -956,6 +959,9 @@
 
 		s->s3->alert_fragment_len = 0;
 
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_ALERT, s->s3->alert_fragment, 2, s, s->msg_callback_arg);
+
 		if (s->info_callback != NULL)
 			cb=s->info_callback;
 		else if (s->ctx->info_callback != NULL)
@@ -1019,6 +1025,10 @@
 			}
 
 		rr->length=0;
+
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, s->msg_callback_arg);
+
 		s->s3->change_cipher_spec=1;
 		if (!do_change_cipher_spec(s))
 			goto err;
@@ -1177,6 +1187,8 @@
 	{
 	/* Map tls/ssl alert value to correct one */
 	desc=s->method->ssl3_enc->alert_value(desc);
+	if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION)
+		desc = SSL_AD_HANDSHAKE_FAILURE; /* SSL 3.0 does not have protocol_version alerts */
 	if (desc < 0) return;
 	/* If a fatal one, remove from cache */
 	if ((level == 2) && (s->session != NULL))
@@ -1210,6 +1222,9 @@
 		if (s->s3->send_alert[0] == SSL3_AL_FATAL)
 			(void)BIO_flush(s->wbio);
 
+		if (s->msg_callback)
+			s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, 2, s, s->msg_callback_arg);
+
 		if (s->info_callback != NULL)
 			cb=s->info_callback;
 		else if (s->ctx->info_callback != NULL)
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index d838bb9..9cea6e3 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -670,6 +670,18 @@
 	s->client_version=(((int)p[0])<<8)|(int)p[1];
 	p+=2;
 
+	if (s->client_version < s->version)
+		{
+		SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
+		if ((s->client_version>>8) == SSL3_VERSION_MAJOR) 
+			{
+			/* similar to ssl3_get_record, send alert using remote version number */
+			s->version = s->client_version;
+			}
+		al = SSL_AD_PROTOCOL_VERSION;
+		goto f_err;
+		}
+
 	/* load the client random */
 	memcpy(s->s3->client_random,p,SSL3_RANDOM_SIZE);
 	p+=SSL3_RANDOM_SIZE;
diff --git a/ssl/ssl.h b/ssl/ssl.h
index f364240..541f494 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -283,8 +283,8 @@
 	int (*ssl_shutdown)(SSL *s);
 	int (*ssl_renegotiate)(SSL *s);
 	int (*ssl_renegotiate_check)(SSL *s);
-	long (*ssl_ctrl)(SSL *s,int cmd,long larg,char *parg);
-	long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,char *parg);
+	long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg);
+	long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg);
 	SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr);
 	int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr);
 	int (*ssl_pending)(SSL *s);
@@ -428,22 +428,30 @@
  * they cannot be used to clear bits. */
 
 #define SSL_CTX_set_options(ctx,op) \
-	SSL_CTX_ctrl(ctx,SSL_CTRL_OPTIONS,op,NULL)
+	SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
 #define SSL_CTX_get_options(ctx) \
-	SSL_CTX_ctrl(ctx,SSL_CTRL_OPTIONS,0,NULL)
+	SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL)
 #define SSL_set_options(ssl,op) \
-	SSL_ctrl(ssl,SSL_CTRL_OPTIONS,op,NULL)
+	SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL)
 #define SSL_get_options(ssl) \
-        SSL_ctrl(ssl,SSL_CTRL_OPTIONS,0,NULL)
+        SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL)
 
 #define SSL_CTX_set_mode(ctx,op) \
-	SSL_CTX_ctrl(ctx,SSL_CTRL_MODE,op,NULL)
+	SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
 #define SSL_CTX_get_mode(ctx) \
-	SSL_CTX_ctrl(ctx,SSL_CTRL_MODE,0,NULL)
+	SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL)
 #define SSL_set_mode(ssl,op) \
-	SSL_ctrl(ssl,SSL_CTRL_MODE,op,NULL)
+	SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL)
 #define SSL_get_mode(ssl) \
-        SSL_ctrl(ssl,SSL_CTRL_MODE,0,NULL)
+        SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL)
+
+
+void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
+void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
+#define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
+#define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
+
+
 
 #if defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32)
 #define SSL_MAX_CERT_LIST_DEFAULT 1024*30 /* 30k max cert list :-) */
@@ -586,7 +594,7 @@
 	int read_ahead;
 
 	/* callback that allows applications to peek at protocol messages */
-	void (*msg_callback)(int write_p, int version, int content_type, size_t len, const char *buf, SSL *ssl, void *arg);
+	void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
 	void *msg_callback_arg;
 
 	int verify_mode;
@@ -732,7 +740,7 @@
 	               	 	 * (for non-blocking reads) */
 
 	/* callback that allows applications to peek at protocol messages */
-	void (*msg_callback)(int write_p, int version, int content_type, size_t len, const char *buf, SSL *ssl, void *arg);
+	void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
 	void *msg_callback_arg;
 
 	int hit;		/* reusing a previous session */
@@ -1205,9 +1213,9 @@
 int 	SSL_read(SSL *ssl,void *buf,int num);
 int 	SSL_peek(SSL *ssl,void *buf,int num);
 int 	SSL_write(SSL *ssl,const void *buf,int num);
-long	SSL_ctrl(SSL *ssl,int cmd, long larg, char *parg);
+long	SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg);
 long	SSL_callback_ctrl(SSL *, int, void (*)());
-long	SSL_CTX_ctrl(SSL_CTX *ctx,int cmd, long larg, char *parg);
+long	SSL_CTX_ctrl(SSL_CTX *ctx,int cmd, long larg, void *parg);
 long	SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)());
 
 int	SSL_get_error(SSL *s,int ret_code);
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 1a434a5..7257daa 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -902,7 +902,7 @@
 	return (s->new_session != 0);
 	}
 
-long SSL_ctrl(SSL *s,int cmd,long larg,char *parg)
+long SSL_ctrl(SSL *s,int cmd,long larg,void *parg)
 	{
 	long l;
 
@@ -939,7 +939,7 @@
 	switch(cmd)
 		{
 	case SSL_CTRL_SET_MSG_CALLBACK:
-		s->msg_callback = (void (*)(int write_p, int version, int content_type, size_t len, const char *buf, SSL *ssl, void *arg))(fp);
+		s->msg_callback = (void (*)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))(fp);
 		return 1;
 		
 	default:
@@ -952,7 +952,7 @@
 	return ctx->sessions;
 	}
 
-long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd,long larg,char *parg)
+long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd,long larg,void *parg)
 	{
 	long l;
 
@@ -1027,7 +1027,7 @@
 	switch(cmd)
 		{
 	case SSL_CTRL_SET_MSG_CALLBACK:
-		ctx->msg_callback = (void (*)(int write_p, int version, int content_type, size_t len, const char *buf, SSL *ssl, void *arg))(fp);
+		ctx->msg_callback = (void (*)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))(fp);
 		return 1;
 
 	default:
@@ -2263,17 +2263,29 @@
 #ifndef OPENSSL_NO_DH
 void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,DH *(*dh)(SSL *ssl,int is_export,
 							int keylength))
-    {
-    SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_DH_CB,(void (*)())dh);
-    }
+	{
+	SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_DH_CB,(void (*)())dh);
+	}
 
 void SSL_set_tmp_dh_callback(SSL *ssl,DH *(*dh)(SSL *ssl,int is_export,
 						int keylength))
-    {
-    SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_DH_CB,(void (*)())dh);
-    }
+	{
+	SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_DH_CB,(void (*)())dh);
+	}
 #endif
 
+
+void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
+	{
+	SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_MSG_CALLBACK, (void (*)())cb);
+	}
+void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
+	{
+	SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)())cb);
+	}
+
+
+
 #if defined(_WINDLL) && defined(OPENSSL_SYS_WIN16)
 #include "../crypto/bio/bss_file.c"
 #endif
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 6f3b710..17e9bef 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -56,7 +56,7 @@
  * [including the GNU Public Licence.]
  */
 /* ====================================================================
- * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -530,8 +530,8 @@
 int	ssl2_write(SSL *s, const void *buf, int len);
 int	ssl2_shutdown(SSL *s);
 void	ssl2_clear(SSL *s);
-long	ssl2_ctrl(SSL *s,int cmd, long larg, char *parg);
-long	ssl2_ctx_ctrl(SSL_CTX *s,int cmd, long larg, char *parg);
+long	ssl2_ctrl(SSL *s,int cmd, long larg, void *parg);
+long	ssl2_ctx_ctrl(SSL_CTX *s,int cmd, long larg, void *parg);
 long	ssl2_callback_ctrl(SSL *s,int cmd, void (*fp)());
 long	ssl2_ctx_callback_ctrl(SSL_CTX *s,int cmd, void (*fp)());
 int	ssl2_pending(SSL *s);
@@ -578,8 +578,8 @@
 int	ssl3_write(SSL *s, const void *buf, int len);
 int	ssl3_shutdown(SSL *s);
 void	ssl3_clear(SSL *s);
-long	ssl3_ctrl(SSL *s,int cmd, long larg, char *parg);
-long	ssl3_ctx_ctrl(SSL_CTX *s,int cmd, long larg, char *parg);
+long	ssl3_ctrl(SSL *s,int cmd, long larg, void *parg);
+long	ssl3_ctx_ctrl(SSL_CTX *s,int cmd, long larg, void *parg);
 long	ssl3_callback_ctrl(SSL *s,int cmd, void (*fp)());
 long	ssl3_ctx_callback_ctrl(SSL_CTX *s,int cmd, void (*fp)());
 int	ssl3_pending(SSL *s);
@@ -592,7 +592,7 @@
 int tls1_new(SSL *s);
 void tls1_free(SSL *s);
 void tls1_clear(SSL *s);
-long tls1_ctrl(SSL *s,int cmd, long larg, char *parg);
+long tls1_ctrl(SSL *s,int cmd, long larg, void *parg);
 long tls1_callback_ctrl(SSL *s,int cmd, void (*fp)());
 SSL_METHOD *tlsv1_base_method(void );