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 
evp_mac_up_ref(void * vmac)19 static 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 
evp_mac_free(void * vmac)28 static 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 
evp_mac_new(void)45 static 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 
evp_mac_from_algorithm(int name_id,const OSSL_ALGORITHM * algodef,OSSL_PROVIDER * prov)60 static 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 
EVP_MAC_fetch(OSSL_LIB_CTX * libctx,const char * algorithm,const char * properties)169 EVP_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 
EVP_MAC_up_ref(EVP_MAC * mac)177 int EVP_MAC_up_ref(EVP_MAC *mac)
178 {
179     return evp_mac_up_ref(mac);
180 }
181 
EVP_MAC_free(EVP_MAC * mac)182 void EVP_MAC_free(EVP_MAC *mac)
183 {
184     evp_mac_free(mac);
185 }
186 
EVP_MAC_get0_provider(const EVP_MAC * mac)187 const OSSL_PROVIDER *EVP_MAC_get0_provider(const EVP_MAC *mac)
188 {
189     return mac->prov;
190 }
191 
EVP_MAC_gettable_params(const EVP_MAC * mac)192 const 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 
EVP_MAC_gettable_ctx_params(const EVP_MAC * mac)199 const 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 
EVP_MAC_settable_ctx_params(const EVP_MAC * mac)209 const 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 
EVP_MAC_CTX_gettable_params(EVP_MAC_CTX * ctx)219 const 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 
EVP_MAC_CTX_settable_params(EVP_MAC_CTX * ctx)229 const 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 
EVP_MAC_do_all_provided(OSSL_LIB_CTX * libctx,void (* fn)(EVP_MAC * mac,void * arg),void * arg)239 void 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