static void dtls1_clear_queues(SSL *s) { pitem *item = 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_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); } dtls1_clear_received_buffer(s); dtls1_clear_sent_buffer(s); }
int main(void) { pitem *item; pqueue pq; pq = pqueue_new(); item = pitem_new(3, NULL); pqueue_insert(pq, item); item = pitem_new(1, NULL); pqueue_insert(pq, item); item = pitem_new(2, NULL); pqueue_insert(pq, item); item = pqueue_find(pq, 1); fprintf(stderr, "found %ld\n", item->priority); item = pqueue_find(pq, 2); fprintf(stderr, "found %ld\n", item->priority); item = pqueue_find(pq, 3); fprintf(stderr, "found %ld\n", item ? item->priority: 0); pqueue_print(pq); for(item = pqueue_pop(pq); item != NULL; item = pqueue_pop(pq)) pitem_free(item); pqueue_free(pq); return 0; }
int main(void) { int i; int p; pqueue_t *pq; node_t *ns; node_t *n; /* We will need (N + 1) slots in "pris" vector. Extra one slot for spare * usages. */ pris = malloc(5 * sizeof(int *)); for (i = 0; i < 5; i++) pris[i] = malloc(2 * sizeof(int)); pris[0][0] = 4; pris[0][1] = 2; pris[1][0] = 3; pris[1][1] = 7; pris[2][0] = 3; pris[2][1] = 1; pris[3][0] = 5; pris[3][1] = 6; p = 4; /* Initialize spare slot. */ pq = pqueue_init(10, cmp_pri, get_pri, set_pri, get_pos, set_pos); ns = malloc(4 * sizeof(node_t)); ns[0].pri = 0; ns[0].val = 0; pqueue_insert(pq, &ns[0]); ns[1].pri = 1; ns[0].val = 1; pqueue_insert(pq, &ns[1]); ns[2].pri = 2; ns[0].val = 2; pqueue_insert(pq, &ns[2]); ns[3].pri = 3; ns[0].val = 3; pqueue_insert(pq, &ns[3]); printf("initial:\n"); pqueue_print(pq, stdout, pr_node); n = pqueue_pop(pq); printf("[pop] pri: %d, val: %d, real-pri: [%d %d]\n", n->pri, n->val, pris[n->pri][0], pris[n->pri][1]); printf("after first pop:\n"); pqueue_print(pq, stdout, pr_node); pris[p][0] = 3; pris[p][1] = 0; pqueue_change_priority(pq, p, &ns[3]); /* 3: (5,6) -> (3,0) */ p = 3; /* Move spare slot to 3. */ printf("after 3: (5,6) -> (3,0):\n"); pqueue_print(pq, stdout, pr_node); pris[p][0] = 3; pris[p][1] = -1; pqueue_change_priority(pq, p, &ns[0]); /* 0: (4,2) -> (3,-1) */ p = 0; /* Move spare slot to 0. */ printf("after 0: (4,2) -> (3,-1):\n"); pqueue_print(pq, stdout, pr_node); while ((n = pqueue_pop(pq))) printf("[pop] pri: %d, val: %d, real-pri: [%d %d]\n", n->pri, n->val, pris[n->pri][0], pris[n->pri][1]); pqueue_free(pq); free(ns); free(pris); return 0; }
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; OPENSSL_free(frag->fragment); OPENSSL_free(frag); pitem_free(item); } while ( (item = pqueue_pop(s->d1->sent_messages)) != NULL) { frag = (hm_fragment *)item->data; OPENSSL_free(frag->fragment); OPENSSL_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); } }
/* 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); } }
void dtls1_free(SSL *s) { pitem *item = NULL; hm_fragment *frag = NULL; ssl3_free(s); while( (item = pqueue_pop(s->d1->unprocessed_rcds.q)) != NULL) { OPENSSL_free(item->data); pitem_free(item); } pqueue_free(s->d1->unprocessed_rcds.q); while( (item = pqueue_pop(s->d1->processed_rcds.q)) != NULL) { OPENSSL_free(item->data); pitem_free(item); } pqueue_free(s->d1->processed_rcds.q); while( (item = pqueue_pop(s->d1->buffered_messages)) != NULL) { frag = (hm_fragment *)item->data; OPENSSL_free(frag->fragment); OPENSSL_free(frag); pitem_free(item); } pqueue_free(s->d1->buffered_messages); while ( (item = pqueue_pop(s->d1->sent_messages)) != NULL) { frag = (hm_fragment *)item->data; OPENSSL_free(frag->fragment); OPENSSL_free(frag); pitem_free(item); } pqueue_free(s->d1->sent_messages); while ( (item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL) { frag = (hm_fragment *)item->data; OPENSSL_free(frag->fragment); OPENSSL_free(frag); pitem_free(item); } pqueue_free(s->d1->buffered_app_data.q); OPENSSL_free(s->d1); }
static void test_push_existing() { size_t i, j; int top; struct pqueue pq; int elt; for (i = 0; i < count; i++) { pqueue_init_copy(&pq, &pqueue); elt = elts[i]; pqueue_push(&pq, &elt); assert_int_equal(pqueue_count(&pq), count + 1); for (j = 0; j < count + 1; j++) { top = *(int *)pqueue_top(&pq); pqueue_pop(&pq); if (j <= i) { assert_int_equal(top, elts[j]); } else { assert_int_equal(top, elts[j - 1]); } } pqueue_destroy(&pq); } }
} T_END_TEST T_TEST(t_pqueue_alt_insert) { struct pqueue* q = pqueue_create(comp); int i; int num = 10; T_ASSERT(q); for (i = 0; i < num; i++) { T_ASSERT(0 == pqueue_insert(q, (void*)((i % 2) ? i : num - i - (num % 2 ? 1 : 2)))); } T_ASSERT(!pqueue_is_empty(q)); i = 0; while (!pqueue_is_empty(q)) { T_ASSERT(i == (int)pqueue_peek(q)); T_ASSERT(i == (int)pqueue_pop(q)); i++; } T_ASSERT(i == num); pqueue_destroy(q); } T_END_TEST
void process_data_samples(uint64_t time) { if(!data_events) return; struct data_ev *event = pqueue_peek(data_events); while(event && event->rdt <= time) { /*printf("%s:%lu:%p:%s\n", event->type==MALLOC?"malloc":"free", event->rdt, (void*)event->free.begin, event->type==MALLOC?event->malloc.info:"");*/ if(event->type==MALLOC) { void * data = rbtree_lookup(active_data, (void*)event->free.begin, pointer_cmp_reverse); if(data) { //printf("#Variable inserted twice ?!\n"); ((struct data_ev *)data)->malloc.end = event->malloc.end; data_fail++; } else { rbtree_insert(active_data, (void*)event->malloc.begin, event, pointer_cmp_reverse); data_success++; } } else if(event->type==FREE) { void * data = rbtree_lookup(active_data, (void*)event->free.begin, pointer_cmp_reverse); if(!data) { //printf("#Free of unknown pointer!\n"); data_fail++; } else { rbtree_delete(active_data, (void*)event->free.begin, pointer_cmp_reverse); data_success++; } } processed_data_samples++; pqueue_pop(data_events); event = pqueue_peek(data_events); } }
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); } }
void dtls1_free(SSL *s) { pitem *item = NULL; hm_fragment *frag = NULL; ssl3_free(s); while( (item = pqueue_pop(s->d1->unprocessed_rcds.q)) != NULL) { OPENSSL_free(item->data); pitem_free(item); } pqueue_free(s->d1->unprocessed_rcds.q); while( (item = pqueue_pop(s->d1->processed_rcds.q)) != NULL) { OPENSSL_free(item->data); pitem_free(item); } pqueue_free(s->d1->processed_rcds.q); while( (item = pqueue_pop(s->d1->buffered_messages)) != NULL) { frag = (hm_fragment *)item->data; OPENSSL_free(frag->fragment); OPENSSL_free(frag); pitem_free(item); } pqueue_free(s->d1->buffered_messages); while ( (item = pqueue_pop(s->d1->sent_messages)) != NULL) { frag = (hm_fragment *)item->data; OPENSSL_free(frag->fragment); OPENSSL_free(frag); pitem_free(item); } pqueue_free(s->d1->sent_messages); 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)); OPENSSL_free(s->d1); }
int main (int argc, char *argv[]) { int i; struct pqueue *pqueue; pqueue = pqueue_create(0, compare, NULL); if (pqueue == NULL) { return -1; } for (i = 1; i < argc; i++) { pqueue_insert(pqueue, argv[i]); } printf("%s ", (char *) pqueue_pop(pqueue)); printf("%s ", (char *) pqueue_pop(pqueue)); printf("%s ", (char *) pqueue_pop(pqueue)); pqueue_destroy(pqueue); return 0; }
void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl) { DTLS_RECORD_LAYER *d; pitem *item = NULL; DTLS1_RECORD_DATA *rdata; pqueue unprocessed_rcds; pqueue processed_rcds; pqueue buffered_app_data; d = rl->d; while ((item = pqueue_pop(d->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(d->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(d->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); } unprocessed_rcds = d->unprocessed_rcds.q; processed_rcds = d->processed_rcds.q; buffered_app_data = d->buffered_app_data.q; memset(d, 0, sizeof *d); d->unprocessed_rcds.q = unprocessed_rcds; d->processed_rcds.q = processed_rcds; d->buffered_app_data.q = buffered_app_data; }
static inline void sweep_line_delete (sweep_line_t *sweep, rectangle_t *rectangle, cairo_boxes_t *out) { sweep_line_delete_edge (sweep, &rectangle->left, out); sweep_line_delete_edge (sweep, &rectangle->right, out); pqueue_pop (&sweep->pq); }
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; }
static int trivial() { pqueue q = pqueue_new(); if (q == NULL) { return 0; } int32_t data = 0xdeadbeef; uint8_t priority[8] = {0}; pitem *item = pitem_new(priority, &data); if (item == NULL || pqueue_insert(q, item) != item || pqueue_size(q) != 1 || pqueue_peek(q) != item || pqueue_pop(q) != item || pqueue_size(q) != 0 || pqueue_pop(q) != NULL) { return 0; } pitem_free(item); pqueue_free(q); return 1; }
void *squeue_pop(squeue_t *q) { squeue_event *evt; void *ptr = NULL; evt = pqueue_pop(q); if (evt) { ptr = evt->data; free(evt); } return ptr; }
int main(void) { pitem *item; pqueue pq; int one = 1; int two = 2; int three = 3; pq = pqueue_new(); item = pitem_new((unsigned char*)&three, NULL); pqueue_insert(pq, item); item = pitem_new((unsigned char*)&one, NULL); pqueue_insert(pq, item); item = pitem_new((unsigned char*)&two, NULL); pqueue_insert(pq, item); item = pqueue_find(pq, (unsigned char*)&one); TINYCLR_SSL_FPRINTF(OPENSSL_TYPE__FILE_STDERR, "found %ld\n", item->priority); item = pqueue_find(pq, (unsigned char*)&two); TINYCLR_SSL_FPRINTF(OPENSSL_TYPE__FILE_STDERR, "found %ld\n", item->priority); item = pqueue_find(pq, (unsigned char*)&three); TINYCLR_SSL_FPRINTF(OPENSSL_TYPE__FILE_STDERR, "found %ld\n", item ? item->priority: 0); pqueue_print(pq); for(item = pqueue_pop(pq); item != NULL; item = pqueue_pop(pq)) pitem_free(item); pqueue_free(pq); return 0; }
int main(void) { pitem *item; pqueue pq; pq = pqueue_new(); item = pitem_new(prio3, NULL); pqueue_insert(pq, item); item = pitem_new(prio1, NULL); pqueue_insert(pq, item); item = pitem_new(prio2, NULL); pqueue_insert(pq, item); item = pqueue_find(pq, prio1); fprintf(stderr, "found %p\n", item->priority); item = pqueue_find(pq, prio2); fprintf(stderr, "found %p\n", item->priority); item = pqueue_find(pq, prio3); fprintf(stderr, "found %p\n", item ? item->priority : 0); pqueue_print(pq); if (!pqueue_test(pq)) return 1; for (item = pqueue_pop(pq); item != NULL; item = pqueue_pop(pq)) pitem_free(item); pqueue_free(pq); return 0; }
} T_END_TEST T_TEST(t_pqueue_duplicate) { struct pqueue* q = pqueue_create(comp); void* v = (void*)0xdeadbeef; T_ASSERT(q); T_ASSERT(0 == pqueue_insert(q, v)); T_ASSERT(0 == pqueue_insert(q, v)); T_ASSERT(!pqueue_is_empty(q)); T_ASSERT(v == pqueue_peek(q)); T_ASSERT(v == pqueue_pop(q)); T_ASSERT(!pqueue_is_empty(q)); T_ASSERT(v == pqueue_peek(q)); T_ASSERT(v == pqueue_pop(q)); T_ASSERT(pqueue_is_empty(q)); pqueue_destroy(q); } T_END_TEST
/* Main sender function. Taken from the state diagram on slide 6, chapter 5 */ void sender(int window, int timeout) { int base = 1; int nextseqnum = 1; bool allsent = false; PQueue sendQ; pqueue_init(&sendQ, window); while ( !(allsent && pqueue_empty(&sendQ)) ) { int acknum = -1; /* Send new data */ if (!allsent && nextseqnum < base + window) { Packet* packet = add_packet(&sendQ, nextseqnum); if (packet == NULL) { allsent = true; } else { send_packet(packet); if (base == nextseqnum) start_timer(timeout); nextseqnum++; } } /* Attempt to receive an ACK. */ acknum = get_ack(0); if (acknum > 0) { base = acknum + 1; if (base == nextseqnum) stop_timer(); else start_timer(timeout); } /* Clean up the queue */ while (!pqueue_empty(&sendQ) && pqueue_head(&sendQ)->seqn < base) { pqueue_pop(&sendQ); } /* Handle timeouts */ if (cnt_active && cnt_time >= cnt_timeout) { start_timer(cnt_timeout); pqueue_map(&sendQ, &send_packet); } pqueue_debug_print(&sendQ); } pqueue_destroy(&sendQ); }
int dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue) { pitem *item; item = pqueue_pop(queue->q); if (item) { dtls1_copy_record(s, item); OPENSSL_free(item->data); pitem_free(item); return 1; } return 0; }
static void squeue_foreach(squeue_t *q, int (*walker)(squeue_event *, void *), void *arg) { squeue_t *dup; void *e, *dup_d; dup = squeue_create(q->size); dup_d = dup->d; memcpy(dup, q, sizeof(*q)); dup->d = dup_d; memcpy(dup->d, q->d, (q->size * sizeof(void *))); while ((e = pqueue_pop(dup))) { walker(e, arg); } squeue_destroy(dup, 0); }
static int dtls1_retrieve_buffered_fragment(SSL *s, unsigned long *copied) { /* (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; unsigned long overlap; unsigned char *p; item = pqueue_peek(s->d1->buffered_messages); if ( item == NULL) return 0; frag = (hm_fragment *)item->data; if ( s->d1->handshake_read_seq == frag->msg_header.seq && frag->msg_header.frag_off <= (unsigned int)s->init_num - DTLS1_HM_HEADER_LENGTH) { pqueue_pop(s->d1->buffered_messages); overlap = s->init_num - DTLS1_HM_HEADER_LENGTH - frag->msg_header.frag_off; p = frag->fragment; memcpy(&s->init_buf->data[s->init_num], p + DTLS1_HM_HEADER_LENGTH + overlap, frag->msg_header.frag_len - overlap); OPENSSL_free(frag->fragment); OPENSSL_free(frag); pitem_free(item); *copied = frag->msg_header.frag_len - overlap; return *copied; } else return 0; }
void pqueue_print(pqueue_t *q, FILE *out, pqueue_print_entry_f print) { pqueue_t *dup; void *e; dup = pqueue_init(q->size, q->cmppri, q->getpri, set_pri, q->getpos, set_pos); dup->size = q->size; dup->avail = q->avail; dup->step = q->step; memcpy(dup->d, q->d, (q->size * sizeof(void *))); while ((e = pqueue_pop(dup))) { print(out, e); } pqueue_free(dup); }
/*- * Return up to 'len' payload bytes received in 'type' records. * 'type' is one of the following: * * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us) * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us) * - 0 (during a shutdown, no data has to be returned) * * If we don't have stored data to work from, read a SSL/TLS record first * (possibly multiple records if we still don't have anything to return). * * This function must handle any surprises the peer may have for us, such as * Alert records (e.g. close_notify) or renegotiation requests. ChangeCipherSpec * messages are treated as if they were handshake messages *if* the |recd_type| * argument is non NULL. * Also if record payloads contain fragments too small to process, we store * them until there is enough for the respective protocol (the record protocol * may use arbitrary fragmentation and even interleaving): * Change cipher spec protocol * just 1 byte needed, no need for keeping anything stored * Alert protocol * 2 bytes needed (AlertLevel, AlertDescription) * Handshake protocol * 4 bytes needed (HandshakeType, uint24 length) -- we just have * to detect unexpected Client Hello and Hello Request messages * here, anything else is handled by higher layers * Application data protocol * none of our business */ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, size_t len, int peek, size_t *readbytes) { int i, j, iret; size_t n; SSL3_RECORD *rr; void (*cb) (const SSL *ssl, int type2, int val) = NULL; if (!SSL3_BUFFER_is_initialised(&s->rlayer.rbuf)) { /* Not initialized yet */ if (!ssl3_setup_buffers(s)) { /* SSLfatal() already called */ return -1; } } if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE)) || (peek && (type != SSL3_RT_APPLICATION_DATA))) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); return -1; } if (!ossl_statem_get_in_handshake(s) && SSL_in_init(s)) { /* type == SSL3_RT_APPLICATION_DATA */ i = s->handshake_func(s); /* SSLfatal() already called if appropriate */ if (i < 0) return i; if (i == 0) return -1; } start: s->rwstate = SSL_NOTHING; /*- * s->s3.rrec.type - is the type of record * s->s3.rrec.data, - data * s->s3.rrec.off, - offset into 'data' for next read * s->s3.rrec.length, - number of bytes. */ rr = s->rlayer.rrec; /* * We are not handshaking and have no data yet, so process data buffered * during the last handshake in advance, if any. */ if (SSL_is_init_finished(s) && SSL3_RECORD_get_length(rr) == 0) { pitem *item; item = pqueue_pop(s->rlayer.d->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); pitem_free(item); } } /* Check for timeout */ if (dtls1_handle_timeout(s) > 0) { goto start; } else if (ossl_statem_in_error(s)) { /* dtls1_handle_timeout() has failed with a fatal error */ return -1; } /* get new packet if necessary */ if ((SSL3_RECORD_get_length(rr) == 0) || (s->rlayer.rstate == SSL_ST_READ_BODY)) { RECORD_LAYER_set_numrpipes(&s->rlayer, 0); iret = dtls1_get_record(s); if (iret <= 0) { iret = dtls1_read_failed(s, iret); /* * Anything other than a timeout is an error. SSLfatal() already * called if appropriate. */ if (iret <= 0) return iret; else goto start; } RECORD_LAYER_set_numrpipes(&s->rlayer, 1); } /* * Reset the count of consecutive warning alerts if we've got a non-empty * record that isn't an alert. */ if (SSL3_RECORD_get_type(rr) != SSL3_RT_ALERT && SSL3_RECORD_get_length(rr) != 0) s->rlayer.alert_count = 0; /* we now have a packet which can be read and processed */ if (s->s3.change_cipher_spec /* set when we receive ChangeCipherSpec, * reset by ssl3_get_finished */ && (SSL3_RECORD_get_type(rr) != SSL3_RT_HANDSHAKE)) { /* * We now have application data between CCS and Finished. Most likely * the packets were reordered on their way, so buffer the application * data for later processing rather than dropping the connection. */ if (dtls1_buffer_record(s, &(s->rlayer.d->buffered_app_data), SSL3_RECORD_get_seq_num(rr)) < 0) { /* SSLfatal() already called */ return -1; } SSL3_RECORD_set_length(rr, 0); SSL3_RECORD_set_read(rr); goto start; } /* * If the other end has shut down, throw anything we read away (even in * 'peek' mode) */ if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { SSL3_RECORD_set_length(rr, 0); SSL3_RECORD_set_read(rr); s->rwstate = SSL_NOTHING; return 0; } if (type == SSL3_RECORD_get_type(rr) || (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC && type == SSL3_RT_HANDSHAKE && recvd_type != NULL)) { /* * SSL3_RT_APPLICATION_DATA or * SSL3_RT_HANDSHAKE or * SSL3_RT_CHANGE_CIPHER_SPEC */ /* * make sure that we are not getting application data when we are * doing a handshake for the first time */ if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) && (s->enc_read_ctx == NULL)) { SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES, SSL_R_APP_DATA_IN_HANDSHAKE); return -1; } if (recvd_type != NULL) *recvd_type = SSL3_RECORD_get_type(rr); if (len == 0) { /* * Mark a zero length record as read. This ensures multiple calls to * SSL_read() with a zero length buffer will eventually cause * SSL_pending() to report data as being available. */ if (SSL3_RECORD_get_length(rr) == 0) SSL3_RECORD_set_read(rr); return 0; } if (len > SSL3_RECORD_get_length(rr)) n = SSL3_RECORD_get_length(rr); else n = len; memcpy(buf, &(SSL3_RECORD_get_data(rr)[SSL3_RECORD_get_off(rr)]), n); if (peek) { if (SSL3_RECORD_get_length(rr) == 0) SSL3_RECORD_set_read(rr); } else { SSL3_RECORD_sub_length(rr, n); SSL3_RECORD_add_off(rr, n); if (SSL3_RECORD_get_length(rr) == 0) { s->rlayer.rstate = SSL_ST_READ_HEADER; SSL3_RECORD_set_off(rr, 0); SSL3_RECORD_set_read(rr); } } #ifndef OPENSSL_NO_SCTP /* * 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 *readbytes = n; return 1; } /* * If we get here, then type != rr->type; if we have a handshake message, * then it was unexpected (Hello Request or Client Hello). */ if (SSL3_RECORD_get_type(rr) == SSL3_RT_ALERT) { unsigned int alert_level, alert_descr; unsigned char *alert_bytes = SSL3_RECORD_get_data(rr) + SSL3_RECORD_get_off(rr); PACKET alert; if (!PACKET_buf_init(&alert, alert_bytes, SSL3_RECORD_get_length(rr)) || !PACKET_get_1(&alert, &alert_level) || !PACKET_get_1(&alert, &alert_descr) || PACKET_remaining(&alert) != 0) { SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES, SSL_R_INVALID_ALERT); return -1; } if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_ALERT, alert_bytes, 2, s, s->msg_callback_arg); if (s->info_callback != NULL) cb = s->info_callback; else if (s->ctx->info_callback != NULL) cb = s->ctx->info_callback; if (cb != NULL) { j = (alert_level << 8) | alert_descr; cb(s, SSL_CB_READ_ALERT, j); } if (alert_level == SSL3_AL_WARNING) { s->s3.warn_alert = alert_descr; SSL3_RECORD_set_read(rr); s->rlayer.alert_count++; if (s->rlayer.alert_count == MAX_WARN_ALERT_COUNT) { SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES, SSL_R_TOO_MANY_WARN_ALERTS); return -1; } 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; } } else if (alert_level == SSL3_AL_FATAL) { char tmp[16]; s->rwstate = SSL_NOTHING; s->s3.fatal_alert = alert_descr; SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_DTLS1_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr); BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr); ERR_add_error_data(2, "SSL alert number ", tmp); s->shutdown |= SSL_RECEIVED_SHUTDOWN; SSL3_RECORD_set_read(rr); SSL_CTX_remove_session(s->session_ctx, s->session); return 0; } else { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_DTLS1_READ_BYTES, SSL_R_UNKNOWN_ALERT_TYPE); return -1; } goto start; } if (s->shutdown & SSL_SENT_SHUTDOWN) { /* but we have not received a * shutdown */ s->rwstate = SSL_NOTHING; SSL3_RECORD_set_length(rr, 0); SSL3_RECORD_set_read(rr); return 0; } if (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC) { /* * We can't process a CCS now, because previous handshake messages * are still missing, so just drop it. */ SSL3_RECORD_set_length(rr, 0); SSL3_RECORD_set_read(rr); goto start; } /* * Unexpected handshake message (Client Hello, or protocol violation) */ if ((SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) && !ossl_statem_get_in_handshake(s)) { struct hm_header_st msg_hdr; /* * This may just be a stale retransmit. Also sanity check that we have * at least enough record bytes for a message header */ if (SSL3_RECORD_get_epoch(rr) != s->rlayer.d->r_epoch || SSL3_RECORD_get_length(rr) < DTLS1_HM_HEADER_LENGTH) { SSL3_RECORD_set_length(rr, 0); SSL3_RECORD_set_read(rr); goto start; } dtls1_get_message_header(rr->data, &msg_hdr); /* * If we are server, we may have a repeated FINISHED of the client * here, then retransmit our CCS and FINISHED. */ if (msg_hdr.type == SSL3_MT_FINISHED) { if (dtls1_check_timeout_num(s) < 0) { /* SSLfatal) already called */ return -1; } if (dtls1_retransmit_buffered_messages(s) <= 0) { /* Fail if we encountered a fatal error */ if (ossl_statem_in_error(s)) return -1; } SSL3_RECORD_set_length(rr, 0); SSL3_RECORD_set_read(rr); if (!(s->mode & SSL_MODE_AUTO_RETRY)) { if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) { /* no read-ahead left? */ BIO *bio; s->rwstate = SSL_READING; bio = SSL_get_rbio(s); BIO_clear_retry_flags(bio); BIO_set_retry_read(bio); return -1; } } goto start; } /* * To get here we must be trying to read app data but found handshake * data. But if we're trying to read app data, and we're not in init * (which is tested for at the top of this function) then init must be * finished */ if (!ossl_assert(SSL_is_init_finished(s))) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); return -1; } /* We found handshake data, so we're going back into init */ ossl_statem_set_in_init(s, 1); i = s->handshake_func(s); /* SSLfatal() called if appropriate */ if (i < 0) return i; if (i == 0) return -1; if (!(s->mode & SSL_MODE_AUTO_RETRY)) { if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) { /* no read-ahead left? */ BIO *bio; /* * In the case where we try to read application data, but we * trigger an SSL handshake, we return -1 with the retry * option set. Otherwise renegotiation may cause nasty * problems in the blocking world */ s->rwstate = SSL_READING; bio = SSL_get_rbio(s); BIO_clear_retry_flags(bio); BIO_set_retry_read(bio); return -1; } } goto start; } switch (SSL3_RECORD_get_type(rr)) { default: SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD); return -1; case SSL3_RT_CHANGE_CIPHER_SPEC: case SSL3_RT_ALERT: case SSL3_RT_HANDSHAKE: /* * we already handled all of these, with the possible exception of * SSL3_RT_HANDSHAKE when ossl_statem_get_in_handshake(s) is true, but * that should not happen when type != rr->type */ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); return -1; case SSL3_RT_APPLICATION_DATA: /* * At this point, we were expecting handshake data, but have * application data. If the library was running inside ssl3_read() * (i.e. in_read_app_data is set) and it makes sense to read * application data at this point (session renegotiation not yet * started), we will indulge it. */ if (s->s3.in_read_app_data && (s->s3.total_renegotiations != 0) && ossl_statem_app_data_allowed(s)) { s->s3.in_read_app_data = 2; return -1; } else { SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD); return -1; } } /* not reached */ }
/*- * Return up to 'len' payload bytes received in 'type' records. * 'type' is one of the following: * * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us) * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us) * - 0 (during a shutdown, no data has to be returned) * * If we don't have stored data to work from, read a SSL/TLS record first * (possibly multiple records if we still don't have anything to return). * * This function must handle any surprises the peer may have for us, such as * Alert records (e.g. close_notify) or renegotiation requests. ChangeCipherSpec * messages are treated as if they were handshake messages *if* the |recd_type| * argument is non NULL. * Also if record payloads contain fragments too small to process, we store * them until there is enough for the respective protocol (the record protocol * may use arbitrary fragmentation and even interleaving): * Change cipher spec protocol * just 1 byte needed, no need for keeping anything stored * Alert protocol * 2 bytes needed (AlertLevel, AlertDescription) * Handshake protocol * 4 bytes needed (HandshakeType, uint24 length) -- we just have * to detect unexpected Client Hello and Hello Request messages * here, anything else is handled by higher layers * Application data protocol * none of our business */ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, int len, int peek) { int al, i, j, ret; unsigned int n; SSL3_RECORD *rr; void (*cb) (const SSL *ssl, int type2, int val) = NULL; if (!SSL3_BUFFER_is_initialised(&s->rlayer.rbuf)) { /* Not initialized yet */ if (!ssl3_setup_buffers(s)) return (-1); } if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE)) || (peek && (type != SSL3_RT_APPLICATION_DATA))) { SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); return -1; } /* * check whether there's a handshake message (client hello?) waiting */ if ((ret = have_handshake_fragment(s, type, buf, len))) { *recvd_type = SSL3_RT_HANDSHAKE; return ret; } /* * Now s->rlayer.d->handshake_fragment_len == 0 if * type == SSL3_RT_HANDSHAKE. */ if (!ossl_statem_get_in_handshake(s) && SSL_in_init(s)) { /* type == SSL3_RT_APPLICATION_DATA */ i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return (-1); } } start: s->rwstate = SSL_NOTHING; /*- * s->s3->rrec.type - is the type of record * s->s3->rrec.data, - data * s->s3->rrec.off, - offset into 'data' for next read * s->s3->rrec.length, - number of bytes. */ rr = s->rlayer.rrec; /* * We are not handshaking and have no data yet, so process data buffered * during the last handshake in advance, if any. */ if (SSL_is_init_finished(s) && SSL3_RECORD_get_length(rr) == 0) { pitem *item; item = pqueue_pop(s->rlayer.d->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); pitem_free(item); } } /* Check for timeout */ if (dtls1_handle_timeout(s) > 0) goto start; /* get new packet if necessary */ if ((SSL3_RECORD_get_length(rr) == 0) || (s->rlayer.rstate == SSL_ST_READ_BODY)) { ret = dtls1_get_record(s); if (ret <= 0) { ret = dtls1_read_failed(s, ret); /* anything other than a timeout is an error */ if (ret <= 0) return (ret); else goto start; } } /* * Reset the count of consecutive warning alerts if we've got a non-empty * record that isn't an alert. */ if (SSL3_RECORD_get_type(rr) != SSL3_RT_ALERT && SSL3_RECORD_get_length(rr) != 0) s->rlayer.alert_count = 0; /* we now have a packet which can be read and processed */ if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec, * reset by ssl3_get_finished */ && (SSL3_RECORD_get_type(rr) != SSL3_RT_HANDSHAKE)) { /* * We now have application data between CCS and Finished. Most likely * the packets were reordered on their way, so buffer the application * data for later processing rather than dropping the connection. */ if (dtls1_buffer_record(s, &(s->rlayer.d->buffered_app_data), SSL3_RECORD_get_seq_num(rr)) < 0) { SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); return -1; } SSL3_RECORD_set_length(rr, 0); goto start; } /* * If the other end has shut down, throw anything we read away (even in * 'peek' mode) */ if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { SSL3_RECORD_set_length(rr, 0); s->rwstate = SSL_NOTHING; return (0); } if (type == SSL3_RECORD_get_type(rr) || (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC && type == SSL3_RT_HANDSHAKE && recvd_type != NULL)) { /* * SSL3_RT_APPLICATION_DATA or * SSL3_RT_HANDSHAKE or * SSL3_RT_CHANGE_CIPHER_SPEC */ /* * make sure that we are not getting application data when we are * doing a handshake for the first time */ if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) && (s->enc_read_ctx == NULL)) { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_APP_DATA_IN_HANDSHAKE); goto f_err; } if (recvd_type != NULL) *recvd_type = SSL3_RECORD_get_type(rr); if (len <= 0) return (len); if ((unsigned int)len > SSL3_RECORD_get_length(rr)) n = SSL3_RECORD_get_length(rr); else n = (unsigned int)len; memcpy(buf, &(SSL3_RECORD_get_data(rr)[SSL3_RECORD_get_off(rr)]), n); if (!peek) { SSL3_RECORD_sub_length(rr, n); SSL3_RECORD_add_off(rr, n); if (SSL3_RECORD_get_length(rr) == 0) { s->rlayer.rstate = SSL_ST_READ_HEADER; SSL3_RECORD_set_off(rr, 0); } } #ifndef OPENSSL_NO_SCTP /* * 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); } /* * If we get here, then type != rr->type; if we have a handshake message, * then it was unexpected (Hello Request or Client Hello). */ /* * In case of record types for which we have 'fragment' storage, fill * that so that we can process the data at a fixed place. */ { unsigned int k, dest_maxlen = 0; unsigned char *dest = NULL; unsigned int *dest_len = NULL; if (SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) { dest_maxlen = sizeof s->rlayer.d->handshake_fragment; dest = s->rlayer.d->handshake_fragment; dest_len = &s->rlayer.d->handshake_fragment_len; } else if (SSL3_RECORD_get_type(rr) == SSL3_RT_ALERT) { dest_maxlen = sizeof(s->rlayer.d->alert_fragment); dest = s->rlayer.d->alert_fragment; dest_len = &s->rlayer.d->alert_fragment_len; } #ifndef OPENSSL_NO_HEARTBEATS else if (SSL3_RECORD_get_type(rr) == DTLS1_RT_HEARTBEAT) { /* We allow a 0 return */ if (dtls1_process_heartbeat(s, SSL3_RECORD_get_data(rr), SSL3_RECORD_get_length(rr)) < 0) { return -1; } /* Exit and notify application to read again */ SSL3_RECORD_set_length(rr, 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 (SSL3_RECORD_get_type(rr) != SSL3_RT_CHANGE_CIPHER_SPEC) { /* * Application data while renegotiating is allowed. Try again * reading. */ if (SSL3_RECORD_get_type(rr) == SSL3_RT_APPLICATION_DATA) { BIO *bio; s->s3->in_read_app_data = 2; bio = SSL_get_rbio(s); s->rwstate = SSL_READING; BIO_clear_retry_flags(bio); BIO_set_retry_read(bio); return (-1); } /* Not certain if this is the right error handling */ al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD); goto f_err; } if (dest_maxlen > 0) { /* * XDTLS: In a pathological case, the Client Hello may be * fragmented--don't always expect dest_maxlen bytes */ if (SSL3_RECORD_get_length(rr) < dest_maxlen) { #ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE /* * for normal alerts rr->length is 2, while * dest_maxlen is 7 if we were to handle this * non-existing alert... */ FIX ME; #endif s->rlayer.rstate = SSL_ST_READ_HEADER; SSL3_RECORD_set_length(rr, 0); goto start; } /* now move 'n' bytes: */ for (k = 0; k < dest_maxlen; k++) { dest[k] = SSL3_RECORD_get_data(rr)[SSL3_RECORD_get_off(rr)]; SSL3_RECORD_add_off(rr, 1); SSL3_RECORD_add_length(rr, -1); } *dest_len = dest_maxlen; } } /*- * s->rlayer.d->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE; * s->rlayer.d->alert_fragment_len == 7 iff rr->type == SSL3_RT_ALERT. * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */ /* If we are a client, check for an incoming 'Hello Request': */ if ((!s->server) && (s->rlayer.d->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && (s->rlayer.d->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) && (s->session != NULL) && (s->session->cipher != NULL)) { s->rlayer.d->handshake_fragment_len = 0; if ((s->rlayer.d->handshake_fragment[1] != 0) || (s->rlayer.d->handshake_fragment[2] != 0) || (s->rlayer.d->handshake_fragment[3] != 0)) { al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_BAD_HELLO_REQUEST); goto f_err; } /* * no need to check sequence number on HELLO REQUEST messages */ if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->rlayer.d->handshake_fragment, 4, s, s->msg_callback_arg); if (SSL_is_init_finished(s) && !(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)) { i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return (-1); } if (!(s->mode & SSL_MODE_AUTO_RETRY)) { if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) { /* no read-ahead left? */ BIO *bio; /* * In the case where we try to read application data, * but we trigger an SSL handshake, we return -1 with * the retry option set. Otherwise renegotiation may * cause nasty problems in the blocking world */ s->rwstate = SSL_READING; bio = SSL_get_rbio(s); BIO_clear_retry_flags(bio); BIO_set_retry_read(bio); return (-1); } } } } /* * we either finished a handshake or ignored the request, now try * again to obtain the (application) data we were asked for */ goto start; } if (s->rlayer.d->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH) { int alert_level = s->rlayer.d->alert_fragment[0]; int alert_descr = s->rlayer.d->alert_fragment[1]; s->rlayer.d->alert_fragment_len = 0; if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_ALERT, s->rlayer.d->alert_fragment, 2, s, s->msg_callback_arg); if (s->info_callback != NULL) cb = s->info_callback; else if (s->ctx->info_callback != NULL) cb = s->ctx->info_callback; if (cb != NULL) { j = (alert_level << 8) | alert_descr; cb(s, SSL_CB_READ_ALERT, j); } if (alert_level == SSL3_AL_WARNING) { s->s3->warn_alert = alert_descr; s->rlayer.alert_count++; if (s->rlayer.alert_count == MAX_WARN_ALERT_COUNT) { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_TOO_MANY_WARN_ALERTS); goto f_err; } 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); } #if 0 /* XXX: this is a possible improvement in the future */ /* now check if it's a missing record */ if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE) { unsigned short seq; unsigned int frag_off; unsigned char *p = &(s->rlayer.d->alert_fragment[2]); n2s(p, seq); n2l3(p, frag_off); dtls1_retransmit_message(s, dtls1_get_queue_priority (frag->msg_header.seq, 0), frag_off, &found); if (!found && SSL_in_init(s)) { /* * fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */ /* * requested a message not yet sent, send an alert * ourselves */ ssl3_send_alert(s, SSL3_AL_WARNING, DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); } } #endif } else if (alert_level == SSL3_AL_FATAL) { char tmp[16]; s->rwstate = SSL_NOTHING; s->s3->fatal_alert = alert_descr; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr); BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr); ERR_add_error_data(2, "SSL alert number ", tmp); s->shutdown |= SSL_RECEIVED_SHUTDOWN; SSL_CTX_remove_session(s->session_ctx, s->session); return (0); } else { al = SSL_AD_ILLEGAL_PARAMETER; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNKNOWN_ALERT_TYPE); goto f_err; } goto start; } if (s->shutdown & SSL_SENT_SHUTDOWN) { /* but we have not received a * shutdown */ s->rwstate = SSL_NOTHING; SSL3_RECORD_set_length(rr, 0); return (0); } if (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC) { /* * We can't process a CCS now, because previous handshake messages * are still missing, so just drop it. */ SSL3_RECORD_set_length(rr, 0); goto start; } /* * Unexpected handshake message (Client Hello, or protocol violation) */ if ((s->rlayer.d->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && !ossl_statem_get_in_handshake(s)) { struct hm_header_st msg_hdr; /* this may just be a stale retransmit */ dtls1_get_message_header(rr->data, &msg_hdr); if (SSL3_RECORD_get_epoch(rr) != s->rlayer.d->r_epoch) { SSL3_RECORD_set_length(rr, 0); goto start; } /* * If we are server, we may have a repeated FINISHED of the client * here, then retransmit our CCS and FINISHED. */ if (msg_hdr.type == SSL3_MT_FINISHED) { if (dtls1_check_timeout_num(s) < 0) return -1; dtls1_retransmit_buffered_messages(s); SSL3_RECORD_set_length(rr, 0); goto start; } if (SSL_is_init_finished(s) && !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) { ossl_statem_set_in_init(s, 1); s->renegotiate = 1; s->new_session = 1; } i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return (-1); } if (!(s->mode & SSL_MODE_AUTO_RETRY)) { if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) { /* no read-ahead left? */ BIO *bio; /* * In the case where we try to read application data, but we * trigger an SSL handshake, we return -1 with the retry * option set. Otherwise renegotiation may cause nasty * problems in the blocking world */ s->rwstate = SSL_READING; bio = SSL_get_rbio(s); BIO_clear_retry_flags(bio); BIO_set_retry_read(bio); return (-1); } } goto start; } switch (SSL3_RECORD_get_type(rr)) { default: /* TLS just ignores unknown message types */ if (s->version == TLS1_VERSION) { SSL3_RECORD_set_length(rr, 0); goto start; } al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD); goto f_err; case SSL3_RT_CHANGE_CIPHER_SPEC: case SSL3_RT_ALERT: case SSL3_RT_HANDSHAKE: /* * we already handled all of these, with the possible exception of * SSL3_RT_HANDSHAKE when ossl_statem_get_in_handshake(s) is true, but * that should not happen when type != rr->type */ al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); goto f_err; case SSL3_RT_APPLICATION_DATA: /* * At this point, we were expecting handshake data, but have * application data. If the library was running inside ssl3_read() * (i.e. in_read_app_data is set) and it makes sense to read * application data at this point (session renegotiation not yet * started), we will indulge it. */ if (s->s3->in_read_app_data && (s->s3->total_renegotiations != 0) && ossl_statem_app_data_allowed(s)) { s->s3->in_read_app_data = 2; return (-1); } else { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD); goto f_err; } } /* not reached */ f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); return (-1); }