Add gnutls_hash_copy() function for copying message digest context.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
<elf-symbol name='gnutls_handshake_set_random' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_handshake_set_timeout' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_hash' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='gnutls_hash_copy' version='GNUTLS_3_6_9' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_hash_deinit' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_hash_fast' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_hash_get_len' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
gnutls_handshake_set_random@GNUTLS_3_4
gnutls_handshake_set_timeout@GNUTLS_3_4
gnutls_hash@GNUTLS_3_4
+gnutls_hash_copy@GNUTLS_3_6_9
gnutls_hash_deinit@GNUTLS_3_4
gnutls_hash_fast@GNUTLS_3_4
gnutls_hash_get_len@GNUTLS_3_4
FUNCS += functions/gnutls_handshake_set_timeout.short
FUNCS += functions/gnutls_hash
FUNCS += functions/gnutls_hash.short
+FUNCS += functions/gnutls_hash_copy
+FUNCS += functions/gnutls_hash_copy.short
FUNCS += functions/gnutls_hash_deinit
FUNCS += functions/gnutls_hash_deinit.short
FUNCS += functions/gnutls_hash_fast
APIMANS += gnutls_handshake_set_random.3
APIMANS += gnutls_handshake_set_timeout.3
APIMANS += gnutls_hash.3
+APIMANS += gnutls_hash_copy.3
APIMANS += gnutls_hash_deinit.3
APIMANS += gnutls_hash_fast.3
APIMANS += gnutls_hash_get_len.3
return _gnutls_hash_fast(algorithm, ptext, ptext_len, digest);
}
+/**
+ * gnutls_hash_copy:
+ * @handle: is a #gnutls_hash_hd_t type
+ *
+ * This function will create a copy of Message Digest context, containing all
+ * its current state. Copying contexts for Message Digests registered using
+ * gnutls_crypto_register_digest() is not supported and will always result in
+ * an error.
+ *
+ * Returns: new Message Digest context or NULL in case of an error.
+ *
+ * Since: 3.6.9
+ */
+gnutls_hash_hd_t gnutls_hash_copy(gnutls_hash_hd_t handle)
+{
+ gnutls_hash_hd_t dig;
+
+ dig = gnutls_malloc(sizeof(digest_hd_st));
+ if (dig == NULL) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ if (_gnutls_hash_copy((const digest_hd_st *) handle, (digest_hd_st *)dig) != GNUTLS_E_SUCCESS) {
+ gnutls_assert();
+ gnutls_free(dig);
+ return NULL;
+ }
+
+ return dig;
+}
+
/**
* gnutls_key_generate:
* @key: is a pointer to a #gnutls_datum_t which will contain a newly
gnutls_digest_output_func output;
gnutls_digest_deinit_func deinit;
gnutls_digest_fast_func fast;
+ gnutls_digest_copy_func copy;
/* Not needed for registered on run-time. Only included
* should define it. */
int ret;
size_t data_size;
gnutls_hash_hd_t hd;
+ gnutls_hash_hd_t copy;
if (_gnutls_digest_exists(dig) == 0)
return 0;
if (ret < 0)
return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ copy = gnutls_hash_copy(hd);
+ /* Returning NULL is not an error here for the time being, but
+ * it might become one later */
+#if 0
+ if (!copy)
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+#endif
+
ret = gnutls_hash(hd,
&vectors[i].plaintext[1],
vectors[i].plaintext_size - 1);
gnutls_digest_get_name(dig), i);
return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
+
+ if (copy != NULL) {
+ ret = gnutls_hash(copy,
+ &vectors[i].plaintext[1],
+ vectors[i].plaintext_size - 1);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+
+ memset(data, 0xaa, data_size);
+ gnutls_hash_deinit(copy, data);
+
+ if (memcmp(data, vectors[i].output,
+ vectors[i].output_size) != 0) {
+ _gnutls_debug_log("%s copy test vector %d failed!\n",
+ gnutls_digest_get_name(dig), i);
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+ }
}
_gnutls_debug_log("%s self check succeeded\n",
dig->hash = cc->hash;
dig->output = cc->output;
dig->deinit = cc->deinit;
+ dig->copy = cc->copy;
return 0;
}
dig->hash = _gnutls_digest_ops.hash;
dig->output = _gnutls_digest_ops.output;
dig->deinit = _gnutls_digest_ops.deinit;
+ dig->copy = _gnutls_digest_ops.copy;
return 0;
}
return _gnutls_digest_ops.exists(algo);
}
+int _gnutls_hash_copy(const digest_hd_st * handle, digest_hd_st * dst)
+{
+ if (handle->copy == NULL)
+ return gnutls_assert_val(GNUTLS_E_HASH_FAILED);
+
+ *dst = *handle; /* copy data */
+ dst->handle = handle->copy(handle->handle);
+
+ if (dst->handle == NULL)
+ return GNUTLS_E_HASH_FAILED;
+
+ return 0;
+}
+
void _gnutls_hash_deinit(digest_hd_st * handle, void *digest)
{
if (handle->handle == NULL) {
hash_func hash;
output_func output;
hash_deinit_func deinit;
+ copy_func copy;
const void *key; /* esoteric use by SSL3 MAC functions */
int keysize;
void _gnutls_hash_deinit(digest_hd_st * handle, void *digest);
+int _gnutls_hash_copy(const digest_hd_st * handle, digest_hd_st * dst);
+
int
_gnutls_hash_fast(gnutls_digest_algorithm_t algorithm,
const void *text, size_t textlen, void *digest);
unsigned gnutls_hash_get_len(gnutls_digest_algorithm_t algorithm) __GNUTLS_CONST__;
int gnutls_hash_fast(gnutls_digest_algorithm_t algorithm,
const void *text, size_t textlen, void *digest);
+gnutls_hash_hd_t gnutls_hash_copy(gnutls_hash_hd_t handle);
/* register ciphers */
typedef void (*gnutls_digest_deinit_func) (void *ctx);
typedef int (*gnutls_digest_fast_func) (gnutls_digest_algorithm_t,
const void *text, size_t textsize, void *digest);
+typedef void *(*gnutls_digest_copy_func) (const void *ctx);
int
gnutls_crypto_register_digest(gnutls_digest_algorithm_t digest,
global:
gnutls_get_system_config_file;
gnutls_hmac_copy;
+ gnutls_hash_copy;
} GNUTLS_3_6_8;
GNUTLS_FIPS140_3_4 {
return 0;
}
+static void *wrap_nettle_hash_copy(const void *_ctx)
+{
+ const struct nettle_hash_ctx *ctx = _ctx;
+ struct nettle_hash_ctx *new_ctx;
+ ptrdiff_t off = (uint8_t *)ctx->ctx_ptr - (uint8_t *)(&ctx->ctx);
+
+ new_ctx = gnutls_calloc(1, sizeof(struct nettle_hash_ctx));
+ if (new_ctx == NULL)
+ return NULL;
+
+ memcpy(new_ctx, ctx, sizeof(*ctx));
+ new_ctx->ctx_ptr = (uint8_t *)&new_ctx->ctx + off;
+
+ return new_ctx;
+}
+
static int
wrap_nettle_hash_output(void *src_ctx, void *digest, size_t digestsize)
{
.deinit = wrap_nettle_hash_deinit,
.fast = wrap_nettle_hash_fast,
.exists = wrap_nettle_hash_exists,
+ .copy = wrap_nettle_hash_copy,
};