Beispiel #1
0
/**
 * gnutls_heartbeat_pong:
 * @session: is a #gnutls_session_t structure.
 * @flags: should be zero
 *
 * This function replies to a ping by sending a pong to the peer.
 *
 * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
 *
 * Since: 3.1.2
 **/
int gnutls_heartbeat_pong(gnutls_session_t session, unsigned int flags)
{
	int ret;

	if (session->internals.record_send_buffer.byte_length > 0 &&
	    session->internals.record_send_buffer.head != NULL &&
	    session->internals.record_send_buffer.head->type ==
	    GNUTLS_HEARTBEAT)
		return _gnutls_io_write_flush(session);

	if (session->internals.hb_remote_data.length == 0)
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

	ret =
	    heartbeat_send_data(session,
				session->internals.hb_remote_data.data,
				session->internals.hb_remote_data.length,
				HEARTBEAT_RESPONSE);

	_gnutls_buffer_reset(&session->internals.hb_remote_data);

	if (ret < 0)
		return gnutls_assert_val(ret);

	return 0;
}
Beispiel #2
0
int _gnutls_krb5_der_to_principal(const gnutls_datum_t * der,
				  gnutls_datum_t * name)
{
	int ret, result;
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	gnutls_buffer_st str;

	_gnutls_buffer_init(&str);

	result =
	    asn1_create_element(_gnutls_get_gnutls_asn(),
				"GNUTLS.KRB5PrincipalName", &c2);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	result = asn1_der_decoding(&c2, der->data, der->size, NULL);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	ret = principal_to_str(c2, &str);
	if (ret < 0) {
		/* for some reason we cannot convert to a human readable string
		 * the principal. Then we use the #HEX format.
		 */
		_gnutls_buffer_reset(&str);
		ret = _gnutls_buffer_append_data(&str, "#", 1);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		_gnutls_buffer_hexprint(&str, der->data, der->size);
	}

	asn1_delete_structure(&c2);
	return _gnutls_buffer_to_datum(&str, name, 1);

 cleanup:
	_gnutls_buffer_clear(&str);
	asn1_delete_structure(&c2);
	return ret;
}
Beispiel #3
0
/*
 * Processes a heartbeat message. 
 */
int _gnutls_heartbeat_handle(gnutls_session_t session, mbuffer_st * bufel)
{
	int ret;
	unsigned type;
	unsigned pos;
	uint8_t *msg = _mbuffer_get_udata_ptr(bufel);
	size_t hb_len, len = _mbuffer_get_udata_size(bufel);

	if (gnutls_heartbeat_allowed
	    (session, GNUTLS_HB_PEER_ALLOWED_TO_SEND) == 0)
		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);

	if (len < 4)
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	pos = 0;
	type = msg[pos++];

	hb_len = _gnutls_read_uint16(&msg[pos]);
	if (hb_len > len - 3)
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	pos += 2;

	switch (type) {
	case HEARTBEAT_REQUEST:
		_gnutls_buffer_reset(&session->internals.hb_remote_data);

		ret =
		    _gnutls_buffer_resize(&session->internals.
					  hb_remote_data, hb_len);
		if (ret < 0)
			return gnutls_assert_val(ret);

		if (hb_len > 0)
			memcpy(session->internals.hb_remote_data.data,
			       &msg[pos], hb_len);
		session->internals.hb_remote_data.length = hb_len;

		return gnutls_assert_val(GNUTLS_E_HEARTBEAT_PING_RECEIVED);

	case HEARTBEAT_RESPONSE:

		if (hb_len != session->internals.hb_local_data.length)
			return
			    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);

		if (hb_len > 0 &&
		    memcmp(&msg[pos],
			   session->internals.hb_local_data.data,
			   hb_len) != 0) {
			if (IS_DTLS(session))
				return gnutls_assert_val(GNUTLS_E_AGAIN);	/* ignore it */
			else
				return
				    gnutls_assert_val
				    (GNUTLS_E_UNEXPECTED_PACKET);
		}

		_gnutls_buffer_reset(&session->internals.hb_local_data);

		return gnutls_assert_val(GNUTLS_E_HEARTBEAT_PONG_RECEIVED);
	default:
		_gnutls_record_log
		    ("REC[%p]: HB: received unknown type %u\n", session,
		     type);
		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
	}
}
Beispiel #4
0
/**
 * gnutls_heartbeat_ping:
 * @session: is a #gnutls_session_t structure.
 * @data_size: is the length of the ping payload.
 * @max_tries: if flags is %GNUTLS_HEARTBEAT_WAIT then this sets the number of retransmissions. Use zero for indefinite (until timeout).
 * @flags: if %GNUTLS_HEARTBEAT_WAIT then wait for pong or timeout instead of returning immediately.
 *
 * This function sends a ping to the peer. If the @flags is set
 * to %GNUTLS_HEARTBEAT_WAIT then it waits for a reply from the peer.
 * 
 * Note that it is highly recommended to use this function with the
 * flag %GNUTLS_HEARTBEAT_WAIT, or you need to handle retransmissions
 * and timeouts manually.
 *
 * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
 *
 * Since: 3.1.2
 **/
int
gnutls_heartbeat_ping(gnutls_session_t session, size_t data_size,
		      unsigned int max_tries, unsigned int flags)
{
	int ret;
	unsigned int retries = 1, diff;
	struct timespec now;

	if (data_size > MAX_HEARTBEAT_LENGTH)
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	if (gnutls_heartbeat_allowed
	    (session, GNUTLS_HB_LOCAL_ALLOWED_TO_SEND) == 0)
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

	/* resume previous call if interrupted */
	if (session->internals.record_send_buffer.byte_length > 0 &&
	    session->internals.record_send_buffer.head != NULL &&
	    session->internals.record_send_buffer.head->type ==
	    GNUTLS_HEARTBEAT)
		return _gnutls_io_write_flush(session);

	switch (session->internals.hb_state) {
	case SHB_SEND1:
		if (data_size > DEFAULT_PAYLOAD_SIZE)
			data_size -= DEFAULT_PAYLOAD_SIZE;
		else
			data_size = 0;

		_gnutls_buffer_reset(&session->internals.hb_local_data);

		ret =
		    _gnutls_buffer_resize(&session->internals.
					  hb_local_data, data_size);
		if (ret < 0)
			return gnutls_assert_val(ret);

		ret =
		    _gnutls_rnd(GNUTLS_RND_NONCE,
				session->internals.hb_local_data.data,
				data_size);
		if (ret < 0)
			return gnutls_assert_val(ret);

		gettime(&session->internals.hb_ping_start);
		session->internals.hb_local_data.length = data_size;
		session->internals.hb_state = SHB_SEND2;
	case SHB_SEND2:
		session->internals.hb_actual_retrans_timeout_ms =
		    session->internals.hb_retrans_timeout_ms;
	      retry:
		ret =
		    heartbeat_send_data(session,
					session->internals.hb_local_data.
					data,
					session->internals.hb_local_data.
					length, HEARTBEAT_REQUEST);
		if (ret < 0)
			return gnutls_assert_val(ret);

		gettime(&session->internals.hb_ping_sent);

		if (!(flags & GNUTLS_HEARTBEAT_WAIT)) {
			session->internals.hb_state = SHB_SEND1;
			break;
		}

		session->internals.hb_state = SHB_RECV;

	case SHB_RECV:
		ret =
		    _gnutls_recv_int(session, GNUTLS_HEARTBEAT, -1, NULL,
				     0, NULL,
				     session->internals.
				     hb_actual_retrans_timeout_ms);
		if (ret == GNUTLS_E_HEARTBEAT_PONG_RECEIVED) {
			session->internals.hb_state = SHB_SEND1;
			break;
		} else if (ret == GNUTLS_E_TIMEDOUT) {
			retries++;
			if (max_tries > 0 && retries > max_tries) {
				session->internals.hb_state = SHB_SEND1;
				return gnutls_assert_val(ret);
			}

			gettime(&now);
			diff =
			    timespec_sub_ms(&now,
					    &session->internals.
					    hb_ping_start);
			if (diff > session->internals.hb_total_timeout_ms) {
				session->internals.hb_state = SHB_SEND1;
				return
				    gnutls_assert_val(GNUTLS_E_TIMEDOUT);
			}

			session->internals.hb_actual_retrans_timeout_ms *=
			    2;
			session->internals.hb_actual_retrans_timeout_ms %=
			    MAX_DTLS_TIMEOUT;

			session->internals.hb_state = SHB_SEND2;
			goto retry;
		} else if (ret < 0) {
			session->internals.hb_state = SHB_SEND1;
			return gnutls_assert_val(ret);
		}
	}

	return 0;
}