]> www.wagner.pp.ru Git - openssl-gost/engine.git/blobdiff - gost_prov_digest.c
Making a gost provider - Add the digests
[openssl-gost/engine.git] / gost_prov_digest.c
diff --git a/gost_prov_digest.c b/gost_prov_digest.c
new file mode 100644 (file)
index 0000000..9acd005
--- /dev/null
@@ -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]);
+}