A memory leak can occur in dtls1_buffer_record if either of the calls to
[openssl.git] / ssl / d1_pkt.c
index 20d24b6fd8da186f911a8bec9b7b94f740ef78ed..082b3fbf8b48ae804def01d843604427d0dcfe8c 100644 (file)
@@ -179,7 +179,6 @@ static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr,
 static int dtls1_buffer_record(SSL *s, record_pqueue *q,
        unsigned char *priority);
 static int dtls1_process_record(SSL *s);
-static void dtls1_clear_timeouts(SSL *s);
 
 /* copy buffered record into SSL structure */
 static int
@@ -196,6 +195,9 @@ dtls1_copy_record(SSL *s, pitem *item)
     s->packet_length = rdata->packet_length;
     memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
     memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
+       
+       /* Set proper sequence number for mac calculation */
+       memcpy(&(s->s3->read_sequence[2]), &(rdata->packet[5]), 6);
     
     return(1);
     }
@@ -210,7 +212,7 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
        /* Limit the size of the queue to prevent DOS attacks */
        if (pqueue_size(queue->q) >= 100)
                return 0;
-               
+
        rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA));
        item = pitem_new(priority, rdata);
        if (rdata == NULL || item == NULL)
@@ -229,13 +231,13 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
 
        item->data = rdata;
 
-       /* insert should not fail, since duplicates are dropped */
-       if (pqueue_insert(queue->q, item) == NULL)
-               {
-               OPENSSL_free(rdata);
-               pitem_free(item);
-               return(0);
-               }
+#ifndef OPENSSL_NO_SCTP
+       /* Store bio_dgram_sctp_rcvinfo struct */
+       if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+           (s->state == SSL3_ST_SR_FINISHED_A || s->state == SSL3_ST_CR_FINISHED_A)) {
+               BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_GET_RCVINFO, sizeof(rdata->recordinfo), &rdata->recordinfo);
+       }
+#endif
 
        s->packet = NULL;
        s->packet_length = 0;
@@ -245,11 +247,24 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
        if (!ssl3_setup_buffers(s))
                {
                SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR);
+               if (rdata->rbuf.buf != NULL)
+                       OPENSSL_free(rdata->rbuf.buf);
                OPENSSL_free(rdata);
                pitem_free(item);
-               return(0);
+               return(-1);
                }
-       
+
+       /* insert should not fail, since duplicates are dropped */
+       if (pqueue_insert(queue->q, item) == NULL)
+               {
+               SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR);
+               if (rdata->rbuf.buf != NULL)
+                       OPENSSL_free(rdata->rbuf.buf);
+               OPENSSL_free(rdata);
+               pitem_free(item);
+               return(-1);
+               }
+
        return(1);
        }
 
@@ -293,9 +308,6 @@ dtls1_process_buffered_records(SSL *s)
     item = pqueue_peek(s->d1->unprocessed_rcds.q);
     if (item)
         {
-        DTLS1_RECORD_DATA *rdata;
-        rdata = (DTLS1_RECORD_DATA *)item->data;
-        
         /* Check if epoch is current. */
         if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
             return(1);  /* Nothing to do. */
@@ -306,8 +318,9 @@ dtls1_process_buffered_records(SSL *s)
             dtls1_get_unprocessed_record(s);
             if ( ! dtls1_process_record(s))
                 return(0);
-            dtls1_buffer_record(s, &(s->d1->processed_rcds), 
-                s->s3->rrec.seq_num);
+            if(dtls1_buffer_record(s, &(s->d1->processed_rcds),
+                s->s3->rrec.seq_num)<0)
+                return -1;
             }
         }
 
@@ -369,14 +382,12 @@ static int
 dtls1_process_record(SSL *s)
 {
        int i,al;
-       int clear=0;
        int enc_err;
        SSL_SESSION *sess;
        SSL3_RECORD *rr;
-       unsigned int mac_size;
+       unsigned int mac_size, orig_len;
        unsigned char md[EVP_MAX_MD_SIZE];
 
-
        rr= &(s->s3->rrec);
        sess = s->session;
 
@@ -407,14 +418,16 @@ dtls1_process_record(SSL *s)
        rr->data=rr->input;
 
        enc_err = s->method->ssl3_enc->enc(s,0);
-       if (enc_err <= 0)
+       /* enc_err is:
+        *    0: (in non-constant time) if the record is publically invalid.
+        *    1: if the padding is valid
+        *    -1: if the padding is invalid */
+       if (enc_err == 0)
                {
-               if (enc_err == 0)
-                       /* SSLerr() and ssl3_send_alert() have been called */
-                       goto err;
-
-               /* otherwise enc_err == -1 */
-               goto decryption_failed_or_bad_record_mac;
+               /* For DTLS we simply ignore bad packets. */
+               rr->length = 0;
+               s->packet_length = 0;
+               goto err;
                }
 
 #ifdef TLS_DEBUG
@@ -424,46 +437,67 @@ printf("\n");
 #endif
 
        /* r->length is now the compressed data plus mac */
-       if (    (sess == NULL) ||
-               (s->enc_read_ctx == NULL) ||
-               (s->read_hash == NULL))
-               clear=1;
-
-       if (!clear)
+       if ((sess != NULL) &&
+           (s->enc_read_ctx != NULL) &&
+           (EVP_MD_CTX_md(s->read_hash) != NULL))
                {
-               /* !clear => s->read_hash != NULL => mac_size != -1 */
-               int t;
-               t=EVP_MD_CTX_size(s->read_hash);
-               OPENSSL_assert(t >= 0);
-               mac_size=t;
-
-               if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size)
-                       {
-#if 0 /* OK only for stream ciphers (then rr->length is visible from ciphertext anyway) */
-                       al=SSL_AD_RECORD_OVERFLOW;
-                       SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG);
-                       goto f_err;
-#else
-                       goto decryption_failed_or_bad_record_mac;
-#endif                 
-                       }
-               /* check the MAC for rr->input (it's in mac_size bytes at the tail) */
-               if (rr->length < mac_size)
+               /* s->read_hash != NULL => mac_size != -1 */
+               unsigned char *mac = NULL;
+               unsigned char mac_tmp[EVP_MAX_MD_SIZE];
+               mac_size=EVP_MD_CTX_size(s->read_hash);
+               OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
+
+               /* kludge: *_cbc_remove_padding passes padding length in rr->type */
+               orig_len = rr->length+((unsigned int)rr->type>>8);
+
+               /* orig_len is the length of the record before any padding was
+                * removed. This is public information, as is the MAC in use,
+                * therefore we can safely process the record in a different
+                * amount of time if it's too short to possibly contain a MAC.
+                */
+               if (orig_len < mac_size ||
+                   /* CBC records must have a padding length byte too. */
+                   (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+                    orig_len < mac_size+1))
                        {
-#if 0 /* OK only for stream ciphers */
                        al=SSL_AD_DECODE_ERROR;
                        SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_LENGTH_TOO_SHORT);
                        goto f_err;
-#else
-                       goto decryption_failed_or_bad_record_mac;
-#endif
                        }
-               rr->length-=mac_size;
-               i=s->method->ssl3_enc->mac(s,md,0);
-               if (i < 0 || memcmp(md,&(rr->data[rr->length]),mac_size) != 0)
+
+               if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE)
+                       {
+                       /* We update the length so that the TLS header bytes
+                        * can be constructed correctly but we need to extract
+                        * the MAC in constant time from within the record,
+                        * without leaking the contents of the padding bytes.
+                        * */
+                       mac = mac_tmp;
+                       ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len);
+                       rr->length -= mac_size;
+                       }
+               else
                        {
-                       goto decryption_failed_or_bad_record_mac;
+                       /* In this case there's no padding, so |orig_len|
+                        * equals |rec->length| and we checked that there's
+                        * enough bytes for |mac_size| above. */
+                       rr->length -= mac_size;
+                       mac = &rr->data[rr->length];
                        }
+
+               i=s->method->ssl3_enc->mac(s,md,0 /* not send */);
+               if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
+                       enc_err = -1;
+               if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size)
+                       enc_err = -1;
+               }
+
+       if (enc_err < 0)
+               {
+               /* decryption failed, silently discard message */
+               rr->length = 0;
+               s->packet_length = 0;
+               goto err;
                }
 
        /* r->length is now just compressed */
@@ -501,17 +535,8 @@ printf("\n");
 
        /* we have pulled in a full packet so zero things */
        s->packet_length=0;
-       dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */
        return(1);
 
-decryption_failed_or_bad_record_mac:
-       /* Separate 'decryption_failed' alert was introduced with TLS 1.0,
-        * SSL 3.0 only has 'bad_record_mac'.  But unless a decryption
-        * failure is directly visible from the ciphertext anyway,
-        * we should not reveal which kind of error occured -- this
-        * might become visible to an attacker (e.g. via logfile) */
-       al=SSL_AD_BAD_RECORD_MAC;
-       SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
 f_err:
        ssl3_send_alert(s,SSL3_AL_FATAL,al);
 err:
@@ -533,19 +558,17 @@ int dtls1_get_record(SSL *s)
        int ssl_major,ssl_minor;
        int i,n;
        SSL3_RECORD *rr;
-       SSL_SESSION *sess;
        unsigned char *p = NULL;
        unsigned short version;
        DTLS1_BITMAP *bitmap;
        unsigned int is_next_epoch;
 
        rr= &(s->s3->rrec);
-       sess=s->session;
 
        /* The epoch may have changed.  If so, process all the
         * pending records.  This is a non-blocking operation. */
-       if ( ! dtls1_process_buffered_records(s))
-            return 0;
+       if(dtls1_process_buffered_records(s)<0)
+               return -1;
 
        /* if we're renegotiating, then there may be buffered records */
        if (dtls1_get_processed_record(s))
@@ -572,6 +595,9 @@ again:
 
                p=s->packet;
 
+               if (s->msg_callback)
+                       s->msg_callback(0, 0, SSL3_RT_HEADER, p, DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+
                /* Pull apart the header into the DTLS1_RECORD */
                rr->type= *(p++);
                ssl_major= *(p++);
@@ -624,8 +650,6 @@ again:
                /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */
                i=rr->length;
                n=ssl3_read_n(s,i,i,1);
-               if (n <= 0) return(n); /* error or non-blocking io */
-
                /* this packet contained a partial record, dump it */
                if ( n != i)
                        {
@@ -648,42 +672,59 @@ again:
                goto again;   /* get another record */
                }
 
-       /* Check whether this is a repeat, or aged record.
-        * Don't check if we're listening and this message is
-        * a ClientHello. They can look as if they're replayed,
-        * since they arrive from different connections and
-        * would be dropped unnecessarily.
-        */
-       if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE &&
-               *p == SSL3_MT_CLIENT_HELLO) &&
-               !dtls1_record_replay_check(s, bitmap))
-               {
-               rr->length = 0;
-               s->packet_length=0; /* dump this record */
-               goto again;     /* get another record */
-               }
+#ifndef OPENSSL_NO_SCTP
+       /* Only do replay check if no SCTP bio */
+       if (!BIO_dgram_is_sctp(SSL_get_rbio(s)))
+               {
+#endif
+               /* Check whether this is a repeat, or aged record.
+                * Don't check if we're listening and this message is
+                * a ClientHello. They can look as if they're replayed,
+                * since they arrive from different connections and
+                * would be dropped unnecessarily.
+                */
+               if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE &&
+                   s->packet_length > DTLS1_RT_HEADER_LENGTH &&
+                   s->packet[DTLS1_RT_HEADER_LENGTH] == SSL3_MT_CLIENT_HELLO) &&
+                   !dtls1_record_replay_check(s, bitmap))
+                       {
+                       rr->length = 0;
+                       s->packet_length=0; /* dump this record */
+                       goto again;     /* get another record */
+                       }
+#ifndef OPENSSL_NO_SCTP
+               }
+#endif
 
        /* just read a 0 length packet */
        if (rr->length == 0) goto again;
 
        /* If this record is from the next epoch (either HM or ALERT),
         * and a handshake is currently in progress, buffer it since it
-        * cannot be processed at this time. */
+        * cannot be processed at this time. However, do not buffer
+        * anything while listening.
+        */
        if (is_next_epoch)
                {
-               if (SSL_in_init(s) || s->in_handshake)
+               if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen)
                        {
-                       dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num);
+                       if(dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num)<0)
+                               return -1;
+                       dtls1_record_bitmap_update(s, bitmap);/* Mark receipt of record. */
                        }
                rr->length = 0;
                s->packet_length = 0;
                goto again;
                }
 
-       if ( ! dtls1_process_record(s))
-               return(0);
+       if (!dtls1_process_record(s))
+               {
+               rr->length = 0;
+               s->packet_length = 0;  /* dump this record */
+               goto again;   /* get another record */
+               }
+       dtls1_record_bitmap_update(s, bitmap);/* Mark receipt of record. */
 
-       dtls1_clear_timeouts(s);  /* done waiting */
        return(1);
 
        }
@@ -741,7 +782,17 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
 
        /* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
 
+#ifndef OPENSSL_NO_SCTP
+       /* Continue handshake if it had to be interrupted to read
+        * app data with SCTP.
+        */
+       if ((!s->in_handshake && SSL_in_init(s)) ||
+           (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+            (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK) &&
+            s->s3->in_read_app_data != 2))
+#else
        if (!s->in_handshake && SSL_in_init(s))
+#endif
                {
                /* type == SSL3_RT_APPLICATION_DATA */
                i=s->handshake_func(s);
@@ -772,6 +823,15 @@ start:
                item = pqueue_pop(s->d1->buffered_app_data.q);
                if (item)
                        {
+#ifndef OPENSSL_NO_SCTP
+                       /* Restore bio_dgram_sctp_rcvinfo struct */
+                       if (BIO_dgram_is_sctp(SSL_get_rbio(s)))
+                               {
+                               DTLS1_RECORD_DATA *rdata = (DTLS1_RECORD_DATA *) item->data;
+                               BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_SET_RCVINFO, sizeof(rdata->recordinfo), &rdata->recordinfo);
+                               }
+#endif
+
                        dtls1_copy_record(s, item);
 
                        OPENSSL_free(item->data);
@@ -798,6 +858,12 @@ start:
                        }
                }
 
+       if (s->d1->listen && rr->type != SSL3_RT_HANDSHAKE)
+               {
+               rr->length = 0;
+               goto start;
+               }
+
        /* we now have a packet which can be read and processed */
 
        if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
@@ -809,7 +875,11 @@ start:
                 * buffer the application data for later processing rather
                 * than dropping the connection.
                 */
-               dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num);
+               if(dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num)<0)
+                       {
+                       SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR);
+                       return -1;
+                       }
                rr->length = 0;
                goto start;
                }
@@ -854,6 +924,31 @@ start:
                                rr->off=0;
                                }
                        }
+
+#ifndef OPENSSL_NO_SCTP
+                       /* We were about to renegotiate but had to read
+                        * belated application data first, so retry.
+                        */
+                       if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+                           rr->type == SSL3_RT_APPLICATION_DATA &&
+                           (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK))
+                               {
+                               s->rwstate=SSL_READING;
+                               BIO_clear_retry_flags(SSL_get_rbio(s));
+                               BIO_set_retry_read(SSL_get_rbio(s));
+                               }
+
+                       /* We might had to delay a close_notify alert because
+                        * of reordered app data. If there was an alert and there
+                        * is no message to read anymore, finally set shutdown.
+                        */
+                       if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+                           s->d1->shutdown_received && !BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
+                               {
+                               s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+                               return(0);
+                               }
+#endif                 
                return(n);
                }
 
@@ -881,6 +976,19 @@ start:
                        dest = s->d1->alert_fragment;
                        dest_len = &s->d1->alert_fragment_len;
                        }
+#ifndef OPENSSL_NO_HEARTBEATS
+               else if (rr->type == TLS1_RT_HEARTBEAT)
+                       {
+                       dtls1_process_heartbeat(s);
+
+                       /* Exit and notify application to read again */
+                       rr->length = 0;
+                       s->rwstate=SSL_READING;
+                       BIO_clear_retry_flags(SSL_get_rbio(s));
+                       BIO_set_retry_read(SSL_get_rbio(s));
+                       return(-1);
+                       }
+#endif
                /* else it's a CCS message, or application data or wrong */
                else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC)
                        {
@@ -964,6 +1072,8 @@ start:
                        !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
                        !s->s3->renegotiate)
                        {
+                       s->d1->handshake_read_seq++;
+                       s->new_session = 1;
                        ssl3_renegotiate(s);
                        if (ssl3_renegotiate_check(s))
                                {
@@ -1025,6 +1135,21 @@ start:
                        s->s3->warn_alert = alert_descr;
                        if (alert_descr == SSL_AD_CLOSE_NOTIFY)
                                {
+#ifndef OPENSSL_NO_SCTP
+                               /* With SCTP and streams the socket may deliver app data
+                                * after a close_notify alert. We have to check this
+                                * first so that nothing gets discarded.
+                                */
+                               if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+                                       BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
+                                       {
+                                       s->d1->shutdown_received = 1;
+                                       s->rwstate=SSL_READING;
+                                       BIO_clear_retry_flags(SSL_get_rbio(s));
+                                       BIO_set_retry_read(SSL_get_rbio(s));
+                                       return -1;
+                                       }
+#endif
                                s->shutdown |= SSL_RECEIVED_SHUTDOWN;
                                return(0);
                                }
@@ -1131,6 +1256,15 @@ start:
                if (s->version == DTLS1_BAD_VER)
                        s->d1->handshake_read_seq++;
 
+#ifndef OPENSSL_NO_SCTP
+               /* Remember that a CCS has been received,
+                * so that an old key of SCTP-Auth can be
+                * deleted when a CCS is sent. Will be ignored
+                * if no SCTP is used
+                */
+               BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD, 1, NULL);
+#endif
+
                goto start;
                }
 
@@ -1153,6 +1287,9 @@ start:
                 */
                if (msg_hdr.type == SSL3_MT_FINISHED)
                        {
+                       if (dtls1_check_timeout_num(s) < 0)
+                               return -1;
+
                        dtls1_retransmit_buffered_messages(s);
                        rr->length = 0;
                        goto start;
@@ -1170,6 +1307,7 @@ start:
 #else
                        s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
 #endif
+                       s->renegotiate=1;
                        s->new_session=1;
                        }
                i=s->handshake_func(s);
@@ -1266,7 +1404,16 @@ dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
        {
        int i;
 
-       if (SSL_in_init(s) && !s->in_handshake)
+#ifndef OPENSSL_NO_SCTP
+               /* Check if we have to continue an interrupted handshake
+                * for reading belated app data with SCTP.
+                */
+               if ((SSL_in_init(s) && !s->in_handshake) ||
+                   (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
+                    (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK)))
+#else
+               if (SSL_in_init(s) && !s->in_handshake)
+#endif
                {
                i=s->handshake_func(s);
                if (i < 0) return(i);
@@ -1340,10 +1487,10 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len,
        unsigned char *p,*pseq;
        int i,mac_size,clear=0;
        int prefix_len = 0;
+       int eivlen;
        SSL3_RECORD *wr;
        SSL3_BUFFER *wb;
        SSL_SESSION *sess;
-       int bs;
 
        /* first check if there is a SSL3_BUFFER still being written
         * out.  This will happen with non blocking IO */
@@ -1420,26 +1567,46 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len,
 
        *(p++)=type&0xff;
        wr->type=type;
-
-       *(p++)=(s->version>>8);
-       *(p++)=s->version&0xff;
+       /* Special case: for hello verify request, client version 1.0 and
+        * we haven't decided which version to use yet send back using 
+        * version 1.0 header: otherwise some clients will ignore it.
+        */
+       if (s->method->version == DTLS_ANY_VERSION)
+               {
+               *(p++)=DTLS1_VERSION>>8;
+               *(p++)=DTLS1_VERSION&0xff;
+               }
+       else
+               {
+               *(p++)=s->version>>8;
+               *(p++)=s->version&0xff;
+               }
 
        /* field where we are to write out packet epoch, seq num and len */
        pseq=p; 
        p+=10;
 
-       /* lets setup the record stuff. */
-
-       /* Make space for the explicit IV in case of CBC.
-        * (this is a bit of a boundary violation, but what the heck).
-        */
-       if ( s->enc_write_ctx && 
-               (EVP_CIPHER_mode( s->enc_write_ctx->cipher ) & EVP_CIPH_CBC_MODE))
-               bs = EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
-       else
-               bs = 0;
+       /* Explicit IV length, block ciphers appropriate version flag */
+       if (s->enc_write_ctx)
+               {
+               int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx);
+               if (mode == EVP_CIPH_CBC_MODE)
+                       {
+                       eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx);
+                       if (eivlen <= 1)
+                               eivlen = 0;
+                       }
+               /* Need explicit part of IV for GCM mode */
+               else if (mode == EVP_CIPH_GCM_MODE)
+                       eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
+               else
+                       eivlen = 0;
+               }
+       else 
+               eivlen = 0;
 
-       wr->data=p + bs;  /* make room for IV in case of CBC */
+       /* lets setup the record stuff. */
+       wr->data=p + eivlen;  /* make room for IV in case of CBC */
        wr->length=(int)len;
        wr->input=(unsigned char *)buf;
 
@@ -1467,7 +1634,7 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len,
 
        if (mac_size != 0)
                {
-               if(s->method->ssl3_enc->mac(s,&(p[wr->length + bs]),1) < 0)
+               if(s->method->ssl3_enc->mac(s,&(p[wr->length + eivlen]),1) < 0)
                        goto err;
                wr->length+=mac_size;
                }
@@ -1476,17 +1643,10 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len,
        wr->input=p;
        wr->data=p;
 
+       if (eivlen)
+               wr->length += eivlen;
 
-       /* ssl3_enc can only have an error on read */
-       if (bs) /* bs != 0 in case of CBC */
-               {
-               RAND_pseudo_bytes(p,bs);
-               /* master IV and last CBC residue stand for
-                * the rest of randomness */
-               wr->length += bs;
-               }
-
-       s->method->ssl3_enc->enc(s,1);
+       if(s->method->ssl3_enc->enc(s,1) < 1) goto err;
 
        /* record length after mac and block padding */
 /*     if (type == SSL3_RT_APPLICATION_DATA ||
@@ -1504,6 +1664,9 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len,
        pseq+=6;
        s2n(wr->length,pseq);
 
+       if (s->msg_callback)
+               s->msg_callback(1, 0, SSL3_RT_HEADER, pseq - DTLS1_RT_HEADER_LENGTH, DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+
        /* we should now have
         * wr->data pointing to the encrypted data, which is
         * wr->length long */
@@ -1766,10 +1929,3 @@ dtls1_reset_seq_numbers(SSL *s, int rw)
 
        memset(seq, 0x00, seq_bytes);
        }
-
-
-static void
-dtls1_clear_timeouts(SSL *s)
-       {
-       memset(&(s->d1->timeout), 0x00, sizeof(struct dtls1_timeout_st));
-       }