aboutsummaryrefslogtreecommitdiff
path: root/gost_prov_digest.c
diff options
context:
space:
mode:
authorRichard Levitte <richard@levitte.org>2021-02-13 14:56:17 +0100
committerDmitry Belyavskiy <beldmit@users.noreply.github.com>2021-10-11 19:34:09 +0300
commitdd645e71d12ec790dc6c2e1c44163e2683ae4c6a (patch)
treee25ee4494237ac6f1e34867c4bbf3d87e2af527d /gost_prov_digest.c
parentbd2d5542f307ae0e9e98a291f0d765a0be58b5fd (diff)
downloadgost-engine-dd645e71d12ec790dc6c2e1c44163e2683ae4c6a.zip
gost-engine-dd645e71d12ec790dc6c2e1c44163e2683ae4c6a.tar.gz
gost-engine-dd645e71d12ec790dc6c2e1c44163e2683ae4c6a.tar.bz2
Making a gost provider - Add the digests
We add the digests for the provider as wrappers around the routines designed for ENGINEs. This is not the most elegant, but it does the job. When an algorithm has an OID, it's included in the OSSL_ALGORITHM name as an aliase. This is the way to avoid having to register the OIDs in OpenSSL proper. test/01-digest.t is modified to test the provider as well.
Diffstat (limited to 'gost_prov_digest.c')
-rw-r--r--gost_prov_digest.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/gost_prov_digest.c b/gost_prov_digest.c
new file mode 100644
index 0000000..9acd005
--- /dev/null
+++ b/gost_prov_digest.c
@@ -0,0 +1,200 @@
+/**********************************************************************
+ * gost_prov_digest.c - Initialize all digests *
+ * *
+ * Copyright (c) 2021 Richard Levitte <richard@levitte.org> *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * OpenSSL provider interface to GOST digest functions *
+ * Requires OpenSSL 3.0 for compilation *
+ **********************************************************************/
+
+#include <openssl/core.h>
+#include <openssl/core_dispatch.h>
+#include "gost_prov.h"
+#include "gost_lcl.h"
+
+/*
+ * Forward declarations of all OSSL_DISPATCH functions, to make sure they
+ * are correctly defined further down.
+ */
+static OSSL_FUNC_digest_dupctx_fn digest_dupctx;
+static OSSL_FUNC_digest_freectx_fn digest_freectx;
+static OSSL_FUNC_digest_init_fn digest_init;
+static OSSL_FUNC_digest_update_fn digest_update;
+static OSSL_FUNC_digest_final_fn digest_final;
+
+
+struct gost_prov_crypt_ctx_st {
+ /* Provider context */
+ PROV_CTX *provctx;
+ /* OSSL_PARAM descriptors */
+ const OSSL_PARAM *known_params;
+ /* GOST_digest descriptor */
+ GOST_digest *descriptor;
+
+ /*
+ * Since existing functionality is designed for ENGINEs, the functions
+ * in this file are accomodated and are simply wrappers that use a local
+ * EVP_MD and EVP_MD_CTX.
+ * Future development should take a more direct approach and have the
+ * appropriate digest functions and digest data directly in this context.
+ */
+
+ /* The EVP_MD created from |descriptor| */
+ EVP_MD *digest;
+ /* The context for the EVP_MD functions */
+ EVP_MD_CTX *dctx;
+};
+typedef struct gost_prov_crypt_ctx_st GOST_CTX;
+
+static void digest_freectx(void *vgctx)
+{
+ GOST_CTX *gctx = vgctx;
+
+ /*
+ * We don't free gctx->digest here.
+ * That will be done by the provider teardown, via
+ * GOST_prov_deinit_digests() (defined at the bottom of this file).
+ */
+ EVP_MD_CTX_free(gctx->dctx);
+ OPENSSL_free(gctx);
+}
+
+static GOST_CTX *digest_newctx(void *provctx, GOST_digest *descriptor,
+ const OSSL_PARAM *known_params)
+{
+ GOST_CTX *gctx = NULL;
+
+ if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) {
+ gctx->provctx = provctx;
+ gctx->known_params = known_params;
+ gctx->descriptor = descriptor;
+ gctx->digest = GOST_init_digest(descriptor);
+ gctx->dctx = EVP_MD_CTX_new();
+
+ if (gctx->digest == NULL || gctx->dctx == NULL) {
+ digest_freectx(gctx);
+ gctx = NULL;
+ }
+ }
+ return gctx;
+}
+
+static void *digest_dupctx(void *vsrc)
+{
+ GOST_CTX *src = vsrc;
+ GOST_CTX *dst =
+ digest_newctx(src->provctx, src->descriptor, src->known_params);
+
+ if (dst != NULL)
+ EVP_MD_CTX_copy(dst->dctx, src->dctx);
+ return dst;
+}
+
+static int digest_get_params(EVP_MD *d, OSSL_PARAM params[])
+{
+ OSSL_PARAM *p;
+
+ if (((p = OSSL_PARAM_locate(params, "blocksize")) != NULL
+ && !OSSL_PARAM_set_size_t(p, EVP_MD_block_size(d)))
+ || ((p = OSSL_PARAM_locate(params, "size")) != NULL
+ && !OSSL_PARAM_set_size_t(p, EVP_MD_size(d)))
+ || ((p = OSSL_PARAM_locate(params, "xof")) != NULL
+ && !OSSL_PARAM_set_size_t(p, EVP_MD_flags(d) & EVP_MD_FLAG_XOF)))
+ return 0;
+ return 1;
+}
+
+static int digest_init(void *vgctx, const OSSL_PARAM unused_params[])
+{
+ GOST_CTX *gctx = vgctx;
+
+ return EVP_DigestInit_ex(gctx->dctx, gctx->digest, gctx->provctx->e) > 0;
+}
+
+static int digest_update(void *vgctx, const unsigned char *in, size_t inl)
+{
+ GOST_CTX *gctx = vgctx;
+
+ return EVP_DigestUpdate(gctx->dctx, in, (int)inl) > 0;
+}
+
+static int digest_final(void *vgctx,
+ unsigned char *out, size_t *outl, size_t outsize)
+{
+ GOST_CTX *gctx = vgctx;
+ unsigned int int_outl = outl != NULL ? *outl : 0;
+ int res = EVP_DigestFinal(gctx->dctx, out, &int_outl);
+
+ if (res > 0 && outl != NULL)
+ *outl = (size_t)int_outl;
+ return res > 0;
+}
+
+static const OSSL_PARAM known_GostR3411_94_digest_params[] = {};
+static const OSSL_PARAM known_GostR3411_2012_256_digest_params[] = {};
+static const OSSL_PARAM known_GostR3411_2012_512_digest_params[] = {};
+
+/*
+ * These are named like the EVP_MD templates in gost_md.c etc, with the
+ * added suffix "_functions". Hopefully, that makes it easy to find the
+ * actual implementation.
+ */
+typedef void (*fptr_t)(void);
+#define MAKE_FUNCTIONS(name) \
+ static OSSL_FUNC_digest_get_params_fn name##_get_params; \
+ static int name##_get_params(OSSL_PARAM *params) \
+ { \
+ return digest_get_params(GOST_init_digest(&name), params); \
+ } \
+ static OSSL_FUNC_digest_newctx_fn name##_newctx; \
+ static void *name##_newctx(void *provctx) \
+ { \
+ return digest_newctx(provctx, &name, known_##name##_params); \
+ } \
+ static const OSSL_DISPATCH name##_functions[] = { \
+ { OSSL_FUNC_DIGEST_GET_PARAMS, (fptr_t)name##_get_params }, \
+ { OSSL_FUNC_DIGEST_NEWCTX, (fptr_t)name##_newctx }, \
+ { OSSL_FUNC_DIGEST_DUPCTX, (fptr_t)digest_dupctx }, \
+ { OSSL_FUNC_DIGEST_FREECTX, (fptr_t)digest_freectx }, \
+ { OSSL_FUNC_DIGEST_INIT, (fptr_t)digest_init }, \
+ { OSSL_FUNC_DIGEST_UPDATE, (fptr_t)digest_update }, \
+ { OSSL_FUNC_DIGEST_FINAL, (fptr_t)digest_final }, \
+ }
+
+MAKE_FUNCTIONS(GostR3411_94_digest);
+MAKE_FUNCTIONS(GostR3411_2012_256_digest);
+MAKE_FUNCTIONS(GostR3411_2012_512_digest);
+
+/* The OSSL_ALGORITHM for the provider's operation query function */
+const OSSL_ALGORITHM GOST_prov_digests[] = {
+ /*
+ * Described in RFC 6986, first name from
+ * https://www.ietf.org/archive/id/draft-deremin-rfc4491-bis-06.txt
+ * (is there not an RFC namming these?)
+ */
+ { "id-tc26-gost3411-12-256:md_gost12_256:1.2.643.7.1.1.2.2", NULL,
+ GostR3411_2012_256_digest_functions,
+ "GOST R 34.11-2012 with 256 bit hash" },
+ { "id-tc26-gost3411-12-512:md_gost12_512:1.2.643.7.1.1.2.3", NULL,
+ GostR3411_2012_512_digest_functions,
+ "GOST R 34.11-2012 with 512 bit hash" },
+
+ /* Described in RFC 5831, first name from RFC 4357, section 10.4 */
+ { "id-GostR3411-94:md_gost94:1.2.643.2.2.9", NULL,
+ GostR3411_94_digest_functions, "GOST R 34.11-94" },
+ { NULL , NULL, NULL }
+};
+
+void GOST_prov_deinit_digests(void) {
+ static GOST_digest *list[] = {
+ &GostR3411_94_digest,
+ &GostR3411_2012_256_digest,
+ &GostR3411_2012_512_digest,
+ };
+ size_t i;
+#define elems(l) (sizeof(l) / sizeof(l[0]))
+
+ for (i = 0; i < elems(list); i++)
+ GOST_deinit_digest(list[i]);
+}