static void check_dtls_window_epoch_higher(void **glob_state) { struct record_parameters_st state; uint64 t; RESET_WINDOW; SET_WINDOW_NEXT(LARGE_INT-1); SET_WINDOW_LAST_RECV(LARGE_INT); uint64_set(&t, BSWAP64(LARGE_INT)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64((LARGE_INT+8)|0x1000000000000LL)); assert_int_equal(_dtls_record_check(&state, &t), -1); }
static void check_dtls_window_uninit_large(void **glob_state) { struct record_parameters_st state; uint64 t; RESET_WINDOW; uint64_set(&t, BSWAP64(LARGE_INT+1+64)); assert_int_equal(_dtls_record_check(&state, &t), 0); }
static void check_dtls_window_uninit_very_large(void **glob_state) { struct record_parameters_st state; uint64 t; RESET_WINDOW; uint64_set(&t, BSWAP64(INT_OVER_32_BITS)); assert_int_equal(_dtls_record_check(&state, &t), 0); }
static void check_dtls_window_uninit_0(void **glob_state) { struct record_parameters_st state; uint64 t; RESET_WINDOW; SET_WINDOW_NEXT(0); uint64_set(&t, 0); assert_int_equal(_dtls_record_check(&state, &t), 0); }
static void check_dtls_window_epoch_lower(void **glob_state) { struct record_parameters_st state; uint64 t; RESET_WINDOW; uint64_set(&t, BSWAP64(0x1000000000000LL)); state.epoch = 1; SET_WINDOW_NEXT(0x1000000000000LL); SET_WINDOW_LAST_RECV((0x1000000000000LL) + 1); uint64_set(&t, BSWAP64(2 | 0x1000000000000LL)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(3 | 0x1000000000000LL)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(5)); assert_int_equal(_dtls_record_check(&state, &t), -1); }
static void check_dtls_window_dup3(void **glob_state) { struct record_parameters_st state; uint64 t; RESET_WINDOW; SET_WINDOW_NEXT(LARGE_INT-1); SET_WINDOW_LAST_RECV(LARGE_INT); uint64_set(&t, BSWAP64(LARGE_INT)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+16)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+15)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+14)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+5)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+5)); assert_int_equal(_dtls_record_check(&state, &t), -3); }
static void check_dtls_window_out_of_order(void **glob_state) { struct record_parameters_st state; uint64 t; RESET_WINDOW; SET_WINDOW_NEXT(LARGE_INT-1); SET_WINDOW_LAST_RECV(LARGE_INT); uint64_set(&t, BSWAP64(LARGE_INT)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+8)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+7)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+6)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+5)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+4)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+3)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+2)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+1)); assert_int_equal(_dtls_record_check(&state, &t), 0); uint64_set(&t, BSWAP64(LARGE_INT+9)); assert_int_equal(_dtls_record_check(&state, &t), 0); }
static void check_dtls_window_very_large_outside(void **glob_state) { struct record_parameters_st state; uint64 t; RESET_WINDOW; SET_WINDOW_NEXT(INT_OVER_32_BITS); SET_WINDOW_LAST_RECV(INT_OVER_32_BITS+1); uint64_set(&t, BSWAP64(INT_OVER_32_BITS+1+64)); assert_int_equal(_dtls_record_check(&state, &t), 0); }
static void check_dtls_window_91(void **glob_state) { struct record_parameters_st state; uint64 t; RESET_WINDOW; SET_WINDOW_NEXT(0); SET_WINDOW_LAST_RECV(9); uint64_set(&t, BSWAP64(1)); assert_int_equal(_dtls_record_check(&state, &t), 0); }
static void check_dtls_window_skip3(void **glob_state) { struct record_parameters_st state; uint64 t; unsigned i; RESET_WINDOW; SET_WINDOW_NEXT(0); SET_WINDOW_LAST_RECV(1); for (i=5;i<256;i+=2) { uint64_set(&t, BSWAP64(i)); assert_int_equal(_dtls_record_check(&state, &t), 0); } }
/* @ms: is the number of milliseconds to wait for data. Use zero for indefinite. * * This will receive record layer packets and add them to * application_data_buffer and handshake_data_buffer. * * If the htype is not -1 then handshake timeouts * will be enforced. */ ssize_t _gnutls_recv_in_buffers (gnutls_session_t session, content_type_t type, gnutls_handshake_description_t htype, unsigned int ms) { uint64 *packet_sequence; gnutls_datum_t ciphertext; mbuffer_st* bufel = NULL, *decrypted = NULL; gnutls_datum_t t; int ret; unsigned int empty_fragments = 0; record_parameters_st *record_params; record_state_st *record_state; struct tls_record_st record; begin: if (empty_fragments > session->internals.priorities.max_empty_records) { gnutls_assert (); return GNUTLS_E_TOO_MANY_EMPTY_PACKETS; } if (session->internals.read_eof != 0) { /* if we have already read an EOF */ return 0; } else if (session_is_valid (session) != 0 || session->internals.may_not_read != 0) return gnutls_assert_val(GNUTLS_E_INVALID_SESSION); /* get the record state parameters */ ret = _gnutls_epoch_get (session, EPOCH_READ_CURRENT, &record_params); if (ret < 0) return gnutls_assert_val (ret); /* Safeguard against processing data with an incomplete cipher state. */ if (!record_params->initialized) return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR); record_state = &record_params->read; /* receive headers */ ret = recv_headers(session, type, htype, &record, &ms); if (ret < 0) { ret = gnutls_assert_val_fatal(ret); goto recv_error; } if (IS_DTLS(session)) packet_sequence = &record.sequence; else packet_sequence = &record_state->sequence_number; /* Read the packet data and insert it to record_recv_buffer. */ ret = _gnutls_io_read_buffered (session, record.packet_size, record.type, &ms); if (ret != record.packet_size) { gnutls_assert(); goto recv_error; } /* ok now we are sure that we have read all the data - so * move on ! */ ret = _mbuffer_linearize (&session->internals.record_recv_buffer); if (ret < 0) return gnutls_assert_val(ret); bufel = _mbuffer_head_get_first (&session->internals.record_recv_buffer, NULL); if (bufel == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); /* We allocate the maximum possible to allow few compressed bytes to expand to a * full record. */ decrypted = _mbuffer_alloc(record.length, record.length); if (decrypted == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); ciphertext.data = (uint8_t*)_mbuffer_get_udata_ptr(bufel) + record.header_size; ciphertext.size = record.length; /* decrypt the data we got. */ t.data = _mbuffer_get_udata_ptr(decrypted); t.size = _mbuffer_get_udata_size(decrypted); ret = _gnutls_decrypt (session, &ciphertext, &t, record.type, record_params, packet_sequence); if (ret >= 0) _mbuffer_set_udata_size(decrypted, ret); _mbuffer_head_remove_bytes (&session->internals.record_recv_buffer, record.header_size + record.length); if (ret < 0) { gnutls_assert(); _gnutls_audit_log(session, "Discarded message[%u] due to invalid decryption\n", (unsigned int)_gnutls_uint64touint32 (packet_sequence)); goto sanity_check_error; } /* check for duplicates. We check after the message * is processed and authenticated to avoid someone * messing with our windows. */ if (IS_DTLS(session) && session->internals.no_replay_protection == 0) { ret = _dtls_record_check(record_params, packet_sequence); if (ret < 0) { _gnutls_audit_log(session, "Discarded duplicate message[%u.%u]: %s\n", (unsigned int)record.sequence.i[0]*256 +(unsigned int)record.sequence.i[1], (unsigned int) _gnutls_uint64touint32 (packet_sequence), _gnutls_packet2str (record.type)); goto sanity_check_error; } _gnutls_record_log ("REC[%p]: Decrypted Packet[%u.%u] %s(%d) with length: %d\n", session, (unsigned int)record.sequence.i[0]*256 +(unsigned int)record.sequence.i[1], (unsigned int) _gnutls_uint64touint32 (packet_sequence), _gnutls_packet2str (record.type), record.type, (int)_mbuffer_get_udata_size(decrypted)); } else { _gnutls_record_log ("REC[%p]: Decrypted Packet[%u] %s(%d) with length: %d\n", session, (unsigned int) _gnutls_uint64touint32 (packet_sequence), _gnutls_packet2str (record.type), record.type, (int)_mbuffer_get_udata_size(decrypted)); } /* increase sequence number */ if (!IS_DTLS(session) && sequence_increment (session, &record_state->sequence_number) != 0) { session_invalidate (session); gnutls_assert (); ret = GNUTLS_E_RECORD_LIMIT_REACHED; goto sanity_check_error; } /* (originally for) TLS 1.0 CBC protection. * Actually this code is called if we just received * an empty packet. An empty TLS packet is usually * sent to protect some vulnerabilities in the CBC mode. * In that case we go to the beginning and start reading * the next packet. */ if (_mbuffer_get_udata_size(decrypted) == 0) { _mbuffer_xfree(&decrypted); empty_fragments++; goto begin; } if (record.v2) decrypted->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2; else { uint8_t * p = _mbuffer_get_udata_ptr(decrypted); decrypted->htype = p[0]; } ret = record_add_to_buffers (session, &record, type, htype, packet_sequence, decrypted); /* bufel is now either deinitialized or buffered somewhere else */ if (ret < 0) return gnutls_assert_val(ret); return ret; discard: session->internals.dtls.packets_dropped++; /* discard the whole received fragment. */ bufel = _mbuffer_head_pop_first(&session->internals.record_recv_buffer); _mbuffer_xfree(&bufel); return gnutls_assert_val(GNUTLS_E_AGAIN); sanity_check_error: if (IS_DTLS(session)) { session->internals.dtls.packets_dropped++; ret = gnutls_assert_val(GNUTLS_E_AGAIN); goto cleanup; } session_unresumable (session); session_invalidate (session); cleanup: _mbuffer_xfree(&decrypted); return ret; recv_error: if (ret < 0 && (gnutls_error_is_fatal (ret) == 0 || ret == GNUTLS_E_TIMEDOUT)) return ret; if (type == GNUTLS_ALERT) /* we were expecting close notify */ { session_invalidate (session); gnutls_assert (); return 0; } if (IS_DTLS(session)) { goto discard; } session_invalidate (session); session_unresumable (session); if (ret == 0) return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; else return ret; }