1/*
2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <openssl/evp.h>
11#include <openssl/err.h>
12#include <openssl/core.h>
13#include <openssl/core_dispatch.h>
14#include "internal/provider.h"
15#include "internal/core.h"
16#include "crypto/evp.h"
17#include "evp_local.h"
18
19static int evp_mac_up_ref(void *vmac)
20{
21    EVP_MAC *mac = vmac;
22    int ref = 0;
23
24    CRYPTO_UP_REF(&mac->refcnt, &ref, mac->lock);
25    return 1;
26}
27
28static void evp_mac_free(void *vmac)
29{
30    EVP_MAC *mac = vmac;
31    int ref = 0;
32
33    if (mac == NULL)
34        return;
35
36    CRYPTO_DOWN_REF(&mac->refcnt, &ref, mac->lock);
37    if (ref > 0)
38        return;
39    OPENSSL_free(mac->type_name);
40    ossl_provider_free(mac->prov);
41    CRYPTO_THREAD_lock_free(mac->lock);
42    OPENSSL_free(mac);
43}
44
45static void *evp_mac_new(void)
46{
47    EVP_MAC *mac = NULL;
48
49    if ((mac = OPENSSL_zalloc(sizeof(*mac))) == NULL
50        || (mac->lock = CRYPTO_THREAD_lock_new()) == NULL) {
51        evp_mac_free(mac);
52        return NULL;
53    }
54
55    mac->refcnt = 1;
56
57    return mac;
58}
59
60static void *evp_mac_from_algorithm(int name_id,
61                                    const OSSL_ALGORITHM *algodef,
62                                    OSSL_PROVIDER *prov)
63{
64    const OSSL_DISPATCH *fns = algodef->implementation;
65    EVP_MAC *mac = NULL;
66    int fnmaccnt = 0, fnctxcnt = 0;
67
68    if ((mac = evp_mac_new()) == NULL) {
69        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
70        return NULL;
71    }
72    mac->name_id = name_id;
73    if ((mac->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
74        evp_mac_free(mac);
75        return NULL;
76    }
77    mac->description = algodef->algorithm_description;
78
79    for (; fns->function_id != 0; fns++) {
80        switch (fns->function_id) {
81        case OSSL_FUNC_MAC_NEWCTX:
82            if (mac->newctx != NULL)
83                break;
84            mac->newctx = OSSL_FUNC_mac_newctx(fns);
85            fnctxcnt++;
86            break;
87        case OSSL_FUNC_MAC_DUPCTX:
88            if (mac->dupctx != NULL)
89                break;
90            mac->dupctx = OSSL_FUNC_mac_dupctx(fns);
91            break;
92        case OSSL_FUNC_MAC_FREECTX:
93            if (mac->freectx != NULL)
94                break;
95            mac->freectx = OSSL_FUNC_mac_freectx(fns);
96            fnctxcnt++;
97            break;
98        case OSSL_FUNC_MAC_INIT:
99            if (mac->init != NULL)
100                break;
101            mac->init = OSSL_FUNC_mac_init(fns);
102            fnmaccnt++;
103            break;
104        case OSSL_FUNC_MAC_UPDATE:
105            if (mac->update != NULL)
106                break;
107            mac->update = OSSL_FUNC_mac_update(fns);
108            fnmaccnt++;
109            break;
110        case OSSL_FUNC_MAC_FINAL:
111            if (mac->final != NULL)
112                break;
113            mac->final = OSSL_FUNC_mac_final(fns);
114            fnmaccnt++;
115            break;
116        case OSSL_FUNC_MAC_GETTABLE_PARAMS:
117            if (mac->gettable_params != NULL)
118                break;
119            mac->gettable_params =
120                OSSL_FUNC_mac_gettable_params(fns);
121            break;
122        case OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS:
123            if (mac->gettable_ctx_params != NULL)
124                break;
125            mac->gettable_ctx_params =
126                OSSL_FUNC_mac_gettable_ctx_params(fns);
127            break;
128        case OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS:
129            if (mac->settable_ctx_params != NULL)
130                break;
131            mac->settable_ctx_params =
132                OSSL_FUNC_mac_settable_ctx_params(fns);
133            break;
134        case OSSL_FUNC_MAC_GET_PARAMS:
135            if (mac->get_params != NULL)
136                break;
137            mac->get_params = OSSL_FUNC_mac_get_params(fns);
138            break;
139        case OSSL_FUNC_MAC_GET_CTX_PARAMS:
140            if (mac->get_ctx_params != NULL)
141                break;
142            mac->get_ctx_params = OSSL_FUNC_mac_get_ctx_params(fns);
143            break;
144        case OSSL_FUNC_MAC_SET_CTX_PARAMS:
145            if (mac->set_ctx_params != NULL)
146                break;
147            mac->set_ctx_params = OSSL_FUNC_mac_set_ctx_params(fns);
148            break;
149        }
150    }
151    if (fnmaccnt != 3
152        || fnctxcnt != 2) {
153        /*
154         * In order to be a consistent set of functions we must have at least
155         * a complete set of "mac" functions, and a complete set of context
156         * management functions, as well as the size function.
157         */
158        evp_mac_free(mac);
159        ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
160        return NULL;
161    }
162    mac->prov = prov;
163    if (prov != NULL)
164        ossl_provider_up_ref(prov);
165
166    return mac;
167}
168
169EVP_MAC *EVP_MAC_fetch(OSSL_LIB_CTX *libctx, const char *algorithm,
170                       const char *properties)
171{
172    return evp_generic_fetch(libctx, OSSL_OP_MAC, algorithm, properties,
173                             evp_mac_from_algorithm, evp_mac_up_ref,
174                             evp_mac_free);
175}
176
177int EVP_MAC_up_ref(EVP_MAC *mac)
178{
179    return evp_mac_up_ref(mac);
180}
181
182void EVP_MAC_free(EVP_MAC *mac)
183{
184    evp_mac_free(mac);
185}
186
187const OSSL_PROVIDER *EVP_MAC_get0_provider(const EVP_MAC *mac)
188{
189    return mac->prov;
190}
191
192const OSSL_PARAM *EVP_MAC_gettable_params(const EVP_MAC *mac)
193{
194    if (mac->gettable_params == NULL)
195        return NULL;
196    return mac->gettable_params(ossl_provider_ctx(EVP_MAC_get0_provider(mac)));
197}
198
199const OSSL_PARAM *EVP_MAC_gettable_ctx_params(const EVP_MAC *mac)
200{
201    void *alg;
202
203    if (mac->gettable_ctx_params == NULL)
204        return NULL;
205    alg = ossl_provider_ctx(EVP_MAC_get0_provider(mac));
206    return mac->gettable_ctx_params(NULL, alg);
207}
208
209const OSSL_PARAM *EVP_MAC_settable_ctx_params(const EVP_MAC *mac)
210{
211    void *alg;
212
213    if (mac->settable_ctx_params == NULL)
214        return NULL;
215    alg = ossl_provider_ctx(EVP_MAC_get0_provider(mac));
216    return mac->settable_ctx_params(NULL, alg);
217}
218
219const OSSL_PARAM *EVP_MAC_CTX_gettable_params(EVP_MAC_CTX *ctx)
220{
221    void *alg;
222
223    if (ctx->meth->gettable_ctx_params == NULL)
224        return NULL;
225    alg = ossl_provider_ctx(EVP_MAC_get0_provider(ctx->meth));
226    return ctx->meth->gettable_ctx_params(ctx->algctx, alg);
227}
228
229const OSSL_PARAM *EVP_MAC_CTX_settable_params(EVP_MAC_CTX *ctx)
230{
231    void *alg;
232
233    if (ctx->meth->settable_ctx_params == NULL)
234        return NULL;
235    alg = ossl_provider_ctx(EVP_MAC_get0_provider(ctx->meth));
236    return ctx->meth->settable_ctx_params(ctx->algctx, alg);
237}
238
239void EVP_MAC_do_all_provided(OSSL_LIB_CTX *libctx,
240                             void (*fn)(EVP_MAC *mac, void *arg),
241                             void *arg)
242{
243    evp_generic_do_all(libctx, OSSL_OP_MAC,
244                       (void (*)(void *, void *))fn, arg,
245                       evp_mac_from_algorithm, evp_mac_up_ref, evp_mac_free);
246}
247