summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2015-03-27 23:01:51 +0000
committerMatt Caswell <matt@openssl.org>2015-05-16 09:19:56 +0100
commit32ec41539b5b23bc42503589fcc5be65d648d1f5 (patch)
tree340cc1e0e9d83d0db3af099741fed33f94ce89df
parent756eff7a31b5b46577e8529645b254ccc256a8ae (diff)
Server side version negotiation rewrite
This commit changes the way that we do server side protocol version negotiation. Previously we had a whole set of code that had an "up front" state machine dedicated to the negotiating the protocol version. This adds significant complexity to the state machine. Historically the justification for doing this was the support of SSLv2 which works quite differently to SSLv3+. However, we have now removed support for SSLv2 so there is little reason to maintain this complexity. The one slight difficulty is that, although we no longer support SSLv2, we do still support an SSLv3+ ClientHello in an SSLv2 backward compatible ClientHello format. This is generally only used by legacy clients. This commit adds support within the SSLv3 code for these legacy format ClientHellos. Server side version negotiation now works in much the same was as DTLS, i.e. we introduce the concept of TLS_ANY_VERSION. If s->version is set to that then when a ClientHello is received it will work out the most appropriate version to respond with. Also, SSLv23_method and SSLv23_server_method have been replaced with TLS_method and TLS_server_method respectively. The old SSLv23* names still exist as macros pointing at the new name, although they are deprecated. Subsequent commits will look at client side version negotiation, as well of removal of the old s23* code. Reviewed-by: Kurt Roeckx <kurt@openssl.org>
-rw-r--r--apps/ciphers.c2
-rw-r--r--apps/s_server.c2
-rw-r--r--crypto/threads/mttest.c2
-rw-r--r--demos/bio/saccept.c2
-rw-r--r--demos/bio/server-arg.c2
-rw-r--r--demos/bio/server-conf.c2
-rw-r--r--demos/easy_tls/easy-tls.c2
-rw-r--r--demos/ssl/serv.cpp2
-rw-r--r--demos/state_machine/state_machine.c2
-rw-r--r--include/openssl/ssl.h13
-rw-r--r--include/openssl/tls1.h3
-rw-r--r--ssl/record/rec_layer_s3.c23
-rw-r--r--ssl/record/record.h8
-rw-r--r--ssl/record/record_locl.h2
-rw-r--r--ssl/record/ssl3_record.c131
-rw-r--r--ssl/s23_meth.c5
-rw-r--r--ssl/s23_srvr.c3
-rw-r--r--ssl/s3_both.c92
-rw-r--r--ssl/s3_lib.c4
-rw-r--r--ssl/s3_srvr.c607
-rw-r--r--ssl/ssl_lib.c26
-rw-r--r--ssl/ssl_locl.h3
-rw-r--r--ssl/t1_meth.c10
-rw-r--r--ssl/t1_srvr.c11
-rw-r--r--test/ssltest.c2
-rwxr-xr-xutil/ssleay.num6
26 files changed, 645 insertions, 322 deletions
diff --git a/apps/ciphers.c b/apps/ciphers.c
index 232fd602fd..47132fdfc5 100644
--- a/apps/ciphers.c
+++ b/apps/ciphers.c
@@ -94,7 +94,7 @@ int ciphers_main(int argc, char **argv)
SSL_CTX *ctx = NULL;
SSL *ssl = NULL;
STACK_OF(SSL_CIPHER) *sk = NULL;
- const SSL_METHOD *meth = SSLv23_server_method();
+ const SSL_METHOD *meth = TLS_server_method();
int ret = 1, i, verbose = 0, Verbose = 0, use_supported = 0;
#ifndef OPENSSL_NO_SSL_TRACE
int stdname = 0;
diff --git a/apps/s_server.c b/apps/s_server.c
index 2ef902a531..61d13f3e0a 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -987,7 +987,7 @@ int s_server_main(int argc, char *argv[])
ENGINE *e = NULL;
EVP_PKEY *s_key = NULL, *s_dkey = NULL;
SSL_CONF_CTX *cctx = NULL;
- const SSL_METHOD *meth = SSLv23_server_method();
+ const SSL_METHOD *meth = TLS_server_method();
SSL_EXCERT *exc = NULL;
STACK_OF(OPENSSL_STRING) *ssl_args = NULL;
STACK_OF(X509) *s_chain = NULL, *s_dchain = NULL;
diff --git a/crypto/threads/mttest.c b/crypto/threads/mttest.c
index f6f8df289c..3218c32924 100644
--- a/crypto/threads/mttest.c
+++ b/crypto/threads/mttest.c
@@ -194,7 +194,7 @@ int main(int argc, char *argv[])
SSL_CTX *c_ctx = NULL;
char *scert = TEST_SERVER_CERT;
char *ccert = TEST_CLIENT_CERT;
- SSL_METHOD *ssl_method = SSLv23_method();
+ SSL_METHOD *ssl_method = TLS_method();
RAND_seed(rnd_seed, sizeof rnd_seed);
diff --git a/demos/bio/saccept.c b/demos/bio/saccept.c
index 505d98b68f..0d173aa039 100644
--- a/demos/bio/saccept.c
+++ b/demos/bio/saccept.c
@@ -45,7 +45,7 @@ int main(int argc, char *argv[])
/* Add ciphers and message digests */
OpenSSL_add_ssl_algorithms();
- ctx = SSL_CTX_new(SSLv23_server_method());
+ ctx = SSL_CTX_new(TLS_server_method());
if (!SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM))
goto err;
if (!SSL_CTX_use_PrivateKey_file(ctx, CERT_FILE, SSL_FILETYPE_PEM))
diff --git a/demos/bio/server-arg.c b/demos/bio/server-arg.c
index b188f6a4ed..242ca6c0af 100644
--- a/demos/bio/server-arg.c
+++ b/demos/bio/server-arg.c
@@ -29,7 +29,7 @@ int main(int argc, char *argv[])
/* Add ciphers and message digests */
OpenSSL_add_ssl_algorithms();
- ctx = SSL_CTX_new(SSLv23_server_method());
+ ctx = SSL_CTX_new(TLS_server_method());
cctx = SSL_CONF_CTX_new();
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER);
diff --git a/demos/bio/server-conf.c b/demos/bio/server-conf.c
index cc9fe8a828..bf3dd067e5 100644
--- a/demos/bio/server-conf.c
+++ b/demos/bio/server-conf.c
@@ -49,7 +49,7 @@ int main(int argc, char *argv[])
goto err;
}
- ctx = SSL_CTX_new(SSLv23_server_method());
+ ctx = SSL_CTX_new(TLS_server_method());
cctx = SSL_CONF_CTX_new();
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER);
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE);
diff --git a/demos/easy_tls/easy-tls.c b/demos/easy_tls/easy-tls.c
index 9346720dae..2befb657a0 100644
--- a/demos/easy_tls/easy-tls.c
+++ b/demos/easy_tls/easy-tls.c
@@ -668,7 +668,7 @@ SSL_CTX *tls_create_ctx(struct tls_create_ctx_args a, void *apparg)
ret =
SSL_CTX_new((a.client_p ? SSLv23_client_method :
- SSLv23_server_method) ());
+ TLS_server_method) ());
if (ret == NULL)
goto err;
diff --git a/demos/ssl/serv.cpp b/demos/ssl/serv.cpp
index 6d4cefd5d0..9cb77f8275 100644
--- a/demos/ssl/serv.cpp
+++ b/demos/ssl/serv.cpp
@@ -55,7 +55,7 @@ void main ()
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
- meth = SSLv23_server_method();
+ meth = TLS_server_method();
ctx = SSL_CTX_new (meth);
if (!ctx) {
ERR_print_errors_fp(stderr);
diff --git a/demos/state_machine/state_machine.c b/demos/state_machine/state_machine.c
index 1dd8c2be22..98802a12ec 100644
--- a/demos/state_machine/state_machine.c
+++ b/demos/state_machine/state_machine.c
@@ -119,7 +119,7 @@ SSLStateMachine *SSLStateMachine_new(const char *szCertificateFile,
die_unless(pMachine);
- pMachine->pCtx = SSL_CTX_new(SSLv23_server_method());
+ pMachine->pCtx = SSL_CTX_new(TLS_server_method());
die_unless(pMachine->pCtx);
n = SSL_CTX_use_certificate_file(pMachine->pCtx, szCertificateFile,
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 27e44cc20f..f169fcd2a9 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1562,13 +1562,18 @@ __owur const SSL_METHOD *SSLv3_server_method(void); /* SSLv3 */
__owur const SSL_METHOD *SSLv3_client_method(void); /* SSLv3 */
# endif
-__owur const SSL_METHOD *SSLv23_method(void); /* Negotiate highest available SSL/TLS
- * version */
-__owur const SSL_METHOD *SSLv23_server_method(void); /* Negotiate highest available
- * SSL/TLS version */
+#ifdef OPENSSL_USE_DEPRECATED
+#define SSLv23_method TLS_method
+#define SSLv23_server_method TLS_server_method
+#endif
+/* This next one will be deprecated in a subsequent commit */
__owur const SSL_METHOD *SSLv23_client_method(void); /* Negotiate highest available
* SSL/TLS version */
+/* Negotiate highest available SSL/TLS version */
+__owur const SSL_METHOD *TLS_method(void);
+__owur const SSL_METHOD *TLS_server_method(void);
+
__owur const SSL_METHOD *TLSv1_method(void); /* TLSv1.0 */
__owur const SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */
__owur const SSL_METHOD *TLSv1_client_method(void); /* TLSv1.0 */
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index e1beaf3bbd..d10739690e 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -167,6 +167,9 @@ extern "C" {
# define TLS1_2_VERSION 0x0303
# define TLS_MAX_VERSION TLS1_2_VERSION
+/* Special value for method supporting multiple versions */
+# define TLS_ANY_VERSION 0x10000
+
# define TLS1_VERSION_MAJOR 0x03
# define TLS1_VERSION_MINOR 0x01
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index eccb5176ba..97f6e900c5 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -1110,6 +1110,21 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
*/
/*
+ * Lets just double check that we've not got an SSLv2 record
+ */
+ if (rr->rec_version == SSL2_VERSION) {
+ /*
+ * Should never happen. ssl3_get_record() should only give us an SSLv2
+ * record back if this is the first packet and we are looking for an
+ * initial ClientHello. Therefore |type| should always be equal to
+ * |rr->type|. If not then something has gone horribly wrong
+ */
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);
+ goto f_err;
+ }
+
+ /*
* In case of record types for which we have 'fragment' storage, fill
* that so that we can process the data at a fixed place.
*/
@@ -1464,4 +1479,12 @@ void ssl3_record_sequence_update(unsigned char *seq)
}
}
+int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl)
+{
+ return SSL3_RECORD_is_sslv2_record(&rl->rrec);
+}
+int RECORD_LAYER_get_rrec_length(RECORD_LAYER *rl)
+{
+ return SSL3_RECORD_get_length(&rl->rrec);
+}
diff --git a/ssl/record/record.h b/ssl/record/record.h
index 6bccb71d83..a778998196 100644
--- a/ssl/record/record.h
+++ b/ssl/record/record.h
@@ -132,6 +132,10 @@ typedef struct ssl3_buffer_st {
#define SEQ_NUM_SIZE 8
typedef struct ssl3_record_st {
+ /* Record layer version */
+ /* r */
+ int rec_version;
+
/* type of record */
/* r */
int type;
@@ -298,6 +302,8 @@ typedef struct record_layer_st {
* *
*****************************************************************************/
+#define MIN_SSL2_RECORD_LEN 9
+
#define RECORD_LAYER_set_read_ahead(rl, ra) ((rl)->read_ahead = (ra))
#define RECORD_LAYER_get_read_ahead(rl) ((rl)->read_ahead)
#define RECORD_LAYER_get_packet(rl) ((rl)->packet)
@@ -319,6 +325,8 @@ void RECORD_LAYER_dup(RECORD_LAYER *dst, RECORD_LAYER *src);
void RECORD_LAYER_reset_read_sequence(RECORD_LAYER *rl);
void RECORD_LAYER_reset_write_sequence(RECORD_LAYER *rl);
int RECORD_LAYER_setup_comp_buffer(RECORD_LAYER *rl);
+int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl);
+int RECORD_LAYER_get_rrec_length(RECORD_LAYER *rl);
__owur int ssl3_pending(const SSL *s);
__owur int ssl23_read_bytes(SSL *s, int n);
__owur int ssl23_write_bytes(SSL *s);
diff --git a/ssl/record/record_locl.h b/ssl/record/record_locl.h
index 72f8e55f3b..b2222d7c22 100644
--- a/ssl/record/record_locl.h
+++ b/ssl/record/record_locl.h
@@ -186,6 +186,8 @@ int ssl3_release_write_buffer(SSL *s);
#define SSL3_RECORD_set_off(r, o) ((r)->off = (o))
#define SSL3_RECORD_add_off(r, o) ((r)->off += (o))
#define SSL3_RECORD_get_epoch(r) ((r)->epoch)
+#define SSL3_RECORD_is_sslv2_record(r) \
+ ((r)->rec_version == SSL2_VERSION)
void SSL3_RECORD_clear(SSL3_RECORD *r);
void SSL3_RECORD_release(SSL3_RECORD *r);
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index 032812772f..190abd26e8 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -166,6 +166,7 @@ void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num)
*/
#define MAX_EMPTY_RECORDS 32
+#define SSL2_RT_HEADER_LENGTH 2
/*-
* Call this to get a new input record.
* It will return <= 0 if more data is needed, normally due to an error
@@ -216,71 +217,121 @@ int ssl3_get_record(SSL *s)
RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY);
p = RECORD_LAYER_get_packet(&s->rlayer);
- if (s->msg_callback)
- s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s,
- s->msg_callback_arg);
- /* Pull apart the header into the SSL3_RECORD */
- rr->type = *(p++);
- ssl_major = *(p++);
- ssl_minor = *(p++);
- version = (ssl_major << 8) | ssl_minor;
- n2s(p, rr->length);
+ /*
+ * Check whether this is a regular record or an SSLv2 style record. The
+ * latter is only used in an initial ClientHello for old clients.
+ */
+ if (s->first_packet && s->server && !s->read_hash && !s->enc_read_ctx
+ && (p[0] & 0x80) && (p[2] == SSL2_MT_CLIENT_HELLO)) {
+ /* SSLv2 style record */
+ if (s->msg_callback)
+ s->msg_callback(0, SSL2_VERSION, 0, p + 2,
+ RECORD_LAYER_get_packet_length(&s->rlayer) - 2,
+ s, s->msg_callback_arg);
+
+ rr->type = SSL3_RT_HANDSHAKE;
+ rr->rec_version = SSL2_VERSION;
+
+ rr->length = ((p[0] & 0x7f) << 8) | p[1];
+
+ if (rr->length > SSL3_BUFFER_get_len(&s->rlayer.rbuf)
+ - SSL2_RT_HEADER_LENGTH) {
+ al = SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG);
+ goto f_err;
+ }
- /* Lets check version */
- if (!s->first_packet) {
- if (version != s->version) {
- SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
- if ((s->version & 0xFF00) == (version & 0xFF00)
- && !s->enc_write_ctx && !s->write_hash)
- /*
- * Send back error using their minor version number :-)
- */
- s->version = (unsigned short)version;
- al = SSL_AD_PROTOCOL_VERSION;
+ if (rr->length < MIN_SSL2_RECORD_LEN) {
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT);
goto f_err;
}
- }
+ } else {
+ /* SSLv3+ style record */
+ if (s->msg_callback)
+ s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s,
+ s->msg_callback_arg);
+
+ /* Pull apart the header into the SSL3_RECORD */
+ rr->type = *(p++);
+ ssl_major = *(p++);
+ ssl_minor = *(p++);
+ version = (ssl_major << 8) | ssl_minor;
+ rr->rec_version = version;
+ n2s(p, rr->length);
+
+ /* Lets check version */
+ if (!s->first_packet) {
+ if (version != s->version) {
+ SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
+ if ((s->version & 0xFF00) == (version & 0xFF00)
+ && !s->enc_write_ctx && !s->write_hash)
+ /*
+ * Send back error using their minor version number :-)
+ */
+ s->version = (unsigned short)version;
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ }
+ }
- if ((version >> 8) != SSL3_VERSION_MAJOR) {
- SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
- goto err;
- }
+ if ((version >> 8) != SSL3_VERSION_MAJOR) {
+ SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
+ goto err;
+ }
- if (rr->length >
- SSL3_BUFFER_get_len(&s->rlayer.rbuf)
- - SSL3_RT_HEADER_LENGTH) {
- al = SSL_AD_RECORD_OVERFLOW;
- SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG);
- goto f_err;
+ if (rr->length >
+ SSL3_BUFFER_get_len(&s->rlayer.rbuf)
+ - SSL3_RT_HEADER_LENGTH) {
+ al = SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG);
+ goto f_err;
+ }
}
/* now s->rlayer.rstate == SSL_ST_READ_BODY */
}
- /* s->rlayer.rstate == SSL_ST_READ_BODY, get and decode the data */
-
- if (rr->length >
- RECORD_LAYER_get_packet_length(&s->rlayer) - SSL3_RT_HEADER_LENGTH) {
- /* now s->packet_length == SSL3_RT_HEADER_LENGTH */
+ /*
+ * s->rlayer.rstate == SSL_ST_READ_BODY, get and decode the data.
+ * Calculate how much more data we need to read for the rest of the record
+ */
+ if (rr->rec_version == SSL2_VERSION) {
+ i = rr->length + SSL2_RT_HEADER_LENGTH - SSL3_RT_HEADER_LENGTH;
+ } else {
i = rr->length;
+ }
+ if (i > 0) {
+ /* now s->packet_length == SSL3_RT_HEADER_LENGTH */
+
n = ssl3_read_n(s, i, i, 1);
if (n <= 0)
return (n); /* error or non-blocking io */
/*
- * now n == rr->length, and s->packet_length == SSL3_RT_HEADER_LENGTH
- * + rr->length
+ * now n == rr->length, and
+ * s->packet_length == SSL3_RT_HEADER_LENGTH + rr->length
+ * or
+ * s->packet_length == SSL2_RT_HEADER_LENGTH + rr->length
+ * (if SSLv2 packet)
*/
+ } else {
+ n = 0;
}
/* set state for later operations */
RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_HEADER);
/*
- * At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
+ * At this point, s->packet_length == SSL3_RT_HEADER_LENGTH + rr->length,
+ * or s->packet_length == SSL2_RT_HEADER_LENGTH + rr->length
* and we have that many bytes in s->packet
*/
- rr->input = &(RECORD_LAYER_get_packet(&s->rlayer)[SSL3_RT_HEADER_LENGTH]);
+ if(rr->rec_version == SSL2_VERSION) {
+ rr->input = &(RECORD_LAYER_get_packet(&s->rlayer)[SSL2_RT_HEADER_LENGTH]);
+ } else {
+ rr->input = &(RECORD_LAYER_get_packet(&s->rlayer)[SSL3_RT_HEADER_LENGTH]);
+ }
/*
* ok, we can now read from 's->packet' data into 'rr' rr->input points
diff --git a/ssl/s23_meth.c b/ssl/s23_meth.c
index 757c5a9dc9..6080fba150 100644
--- a/ssl/s23_meth.c
+++ b/ssl/s23_meth.c
@@ -60,6 +60,7 @@
#include <openssl/objects.h>
#include "ssl_locl.h"
+/*
static const SSL_METHOD *ssl23_get_method(int ver);
static const SSL_METHOD *ssl23_get_method(int ver)
{
@@ -76,7 +77,5 @@ static const SSL_METHOD *ssl23_get_method(int ver)
return (TLSv1_2_method());
else
return (NULL);
-}
+}*/
-IMPLEMENT_ssl23_meth_func(SSLv23_method,
- ssl23_accept, ssl23_connect, ssl23_get_method)
diff --git a/ssl/s23_srvr.c b/ssl/s23_srvr.c
index 50d634e265..58b89a6c93 100644
--- a/ssl/s23_srvr.c
+++ b/ssl/s23_srvr.c
@@ -134,9 +134,6 @@ static const SSL_METHOD *ssl23_get_server_method(int ver)
return (NULL);
}
-IMPLEMENT_ssl23_meth_func(SSLv23_server_method,
- ssl23_accept,
- ssl_undefined_function, ssl23_get_server_method)
int ssl23_accept(SSL *s)
{
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index bf5e8c7c2d..193270b315 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -356,7 +356,7 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
}
*ok = 1;
s->state = stn;
- s->init_msg = s->init_buf->data + 4;
+ s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
s->init_num = (int)s->s3->tmp.message_size;
return s->init_num;
}
@@ -367,10 +367,9 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
int skip_message;
do {
- while (s->init_num < 4) {
+ while (s->init_num < SSL3_HM_HEADER_LENGTH) {
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
- &p[s->init_num],
- 4 - s->init_num, 0);
+ &p[s->init_num], SSL3_HM_HEADER_LENGTH - s->init_num, 0);
if (i <= 0) {
s->rwstate = SSL_READING;
*ok = 0;
@@ -409,26 +408,49 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
s->s3->tmp.message_type = *(p++);
- n2l3(p, l);
- if (l > (unsigned long)max) {
- al = SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_MESSAGE, SSL_R_EXCESSIVE_MESSAGE_SIZE);
- goto f_err;
- }
- if (l > (INT_MAX - 4)) { /* BUF_MEM_grow takes an 'int' parameter */
- al = SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_MESSAGE, SSL_R_EXCESSIVE_MESSAGE_SIZE);
- goto f_err;
- }
- if (l && !BUF_MEM_grow_clean(s->init_buf, (int)l + 4)) {
- SSLerr(SSL_F_SSL3_GET_MESSAGE, ERR_R_BUF_LIB);
- goto err;
- }
- s->s3->tmp.message_size = l;
- s->state = stn;
+ if(RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
+ /*
+ * Only happens with SSLv3+ in an SSLv2 backward compatible
+ * ClientHello
+ */
+ /*
+ * Total message size is the remaining record bytes to read
+ * plus the SSL3_HM_HEADER_LENGTH bytes that we already read
+ */
+ l = RECORD_LAYER_get_rrec_length(&s->rlayer)
+ + SSL3_HM_HEADER_LENGTH;
+ if (l && !BUF_MEM_grow_clean(s->init_buf, (int)l)) {
+ SSLerr(SSL_F_SSL3_GET_MESSAGE, ERR_R_BUF_LIB);
+ goto err;
+ }
+ s->s3->tmp.message_size = l;
+ s->state = stn;
- s->init_msg = s->init_buf->data + 4;
- s->init_num = 0;
+ s->init_msg = s->init_buf->data;
+ s->init_num = SSL3_HM_HEADER_LENGTH;
+ } else {
+ n2l3(p, l);
+ if (l > (unsigned long)max) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_MESSAGE, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ goto f_err;
+ }
+ /* BUF_MEM_grow takes an 'int' parameter */
+ if (l > (INT_MAX - SSL3_HM_HEADER_LENGTH)) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_MESSAGE, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ goto f_err;
+ }
+ if (l && !BUF_MEM_grow_clean(s->init_buf, (int)l + 4)) {
+ SSLerr(SSL_F_SSL3_GET_MESSAGE, ERR_R_BUF_LIB);
+ goto err;
+ }
+ s->s3->tmp.message_size = l;
+ s->state = stn;
+
+ s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
+ s->init_num = 0;
+ }
}
/* next state (stn) */
@@ -456,10 +478,26 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
#endif
/* Feed this message into MAC computation. */
- 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);
+ if(RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
+ ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, s->init_num);
+ /*
+ * In previous versions we would have rewritten the SSLv2 record into
+ * something that looked like a SSLv3+ record and passed that to the
+ * callback. As we're not doing the rewriting anymore it's not clear
+ * what we should do here.
+ */
+ if (s->msg_callback)
+ s->msg_callback(0, SSL2_VERSION, 0, s->init_buf->data,
+ (size_t)s->init_num, s, s->msg_callback_arg);
+ } else {
+ ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+ s->init_num + SSL3_HM_HEADER_LENGTH);
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data,
+ (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, 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 e7f1898e81..d3265f676e 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3386,9 +3386,9 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
* Apparently we're using a version-flexible SSL_METHOD (not at its
* highest protocol version).
*/
- if (s->ctx->method->version == SSLv23_method()->version) {
+ if (s->ctx->method->version == TLS_method()->version) {
#if TLS_MAX_VERSION != TLS1_2_VERSION
-# error Code needs update for SSLv23_method() support beyond TLS1_2_VERSION.
+# error Code needs update for TLS_method() support beyond TLS1_2_VERSION.
#endif
if (!(s->options & SSL_OP_NO_TLSv1_2))
return s->version == TLS1_2_VERSION;
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 4ee45eb57f..14daf8fe4e 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -256,7 +256,7 @@ int ssl3_accept(SSL *s)
if (cb != NULL)
cb(s, SSL_CB_HANDSHAKE_START, 1);
- if ((s->version >> 8) != 3) {
+ if ((s->version >> 8 != 3) && s->version != TLS_ANY_VERSION) {
SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR);
s->state = SSL_ST_ERR;
return -1;
@@ -905,6 +905,7 @@ int ssl3_get_client_hello(SSL *s)
SSL_COMP *comp = NULL;
#endif
STACK_OF(SSL_CIPHER) *ciphers = NULL;
+ int protverr = 1;
if (s->state == SSL3_ST_SR_CLNT_HELLO_C && !s->first_packet)
goto retry_cert;
@@ -930,29 +931,130 @@ int ssl3_get_client_hello(SSL *s)
s->first_packet = 0;
d = p = (unsigned char *)s->init_msg;
- /*
- * 2 bytes for client version, SSL3_RANDOM_SIZE bytes for random, 1 byte
- * for session id length
- */
- if (n < 2 + SSL3_RANDOM_SIZE + 1) {
- al = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
- goto f_err;
+ /* First lets get s->client_version set correctly */
+ if (!s->read_hash && !s->enc_read_ctx
+ && RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
+ if (n < MIN_SSL2_RECORD_LEN) {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_RECORD_LENGTH_MISMATCH);
+ al = SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+ /*-
+ * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2
+ * header is sent directly on the wire, not wrapped as a TLS
+ * record. Our record layer just processes the message length and passes
+ * the rest right through. Its format is:
+ * Byte Content
+ * 0-1 msg_length - decoded by the record layer
+ * 2 msg_type - s->init_msg points here
+ * 3-4 version
+ * 5-6 cipher_spec_length
+ * 7-8 session_id_length
+ * 9-10 challenge_length
+ * ... ...
+ */
+
+ if (p[0] != SSL2_MT_CLIENT_HELLO) {
+ /*
+ * Should never happen. We should have tested this in the record
+ * layer in order to have determined that this is a SSLv2 record
+ * in the first place
+ */
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+ goto f_err;
+ }
+
+ if ((p[1] == 0x00) && (p[2] == 0x02)) {
+ /* This is real SSLv2. We don't support it. */
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+ goto err;
+ } else if (p[1] == SSL3_VERSION_MAJOR) {
+ /* SSLv3/TLS */
+ s->client_version = (((int)p[1]) << 8) | (int)p[2];
+ } else {
+ /* No idea what protocol this is */
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+ goto err;
+ }
+ } else {
+ /*
+ * 2 bytes for client version, SSL3_RANDOM_SIZE bytes for random, 1 byte
+ * for session id length
+