static void dtls1_clear_queues (SSL * s) { pitem *item = NULL; hm_fragment *frag = NULL; DTLS1_RECORD_DATA *rdata; while ((item = pqueue_pop (s->d1->unprocessed_rcds.q)) != NULL) { rdata = (DTLS1_RECORD_DATA *) item->data; if (rdata->rbuf.buf) { OPENSSL_free (rdata->rbuf.buf); } OPENSSL_free (item->data); pitem_free (item); } while ((item = pqueue_pop (s->d1->processed_rcds.q)) != NULL) { rdata = (DTLS1_RECORD_DATA *) item->data; if (rdata->rbuf.buf) { OPENSSL_free (rdata->rbuf.buf); } OPENSSL_free (item->data); pitem_free (item); } while ((item = pqueue_pop (s->d1->buffered_messages)) != NULL) { frag = (hm_fragment *) item->data; dtls1_hm_fragment_free (frag); pitem_free (item); } while ((item = pqueue_pop (s->d1->sent_messages)) != NULL) { frag = (hm_fragment *) item->data; dtls1_hm_fragment_free (frag); pitem_free (item); } while ((item = pqueue_pop (s->d1->buffered_app_data.q)) != NULL) { rdata = (DTLS1_RECORD_DATA *) item->data; if (rdata->rbuf.buf) { OPENSSL_free (rdata->rbuf.buf); } OPENSSL_free (item->data); pitem_free (item); } }
static void dtls1_clear_queues(SSL *s) { pitem *item = NULL; hm_fragment *frag = NULL; while ((item = pqueue_pop(s->d1->buffered_messages)) != NULL) { frag = (hm_fragment *)item->data; dtls1_hm_fragment_free(frag); pitem_free(item); } while ((item = pqueue_pop(s->d1->sent_messages)) != NULL) { frag = (hm_fragment *)item->data; dtls1_hm_fragment_free(frag); pitem_free(item); } }
static int dtls1_buffer_handshake_fragment(SSL *s, struct hm_header_st* msg_hdr) { hm_fragment *frag = NULL; pitem *item = NULL; PQ_64BIT seq64; frag = dtls1_hm_fragment_new(msg_hdr->frag_len); if ( frag == NULL) goto err; memcpy(frag->fragment, &(s->init_buf->data[s->init_num]), msg_hdr->frag_len + DTLS1_HM_HEADER_LENGTH); memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, msg_hdr->seq); item = pitem_new(seq64, frag); if ( item == NULL) goto err; pq_64bit_free(&seq64); pqueue_insert(s->d1->buffered_messages, item); return 1; err: if ( frag != NULL) dtls1_hm_fragment_free(frag); if ( item != NULL) OPENSSL_free(item); return 0; }
static int dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok) { int i=-1; hm_fragment *frag = NULL; pitem *item = NULL; PQ_64BIT seq64; unsigned long frag_len = msg_hdr->frag_len; if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len) goto err; if (msg_hdr->seq <= s->d1->handshake_read_seq) { unsigned char devnull [256]; while (frag_len) { i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, devnull, frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0); if (i<=0) goto err; frag_len -= i; } } frag = dtls1_hm_fragment_new(frag_len); if ( frag == NULL) goto err; memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); if (frag_len) { /* read the body of the fragment (header has already been read */ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, frag->fragment,frag_len,0); if (i<=0 || (unsigned long)i!=frag_len) goto err; } pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, msg_hdr->seq); item = pitem_new(seq64, frag); pq_64bit_free(&seq64); if ( item == NULL) goto err; pqueue_insert(s->d1->buffered_messages, item); return DTLS1_HM_FRAGMENT_RETRY; err: if ( frag != NULL) dtls1_hm_fragment_free(frag); if ( item != NULL) OPENSSL_free(item); *ok = 0; return i; }
int dtls1_buffer_message(SSL *s, int is_ccs) { pitem *item; hm_fragment *frag; PQ_64BIT seq64; unsigned int epoch = s->d1->w_epoch; /* this function is called immediately after a message has * been serialized */ OPENSSL_assert(s->init_off == 0); frag = dtls1_hm_fragment_new(s->init_num); memcpy(frag->fragment, s->init_buf->data, s->init_num); if ( is_ccs) { OPENSSL_assert(s->d1->w_msg_hdr.msg_len + DTLS1_CCS_HEADER_LENGTH <= (unsigned int)s->init_num); epoch++; } else { OPENSSL_assert(s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num); } frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len; frag->msg_header.seq = s->d1->w_msg_hdr.seq; frag->msg_header.type = s->d1->w_msg_hdr.type; frag->msg_header.frag_off = 0; frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len; frag->msg_header.is_ccs = is_ccs; pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, epoch<<16 | frag->msg_header.seq); item = pitem_new(seq64, frag); pq_64bit_free(&seq64); if ( item == NULL) { dtls1_hm_fragment_free(frag); return 0; } #if 0 fprintf( stderr, "buffered messge: \ttype = %xx\n", msg_buf->type); fprintf( stderr, "\t\t\t\t\tlen = %d\n", msg_buf->len); fprintf( stderr, "\t\t\t\t\tseq_num = %d\n", msg_buf->seq_num); #endif pqueue_insert(s->d1->sent_messages, item); return 1; }
static int dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok) { /* (0) check whether the desired fragment is available * if so: * (1) copy over the fragment to s->init_buf->data[] * (2) update s->init_num */ pitem *item; hm_fragment *frag; int al; *ok = 0; item = pqueue_peek(s->d1->buffered_messages); if ( item == NULL) return 0; frag = (hm_fragment *)item->data; /* Don't return if reassembly still in progress */ if (frag->reassembly != NULL) return 0; if ( s->d1->handshake_read_seq == frag->msg_header.seq) { unsigned long frag_len = frag->msg_header.frag_len; pqueue_pop(s->d1->buffered_messages); al=dtls1_preprocess_fragment(s,&frag->msg_header,max); if (al==0) /* no alert */ { unsigned char *p = (unsigned char *)s->init_buf->data+DTLS1_HM_HEADER_LENGTH; memcpy(&p[frag->msg_header.frag_off], frag->fragment,frag->msg_header.frag_len); } dtls1_hm_fragment_free(frag); pitem_free(item); if (al==0) { *ok = 1; return frag_len; } ssl3_send_alert(s,SSL3_AL_FATAL,al); s->init_num = 0; *ok = 0; return -1; } else return 0; }
/* call this function when the buffered messages are no longer needed */ void dtls1_clear_record_buffer(SSL *s) { pitem *item; for(item = pqueue_pop(s->d1->sent_messages); item != NULL; item = pqueue_pop(s->d1->sent_messages)) { dtls1_hm_fragment_free((hm_fragment *)item->data); pitem_free(item); } }
static int dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok) { int i=-1; hm_fragment *frag = NULL; pitem *item = NULL; PQ_64BIT seq64; unsigned long frag_len = msg_hdr->frag_len; if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len) goto err; /* Try to find item in queue, to prevent duplicate entries */ pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, msg_hdr->seq); item = pqueue_find(s->d1->buffered_messages, seq64); pq_64bit_free(&seq64); /* If we already have an entry and this one is a fragment, * don't discard it and rather try to reassemble it. */ if (item != NULL && frag_len < msg_hdr->msg_len) item = NULL; /* Discard the message if sequence number was already there, is * too far in the future, already in the queue or if we received * a FINISHED before the SERVER_HELLO, which then must be a stale * retransmit. */ if (msg_hdr->seq <= s->d1->handshake_read_seq || msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL || (s->d1->handshake_read_seq == 0 && msg_hdr->type == SSL3_MT_FINISHED)) { unsigned char devnull [256]; while (frag_len) { i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, devnull, frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0); if (i<=0) goto err; frag_len -= i; } } else { if (frag_len && frag_len < msg_hdr->msg_len) return dtls1_reassemble_fragment(s, msg_hdr, ok); frag = dtls1_hm_fragment_new(frag_len, 0); if ( frag == NULL) goto err; memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); if (frag_len) { /* read the body of the fragment (header has already been read) */ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, frag->fragment,frag_len,0); if (i<=0 || (unsigned long)i!=frag_len) goto err; } pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, msg_hdr->seq); item = pitem_new(seq64, frag); pq_64bit_free(&seq64); if ( item == NULL) goto err; pqueue_insert(s->d1->buffered_messages, item); } return DTLS1_HM_FRAGMENT_RETRY; err: if ( frag != NULL) dtls1_hm_fragment_free(frag); if ( item != NULL) OPENSSL_free(item); *ok = 0; return i; }
static int dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok) { hm_fragment *frag = NULL; pitem *item = NULL; int i = -1, is_complete; PQ_64BIT seq64; unsigned long frag_len = msg_hdr->frag_len, max_len; if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len) goto err; /* Determine maximum allowed message size. Depends on (user set) * maximum certificate length, but 16k is minimum. */ if (DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH < s->max_cert_list) max_len = s->max_cert_list; else max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH; if ((msg_hdr->frag_off+frag_len) > max_len) goto err; /* Try to find item in queue */ pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, msg_hdr->seq); item = pqueue_find(s->d1->buffered_messages, seq64); pq_64bit_free(&seq64); if (item == NULL) { frag = dtls1_hm_fragment_new(msg_hdr->msg_len, 1); if ( frag == NULL) goto err; memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); frag->msg_header.frag_len = frag->msg_header.msg_len; frag->msg_header.frag_off = 0; } else { frag = (hm_fragment*) item->data; if (frag->msg_header.msg_len != msg_hdr->msg_len) { item = NULL; frag = NULL; goto err; } } /* If message is already reassembled, this must be a * retransmit and can be dropped. */ if (frag->reassembly == NULL) { unsigned char devnull [256]; while (frag_len) { i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, devnull, frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0); if (i<=0) goto err; frag_len -= i; } return DTLS1_HM_FRAGMENT_RETRY; } /* read the body of the fragment (header has already been read */ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, frag->fragment + msg_hdr->frag_off,frag_len,0); if (i<=0 || (unsigned long)i!=frag_len) goto err; RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off, (long)(msg_hdr->frag_off + frag_len)); RSMBLY_BITMASK_IS_COMPLETE(frag->reassembly, (long)msg_hdr->msg_len, is_complete); if (is_complete) { OPENSSL_free(frag->reassembly); frag->reassembly = NULL; } if (item == NULL) { pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, msg_hdr->seq); item = pitem_new(seq64, frag); pq_64bit_free(&seq64); if (item == NULL) { i = -1; goto err; } pqueue_insert(s->d1->buffered_messages, item); } return DTLS1_HM_FRAGMENT_RETRY; err: if (frag != NULL) dtls1_hm_fragment_free(frag); if (item != NULL) OPENSSL_free(item); *ok = 0; return i; }
int dtls1_buffer_message(SSL *s, int is_ccs) { pitem *item; hm_fragment *frag; PQ_64BIT seq64; /* this function is called immediately after a message has * been serialized */ OPENSSL_assert(s->init_off == 0); frag = dtls1_hm_fragment_new(s->init_num, 0); memcpy(frag->fragment, s->init_buf->data, s->init_num); if ( is_ccs) { OPENSSL_assert(s->d1->w_msg_hdr.msg_len + DTLS1_CCS_HEADER_LENGTH <= (unsigned int)s->init_num); } else { OPENSSL_assert(s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num); } frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len; frag->msg_header.seq = s->d1->w_msg_hdr.seq; frag->msg_header.type = s->d1->w_msg_hdr.type; frag->msg_header.frag_off = 0; frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len; frag->msg_header.is_ccs = is_ccs; /* save current state*/ frag->msg_header.saved_retransmit_state.enc_write_ctx = s->enc_write_ctx; frag->msg_header.saved_retransmit_state.write_hash = s->write_hash; frag->msg_header.saved_retransmit_state.compress = s->compress; frag->msg_header.saved_retransmit_state.session = s->session; frag->msg_header.saved_retransmit_state.epoch = s->d1->w_epoch; pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, dtls1_get_queue_priority(frag->msg_header.seq, frag->msg_header.is_ccs)); item = pitem_new(seq64, frag); pq_64bit_free(&seq64); if ( item == NULL) { dtls1_hm_fragment_free(frag); return 0; } #if 0 fprintf( stderr, "buffered messge: \ttype = %xx\n", msg_buf->type); fprintf( stderr, "\t\t\t\t\tlen = %d\n", msg_buf->len); fprintf( stderr, "\t\t\t\t\tseq_num = %d\n", msg_buf->seq_num); #endif pqueue_insert(s->d1->sent_messages, item); return 1; }
static int dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok) { int i=-1; hm_fragment *frag = NULL; pitem *item = NULL; PQ_64BIT seq64; unsigned long frag_len = msg_hdr->frag_len; if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len) goto err; /* Try to find item in queue, to prevent duplicate entries */ pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, msg_hdr->seq); item = pqueue_find(s->d1->buffered_messages, seq64); pq_64bit_free(&seq64); /* Discard the message if sequence number was already there, is * too far in the future or the fragment is already in the queue */ if (msg_hdr->seq <= s->d1->handshake_read_seq || msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL) { unsigned char devnull [256]; while (frag_len) { i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, devnull, frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0); if (i<=0) goto err; frag_len -= i; } } if (frag_len) { frag = dtls1_hm_fragment_new(frag_len); if ( frag == NULL) goto err; memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); /* read the body of the fragment (header has already been read) */ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, frag->fragment,frag_len,0); if (i<=0 || (unsigned long)i!=frag_len) goto err; pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, msg_hdr->seq); item = pitem_new(seq64, frag); pq_64bit_free(&seq64); if ( item == NULL) goto err; pqueue_insert(s->d1->buffered_messages, item); } return DTLS1_HM_FRAGMENT_RETRY; err: if ( frag != NULL) dtls1_hm_fragment_free(frag); if ( item != NULL) OPENSSL_free(item); *ok = 0; return i; }