1/*
2 * Copyright 1995-2021 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 <stdio.h>
11#include <openssl/evp.h>
12#include <openssl/kdf.h>
13#include <openssl/x509.h>
14#include "internal/cryptlib.h"
15#include "internal/namemap.h"
16#include "crypto/objects.h"
17#include "crypto/evp.h"
18
19int EVP_add_cipher(const EVP_CIPHER *c)
20{
21    int r;
22
23    if (c == NULL)
24        return 0;
25
26    r = OBJ_NAME_add(OBJ_nid2sn(c->nid), OBJ_NAME_TYPE_CIPHER_METH,
27                     (const char *)c);
28    if (r == 0)
29        return 0;
30    r = OBJ_NAME_add(OBJ_nid2ln(c->nid), OBJ_NAME_TYPE_CIPHER_METH,
31                     (const char *)c);
32    return r;
33}
34
35int EVP_add_digest(const EVP_MD *md)
36{
37    int r;
38    const char *name;
39
40    name = OBJ_nid2sn(md->type);
41    r = OBJ_NAME_add(name, OBJ_NAME_TYPE_MD_METH, (const char *)md);
42    if (r == 0)
43        return 0;
44    r = OBJ_NAME_add(OBJ_nid2ln(md->type), OBJ_NAME_TYPE_MD_METH,
45                     (const char *)md);
46    if (r == 0)
47        return 0;
48
49    if (md->pkey_type && md->type != md->pkey_type) {
50        r = OBJ_NAME_add(OBJ_nid2sn(md->pkey_type),
51                         OBJ_NAME_TYPE_MD_METH | OBJ_NAME_ALIAS, name);
52        if (r == 0)
53            return 0;
54        r = OBJ_NAME_add(OBJ_nid2ln(md->pkey_type),
55                         OBJ_NAME_TYPE_MD_METH | OBJ_NAME_ALIAS, name);
56    }
57    return r;
58}
59
60static void cipher_from_name(const char *name, void *data)
61{
62    const EVP_CIPHER **cipher = data;
63
64    if (*cipher != NULL)
65        return;
66
67    *cipher = (const EVP_CIPHER *)OBJ_NAME_get(name, OBJ_NAME_TYPE_CIPHER_METH);
68}
69
70const EVP_CIPHER *EVP_get_cipherbyname(const char *name)
71{
72    return evp_get_cipherbyname_ex(NULL, name);
73}
74
75const EVP_CIPHER *evp_get_cipherbyname_ex(OSSL_LIB_CTX *libctx,
76                                          const char *name)
77{
78    const EVP_CIPHER *cp;
79    OSSL_NAMEMAP *namemap;
80    int id;
81
82    if (!OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS, NULL))
83        return NULL;
84
85    cp = (const EVP_CIPHER *)OBJ_NAME_get(name, OBJ_NAME_TYPE_CIPHER_METH);
86
87    if (cp != NULL)
88        return cp;
89
90    /*
91     * It's not in the method database, but it might be there under a different
92     * name. So we check for aliases in the EVP namemap and try all of those
93     * in turn.
94     */
95
96    namemap = ossl_namemap_stored(libctx);
97    id = ossl_namemap_name2num(namemap, name);
98    if (id == 0)
99        return NULL;
100
101    if (!ossl_namemap_doall_names(namemap, id, cipher_from_name, &cp))
102        return NULL;
103
104    return cp;
105}
106
107static void digest_from_name(const char *name, void *data)
108{
109    const EVP_MD **md = data;
110
111    if (*md != NULL)
112        return;
113
114    *md = (const EVP_MD *)OBJ_NAME_get(name, OBJ_NAME_TYPE_MD_METH);
115}
116
117const EVP_MD *EVP_get_digestbyname(const char *name)
118{
119    return evp_get_digestbyname_ex(NULL, name);
120}
121
122const EVP_MD *evp_get_digestbyname_ex(OSSL_LIB_CTX *libctx, const char *name)
123{
124    const EVP_MD *dp;
125    OSSL_NAMEMAP *namemap;
126    int id;
127
128    if (!OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL))
129        return NULL;
130
131    dp = (const EVP_MD *)OBJ_NAME_get(name, OBJ_NAME_TYPE_MD_METH);
132
133    if (dp != NULL)
134        return dp;
135
136    /*
137     * It's not in the method database, but it might be there under a different
138     * name. So we check for aliases in the EVP namemap and try all of those
139     * in turn.
140     */
141
142    namemap = ossl_namemap_stored(libctx);
143    id = ossl_namemap_name2num(namemap, name);
144    if (id == 0)
145        return NULL;
146
147    if (!ossl_namemap_doall_names(namemap, id, digest_from_name, &dp))
148        return NULL;
149
150    return dp;
151}
152
153void evp_cleanup_int(void)
154{
155    OBJ_NAME_cleanup(OBJ_NAME_TYPE_KDF_METH);
156    OBJ_NAME_cleanup(OBJ_NAME_TYPE_CIPHER_METH);
157    OBJ_NAME_cleanup(OBJ_NAME_TYPE_MD_METH);
158    /*
159     * The above calls will only clean out the contents of the name hash
160     * table, but not the hash table itself.  The following line does that
161     * part.  -- Richard Levitte
162     */
163    OBJ_NAME_cleanup(-1);
164
165    EVP_PBE_cleanup();
166    OBJ_sigid_free();
167
168    evp_app_cleanup_int();
169}
170
171struct doall_cipher {
172    void *arg;
173    void (*fn) (const EVP_CIPHER *ciph,
174                const char *from, const char *to, void *arg);
175};
176
177static void do_all_cipher_fn(const OBJ_NAME *nm, void *arg)
178{
179    struct doall_cipher *dc = arg;
180    if (nm->alias)
181        dc->fn(NULL, nm->name, nm->data, dc->arg);
182    else
183        dc->fn((const EVP_CIPHER *)nm->data, nm->name, NULL, dc->arg);
184}
185
186void EVP_CIPHER_do_all(void (*fn) (const EVP_CIPHER *ciph,
187                                   const char *from, const char *to, void *x),
188                       void *arg)
189{
190    struct doall_cipher dc;
191
192    /* Ignore errors */
193    OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS, NULL);
194
195    dc.fn = fn;
196    dc.arg = arg;
197    OBJ_NAME_do_all(OBJ_NAME_TYPE_CIPHER_METH, do_all_cipher_fn, &dc);
198}
199
200void EVP_CIPHER_do_all_sorted(void (*fn) (const EVP_CIPHER *ciph,
201                                          const char *from, const char *to,
202                                          void *x), void *arg)
203{
204    struct doall_cipher dc;
205
206    /* Ignore errors */
207    OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS, NULL);
208
209    dc.fn = fn;
210    dc.arg = arg;
211    OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, do_all_cipher_fn, &dc);
212}
213
214struct doall_md {
215    void *arg;
216    void (*fn) (const EVP_MD *ciph,
217                const char *from, const char *to, void *arg);
218};
219
220static void do_all_md_fn(const OBJ_NAME *nm, void *arg)
221{
222    struct doall_md *dc = arg;
223    if (nm->alias)
224        dc->fn(NULL, nm->name, nm->data, dc->arg);
225    else
226        dc->fn((const EVP_MD *)nm->data, nm->name, NULL, dc->arg);
227}
228
229void EVP_MD_do_all(void (*fn) (const EVP_MD *md,
230                               const char *from, const char *to, void *x),
231                   void *arg)
232{
233    struct doall_md dc;
234
235    /* Ignore errors */
236    OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
237
238    dc.fn = fn;
239    dc.arg = arg;
240    OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, do_all_md_fn, &dc);
241}
242
243void EVP_MD_do_all_sorted(void (*fn) (const EVP_MD *md,
244                                      const char *from, const char *to,
245                                      void *x), void *arg)
246{
247    struct doall_md dc;
248
249    OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
250
251    dc.fn = fn;
252    dc.arg = arg;
253    OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH, do_all_md_fn, &dc);
254}
255