From b452f43322d1a39cc23526948fe67918f0a034a7 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Sun, 19 Apr 2009 18:03:13 +0000 Subject: [PATCH] PR: 1751 Submitted by: David Woodhouse Approved by: steve@openssl.org Compatibility patches for Cisco VPN client DTLS. --- ssl/d1_both.c | 17 +++++++++++++---- ssl/d1_clnt.c | 5 +++-- ssl/d1_lib.c | 5 ++++- ssl/d1_pkt.c | 14 ++++++++++---- ssl/d1_srvr.c | 3 ++- ssl/dtls1.h | 1 + ssl/s3_clnt.c | 2 +- ssl/s3_pkt.c | 7 ++++--- ssl/s3_srvr.c | 2 +- ssl/ssl.h | 2 ++ ssl/ssl_lib.c | 3 ++- ssl/ssl_sess.c | 5 +++++ ssl/t1_enc.c | 4 ++-- 13 files changed, 50 insertions(+), 20 deletions(-) diff --git a/ssl/d1_both.c b/ssl/d1_both.c index 9130983611..1abfd0007a 100644 --- a/ssl/d1_both.c +++ b/ssl/d1_both.c @@ -300,7 +300,7 @@ int dtls1_do_write(SSL *s, int type) const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; int xlen; - if (frag_off == 0) + if (frag_off == 0 && s->version != DTLS1_BAD_VER) { /* reconstruct message header is if it * is being sent in single fragment */ @@ -407,8 +407,10 @@ long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok) s2n (msg_hdr->seq,p); l2n3(0,p); l2n3(msg_len,p); - p -= DTLS1_HM_HEADER_LENGTH; - msg_len += DTLS1_HM_HEADER_LENGTH; + if (s->version != DTLS1_BAD_VER) { + p -= DTLS1_HM_HEADER_LENGTH; + msg_len += DTLS1_HM_HEADER_LENGTH; + } ssl3_finish_mac(s, p, msg_len); if (s->msg_callback) @@ -775,6 +777,13 @@ int dtls1_send_change_cipher_spec(SSL *s, int a, int b) *p++=SSL3_MT_CCS; s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; s->init_num=DTLS1_CCS_HEADER_LENGTH; + + if (s->version == DTLS1_BAD_VER) { + s->d1->next_handshake_write_seq++; + s2n(s->d1->handshake_write_seq,p); + s->init_num+=2; + } + s->init_off=0; dtls1_set_message_header_int(s, SSL3_MT_CCS, 0, @@ -989,7 +998,7 @@ dtls1_buffer_message(SSL *s, int is_ccs) if ( is_ccs) { OPENSSL_assert(s->d1->w_msg_hdr.msg_len + - DTLS1_CCS_HEADER_LENGTH == (unsigned int)s->init_num); + ((s->version==DTLS1_VERSION)?DTLS1_CCS_HEADER_LENGTH:3) == (unsigned int)s->init_num); } else { diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c index c151264e56..b2ed383c34 100644 --- a/ssl/d1_clnt.c +++ b/ssl/d1_clnt.c @@ -130,7 +130,7 @@ static int dtls1_get_hello_verify(SSL *s); static const SSL_METHOD *dtls1_get_client_method(int ver) { - if (ver == DTLS1_VERSION) + if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER) return(DTLSv1_client_method()); else return(NULL); @@ -181,7 +181,8 @@ int dtls1_connect(SSL *s) s->server=0; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1); - if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00)) + if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00) && + (s->version & 0xff00 ) != (DTLS1_BAD_VER & 0xff00)) { SSLerr(SSL_F_DTLS1_CONNECT, ERR_R_INTERNAL_ERROR); ret = -1; diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index be47541440..712b880f91 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -176,7 +176,10 @@ void dtls1_free(SSL *s) void dtls1_clear(SSL *s) { ssl3_clear(s); - s->version=DTLS1_VERSION; + if (s->options & SSL_OP_CISCO_ANYCONNECT) + s->version=DTLS1_BAD_VER; + else + s->version=DTLS1_VERSION; } /* diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c index 2e9d5452f7..918dc70798 100644 --- a/ssl/d1_pkt.c +++ b/ssl/d1_pkt.c @@ -591,7 +591,7 @@ again: } } - if ((version & 0xff00) != (DTLS1_VERSION & 0xff00)) + if ((version & 0xff00) != (s->version & 0xff00)) { SSLerr(SSL_F_DTLS1_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER); goto err; @@ -1067,13 +1067,17 @@ start: if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { struct ccs_header_st ccs_hdr; + int ccs_hdr_len = DTLS1_CCS_HEADER_LENGTH; dtls1_get_ccs_header(rr->data, &ccs_hdr); + if (s->version == DTLS1_BAD_VER) + ccs_hdr_len = 3; + /* 'Change Cipher Spec' is just a single byte, so we know * exactly what the record payload has to look like */ /* XDTLS: check that epoch is consistent */ - if ( (rr->length != DTLS1_CCS_HEADER_LENGTH) || + if ( (rr->length != ccs_hdr_len) || (rr->off != 0) || (rr->data[0] != SSL3_MT_CCS)) { i=SSL_AD_ILLEGAL_PARAMETER; @@ -1094,6 +1098,9 @@ start: /* do this whenever CCS is processed */ dtls1_reset_seq_numbers(s, SSL3_CC_READ); + if (s->version == DTLS1_BAD_VER) + s->d1->handshake_read_seq++; + goto start; } @@ -1401,7 +1408,7 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, #if 0 /* 'create_empty_fragment' is true only when this function calls itself */ if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done - && SSL_version(s) != DTLS1_VERSION) + && SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER) { /* countermeasure against known-IV weakness in CBC ciphersuites * (see http://www.openssl.org/~bodo/tls-cbc.txt) @@ -1428,7 +1435,6 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, s->s3->empty_fragment_done = 1; } #endif - p = wb->buf + prefix_len; /* write the header */ diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c index ebd35c7161..666ab75d1d 100644 --- a/ssl/d1_srvr.c +++ b/ssl/d1_srvr.c @@ -292,7 +292,8 @@ int dtls1_accept(SSL *s) s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A; /* HelloVerifyRequest resets Finished MAC */ - ssl3_init_finished_mac(s); + if (s->version != DTLS1_BAD_VER) + ssl3_init_finished_mac(s); break; case SSL3_ST_SW_SRVR_HELLO_A: diff --git a/ssl/dtls1.h b/ssl/dtls1.h index cb8bd7cdfe..2066638f94 100644 --- a/ssl/dtls1.h +++ b/ssl/dtls1.h @@ -68,6 +68,7 @@ extern "C" { #endif #define DTLS1_VERSION 0xFEFF +#define DTLS1_BAD_VER 0x0100 #if 0 /* this alert description is not specified anywhere... */ diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index f83389b543..ceab11eb4a 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -737,7 +737,7 @@ int ssl3_get_server_hello(SSL *s) if (!ok) return((int)n); - if ( SSL_version(s) == DTLS1_VERSION) + if ( SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) { if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) { diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c index 2ae6b59402..77cf037eed 100644 --- a/ssl/s3_pkt.c +++ b/ssl/s3_pkt.c @@ -177,8 +177,8 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) } /* extend reads should not span multiple packets for DTLS */ - if ( SSL_version(s) == DTLS1_VERSION && - extend) + if ( (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) + && extend) { if ( left > 0 && n > left) n = left; @@ -836,7 +836,8 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, return(s->s3->wpend_ret); } else if (i <= 0) { - if (s->version == DTLS1_VERSION) { + if (s->version == DTLS1_VERSION || + s->version == DTLS1_BAD_VER) { /* For DTLS, just drop it. That's kind of the whole point in using a datagram service */ wb->left = 0; diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 44a67f86d5..55b2166d2b 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -1920,7 +1920,7 @@ int ssl3_get_client_key_exchange(SSL *s) } /* TLS and [incidentally] DTLS{0xFEFF} */ - if (s->version > SSL3_VERSION) + if (s->version > SSL3_VERSION && s->version != DTLS1_BAD_VER) { n2s(p,i); if (n != i+2) diff --git a/ssl/ssl.h b/ssl/ssl.h index a9d1fa5fcc..82fa94a07d 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -542,6 +542,8 @@ typedef struct ssl_session_st #define SSL_OP_COOKIE_EXCHANGE 0x00002000L /* Don't use RFC4507 ticket extension */ #define SSL_OP_NO_TICKET 0x00004000L +/* Use Cisco's "speshul" version of DTLS_BAD_VER (as client) */ +#define SSL_OP_CISCO_ANYCONNECT 0x00008000L /* As server, disallow session resumption on renegotiation */ #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 24cd4268e4..f305bc7b36 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1038,7 +1038,8 @@ long SSL_ctrl(SSL *s,int cmd,long larg,void *parg) s->max_cert_list=larg; return(l); case SSL_CTRL_SET_MTU: - if (SSL_version(s) == DTLS1_VERSION) + if (SSL_version(s) == DTLS1_VERSION || + SSL_version(s) == DTLS1_BAD_VER) { s->d1->mtu = larg; return larg; diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index 4c72f18a75..bebbfa099d 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -300,6 +300,11 @@ int ssl_get_new_session(SSL *s, int session) ss->ssl_version=TLS1_VERSION; ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; } + else if (s->version == DTLS1_BAD_VER) + { + ss->ssl_version=DTLS1_BAD_VER; + ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; + } else if (s->version == DTLS1_VERSION) { ss->ssl_version=DTLS1_VERSION; diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index e351738237..d9cb059d0c 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -882,7 +882,7 @@ int tls1_mac(SSL *ssl, unsigned char *md, int send) mac_ctx = &hmac; } - if (ssl->version == DTLS1_VERSION) + if (ssl->version == DTLS1_VERSION || ssl->version == DTLS1_BAD_VER) { unsigned char dtlsseq[8],*p=dtlsseq; @@ -911,7 +911,7 @@ printf("rec="); {unsigned int z; for (z=0; zlength; z++) printf("%02X ",buf[z]); printf("\n"); } #endif - if (ssl->version != DTLS1_VERSION) + if (ssl->version != DTLS1_VERSION && ssl->version != DTLS1_BAD_VER) { for (i=7; i>=0; i--) { -- 2.34.1