]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
lib: add support for gnutls_hash_copy()
authorDmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Wed, 26 Jun 2019 08:00:39 +0000 (11:00 +0300)
committerDmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Wed, 26 Jun 2019 08:01:19 +0000 (11:01 +0300)
Add gnutls_hash_copy() function for copying message digest context.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
12 files changed:
devel/libgnutls-latest-x86_64.abi
devel/symbols.last
doc/Makefile.am
doc/manpages/Makefile.am
lib/crypto-api.c
lib/crypto-backend.h
lib/crypto-selftests.c
lib/hash_int.c
lib/hash_int.h
lib/includes/gnutls/crypto.h
lib/libgnutls.map
lib/nettle/mac.c

index c63a68d94e45ece90f26b0bcc5fae8fb39306041..3fa7f452388af60135267ffb7224a54c7b9882ee 100644 (file)
     <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'/>
index e3d5fa22a51854691307419619da4e9c00a29588..e5ff89d5e4bb951a04ff0672f6391d980a46694e 100644 (file)
@@ -262,6 +262,7 @@ gnutls_handshake_set_private_extensions@GNUTLS_3_4
 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
index f5788e7618e0b7bb564636c55d45f0d71a8e26aa..6d21d74820cd281258edcea8da59f6583eaa4bb9 100644 (file)
@@ -1079,6 +1079,8 @@ FUNCS += functions/gnutls_handshake_set_timeout
 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
index d4d358ea5cc28f88c456ba7a53cbf18254ad752d..d06c180138df3bd1d50a34f1c33682a0cf05d2e0 100644 (file)
@@ -341,6 +341,7 @@ APIMANS += gnutls_handshake_set_private_extensions.3
 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
index db7a08fd92d63d4e2f14286c3b8c0c92be9d62e5..0cd3d21723a8b84de640faa40f69820d8859754c 100644 (file)
@@ -636,6 +636,38 @@ gnutls_hash_fast(gnutls_digest_algorithm_t algorithm,
        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
index f91a5387d10dbfa585ae92cd1e32dd073a70ba05..43124abafbdc842a48352f4f044c1902562f090e 100644 (file)
@@ -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. */
index 200d98ee8d81e33aef04736f22a136362e08c8ae..51105938459926b9519a6f8cb081bdad9f81bf40 100644 (file)
@@ -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",
index 61e24d53750d36b13936302ed700d7e546655fee..d326960e8078d901446f28210df3929032a79273 100644 (file)
@@ -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) {
index 8e3154daa6ad77e85b9269eafff39d73446f966a..9f6059da33745ab2b436a5e099e9ff7fe64f749e 100644 (file)
@@ -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);
index 1afadd8759050fa2f89218063bb2119060b89247..d2b8cae8f4cc6a0ab207c9aedc89c501747e9f7a 100644 (file)
@@ -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,
index 8f504b70f0e472e51b010ce64b941cad0131b8cf..0f31f4aef42ac51ca248b3bd5737b3b7d4f46892 100644 (file)
@@ -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 {
index 90789d876f32d717aea56b005ca0e3c863509795..8107f7cea448927670ebc1dc6bdbdefbff0e2a7e 100644 (file)
@@ -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,
 };