diff --git a/src/knot/query/layer.h b/src/knot/query/layer.h
index 948663a11e8cea669a04305314d9f23093481515..a1f6eaf64a379dfbe80649d7a3f49396369c7d1c 100644
--- a/src/knot/query/layer.h
+++ b/src/knot/query/layer.h
@@ -29,6 +29,7 @@ enum knot_layer_state {
 	KNOT_STATE_NOOP = 0,   //!< Invalid.
 	KNOT_STATE_CONSUME,    //!< Consume data.
 	KNOT_STATE_PRODUCE,    //!< Produce data.
+	KNOT_STATE_RESET,      //!< Restart processing.
 	KNOT_STATE_DONE,       //!< Finished.
 	KNOT_STATE_FAIL        //!< Error.
 };
diff --git a/src/knot/query/requestor.c b/src/knot/query/requestor.c
index 5a9a435d51bd98e3ca89d61a10061124df247df7..6024a3c03fa9575963e51cf00e2a40798787681d 100644
--- a/src/knot/query/requestor.c
+++ b/src/knot/query/requestor.c
@@ -105,6 +105,7 @@ struct knot_request *knot_request_make(knot_mm_t *mm,
                                        const struct sockaddr *remote,
                                        const struct sockaddr *source,
                                        knot_pkt_t *query,
+                                       const knot_tsig_key_t *tsig_key,
                                        unsigned flags)
 {
 	if (remote == NULL || query == NULL) {
@@ -133,6 +134,8 @@ struct knot_request *knot_request_make(knot_mm_t *mm,
 		request->source.ss_family = AF_UNSPEC;
 	}
 
+	tsig_init(&request->tsig, tsig_key);
+
 	return request;
 }
 
@@ -147,6 +150,7 @@ void knot_request_free(struct knot_request *request, knot_mm_t *mm)
 	}
 	knot_pkt_free(&request->query);
 	knot_pkt_free(&request->resp);
+	tsig_cleanup(&request->tsig);
 
 	mm_free(mm, request);
 }
@@ -163,7 +167,7 @@ int knot_requestor_init(struct knot_requestor *requestor,
 
 	requestor->mm = mm;
 	knot_layer_init(&requestor->layer, mm, proc);
-	requestor->layer.state = knot_layer_begin(&requestor->layer, proc_param);
+	knot_layer_begin(&requestor->layer, proc_param);
 
 	return KNOT_EOK;
 }
@@ -179,53 +183,89 @@ void knot_requestor_clear(struct knot_requestor *requestor)
 	memset(requestor, 0, sizeof(*requestor));
 }
 
-static int request_io(struct knot_requestor *req, struct knot_request *last,
-                      int timeout_ms)
+static int request_reset(struct knot_requestor *req,
+                         struct knot_request *last)
 {
-	int ret = KNOT_EOK;
-	knot_pkt_t *query = last->query;
-	knot_pkt_t *resp = last->resp;
+	knot_layer_reset(&req->layer);
+	tsig_reset(&last->tsig);
+
+	if (req->layer.state == KNOT_STATE_RESET) {
+		return KNOT_LAYER_ERROR;
+	}
 
-	/* Data to be sent. */
-	if (req->layer.state == KNOT_STATE_PRODUCE) {
+	return KNOT_EOK;
+}
 
-		/* Process query and send it out. */
-		knot_layer_produce(&req->layer, query);
+static int request_produce(struct knot_requestor *req,
+                           struct knot_request *last,
+                           int timeout_ms)
+{
+	knot_layer_produce(&req->layer, last->query);
 
-		if (req->layer.state == KNOT_STATE_CONSUME) {
-			ret = request_send(last, timeout_ms);
-			if (ret != KNOT_EOK) {
-				return ret;
-			}
-		}
+	int ret = tsig_sign_packet(&last->tsig, last->query);
+	if (ret != KNOT_EOK) {
+		return ret;
 	}
 
-	/* Data to be read. */
+	// TODO: verify condition
 	if (req->layer.state == KNOT_STATE_CONSUME) {
-		/* Read answer and process it. */
-		ret = request_recv(last, timeout_ms);
-		if (ret < 0) {
-			return ret;
-		}
+		ret = request_send(last, timeout_ms);
+	}
+
+	return ret;
+}
 
-		(void) knot_pkt_parse(resp, 0);
-		knot_layer_consume(&req->layer, resp);
+static int request_consume(struct knot_requestor *req,
+                           struct knot_request *last,
+                           int timeout_ms)
+{
+	int ret = request_recv(last, timeout_ms);
+	if (ret < 0) {
+		return ret;
 	}
 
+	ret = knot_pkt_parse(last->resp, 0);
+	if (ret != KNOT_EOK) {
+		return ret;
+	}
+
+	ret = tsig_verify_packet(&last->tsig, last->resp);
+	if (ret != KNOT_EOK) {
+		return ret;
+	}
+
+	knot_layer_consume(&req->layer, last->resp);
+
 	return KNOT_EOK;
 }
 
 static bool layer_active(enum knot_layer_state state)
 {
 	switch (state) {
-	case KNOT_STATE_PRODUCE:
 	case KNOT_STATE_CONSUME:
+	case KNOT_STATE_PRODUCE:
+	case KNOT_STATE_RESET:
 		return true;
 	default:
 		return false;
 	}
 }
 
+static int request_io(struct knot_requestor *req, struct knot_request *last,
+                      int timeout_ms)
+{
+	switch (req->layer.state) {
+	case KNOT_STATE_CONSUME:
+		return request_consume(req, last, timeout_ms);
+	case KNOT_STATE_PRODUCE:
+		return request_produce(req, last, timeout_ms);
+	case KNOT_STATE_RESET:
+		return request_reset(req, last);
+	default:
+		return KNOT_EINVAL;
+	}
+}
+
 int knot_requestor_exec(struct knot_requestor *requestor,
                         struct knot_request *request,
                         int timeout_ms)
@@ -240,7 +280,7 @@ int knot_requestor_exec(struct knot_requestor *requestor,
 	while (layer_active(requestor->layer.state)) {
 		ret = request_io(requestor, request, timeout_ms);
 		if (ret != KNOT_EOK) {
-			knot_layer_reset(&requestor->layer);
+			knot_layer_finish(&requestor->layer);
 			return ret;
 		}
 	}
@@ -250,8 +290,13 @@ int knot_requestor_exec(struct knot_requestor *requestor,
 		ret = KNOT_LAYER_ERROR;
 	}
 
+	/* Verify last TSIG */
+	if (tsig_unsigned_count(&request->tsig) != 0) {
+		ret = KNOT_LAYER_ERROR;
+	}
+
 	/* Finish current query processing. */
-	knot_layer_reset(&requestor->layer);
+	knot_layer_finish(&requestor->layer);
 
 	return ret;
 }
diff --git a/src/knot/query/requestor.h b/src/knot/query/requestor.h
index 1a8822a7c6c7071b3df05bbbe691fbe13e3ef8f4..335a4b15faf5cd345c7bacdefaf1d7bb646ed4a0 100644
--- a/src/knot/query/requestor.h
+++ b/src/knot/query/requestor.h
@@ -19,6 +19,7 @@
 #include <sys/socket.h>
 #include <sys/time.h>
 
+#include "knot/nameserver/tsig_ctx.h"
 #include "knot/query/layer.h"
 #include "libknot/mm_ctx.h"
 #include "libknot/rrtype/tsig.h"
@@ -46,7 +47,9 @@ struct knot_request {
 	struct sockaddr_storage remote, source;
 	knot_pkt_t *query;
 	knot_pkt_t *resp;
-	knot_sign_context_t sign;
+	tsig_ctx_t tsig;
+	knot_sign_context_t sign; // TODO: WIPE?
+	knot_layer_t layer;
 };
 
 /*!
@@ -56,6 +59,7 @@ struct knot_request {
  * \param dst    Remote endpoint address.
  * \param src    Source address (or NULL).
  * \param query  Query message.
+ * \param key    TSIG key for authentication.
  * \param flags  Request flags.
  *
  * \return Prepared request or NULL in case of error.
@@ -64,6 +68,7 @@ struct knot_request *knot_request_make(knot_mm_t *mm,
                                        const struct sockaddr *dst,
                                        const struct sockaddr *src,
                                        knot_pkt_t *query,
+                                       const knot_tsig_key_t *key,
                                        unsigned flags);
 
 /*!
diff --git a/tests/requestor.c b/tests/requestor.c
index d3afc5ac394bcf41a51bbe766cb1d6a9f8b44556..13c32438526b26c6b472d2023f3944e4986311f8 100644
--- a/tests/requestor.c
+++ b/tests/requestor.c
@@ -34,7 +34,7 @@
  *       but simply if the requesting/receiving works, so mirror is okay. */
 static int reset(knot_layer_t *ctx) { return KNOT_STATE_PRODUCE; }
 static int begin(knot_layer_t *ctx, void *module_param) { return reset(ctx); }
-static int finish(knot_layer_t *ctx) { return KNOT_STATE_NOOP; }
+static int finish(knot_layer_t *ctx) { return reset(ctx); }
 static int in(knot_layer_t *ctx, knot_pkt_t *pkt) { return KNOT_STATE_DONE; }
 static int out(knot_layer_t *ctx, knot_pkt_t *pkt) { return KNOT_STATE_CONSUME; }
 
@@ -42,8 +42,7 @@ static const int TIMEOUT = 2000;
 
 /*! \brief Dummy answer processing module. */
 const knot_layer_api_t dummy_module = {
-        &begin, &reset, &finish,
-        &in, &out, NULL
+        &begin, &reset, &finish, &in, &out, NULL
 };
 
 static void set_blocking_mode(int sock)