/* @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, record_params, 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_align16(&session->internals.record_recv_buffer, get_total_headers2(session, record_params)); 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. Moreover we add space for any pad and the MAC (in case * they are encrypted). */ ret = max_decrypted_size(session) + MAX_PAD_SIZE + MAX_HASH_SIZE; decrypted = _mbuffer_alloc_align16(ret, 0); if (decrypted == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _mbuffer_set_udata_size(decrypted, ret); 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_record_log ("REC[%p]: Discarded duplicate message[%u.%u]: %s\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)); 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); /* decrypted 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) && (ret == GNUTLS_E_DECRYPTION_FAILED || ret == GNUTLS_E_UNSUPPORTED_VERSION_PACKET || ret == GNUTLS_E_UNEXPECTED_PACKET_LENGTH || ret == GNUTLS_E_UNEXPECTED_PACKET || ret == GNUTLS_E_ERROR_IN_FINISHED_PACKET || ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET)) { goto discard; } session_invalidate(session); session_unresumable(session); if (ret == 0) return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; else return ret; }
static int decrypt_packet_tls13(gnutls_session_t session, gnutls_datum_t *ciphertext, gnutls_datum_t *plain, content_type_t *type, record_parameters_st *params, gnutls_uint64 *sequence) { uint8_t nonce[MAX_CIPHER_IV_SIZE]; size_t length, length_to_decrypt; int ret; const version_entry_st *ver = get_version(session); unsigned int tag_size = params->read.aead_tag_size; unsigned iv_size; unsigned j; volatile unsigned length_set; uint8_t aad[5]; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); if (params->cipher->id == GNUTLS_CIPHER_NULL) { if (plain->size < ciphertext->size) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); length = ciphertext->size; memcpy(plain->data, ciphertext->data, length); return length; } iv_size = _gnutls_cipher_get_iv_size(params->cipher); /* The way AEAD ciphers are defined in RFC5246, it allows * only stream ciphers. */ if (unlikely(ciphertext->size < tag_size)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); if (unlikely(params->read.iv_size != iv_size || iv_size < 8)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); memcpy(nonce, params->read.iv, params->read.iv_size); memxor(&nonce[iv_size-8], UINT64DATA(*sequence), 8); length = ciphertext->size - tag_size; length_to_decrypt = ciphertext->size; if (unlikely ((unsigned) length_to_decrypt > plain->size)) { _gnutls_audit_log(session, "Received %u bytes, while expecting less than %u\n", (unsigned int) length_to_decrypt, (unsigned int) plain->size); return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } aad[0] = GNUTLS_APPLICATION_DATA; aad[1] = 0x03; aad[2] = 0x03; _gnutls_write_uint16(ciphertext->size, &aad[3]); ret = gnutls_aead_cipher_decrypt(¶ms->read.ctx.aead, nonce, iv_size, aad, sizeof(aad), tag_size, ciphertext->data, length_to_decrypt, plain->data, &length); if (unlikely(ret < 0)) return gnutls_assert_val(ret); /* 1 octet for content type */ if (length > max_decrypted_size(session) + 1) { _gnutls_audit_log (session, "Received packet with illegal length: %u\n", (unsigned int) length); return gnutls_assert_val(GNUTLS_E_RECORD_OVERFLOW); } length_set = 0; /* now figure the actual data size. We intentionally iterate through all data, * to avoid leaking the padding length due to timing differences in processing. */ for (j=length;j>0;j--) { if (plain->data[j-1]!=0 && length_set == 0) { *type = plain->data[j-1]; length = j-1; length_set = 1; if (!(session->internals.flags & GNUTLS_SAFE_PADDING_CHECK)) break; } } if (!length_set) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); return length; }