hkdf: when HMAC key is all zeros, still set a valid key length
[openssl.git] / providers / common / provider_util.c
1 /*
2  * Copyright 2019-2020 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 /* We need to use some engine deprecated APIs */
11 #define OPENSSL_SUPPRESS_DEPRECATED
12
13 #include <openssl/evp.h>
14 #include <openssl/core_names.h>
15 #include <openssl/err.h>
16 #include "prov/provider_util.h"
17 #include "prov/providercommonerr.h"
18 #include "internal/nelem.h"
19
20 void ossl_prov_cipher_reset(PROV_CIPHER *pc)
21 {
22     EVP_CIPHER_free(pc->alloc_cipher);
23     pc->alloc_cipher = NULL;
24     pc->cipher = NULL;
25     pc->engine = NULL;
26 }
27
28 int ossl_prov_cipher_copy(PROV_CIPHER *dst, const PROV_CIPHER *src)
29 {
30     if (src->alloc_cipher != NULL && !EVP_CIPHER_up_ref(src->alloc_cipher))
31         return 0;
32     dst->engine = src->engine;
33     dst->cipher = src->cipher;
34     dst->alloc_cipher = src->alloc_cipher;
35     return 1;
36 }
37
38 static int load_common(const OSSL_PARAM params[], const char **propquery,
39                        ENGINE **engine)
40 {
41     const OSSL_PARAM *p;
42
43     *propquery = NULL;
44     p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_PROPERTIES);
45     if (p != NULL) {
46         if (p->data_type != OSSL_PARAM_UTF8_STRING)
47             return 0;
48         *propquery = p->data;
49     }
50
51     *engine = NULL;
52     /* TODO legacy stuff, to be removed */
53     /* Inside the FIPS module, we don't support legacy ciphers */
54 #if !defined(FIPS_MODULE) && !defined(OPENSSL_NO_ENGINE)
55     p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_ENGINE);
56     if (p != NULL) {
57         if (p->data_type != OSSL_PARAM_UTF8_STRING)
58             return 0;
59         ENGINE_finish(*engine);
60         *engine = ENGINE_by_id(p->data);
61         if (*engine == NULL)
62             return 0;
63     }
64 #endif
65     return 1;
66 }
67
68 int ossl_prov_cipher_load_from_params(PROV_CIPHER *pc,
69                                       const OSSL_PARAM params[],
70                                       OSSL_LIB_CTX *ctx)
71 {
72     const OSSL_PARAM *p;
73     const char *propquery;
74
75     if (!load_common(params, &propquery, &pc->engine))
76         return 0;
77
78     p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_CIPHER);
79     if (p == NULL)
80         return 1;
81     if (p->data_type != OSSL_PARAM_UTF8_STRING)
82         return 0;
83
84     EVP_CIPHER_free(pc->alloc_cipher);
85     ERR_set_mark();
86     pc->cipher = pc->alloc_cipher = EVP_CIPHER_fetch(ctx, p->data, propquery);
87     /* TODO legacy stuff, to be removed */
88 #ifndef FIPS_MODULE /* Inside the FIPS module, we don't support legacy ciphers */
89     if (pc->cipher == NULL)
90         pc->cipher = EVP_get_cipherbyname(p->data);
91 #endif
92     if (pc->cipher != NULL)
93         ERR_pop_to_mark();
94     else
95         ERR_clear_last_mark();
96     return pc->cipher != NULL;
97 }
98
99 const EVP_CIPHER *ossl_prov_cipher_cipher(const PROV_CIPHER *pc)
100 {
101     return pc->cipher;
102 }
103
104 ENGINE *ossl_prov_cipher_engine(const PROV_CIPHER *pc)
105 {
106     return pc->engine;
107 }
108
109 void ossl_prov_digest_reset(PROV_DIGEST *pd)
110 {
111     EVP_MD_free(pd->alloc_md);
112     pd->alloc_md = NULL;
113     pd->md = NULL;
114     pd->engine = NULL;
115 }
116
117 int ossl_prov_digest_copy(PROV_DIGEST *dst, const PROV_DIGEST *src)
118 {
119     if (src->alloc_md != NULL && !EVP_MD_up_ref(src->alloc_md))
120         return 0;
121     dst->engine = src->engine;
122     dst->md = src->md;
123     dst->alloc_md = src->alloc_md;
124     return 1;
125 }
126
127 const EVP_MD *ossl_prov_digest_fetch(PROV_DIGEST *pd, OSSL_LIB_CTX *libctx,
128                            const char *mdname, const char *propquery)
129 {
130     EVP_MD_free(pd->alloc_md);
131     pd->md = pd->alloc_md = EVP_MD_fetch(libctx, mdname, propquery);
132
133     return pd->md;
134 }
135
136 int ossl_prov_digest_load_from_params(PROV_DIGEST *pd,
137                                       const OSSL_PARAM params[],
138                                       OSSL_LIB_CTX *ctx)
139 {
140     const OSSL_PARAM *p;
141     const char *propquery;
142
143     if (!load_common(params, &propquery, &pd->engine))
144         return 0;
145
146
147     p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST);
148     if (p == NULL)
149         return 1;
150     if (p->data_type != OSSL_PARAM_UTF8_STRING)
151         return 0;
152
153     ERR_set_mark();
154     ossl_prov_digest_fetch(pd, ctx, p->data, propquery);
155     /* TODO legacy stuff, to be removed */
156 #ifndef FIPS_MODULE /* Inside the FIPS module, we don't support legacy digests */
157     if (pd->md == NULL)
158         pd->md = EVP_get_digestbyname(p->data);
159 #endif
160     if (pd->md != NULL)
161         ERR_pop_to_mark();
162     else
163         ERR_clear_last_mark();
164     return pd->md != NULL;
165 }
166
167 const EVP_MD *ossl_prov_digest_md(const PROV_DIGEST *pd)
168 {
169     return pd->md;
170 }
171
172 ENGINE *ossl_prov_digest_engine(const PROV_DIGEST *pd)
173 {
174     return pd->engine;
175 }
176
177 int ossl_prov_set_macctx(EVP_MAC_CTX *macctx,
178                          const OSSL_PARAM params[],
179                          const char *ciphername,
180                          const char *mdname,
181                          const char *engine,
182                          const char *properties,
183                          const unsigned char *key,
184                          size_t keylen)
185 {
186     const OSSL_PARAM *p;
187     OSSL_PARAM mac_params[6], *mp = mac_params;
188
189     if (params != NULL) {
190         if (mdname == NULL) {
191             if ((p = OSSL_PARAM_locate_const(params,
192                                             OSSL_ALG_PARAM_DIGEST)) != NULL) {
193                 if (p->data_type != OSSL_PARAM_UTF8_STRING)
194                     return 0;
195                 mdname = p->data;
196             }
197         }
198         if (ciphername == NULL) {
199             if ((p = OSSL_PARAM_locate_const(params,
200                                             OSSL_ALG_PARAM_CIPHER)) != NULL) {
201                 if (p->data_type != OSSL_PARAM_UTF8_STRING)
202                     return 0;
203                 ciphername = p->data;
204             }
205         }
206         if (engine == NULL) {
207             if ((p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_ENGINE))
208                     != NULL) {
209                 if (p->data_type != OSSL_PARAM_UTF8_STRING)
210                     return 0;
211                 engine = p->data;
212             }
213         }
214     }
215
216     if (mdname != NULL)
217         *mp++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
218                                                  (char *)mdname, 0);
219     if (ciphername != NULL)
220         *mp++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER,
221                                                  (char *)ciphername, 0);
222     if (properties != NULL)
223         *mp++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_PROPERTIES,
224                                                  (char *)properties, 0);
225
226 #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE)
227     if (engine != NULL)
228         *mp++ = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_ENGINE,
229                                                  (char *) engine, 0);
230 #endif
231
232     if (key != NULL)
233         *mp++ = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
234                                                   (unsigned char *)key,
235                                                   keylen);
236
237     *mp = OSSL_PARAM_construct_end();
238
239     return EVP_MAC_CTX_set_params(macctx, mac_params);
240
241 }
242
243 int ossl_prov_macctx_load_from_params(EVP_MAC_CTX **macctx,
244                                       const OSSL_PARAM params[],
245                                       const char *macname,
246                                       const char *ciphername,
247                                       const char *mdname,
248                                       OSSL_LIB_CTX *libctx)
249 {
250     const OSSL_PARAM *p;
251     const char *properties = NULL;
252
253     if (macname == NULL
254         && (p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_MAC)) != NULL) {
255         if (p->data_type != OSSL_PARAM_UTF8_STRING)
256             return 0;
257         macname = p->data;
258     }
259     if ((p = OSSL_PARAM_locate_const(params,
260                                      OSSL_ALG_PARAM_PROPERTIES)) != NULL) {
261         if (p->data_type != OSSL_PARAM_UTF8_STRING)
262             return 0;
263         properties = p->data;
264     }
265
266     /* If we got a new mac name, we make a new EVP_MAC_CTX */
267     if (macname != NULL) {
268         EVP_MAC *mac = EVP_MAC_fetch(libctx, macname, properties);
269
270         EVP_MAC_CTX_free(*macctx);
271         *macctx = mac == NULL ? NULL : EVP_MAC_CTX_new(mac);
272         /* The context holds on to the MAC */
273         EVP_MAC_free(mac);
274         if (*macctx == NULL)
275             return 0;
276     }
277
278     /*
279      * If there is no MAC yet (and therefore, no MAC context), we ignore
280      * all other parameters.
281      */
282     if (*macctx == NULL)
283         return 1;
284
285     if (ossl_prov_set_macctx(*macctx, params, ciphername, mdname, NULL,
286                              properties, NULL, 0))
287         return 1;
288
289     EVP_MAC_CTX_free(*macctx);
290     *macctx = NULL;
291     return 0;
292 }
293
294 void ossl_prov_cache_exported_algorithms(const OSSL_ALGORITHM_CAPABLE *in,
295                                          OSSL_ALGORITHM *out)
296 {
297     int i, j;
298
299     if (out[0].algorithm_names == NULL) {
300         for (i = j = 0; in[i].alg.algorithm_names != NULL; ++i) {
301             if (in[i].capable == NULL || in[i].capable())
302                 out[j++] = in[i].alg;
303         }
304         out[j++] = in[i].alg;
305     }
306 }