void dtls1_clear(SSL *s) { pqueue unprocessed_rcds; pqueue processed_rcds; pqueue buffered_messages; pqueue sent_messages; pqueue buffered_app_data; unsigned int mtu; if (s->d1) { unprocessed_rcds = s->d1->unprocessed_rcds.q; processed_rcds = s->d1->processed_rcds.q; buffered_messages = s->d1->buffered_messages; sent_messages = s->d1->sent_messages; buffered_app_data = s->d1->buffered_app_data.q; mtu = s->d1->mtu; dtls1_clear_queues(s); pq_64bit_free(&(s->d1->bitmap.map)); pq_64bit_free(&(s->d1->bitmap.max_seq_num)); pq_64bit_free(&(s->d1->next_bitmap.map)); pq_64bit_free(&(s->d1->next_bitmap.max_seq_num)); memset(s->d1, 0, sizeof(*(s->d1))); if (s->server) { s->d1->cookie_len = sizeof(s->d1->cookie); } if (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU) { s->d1->mtu = mtu; } s->d1->unprocessed_rcds.q = unprocessed_rcds; s->d1->processed_rcds.q = processed_rcds; s->d1->buffered_messages = buffered_messages; s->d1->sent_messages = sent_messages; s->d1->buffered_app_data.q = buffered_app_data; #if defined(OPENSSL_SYS_VMS) || defined(VMS_TEST) s->d1->bitmap.length = 64; #else s->d1->bitmap.length = sizeof(s->d1->bitmap.map) * 8; #endif pq_64bit_init(&(s->d1->bitmap.map)); pq_64bit_init(&(s->d1->bitmap.max_seq_num)); s->d1->next_bitmap.length = s->d1->bitmap.length; pq_64bit_init(&(s->d1->next_bitmap.map)); pq_64bit_init(&(s->d1->next_bitmap.max_seq_num)); } ssl3_clear(s); if (s->options & SSL_OP_CISCO_ANYCONNECT) s->version = DTLS1_BAD_VER; else s->version = DTLS1_VERSION; }
int dtls1_new(SSL *s) { DTLS1_STATE *d1; if (!ssl3_new(s)) return (0); if ((d1 = OPENSSL_malloc(sizeof *d1)) == NULL) return (0); memset(d1, 0, sizeof *d1); /* d1->handshake_epoch=0; */ #if defined(OPENSSL_SYS_VMS) || defined(VMS_TEST) d1->bitmap.length = 64; #else d1->bitmap.length = sizeof(d1->bitmap.map) * 8; #endif pq_64bit_init(&(d1->bitmap.map)); pq_64bit_init(&(d1->bitmap.max_seq_num)); d1->next_bitmap.length = d1->bitmap.length; pq_64bit_init(&(d1->next_bitmap.map)); pq_64bit_init(&(d1->next_bitmap.max_seq_num)); d1->unprocessed_rcds.q = pqueue_new(); d1->processed_rcds.q = pqueue_new(); d1->buffered_messages = pqueue_new(); d1->sent_messages = pqueue_new(); d1->buffered_app_data.q = pqueue_new(); if (s->server) { d1->cookie_len = sizeof(s->d1->cookie); } if (!d1->unprocessed_rcds.q || !d1->processed_rcds.q || !d1->buffered_messages || !d1->sent_messages || !d1->buffered_app_data.q) { if (d1->unprocessed_rcds.q) pqueue_free(d1->unprocessed_rcds.q); if (d1->processed_rcds.q) pqueue_free(d1->processed_rcds.q); if (d1->buffered_messages) pqueue_free(d1->buffered_messages); if (d1->sent_messages) pqueue_free(d1->sent_messages); if (d1->buffered_app_data.q) pqueue_free(d1->buffered_app_data.q); OPENSSL_free(d1); return (0); } s->d1 = d1; s->method->ssl_clear(s); return (1); }
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; }
int dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, int *found) { int ret; /* XDTLS: for now assuming that read/writes are blocking */ pitem *item; hm_fragment *frag ; unsigned long header_length; PQ_64BIT seq64; /* OPENSSL_assert(s->init_num == 0); OPENSSL_assert(s->init_off == 0); */ /* XDTLS: the requested message ought to be found, otherwise error */ pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, seq); item = pqueue_find(s->d1->sent_messages, seq64); pq_64bit_free(&seq64); if ( item == NULL) { fprintf(stderr, "retransmit: message %d non-existant\n", seq); *found = 0; return 0; } *found = 1; frag = (hm_fragment *)item->data; if ( frag->msg_header.is_ccs) header_length = DTLS1_CCS_HEADER_LENGTH; else header_length = DTLS1_HM_HEADER_LENGTH; memcpy(s->init_buf->data, frag->fragment, frag->msg_header.msg_len + header_length); s->init_num = frag->msg_header.msg_len + header_length; dtls1_set_message_header_int(s, frag->msg_header.type, frag->msg_header.msg_len, frag->msg_header.seq, 0, frag->msg_header.frag_len); s->d1->retransmitting = 1; ret = dtls1_do_write(s, frag->msg_header.is_ccs ? SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE); s->d1->retransmitting = 0; (void)BIO_flush(SSL_get_wbio(s)); return ret; }
pitem * pitem_new(PQ_64BIT priority, void *data) { pitem *item = (pitem *) OPENSSL_malloc(sizeof(pitem)); if (item == NULL) return NULL; pq_64bit_init(&(item->priority)); pq_64bit_assign(&item->priority, &priority); item->data = data; item->next = NULL; return 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_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, int *found) { int ret; /* XDTLS: for now assuming that read/writes are blocking */ pitem *item; hm_fragment *frag ; unsigned long header_length; PQ_64BIT seq64; struct dtls1_retransmit_state saved_state; unsigned char save_write_sequence[8]; /* OPENSSL_assert(s->init_num == 0); OPENSSL_assert(s->init_off == 0); */ /* XDTLS: the requested message ought to be found, otherwise error */ pq_64bit_init(&seq64); pq_64bit_assign_word(&seq64, seq); item = pqueue_find(s->d1->sent_messages, seq64); pq_64bit_free(&seq64); if ( item == NULL) { fprintf(stderr, "retransmit: message %d non-existant\n", seq); *found = 0; return 0; } *found = 1; frag = (hm_fragment *)item->data; if ( frag->msg_header.is_ccs) header_length = DTLS1_CCS_HEADER_LENGTH; else header_length = DTLS1_HM_HEADER_LENGTH; memcpy(s->init_buf->data, frag->fragment, frag->msg_header.msg_len + header_length); s->init_num = frag->msg_header.msg_len + header_length; dtls1_set_message_header_int(s, frag->msg_header.type, frag->msg_header.msg_len, frag->msg_header.seq, 0, frag->msg_header.frag_len); /* save current state */ saved_state.enc_write_ctx = s->enc_write_ctx; saved_state.write_hash = s->write_hash; saved_state.compress = s->compress; saved_state.session = s->session; saved_state.epoch = s->d1->w_epoch; saved_state.epoch = s->d1->w_epoch; s->d1->retransmitting = 1; /* restore state in which the message was originally sent */ s->enc_write_ctx = frag->msg_header.saved_retransmit_state.enc_write_ctx; s->write_hash = frag->msg_header.saved_retransmit_state.write_hash; s->compress = frag->msg_header.saved_retransmit_state.compress; s->session = frag->msg_header.saved_retransmit_state.session; s->d1->w_epoch = frag->msg_header.saved_retransmit_state.epoch; if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1) { memcpy(save_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence)); memcpy(s->s3->write_sequence, s->d1->last_write_sequence, sizeof(s->s3->write_sequence)); } ret = dtls1_do_write(s, frag->msg_header.is_ccs ? SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE); /* restore current state */ s->enc_write_ctx = saved_state.enc_write_ctx; s->write_hash = saved_state.write_hash; s->compress = saved_state.compress; s->session = saved_state.session; s->d1->w_epoch = saved_state.epoch; if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1) { memcpy(s->d1->last_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence)); memcpy(s->s3->write_sequence, save_write_sequence, sizeof(s->s3->write_sequence)); } s->d1->retransmitting = 0; (void)BIO_flush(SSL_get_wbio(s)); return ret; }
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; }