aboutsummaryrefslogtreecommitdiff
path: root/gost_prov_digest.c
blob: 79eb5a30a128faf537aaccf3a41291f45fe8d4d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
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]);
}