/** * gnutls_dtls_get_data_mtu: * @session: is a #gnutls_session_t structure. * * This function will return the actual maximum transfer unit for * application data. I.e. DTLS headers are subtracted from the * actual MTU. * * Returns: the maximum allowed transfer unit. * * Since: 3.0 **/ unsigned int gnutls_dtls_get_data_mtu (gnutls_session_t session) { int ret; ret = _gnutls_record_overhead_rt(session); if (ret >= 0) return session->internals.dtls.mtu - ret; else return session->internals.dtls.mtu - RECORD_HEADER_SIZE(session); }
/** * gnutls_dtls_get_data_mtu: * @session: is a #gnutls_session_t structure. * * This function will return the actual maximum transfer unit for * application data. I.e. DTLS headers are subtracted from the * actual MTU. * * Returns: the maximum allowed transfer unit. * * Since: 3.0 **/ unsigned int gnutls_dtls_get_data_mtu (gnutls_session_t session) { int mtu = session->internals.dtls.mtu; unsigned int blocksize = 1; int overhead; mtu -= RECORD_HEADER_SIZE(session); overhead = record_overhead_rt(session, &blocksize); if (overhead < 0) return mtu; if (blocksize) mtu -= mtu % blocksize; return mtu - overhead; }
/** * gnutls_dtls_set_data_mtu: * @session: is a #gnutls_session_t structure. * @mtu: The maximum unencrypted transfer unit of the session * * This function will set the maximum size of the *unencrypted* records * which will be sent over a DTLS session. It is equivalent to calculating * the DTLS packet overhead with the current encryption parameters, and * calling gnutls_dtls_set_mtu() with that value. In particular, this means * that you may need to call this function again after any negotiation or * renegotiation, in order to ensure that the MTU is still sufficient to * account for the new protocol overhead. * * Returns: %GNUTLS_E_SUCCESS (0) on success, or a negative error code. * * Since: 3.1 **/ int gnutls_dtls_set_data_mtu (gnutls_session_t session, unsigned int mtu) { unsigned int blocksize; int overhead = record_overhead_rt(session, &blocksize); /* You can't call this until the session is actually running */ if (overhead < 0) return GNUTLS_E_INVALID_SESSION; /* Add the overhead inside the encrypted part */ mtu += overhead; /* Round it up to the next multiple of blocksize */ mtu += blocksize - 1; mtu -= mtu % blocksize; /* Add the *unencrypted header size */ mtu += RECORD_HEADER_SIZE(session); gnutls_dtls_set_mtu(session, mtu); return GNUTLS_E_SUCCESS; }
/* This function behaves exactly like write(). The only difference is * that it accepts, the gnutls_session_t and the content_type_t of data to * send (if called by the user the Content is specific) * It is intended to transfer data, under the current session. * * @type: The content type to send * @htype: If this is a handshake message then the handshake type * @epoch_rel: %EPOCH_READ_* or %EPOCH_WRITE_* * @data: the data to be sent * @data_size: the size of the @data * @target_length: @data_size + minimum required padding * @mflags: zero or %MBUFFER_FLUSH * * Oct 30 2001: Removed capability to send data more than MAX_RECORD_SIZE. * This makes the function much easier to read, and more error resistant * (there were cases were the old function could mess everything up). * --nmav * * This function may accept a NULL pointer for data, and 0 for size, if * and only if the previous send was interrupted for some reason. * */ ssize_t _gnutls_send_tlen_int (gnutls_session_t session, content_type_t type, gnutls_handshake_description_t htype, unsigned int epoch_rel, const void *_data, size_t data_size, size_t target_length, unsigned int mflags) { mbuffer_st *bufel; ssize_t cipher_size; int retval, ret; int send_data_size; uint8_t *headers; int header_size; const uint8_t *data = _data; record_parameters_st *record_params; record_state_st *record_state; ret = _gnutls_epoch_get (session, epoch_rel, &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_INVALID_REQUEST); record_state = &record_params->write; /* Do not allow null pointer if the send buffer is empty. * If the previous send was interrupted then a null pointer is * ok, and means to resume. */ if (session->internals.record_send_buffer.byte_length == 0 && (data_size == 0 && _data == NULL)) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (type != GNUTLS_ALERT) /* alert messages are sent anyway */ if (session_is_valid (session) || session->internals.may_not_write != 0) { gnutls_assert (); return GNUTLS_E_INVALID_SESSION; } if (data_size > MAX_USER_SEND_SIZE(session)) { if (IS_DTLS(session)) return gnutls_assert_val(GNUTLS_E_LARGE_PACKET); send_data_size = MAX_USER_SEND_SIZE(session); } else send_data_size = data_size; /* Only encrypt if we don't have data to send * from the previous run. - probably interrupted. */ if (mflags != 0 && session->internals.record_send_buffer.byte_length > 0) { ret = _gnutls_io_write_flush (session); if (ret > 0) cipher_size = ret; else cipher_size = 0; retval = session->internals.record_send_buffer_user_size; } else { if (unlikely((send_data_size == 0 && target_length == 0))) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); /* now proceed to packet encryption */ cipher_size = MAX_RECORD_SEND_SIZE(session); bufel = _mbuffer_alloc (0, cipher_size+CIPHER_SLACK_SIZE); if (bufel == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); headers = _mbuffer_get_uhead_ptr(bufel); headers[0] = type; /* Use the default record version, if it is * set. */ copy_record_version (session, htype, &headers[1]); header_size = RECORD_HEADER_SIZE(session); /* Adjust header length and add sequence for DTLS */ if (IS_DTLS(session)) memcpy(&headers[3], &record_state->sequence_number.i, 8); _gnutls_record_log ("REC[%p]: Preparing Packet %s(%d) with length: %d and target length: %d\n", session, _gnutls_packet2str (type), type, (int) data_size, (int) target_length); _mbuffer_set_udata_size(bufel, cipher_size); _mbuffer_set_uhead_size(bufel, header_size); ret = _gnutls_encrypt (session, data, send_data_size, target_length, bufel, type, record_params); if (ret <= 0) { gnutls_assert (); if (ret == 0) ret = GNUTLS_E_ENCRYPTION_FAILED; gnutls_free (bufel); return ret; /* error */ } cipher_size = _mbuffer_get_udata_size(bufel); retval = send_data_size; session->internals.record_send_buffer_user_size = send_data_size; /* increase sequence number */ if (sequence_increment (session, &record_state->sequence_number) != 0) { session_invalidate (session); gnutls_free (bufel); return gnutls_assert_val(GNUTLS_E_RECORD_LIMIT_REACHED); } ret = _gnutls_io_write_buffered (session, bufel, mflags); } if (ret != cipher_size) { /* If we have sent any data then just return * the error value. Do not invalidate the session. */ if (ret < 0 && gnutls_error_is_fatal (ret) == 0) return gnutls_assert_val(ret); if (ret > 0) ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); session_unresumable (session); session->internals.may_not_write = 1; return gnutls_assert_val(ret); } session->internals.record_send_buffer_user_size = 0; _gnutls_record_log ("REC[%p]: Sent Packet[%d] %s(%d) in epoch %d and length: %d\n", session, (unsigned int) _gnutls_uint64touint32 (&record_state->sequence_number), _gnutls_packet2str (type), type, (int) record_params->epoch, (int) cipher_size); return retval; }
static int recv_headers( gnutls_session_t session, content_type_t type, gnutls_handshake_description_t htype, struct tls_record_st* record, unsigned int *ms) { int ret; gnutls_datum_t raw; /* raw headers */ /* Read the headers. */ record->header_size = record->packet_size = RECORD_HEADER_SIZE(session); ret = _gnutls_io_read_buffered (session, record->header_size, -1, ms); if (ret != record->header_size) { if (ret < 0 && gnutls_error_is_fatal (ret) == 0) return ret; if (ret > 0) ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; else if (ret == 0) ret = GNUTLS_E_PREMATURE_TERMINATION; return gnutls_assert_val(ret); } ret = _mbuffer_linearize (&session->internals.record_recv_buffer); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_head_get_first (&session->internals.record_recv_buffer, &raw); if (raw.size < RECORD_HEADER_SIZE(session)) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); record_read_headers (session, raw.data, type, htype, record); /* Check if the DTLS epoch is valid */ if (IS_DTLS(session)) { if (_gnutls_epoch_is_valid(session, record->epoch) == 0) { _gnutls_audit_log(session, "Discarded message[%u] with invalid epoch %u.\n", (unsigned int)_gnutls_uint64touint32 (&record->sequence), (unsigned int)record->sequence.i[0]*256+(unsigned int)record->sequence.i[1]); gnutls_assert(); /* doesn't matter, just a fatal error */ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } } /* Here we check if the Type of the received packet is * ok. */ if ((ret = check_recv_type (session, record->type)) < 0) return gnutls_assert_val(ret); /* Here we check if the advertized version is the one we * negotiated in the handshake. */ if ((ret = record_check_version (session, htype, record->version)) < 0) return gnutls_assert_val(ret); if (record->length > MAX_RECV_SIZE(session)) { _gnutls_audit_log (session, "Received packet with illegal length: %u\n", (unsigned int)record->length); return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); } _gnutls_record_log ("REC[%p]: Expected Packet %s(%d)\n", session, _gnutls_packet2str (type), type); _gnutls_record_log ("REC[%p]: Received Packet %s(%d) with length: %d\n", session, _gnutls_packet2str (record->type), record->type, record->length); return 0; }