diff --git a/src/libknot/dnssec/config.h b/src/libknot/dnssec/config.h
index 41eeaef0808c3c3001d382bc020b0ccaf3412330..79cab3427cac9807a647d3777946bd8f807eccea 100644
--- a/src/libknot/dnssec/config.h
+++ b/src/libknot/dnssec/config.h
@@ -28,6 +28,11 @@
 #define _KNOT_DNSSEC_CONFIG_H_
 
 #include <openssl/opensslconf.h>
+#include <openssl/opensslv.h>
+
+#ifndef OPENSSL_VERSION_NUMBER
+#error "OpenSSL version is not defined."
+#endif
 
 // ECDSA support requires OpenSSL version >= 1.0.1
 #if !defined(OPENSSL_NO_ECDSA) && OPENSSL_VERSION_NUMBER >= 0x10001000
@@ -36,6 +41,12 @@
   #undef KNOT_ENABLE_ECDSA
 #endif
 
+#if !defined(OPENSSL_NO_GOST)
+  #define KNOT_ENABLE_GOST 1
+#else
+  #undef KNOT_ENABLE_GOST
+#endif
+
 #endif // _KNOT_DNSSEC_CONFIG_H_
 
 /*! @} */
diff --git a/src/libknot/dnssec/crypto.c b/src/libknot/dnssec/crypto.c
index 6faa12a05f6f2e835bcb28216146cd5b97836452..c8c5a3444e61e2d80f84525bb02db6723d96064e 100644
--- a/src/libknot/dnssec/crypto.c
+++ b/src/libknot/dnssec/crypto.c
@@ -16,13 +16,17 @@
 
 #include <assert.h>
 #include <openssl/crypto.h>
+#include <openssl/engine.h>
 #include <openssl/err.h>
 #include <openssl/evp.h>
 #include <pthread.h>
 
 #include "libknot/common.h"
+#include "libknot/dnssec/config.h"
 #include "libknot/dnssec/crypto.h"
 
+/*- thread safety -----------------------------------------------------------*/
+
 /*!
  * \brief Mutexes to be used by OpenSSL.
  */
@@ -107,6 +111,45 @@ static void openssl_threadid_cb(CRYPTO_THREADID *openssl_id)
 	CRYPTO_THREADID_set_pointer(openssl_id, (void *)id);
 }
 
+/*- pluggable engines -------------------------------------------------------*/
+
+#if KNOT_ENABLE_GOST
+
+static ENGINE *gost_engine = NULL;
+
+static void init_gost_engine(void)
+{
+	assert(gost_engine == NULL);
+
+#ifndef OPENSSL_NO_STATIC_ENGINE
+	ENGINE_load_gost();
+#else
+	ENGINE_load_dynamic();
+#endif
+
+	gost_engine = ENGINE_by_id("gost");
+	if (!gost_engine) {
+		return;
+	}
+
+	ENGINE_init(gost_engine);
+	ENGINE_register_pkey_asn1_meths(gost_engine);
+	ENGINE_ctrl_cmd_string(gost_engine, "CRYPT_PARAMS",
+	                       "id-Gost28147-89-CryptoPro-A-ParamSet", 0);
+}
+
+static void deinit_gost_engine(void)
+{
+	assert(gost_engine);
+
+	ENGINE_finish(gost_engine);
+	ENGINE_free(gost_engine);
+
+	gost_engine = NULL;
+}
+
+#endif
+
 /*- public API --------------------------------------------------------------*/
 
 void knot_crypto_init(void)
@@ -116,6 +159,8 @@ void knot_crypto_init(void)
 
 void knot_crypto_cleanup(void)
 {
+	knot_crypto_unload_engines();
+
 	EVP_cleanup();
 	CRYPTO_cleanup_all_ex_data();
 	ERR_free_strings();
@@ -145,3 +190,21 @@ void knot_crypto_cleanup_threads(void)
 		openssl_mutexes_destroy();
 	}
 }
+
+void knot_crypto_load_engines(void)
+{
+#if KNOT_ENABLE_GOST
+	if (!gost_engine) {
+		init_gost_engine();
+	}
+#endif
+}
+
+void knot_crypto_unload_engines(void)
+{
+#if KNOT_ENABLE_GOST
+	if (gost_engine) {
+		deinit_gost_engine();
+	}
+#endif
+}
diff --git a/src/libknot/dnssec/crypto.h b/src/libknot/dnssec/crypto.h
index 4273c5aeb59bbc70226d1fa5f275f6a2e0322ff4..22e5046a14f240bf8253f66ce59d5ec071bad64b 100644
--- a/src/libknot/dnssec/crypto.h
+++ b/src/libknot/dnssec/crypto.h
@@ -54,6 +54,16 @@ void knot_crypto_init_threads(void);
  */
 void knot_crypto_cleanup_threads(void);
 
+/*!
+ * \brief Load pluggable crypto engines.
+ */
+void knot_crypto_load_engines(void);
+
+/*!
+ * \brief Unload pluggable crypto engines.
+ */
+void knot_crypto_unload_engines(void);
+
 #endif // _KNOT_DNSSEC_CRYPTO_H_
 
 /*! @} */
diff --git a/src/libknot/dnssec/key.c b/src/libknot/dnssec/key.c
index a5c9a9fa727675019e9ec3d9d868305a33c2b392..918d7be538f99e1cf29b316ca6d3789bbc6cabc7 100644
--- a/src/libknot/dnssec/key.c
+++ b/src/libknot/dnssec/key.c
@@ -295,6 +295,7 @@ static const struct key_parameter key_parameters[] = {
 	{ "Private_value(x)",key_offset(private_value),    key_param_base64 },
 	{ "Public_value(y)", key_offset(public_value),     key_param_base64 },
 	{ "PrivateKey",      key_offset(private_key),      key_param_base64 },
+	{ "GostAsn1",        key_offset(private_key),      key_param_base64 },
 	{ "Publish",         key_offset(time_publish),     key_param_time },
 	{ "Activate",        key_offset(time_activate),    key_param_time },
 	{ "Inactive",        key_offset(time_inactive),    key_param_time },
diff --git a/src/libknot/dnssec/key.h b/src/libknot/dnssec/key.h
index 4dcb52cdc938cb1f253505b1c14cf972d70e474e..789e3ad9a15cf41ef8acd9db0cf4a377d5aabf24 100644
--- a/src/libknot/dnssec/key.h
+++ b/src/libknot/dnssec/key.h
@@ -66,7 +66,7 @@ typedef struct {
 	knot_binary_t private_value;
 	knot_binary_t public_value;
 
-	// EC
+	// EC/GOST
 	knot_binary_t private_key;
 
 	// key lifetime
diff --git a/src/libknot/dnssec/rrset-sign.c b/src/libknot/dnssec/rrset-sign.c
index a06ea7817981ddaf6ae8cfc6cfd428d17f65b4d5..75995fc01abedc8802fd483b62a62570c4fbd9b5 100644
--- a/src/libknot/dnssec/rrset-sign.c
+++ b/src/libknot/dnssec/rrset-sign.c
@@ -106,29 +106,35 @@ int knot_rrsig_write_rdata(uint8_t *rdata, const knot_dnssec_key_t *key,
 /*!
  * \brief Create RRSIG RDATA (all fields except signature are filled).
  *
- * \param rrsigs        RR set with RRSIGS.
- * \param covered       RR covered by the signature.
- * \param key           Key used for signing.
- * \param sig_incepted  Timestamp of signature inception.
- * \param sig_expires   Timestamp of signature expiration.
+ * \param[in]  rrsigs        RR set with RRSIGS.
+ * \param[in]  covered       RR covered by the signature.
+ * \param[in]  key           Key used for signing.
+ * \param[in]  sig_incepted  Timestamp of signature inception.
+ * \param[in]  sig_expires   Timestamp of signature expiration.
+ * \param[out] rdata         Created RDATA.
+ * \param[out] rdata_size    Size of created RDATA.
+ *
+ * \return Error code, KNOT_EOK if succesful.
  */
-static uint8_t *rrsigs_create_rdata(knot_rrset_t *rrsigs,
-                                    const knot_rrset_t *covered,
-                                    const knot_dnssec_key_t *key,
-                                    uint32_t sig_incepted,
-                                    uint32_t sig_expires)
+static int rrsigs_create_rdata(knot_rrset_t *rrsigs,
+                               const knot_rrset_t *covered,
+                               const knot_dnssec_key_t *key,
+			       uint32_t sig_incepted, uint32_t sig_expires,
+                               uint8_t **rdata, size_t *rdata_size)
 {
 	assert(rrsigs);
 	assert(rrsigs->type == KNOT_RRTYPE_RRSIG);
 	assert(covered);
 	assert(key);
+	assert(rdata);
+	assert(rdata_size);
 
-	size_t rdata_size = knot_rrsig_rdata_size(key);
-	assert(rdata_size != 0);
+	size_t size = knot_rrsig_rdata_size(key);
+	assert(size != 0);
 
-	uint8_t *rdata = knot_rrset_create_rdata(rrsigs, rdata_size);
-	if (!rdata) {
-		return NULL;
+	uint8_t *result = knot_rrset_create_rdata(rrsigs, size);
+	if (!result) {
+		return KNOT_ENOMEM;
 	}
 
 	uint8_t owner_labels = knot_dname_labels(covered->owner, NULL);
@@ -136,12 +142,16 @@ static uint8_t *rrsigs_create_rdata(knot_rrset_t *rrsigs,
 		owner_labels -= 1;
 	}
 
-	int res = knot_rrsig_write_rdata(rdata, key, covered->type, owner_labels,
-	                                covered->ttl, sig_incepted, sig_expires);
+	int res = knot_rrsig_write_rdata(result, key, covered->type, owner_labels,
+	                                 covered->ttl, sig_incepted, sig_expires);
+
 	assert(res == KNOT_EOK);
+	UNUSED(res);
 
+	*rdata = result;
+	*rdata_size = size;
 
-	return rdata;
+	return KNOT_EOK;
 }
 
 /*- Computation of signatures ------------------------------------------------*/
@@ -280,13 +290,16 @@ int knot_sign_rrset(knot_rrset_t *rrsigs, const knot_rrset_t *covered,
 	uint32_t sig_incept = policy->now;
 	uint32_t sig_expire = sig_incept + policy->sign_lifetime;
 
-	uint8_t *rdata = rrsigs_create_rdata(rrsigs, covered, key,
-	                                     sig_incept, sig_expire);
-	if (!rdata) {
-		return KNOT_ENOMEM;
+	uint8_t *rdata = NULL;
+	size_t rdata_size = 0;
+
+	int result = rrsigs_create_rdata(rrsigs, covered, key, sig_incept,
+	                                 sig_expire, &rdata, &rdata_size);
+	if (result != KNOT_EOK) {
+		return result;
 	}
 
-	int result = knot_dnssec_sign_new(sign_ctx);
+	result = knot_dnssec_sign_new(sign_ctx);
 	if (result != KNOT_EOK) {
 		return result;
 	}
@@ -296,10 +309,11 @@ int knot_sign_rrset(knot_rrset_t *rrsigs, const knot_rrset_t *covered,
 		return result;
 	}
 
-	uint8_t *rdata_signature = rdata + RRSIG_RDATA_SIGNER_OFFSET
-	                           + knot_dname_size(key->name);
+	size_t signature_offset = RRSIG_RDATA_SIGNER_OFFSET + knot_dname_size(key->name);
+	uint8_t *signature = rdata + signature_offset;
+	size_t signature_size = rdata_size - signature_offset;
 
-	return knot_dnssec_sign_write(sign_ctx, rdata_signature);
+	return knot_dnssec_sign_write(sign_ctx, signature, signature_size);
 }
 
 /*- Verification of signatures -----------------------------------------------*/
diff --git a/src/libknot/dnssec/sig0.c b/src/libknot/dnssec/sig0.c
index b8f255c94d5ac599d4cdb9e8a58cc29e85ab2fb4..65827b12d684d6567c4b15a087c0e16e582c31a5 100644
--- a/src/libknot/dnssec/sig0.c
+++ b/src/libknot/dnssec/sig0.c
@@ -105,8 +105,9 @@ static int sig0_write_signature(uint8_t* wire, size_t request_size,
 	assert(key->data);
 
 	knot_dnssec_sign_context_t *ctx = knot_dnssec_sign_init(key);
-	if (!ctx)
+	if (!ctx) {
 		return KNOT_ENOMEM;
+	}
 
 	size_t signature_size = knot_dnssec_sign_size(key);
 	size_t sig_rr_header_size = 11; // owner (== root), type, class, TTL
@@ -117,7 +118,7 @@ static int sig0_write_signature(uint8_t* wire, size_t request_size,
 
 	knot_dnssec_sign_add(ctx, sig_rdata, sig_rdata_size - signature_size);
 	knot_dnssec_sign_add(ctx, wire, request_size);
-	int result = knot_dnssec_sign_write(ctx, signature);
+	int result = knot_dnssec_sign_write(ctx, signature, signature_size);
 
 	knot_dnssec_sign_free(ctx);
 
diff --git a/src/libknot/dnssec/sign.c b/src/libknot/dnssec/sign.c
index 8f9a681baa69564c11c5994437488b81526d34a0..1d432267c1e1f407cbe0cebb87e92498ec326d2a 100644
--- a/src/libknot/dnssec/sign.c
+++ b/src/libknot/dnssec/sign.c
@@ -17,20 +17,25 @@
 #include <config.h>
 #include <assert.h>
 #include <openssl/dsa.h>
-#include <openssl/opensslconf.h>
 #include <openssl/evp.h>
+#include <openssl/opensslconf.h>
 #include <openssl/rsa.h>
+#include <pthread.h>
 #include "common/descriptor.h"
 #include "common/errcode.h"
 #include "libknot/common.h"
 #include "libknot/consts.h"
 #include "libknot/dnssec/config.h"
+#include "libknot/dnssec/crypto.h"
 #include "libknot/dnssec/key.h"
 #include "libknot/dnssec/sign.h"
 
 #ifdef KNOT_ENABLE_ECDSA
 #include <openssl/ecdsa.h>
 #endif
+#ifdef KNOT_ENABLE_GOST
+#include <openssl/x509.h>
+#endif
 
 #define DNSKEY_RDATA_PUBKEY_OFFSET 4
 
@@ -53,6 +58,8 @@ struct knot_dnssec_sign_context {
  * \brief Algorithm implementation specific functions.
  */
 struct algorithm_functions {
+	//! \brief Callback: function called before creating any keys/contexts
+	int (*algorithm_init)(void);
 	//! \brief Callback: create private key from key parameters.
 	int (*create_pkey)(const knot_key_params_t *, EVP_PKEY *);
 	//! \brief Callback: get signature size in bytes.
@@ -60,7 +67,7 @@ struct algorithm_functions {
 	//! \brief Callback: cover supplied data with the signature.
 	int (*sign_add)(const knot_dnssec_sign_context_t *, const uint8_t *, size_t);
 	//! \brief Callback: finish the signing and write out the signature.
-	int (*sign_write)(const knot_dnssec_sign_context_t *, uint8_t *);
+	int (*sign_write)(const knot_dnssec_sign_context_t *, uint8_t *, size_t);
 	//! \brief Callback: finish the signing and validate the signature.
 	int (*sign_verify)(const knot_dnssec_sign_context_t *, const uint8_t *, size_t);
 };
@@ -75,6 +82,14 @@ static BIGNUM *binary_to_bn(const knot_binary_t *bin)
 
 /*- Algorithm independent ----------------------------------------------------*/
 
+/*!
+ * \brief Initialize algorithm.
+ */
+static int any_algorithm_init(void)
+{
+	return KNOT_EOK;
+}
+
 /*!
  * \brief Get size of the resulting signature.
  *
@@ -112,45 +127,114 @@ static int any_sign_add(const knot_dnssec_sign_context_t *context,
 }
 
 /*!
- * \brief Finish the signing and get the RAW signature.
- *
- * Caller should free the memory returned via signature parameter.
+ * \brief Finish the signing and write the signature while checking boundaries.
  *
- * \param context         DNSSEC signature context.
- * \param signature       Pointer to signature (output).
- * \param signature_size  Signature size (output).
+ * \param context    DNSSEC signing context.
+ * \param signature  Pointer to signature to be written.
+ * \param max_size   Maximal size of the signature.
+ * \param size       Actual size of written signature.
  *
  * \return Error code, KNOT_EOK if successful.
  */
-static int any_sign_write(const knot_dnssec_sign_context_t *context,
-                           uint8_t **signature, size_t *signature_size)
+static int sign_safe_write(const knot_dnssec_sign_context_t *context,
+                           uint8_t *signature, size_t max_size, size_t *size)
 {
 	assert(context);
 	assert(signature);
-	assert(signature_size);
+	assert(size);
 
-	size_t max_size = (size_t)EVP_PKEY_size(context->key->data->private_key);
-	uint8_t *output = calloc(1, max_size);
-	if (!output) {
-		return KNOT_ENOMEM;
+	EVP_MD_CTX *digest_ctx = context->digest_context;
+	EVP_PKEY *private_key = context->key->data->private_key;
+
+	// check target size
+
+	unsigned int max_write = 0;
+	int result = EVP_SignFinal(digest_ctx, NULL, &max_write, private_key);
+	if (!result) {
+		return KNOT_DNSSEC_ESIGN;
+	}
+
+	if (max_write > max_size) {
+		return KNOT_DNSSEC_EUNEXPECTED_SIGNATURE_SIZE;
 	}
 
-	unsigned int actual_size;
-	int result = EVP_SignFinal(context->digest_context, output,
-	                           &actual_size, context->key->data->private_key);
+	// write signature
+
+	unsigned int written = 0;
+	result = EVP_SignFinal(digest_ctx, signature, &written, private_key);
 	if (!result) {
-		free(output);
 		return KNOT_DNSSEC_ESIGN;
 	}
 
-	assert(actual_size <= max_size);
+	assert(written <= max_write);
+	*size = written;
+
+	return KNOT_EOK;
+}
+
+/*!
+ * \brief Allocate space for signature, finish signature, and write it.
+ *
+ * \param context    DNSSEC signing context.
+ * \param signature  Pointer to allocated signature.
+ * \param size       Size of the written signature.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int sign_alloc_and_write(const knot_dnssec_sign_context_t *context,
+                                uint8_t **signature, size_t *size)
+{
+	assert(context);
+	assert(signature);
+	assert(size);
+
+	size_t buffer_size = EVP_PKEY_size(context->key->data->private_key);
+	uint8_t *buffer = malloc(buffer_size);
+	if (!buffer) {
+		return KNOT_ENOMEM;
+	}
+
+	size_t written = 0;
+	int result = sign_safe_write(context, buffer, buffer_size, &written);
+	if (result != KNOT_EOK) {
+		free(buffer);
+		return result;
+	}
+
+	assert(written <= buffer_size);
 
-	*signature = output;
-	*signature_size = actual_size;
+	*signature = buffer;
+	*size = written;
 
 	return KNOT_EOK;
 }
 
+/*!
+ * \brief Finish the signing and write out the signature.
+ *
+ * \note Expects algorithm whose signature size is constant.
+ *
+ * \param context         DNSSEC signing context.
+ * \param signature       Pointer to memory where the signature will be written.
+ * \param signature_size  Expected size of the signature.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int any_sign_write(const knot_dnssec_sign_context_t *context,
+                          uint8_t *signature, size_t signature_size)
+{
+	assert(context);
+	assert(signature);
+
+	size_t written_size = 0;
+	int result = sign_safe_write(context, signature,
+	                             signature_size, &written_size);
+
+	assert(written_size == signature_size);
+
+	return result;
+}
+
 /*!
  * \brief Verify the DNSSEC signature for supplied data.
  *
@@ -183,6 +267,32 @@ static int any_sign_verify(const knot_dnssec_sign_context_t *context,
 	};
 }
 
+/*!
+ * \brief Get pointer to and size of public key in DNSKEY RDATA.
+ *
+ * \param[in]  rdata        DNSKEY RDATA.
+ * \param[out] pubkey       Public key.
+ * \param[out] pubkey_size  Size of public key.
+ *
+ * \return Success.
+ */
+static bool any_dnskey_get_pubkey(const knot_binary_t *rdata,
+                                  const uint8_t **pubkey, size_t *pubkey_size)
+{
+	assert(rdata);
+	assert(pubkey);
+	assert(pubkey_size);
+
+	if (rdata->size <= DNSKEY_RDATA_PUBKEY_OFFSET) {
+		return false;
+	}
+
+	*pubkey = rdata->data + DNSKEY_RDATA_PUBKEY_OFFSET;
+	*pubkey_size = rdata->size - DNSKEY_RDATA_PUBKEY_OFFSET;
+
+	return true;
+}
+
 /*- RSA specific -------------------------------------------------------------*/
 
 /*!
@@ -225,41 +335,6 @@ static int rsa_create_pkey(const knot_key_params_t *params, EVP_PKEY *key)
 	return KNOT_EOK;
 }
 
-/*!
- * \brief Finish the signing and write out the RSA signature.
- *
- * \param context    DNSSEC signing context.
- * \param signature  Pointer to memory where the signature will be written.
- *
- * \return Error code, KNOT_EOK if successful.
- */
-static int rsa_sign_write(const knot_dnssec_sign_context_t *context,
-                          uint8_t *signature)
-{
-	assert(context);
-	assert(signature);
-
-	int result;
-	uint8_t *raw_signature;
-	size_t raw_signature_size;
-	const knot_dnssec_key_t *key = context->key;
-
-	result = any_sign_write(context, &raw_signature, &raw_signature_size);
-	if (result != KNOT_EOK) {
-		return result;
-	}
-
-	if (raw_signature_size != key->data->functions->sign_size(key)) {
-		free(raw_signature);
-		return KNOT_DNSSEC_EUNEXPECTED_SIGNATURE_SIZE;
-	}
-
-	memcpy(signature, raw_signature, raw_signature_size);
-	free(raw_signature);
-
-	return KNOT_EOK;
-}
-
 /*- DSA specific -------------------------------------------------------------*/
 
 /*!
@@ -303,19 +378,24 @@ static size_t dsa_sign_size(const knot_dnssec_key_t *key)
 
 /*!
  * \brief Finish the signing and write out the DSA signature.
- * \see rsa_sign_write
+ * \see any_sign_write
  */
 static int dsa_sign_write(const knot_dnssec_sign_context_t *context,
-                          uint8_t *signature)
+                          uint8_t *signature, size_t signature_size)
 {
 	assert(context);
 	assert(signature);
 
-	int result;
-	uint8_t *raw_signature;
-	size_t raw_signature_size;
+	size_t output_size = dsa_sign_size(context->key);
+	if (output_size != signature_size) {
+		return KNOT_DNSSEC_EUNEXPECTED_SIGNATURE_SIZE;
+	}
+
+	// create raw signature
 
-	result = any_sign_write(context, &raw_signature, &raw_signature_size);
+	uint8_t *raw_signature = NULL;
+	size_t raw_size = 0;
+	int result = sign_alloc_and_write(context, &raw_signature, &raw_size);
 	if (result != KNOT_EOK) {
 		return result;
 	}
@@ -329,7 +409,7 @@ static int dsa_sign_write(const knot_dnssec_sign_context_t *context,
 	}
 
 	const uint8_t *decode_scan = raw_signature;
-	if (!d2i_DSA_SIG(&decoded, &decode_scan, (long)raw_signature_size)) {
+	if (!d2i_DSA_SIG(&decoded, &decode_scan, (long)raw_size)) {
 		DSA_SIG_free(decoded);
 		free(raw_signature);
 		return KNOT_DNSSEC_EDECODE_RAW_SIGNATURE;
@@ -344,7 +424,7 @@ static int dsa_sign_write(const knot_dnssec_sign_context_t *context,
 	uint8_t *signature_r = signature + 21 - BN_num_bytes(decoded->r);
 	uint8_t *signature_s = signature + 41 - BN_num_bytes(decoded->s);
 
-	memset(signature, '\0', dsa_sign_size(context->key));
+	memset(signature, '\0', output_size);
 	*signature_t = 0x00; //! \todo Take from public key. Only recommended.
 	BN_bn2bin(decoded->r, signature_r);
 	BN_bn2bin(decoded->s, signature_s);
@@ -419,20 +499,19 @@ static int ecdsa_set_public_key(const knot_binary_t *rdata, EC_KEY *ec_key)
 	assert(rdata);
 	assert(ec_key);
 
-	if (rdata->size <= DNSKEY_RDATA_PUBKEY_OFFSET) {
+	const uint8_t *pubkey_data = NULL;
+	size_t pubkey_size = 0;
+	if (!any_dnskey_get_pubkey(rdata, &pubkey_data, &pubkey_size)) {
 		return KNOT_EINVAL;
 	}
 
-	uint8_t *pubkey_data = rdata->data + DNSKEY_RDATA_PUBKEY_OFFSET;
-	size_t pubkey_size = rdata->size - DNSKEY_RDATA_PUBKEY_OFFSET;
-
 	if (pubkey_size % 2 != 0) {
 		return KNOT_EINVAL;
 	}
 
 	size_t param_size = pubkey_size / 2;
-	uint8_t *x_ptr = pubkey_data;
-	uint8_t *y_ptr = pubkey_data + param_size;
+	const uint8_t *x_ptr = pubkey_data;
+	const uint8_t *y_ptr = pubkey_data + param_size;
 
 	BIGNUM *x = BN_bin2bn(x_ptr, param_size, NULL);
 	BIGNUM *y = BN_bin2bn(y_ptr, param_size, NULL);
@@ -531,16 +610,21 @@ static size_t ecdsa_sign_size(const knot_dnssec_key_t *key)
  * \see rsa_sign_write
  */
 static int ecdsa_sign_write(const knot_dnssec_sign_context_t *context,
-                            uint8_t *signature)
+                            uint8_t *signature, size_t signature_size)
 {
 	assert(context);
 	assert(signature);
 
-	int result;
-	uint8_t *raw_signature;
-	size_t raw_signature_size;
+	size_t output_size = ecdsa_sign_size(context->key);
+	if (output_size != signature_size) {
+		return KNOT_DNSSEC_EUNEXPECTED_SIGNATURE_SIZE;
+	}
 
-	result = any_sign_write(context, &raw_signature, &raw_signature_size);
+	// create raw signature
+
+	uint8_t *raw_signature = NULL;
+	size_t raw_size = 0;
+	int result = sign_alloc_and_write(context, &raw_signature, &raw_size);
 	if (result != KNOT_EOK) {
 		return result;
 	}
@@ -554,7 +638,7 @@ static int ecdsa_sign_write(const knot_dnssec_sign_context_t *context,
 	}
 
 	const uint8_t *decode_scan = raw_signature;
-	if (!d2i_ECDSA_SIG(&decoded, &decode_scan, (long)raw_signature_size)) {
+	if (!d2i_ECDSA_SIG(&decoded, &decode_scan, (long)raw_size)) {
 		ECDSA_SIG_free(decoded);
 		free(raw_signature);
 		return KNOT_DNSSEC_EDECODE_RAW_SIGNATURE;
@@ -567,10 +651,9 @@ static int ecdsa_sign_write(const knot_dnssec_sign_context_t *context,
 
 	uint8_t *signature_r;
 	uint8_t *signature_s;
-	size_t signature_size = ecdsa_sign_size(context->key);
-	size_t param_size = signature_size / 2;
+	size_t param_size = output_size / 2;
 
-	memset(signature, '\0', signature_size);
+	memset(signature, '\0', output_size);
 	signature_r = signature + param_size - BN_num_bytes(decoded->r);
 	signature_s = signature + 2 * param_size - BN_num_bytes(decoded->s);
 
@@ -637,17 +720,136 @@ static int ecdsa_sign_verify(const knot_dnssec_sign_context_t *context,
 
 #endif
 
+/*- GOST specific ------------------------------------------------------------*/
+
+#ifdef KNOT_ENABLE_GOST
+
+static pthread_once_t gost_init_control = PTHREAD_ONCE_INIT;
+
+static void gost_algorithm_init_once(void)
+{
+	knot_crypto_load_engines();
+}
+
+/*!
+ * \brief Initialize GOST algorithm.
+ * \see any_algorithm_init
+ */
+static int gost_algorithm_init(void)
+{
+	pthread_once(&gost_init_control, gost_algorithm_init_once);
+
+	return KNOT_EOK;
+}
+
+// future feature (disabled now)
+#if 0
+/*!
+ * Prefix for GOST public keys allowing to load them using X.509 API functions.
+ *
+ * GOST keys in X.509 PKI start with prefix which identifies key algorithm.
+ * GOST public keys in DNS do not contain this prefix. We have to add it as
+ * OpenSSL supports GOST using dynamic engine and has no GOST specific API.
+ *
+ * RFC 5933 (GOST in DNSSEC, specifies this prefix), RFC 4491 (GOST in X.509)
+ */
+static const uint8_t gost_x509_pubkey_prefix[] = {
+	0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02,
+	0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02,
+	0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
+	0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40
+};
+
+#define GOST_DNSSEC_PUBKEY_SIZE 64
+#define GOST_X509_PUBKEY_PREFIX_SIZE sizeof(gost_x509_pubkey_prefix)
+#define GOST_X509_PUBKEY_SIZE (GOST_X509_PUBKEY_PREFIX_SIZE + GOST_DNSSEC_PUBKEY_SIZE)
+
+static int gost_get_public_key(const knot_binary_t *dnskey_rdata, EVP_PKEY **key)
+{
+	assert(dnskey_rdata);
+	assert(key);
+
+	const uint8_t *pubkey_data = NULL;
+	size_t pubkey_size = 0;
+	if (!any_dnskey_get_pubkey(dnskey_rdata, &pubkey_data, &pubkey_size)) {
+		return KNOT_EINVAL;
+	}
+
+	if (pubkey_size != GOST_DNSSEC_PUBKEY_SIZE) {
+		return KNOT_DNSSEC_EINVALID_KEY;
+	}
+
+	// construct X.509 public key
+
+	uint8_t x509_pubkey[GOST_X509_PUBKEY_SIZE] = { '\0' };
+	uint8_t *prefix = x509_pubkey;
+	uint8_t *keydata = x509_pubkey + GOST_X509_PUBKEY_PREFIX_SIZE;
+
+	memcpy(prefix, gost_x509_pubkey_prefix, GOST_X509_PUBKEY_PREFIX_SIZE);
+	memcpy(keydata, pubkey_data, pubkey_size);
+
+	// construct EVP_PKEY
+
+	const unsigned char **parse = (const unsigned char **)&prefix;
+	EVP_PKEY *result = d2i_PUBKEY(NULL, parse, GOST_X509_PUBKEY_SIZE);
+	if (!result) {
+		return KNOT_DNSSEC_EINVALID_KEY;
+	}
+
+	*key = result;
+
+	return KNOT_EOK;
+}
+#endif
+
+static int gost_set_private_key(const knot_binary_t *private, EVP_PKEY **key)
+{
+	assert(private);
+	assert(key && *key);
+
+	const unsigned char *parse = private->data;
+	EVP_PKEY *result = d2i_PrivateKey(NID_id_GostR3410_2001, key,
+	                                  &parse, private->size);
+
+	if (result != *key) {
+		return KNOT_DNSSEC_EINVALID_KEY;
+	}
+
+	return KNOT_EOK;
+}
+
+/*!
+ * \brief Create GOST private key from key parameters.
+ * \see rsa_create_pkey
+ */
+static int gost_create_pkey(const knot_key_params_t *params, EVP_PKEY * key)
+{
+	assert(params);
+	assert(key);
+
+	int result = gost_set_private_key(&params->private_key, &key);
+	if (result != KNOT_EOK) {
+		return result;
+	}
+
+	return KNOT_EOK;
+}
+
+#endif
+
 /*- Algorithm specifications -------------------------------------------------*/
 
 static const algorithm_functions_t rsa_functions = {
+	any_algorithm_init,
 	rsa_create_pkey,
 	any_sign_size,
 	any_sign_add,
-	rsa_sign_write,
+	any_sign_write,
 	any_sign_verify
 };
 
 static const algorithm_functions_t dsa_functions = {
+	any_algorithm_init,
 	dsa_create_pkey,
 	dsa_sign_size,
 	any_sign_add,
@@ -657,6 +859,7 @@ static const algorithm_functions_t dsa_functions = {
 
 #ifdef KNOT_ENABLE_ECDSA
 static const algorithm_functions_t ecdsa_functions = {
+	any_algorithm_init,
 	ecdsa_create_pkey,
 	ecdsa_sign_size,
 	any_sign_add,
@@ -665,6 +868,17 @@ static const algorithm_functions_t ecdsa_functions = {
 };
 #endif
 
+#ifdef KNOT_ENABLE_GOST
+static const algorithm_functions_t gost_functions = {
+	gost_algorithm_init,
+	gost_create_pkey,
+	any_sign_size,
+	any_sign_add,
+	any_sign_write,
+	any_sign_verify
+};
+#endif
+
 /*!
  * \brief Get implementation specific callbacks for a given algorithm.
  *
@@ -684,10 +898,14 @@ static const algorithm_functions_t *get_implementation(int algorithm)
 	case KNOT_DNSSEC_ALG_DSA:
 	case KNOT_DNSSEC_ALG_DSA_NSEC3_SHA1:
 		return &dsa_functions;
+#ifdef KNOT_ENABLE_ECDSA
 	case KNOT_DNSSEC_ALG_ECDSAP256SHA256:
 	case KNOT_DNSSEC_ALG_ECDSAP384SHA384:
-#ifdef KNOT_ENABLE_ECDSA
 		return &ecdsa_functions;
+#endif
+#ifdef KNOT_ENABLE_GOST
+	case KNOT_DNSSEC_ALG_ECC_GOST:
+		return &gost_functions;
 #endif
 	default:
 		return NULL;
@@ -720,6 +938,10 @@ static const EVP_MD *get_digest_type(knot_dnssec_algorithm_t algorithm)
 		return EVP_sha384();
 	case KNOT_DNSSEC_ALG_RSASHA512:
 		return EVP_sha512();
+#if KNOT_ENABLE_GOST
+	case KNOT_DNSSEC_ALG_ECC_GOST:
+		return EVP_get_digestbyname(SN_id_GostR3411_94);
+#endif
 	default:
 		return NULL;
 	}
@@ -811,6 +1033,21 @@ static int destroy_digest_context(EVP_MD_CTX **context)
 	return KNOT_EOK;
 }
 
+/*!
+ * \brief Initialize algorithm.
+ *
+ * \param functions  Algorithm specific callbacks.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int init_algorithm(const algorithm_functions_t *functions)
+{
+	assert(functions);
+	assert(functions->algorithm_init);
+
+	return functions->algorithm_init();
+}
+
 /*!
  * \brief Free algorithm data.
  *
@@ -827,6 +1064,8 @@ static int clean_algorithm_data(knot_dnssec_key_data_t *data)
 		data->private_key = NULL;
 	}
 
+	memset(data, '\0', sizeof(*data));
+
 	return KNOT_EOK;
 }
 
@@ -844,17 +1083,25 @@ static int init_algorithm_data(const knot_key_params_t *params,
 	assert(params);
 	assert(data);
 
-	data->functions = get_implementation(params->algorithm);
-	if (!data->functions) {
+	knot_dnssec_key_data_t result = { '\0' };
+
+	result.functions = get_implementation(params->algorithm);
+	if (!result.functions) {
 		return KNOT_DNSSEC_ENOTSUP;
 	}
 
-	int result = create_pkey(params, data->functions, &data->private_key);
-	if (result != KNOT_EOK) {
-		clean_algorithm_data(data);
-		return result;
+	int error = init_algorithm(result.functions);
+	if (error != KNOT_EOK) {
+		return error;
+	}
+
+	error = create_pkey(params, result.functions, &result.private_key);
+	if (error != KNOT_EOK) {
+		return error;
 	}
 
+	*data = result;
+
 	return KNOT_EOK;
 }
 
@@ -1011,13 +1258,15 @@ int knot_dnssec_sign_add(knot_dnssec_sign_context_t *context,
 /**
  * \brief Write down the DNSSEC signature for supplied data.
  */
-int knot_dnssec_sign_write(knot_dnssec_sign_context_t *context, uint8_t *signature)
+int knot_dnssec_sign_write(knot_dnssec_sign_context_t *context,
+                           uint8_t *signature, size_t signature_size)
 {
-	if (!context || !context->key || !signature) {
+	if (!context || !context->key || !signature || signature_size == 0) {
 		return KNOT_EINVAL;
 	}
 
-	return context->key->data->functions->sign_write(context, signature);
+	return context->key->data->functions->sign_write(context, signature,
+	                                                 signature_size);
 }
 
 /**
diff --git a/src/libknot/dnssec/sign.h b/src/libknot/dnssec/sign.h
index a4f321c991fd324fb8dbf298df30551e8ef85232..319f08700781642cdbcfbb68b1cca13396382ded 100644
--- a/src/libknot/dnssec/sign.h
+++ b/src/libknot/dnssec/sign.h
@@ -132,13 +132,14 @@ int knot_dnssec_sign_add(knot_dnssec_sign_context_t *context,
 /**
  * \brief Write down the DNSSEC signature for supplied data.
  *
- * \param context    DNSSEC signing context.
- * \param signature  Pointer to signature to be written.
+ * \param context         DNSSEC signing context.
+ * \param signature       Pointer to signature to be written.
+ * \param signature_size  Allocated size for the signature.
  *
  * \return Error code, KNOT_EOK if successful.
  */
 int knot_dnssec_sign_write(knot_dnssec_sign_context_t *context,
-                           uint8_t *signature);
+                           uint8_t *signature, size_t signature_size);
 
 /**
  * \brief Verify the DNSSEC signature for supplied data.
diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c
index da8a0246126b8a3323816bc82a44cf1dc749f0aa..f61d4c2d6ebd8439f4a5e0efde09d9dc9772f8b4 100644
--- a/src/libknot/updates/xfr-in.c
+++ b/src/libknot/updates/xfr-in.c
@@ -1508,14 +1508,6 @@ static knot_node_t *xfrin_add_new_node(knot_zone_contents_t *contents,
 		return NULL;
 	}
 
-	/*!
-	 * \note It is not needed to set the previous node, we will do this
-	 *       in adjusting after the transfer.
-	 */
-
-	assert(contents->zone != NULL);
-	knot_node_set_zone(node, contents->zone);
-
 	return node;
 }
 
@@ -1964,10 +1956,10 @@ static void xfrin_cleanup_failed_update(knot_zone_contents_t *old_contents,
 
 	if (old_contents != NULL) {
 		// cleanup old zone tree - reset pointers to new node to NULL
-		knot_zone_tree_apply(old_contents, xfrin_cleanup_old_nodes,
+		knot_zone_tree_apply(old_contents->nodes, xfrin_cleanup_old_nodes,
 				     NULL);
 
-		knot_zone_tree_apply(old_contents, xfrin_cleanup_old_nodes,
+		knot_zone_tree_apply(old_contents->nsec3_nodes, xfrin_cleanup_old_nodes,
 				     NULL);
 	}
 }
diff --git a/src/libknot/zone/node.c b/src/libknot/zone/node.c
index 062ffcadb6105f9a0fcfdb1d23db8bf008aa5461..2bbb7068a99ef0e8b00189432bbb624bc3a56105 100644
--- a/src/libknot/zone/node.c
+++ b/src/libknot/zone/node.c
@@ -488,28 +488,6 @@ void knot_node_set_new_node(knot_node_t *node,
 
 /*----------------------------------------------------------------------------*/
 
-void knot_node_set_zone(knot_node_t *node, const knot_zone_t *zone)
-{
-	if (node == NULL) {
-		return;
-	}
-
-	node->zone = zone;
-}
-
-/*----------------------------------------------------------------------------*/
-
-const knot_zone_t *knot_node_zone(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return NULL;
-	}
-
-	return node->zone;
-}
-
-/*----------------------------------------------------------------------------*/
-
 void knot_node_update_ref(knot_node_t **ref)
 {
 	if (*ref != NULL && (*ref)->new_node != NULL) {
diff --git a/src/libknot/zone/node.h b/src/libknot/zone/node.h
index 0fdb731c53f61aefde7aebd5bb912e039ca477ab..bbf81b826b9f24b38143d624289ceb5dcc7abaee 100644
--- a/src/libknot/zone/node.h
+++ b/src/libknot/zone/node.h
@@ -70,8 +70,6 @@ struct knot_node {
 	 */
 	struct knot_node *nsec3_node;
 
-	const struct knot_zone *zone;
-
 	struct knot_node *new_node;
 
 	unsigned int children;
@@ -331,10 +329,6 @@ knot_node_t *knot_node_get_new_node(const knot_node_t *node);
 
 void knot_node_set_new_node(knot_node_t *node, knot_node_t *new_node);
 
-void knot_node_set_zone(knot_node_t *node, const struct knot_zone *zone);
-
-const struct knot_zone *knot_node_zone(const knot_node_t *node);
-
 void knot_node_update_ref(knot_node_t **ref);
 
 void knot_node_update_refs(knot_node_t *node);
diff --git a/src/libknot/zone/zone-contents.c b/src/libknot/zone/zone-contents.c
index 058db8d5c0899cf85c1d94e9ec0508e6ce25043e..f8f1a8d8b885c319cc92d892f8c0320bc3d6b2aa 100644
--- a/src/libknot/zone/zone-contents.c
+++ b/src/libknot/zone/zone-contents.c
@@ -350,7 +350,6 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex,
 
 	contents->apex = apex;
 	contents->zone = zone;
-	knot_node_set_zone(apex, contents->zone);
 	contents->node_count = 1;
 
 	dbg_zone_verb("Creating tree for normal nodes.\n");
@@ -510,8 +509,6 @@ dbg_zone_exec_detail(
 		return ret;
 	}
 
-	knot_node_set_zone(node, zone->zone);
-
 	++zone->node_count;
 
 	if (!create_parents) {
@@ -557,7 +554,6 @@ dbg_zone_exec_detail(
 
 			/* Update node pointers. */
 			knot_node_set_parent(node, next_node);
-			knot_node_set_zone(next_node, zone->zone);
 			if (knot_dname_is_wildcard(knot_node_owner(node))) {
 				knot_node_set_wildcard_child(next_node, node);
 			}
@@ -790,9 +786,6 @@ int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone,
 	// set the apex as the parent of the node
 	knot_node_set_parent(node, zone->apex);
 
-	// set the zone to the node
-	knot_node_set_zone(node, zone->zone);
-
 	// cannot be wildcard child, so nothing to be done
 
 	return KNOT_EOK;
@@ -1587,7 +1580,9 @@ void knot_zone_contents_free(knot_zone_contents_t **contents)
 	}
 
 	// free the zone tree, but only the structure
+	dbg_zone("Destroying zone tree.\n");
 	knot_zone_tree_free(&(*contents)->nodes);
+	dbg_zone("Destroying NSEC3 zone tree.\n");
 	knot_zone_tree_free(&(*contents)->nsec3_nodes);
 
 	knot_nsec3_params_free(&(*contents)->nsec3_params);
@@ -1619,19 +1614,9 @@ void knot_zone_contents_deep_free(knot_zone_contents_t **contents)
 			(*contents)->nodes,
 			knot_zone_contents_destroy_node_rrsets_from_tree,
 			(void*)1);
-
-		// free the zone tree, but only the structure
-		// (nodes are already destroyed)
-		dbg_zone("Destroying zone tree.\n");
-		knot_zone_tree_free(&(*contents)->nodes);
-		dbg_zone("Destroying NSEC3 zone tree.\n");
-		knot_zone_tree_free(&(*contents)->nsec3_nodes);
-
-		knot_nsec3_params_free(&(*contents)->nsec3_params);
 	}
 
-	free((*contents));
-	*contents = NULL;
+	knot_zone_contents_free(contents);
 }
 
 /*----------------------------------------------------------------------------*/
diff --git a/tests/dnssec_sign.c b/tests/dnssec_sign.c
index aade0d47224451e3ae70ca0bb1f5921c9a3a8fd8..c53976e0501cef3b48cd061736a569bbfca78b5d 100644
--- a/tests/dnssec_sign.c
+++ b/tests/dnssec_sign.c
@@ -24,12 +24,6 @@
 #include "libknot/dnssec/crypto.h"
 #include "libknot/dnssec/sign.h"
 
-#ifdef KNOT_ENABLE_ECDSA
-static const int ecdsa_supported = 1;
-#else
-static const int ecdsa_supported = 0;
-#endif
-
 static void test_algorithm(const char *alg, const knot_key_params_t *kp)
 {
 	int result;
@@ -64,7 +58,7 @@ static void test_algorithm(const char *alg, const knot_key_params_t *kp)
 		result = knot_dnssec_sign_add(ctx, (uint8_t *)"dns", 3);
 		is_int(KNOT_EOK, result, "%s: add data C", alg);
 
-		result = knot_dnssec_sign_write(ctx, sig);
+		result = knot_dnssec_sign_write(ctx, sig, sig_size);
 		is_int(KNOT_EOK, result, "%s: write signature", alg);
 
 		result = knot_dnssec_sign_new(ctx);
@@ -94,7 +88,7 @@ static void test_algorithm(const char *alg, const knot_key_params_t *kp)
 
 int main(int argc, char *argv[])
 {
-	plan(42);
+	plan(4 * 14);
 
 	knot_key_params_t kp = { 0 };
 
@@ -129,17 +123,29 @@ int main(int argc, char *argv[])
 
 	// ECDSA
 
-	if (!ecdsa_supported) {
-		skip_block(14, "ECDSA: not supported on this system");
-	} else {
-		kp.name = knot_dname_from_str("example.com");
-		kp.algorithm = 13;
-		knot_binary_from_base64("1N/PvpB8jZcvv+zr3Q987RKK1cBxDKULzEc5F/nnpSg=", &kp.private_key);
-		knot_binary_from_base64("AAAAAH3t6EfkvHK5fQMGslhWcCfMF6Q3oNbol2f19DGAb8r49ZX7iQ12sFIyrs2CiwDxFR9Y7fF2zOZ005VV1LA3m1Q=", &kp.rdata);
+#ifdef KNOT_ENABLE_ECDSA
+	kp.name = knot_dname_from_str("example.com");
+	kp.algorithm = 13;
+	knot_binary_from_base64("1N/PvpB8jZcvv+zr3Q987RKK1cBxDKULzEc5F/nnpSg=", &kp.private_key);
+	knot_binary_from_base64("AAAAAH3t6EfkvHK5fQMGslhWcCfMF6Q3oNbol2f19DGAb8r49ZX7iQ12sFIyrs2CiwDxFR9Y7fF2zOZ005VV1LA3m1Q=", &kp.rdata);
 
-		test_algorithm("ECDSA", &kp);
-		knot_free_key_params(&kp);
-	}
+	test_algorithm("ECDSA", &kp);
+	knot_free_key_params(&kp);
+#else
+	skip_block(14, "ECDSA: not supported on this system");
+#endif
+
+#if KNOT_ENABLE_GOST
+	kp.name = knot_dname_from_str("example.com");
+	kp.algorithm = 12;
+	knot_binary_from_base64("MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgIgN2CMRL538HmFM9+GHYM54rEDYO+tLDV3q7AtK1nZ4iA=", &kp.private_key);
+	knot_binary_from_base64("eHh4eOJ4YHvlasoDRc4ZnvRzldoTUgwWSW0bPv7r9xJ074Dn8KzM4yU9fJgTwIT1TsaHmejYopDnVdjxZyrKNra8Keo=", &kp.rdata);
+
+	test_algorithm("GOST", &kp);
+	knot_free_key_params(&kp);
+#else
+	skip_block(14, "GOST: not supported on this system");
+#endif
 
 	knot_crypto_cleanup();