summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/crypto-api.c32
-rw-r--r--lib/crypto-backend.h1
-rw-r--r--lib/crypto-selftests.c27
-rw-r--r--lib/hash_int.c16
-rw-r--r--lib/hash_int.h3
-rw-r--r--lib/includes/gnutls/crypto.h2
-rw-r--r--lib/libgnutls.map1
-rw-r--r--lib/nettle/mac.c17
8 files changed, 99 insertions, 0 deletions
diff --git a/lib/crypto-api.c b/lib/crypto-api.c
index db7a08fd92..0cd3d21723 100644
--- a/lib/crypto-api.c
+++ b/lib/crypto-api.c
@@ -637,6 +637,38 @@ gnutls_hash_fast(gnutls_digest_algorithm_t algorithm,
}
/**
+ * 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
* created key
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h
index f91a5387d1..43124abafb 100644
--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -68,6 +68,7 @@ typedef struct {
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. */
diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c
index 200d98ee8d..5110593845 100644
--- a/lib/crypto-selftests.c
+++ b/lib/crypto-selftests.c
@@ -1355,6 +1355,7 @@ static int test_digest(gnutls_digest_algorithm_t dig,
int ret;
size_t data_size;
gnutls_hash_hd_t hd;
+ gnutls_hash_hd_t copy;
if (_gnutls_digest_exists(dig) == 0)
return 0;
@@ -1371,6 +1372,14 @@ static int test_digest(gnutls_digest_algorithm_t dig,
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);
@@ -1390,6 +1399,24 @@ static int test_digest(gnutls_digest_algorithm_t dig,
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",
diff --git a/lib/hash_int.c b/lib/hash_int.c
index 61e24d5375..d326960e80 100644
--- a/lib/hash_int.c
+++ b/lib/hash_int.c
@@ -54,6 +54,7 @@ int _gnutls_hash_init(digest_hd_st * dig, const mac_entry_st * e)
dig->hash = cc->hash;
dig->output = cc->output;
dig->deinit = cc->deinit;
+ dig->copy = cc->copy;
return 0;
}
@@ -67,6 +68,7 @@ int _gnutls_hash_init(digest_hd_st * dig, const mac_entry_st * e)
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;
}
@@ -88,6 +90,20 @@ int _gnutls_digest_exists(gnutls_digest_algorithm_t algo)
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) {
diff --git a/lib/hash_int.h b/lib/hash_int.h
index 8e3154daa6..9f6059da33 100644
--- a/lib/hash_int.h
+++ b/lib/hash_int.h
@@ -48,6 +48,7 @@ typedef struct {
hash_func hash;
output_func output;
hash_deinit_func deinit;
+ copy_func copy;
const void *key; /* esoteric use by SSL3 MAC functions */
int keysize;
@@ -126,6 +127,8 @@ _gnutls_hash(digest_hd_st * handle, const void *text, size_t textlen)
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);
diff --git a/lib/includes/gnutls/crypto.h b/lib/includes/gnutls/crypto.h
index 1afadd8759..d2b8cae8f4 100644
--- a/lib/includes/gnutls/crypto.h
+++ b/lib/includes/gnutls/crypto.h
@@ -122,6 +122,7 @@ void gnutls_hash_deinit(gnutls_hash_hd_t handle, 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 */
@@ -229,6 +230,7 @@ typedef int (*gnutls_digest_output_func) (void *src_ctx, void *digest, size_t di
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,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 8f504b70f0..0f31f4aef4 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1291,6 +1291,7 @@ GNUTLS_3_6_9
global:
gnutls_get_system_config_file;
gnutls_hmac_copy;
+ gnutls_hash_copy;
} GNUTLS_3_6_8;
GNUTLS_FIPS140_3_4 {
diff --git a/lib/nettle/mac.c b/lib/nettle/mac.c
index 90789d876f..8107f7cea4 100644
--- a/lib/nettle/mac.c
+++ b/lib/nettle/mac.c
@@ -632,6 +632,22 @@ wrap_nettle_hash_init(gnutls_digest_algorithm_t algo, void **_ctx)
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)
{
@@ -667,4 +683,5 @@ gnutls_crypto_digest_st _gnutls_digest_ops = {
.deinit = wrap_nettle_hash_deinit,
.fast = wrap_nettle_hash_fast,
.exists = wrap_nettle_hash_exists,
+ .copy = wrap_nettle_hash_copy,
};