1 | /*
|
---|
2 | * Copyright 2019-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 <openssl/core.h>
|
---|
11 | #include <openssl/core_dispatch.h>
|
---|
12 | #include "internal/core.h"
|
---|
13 | #include "internal/property.h"
|
---|
14 | #include "internal/provider.h"
|
---|
15 |
|
---|
16 | struct algorithm_data_st {
|
---|
17 | OSSL_LIB_CTX *libctx;
|
---|
18 | int operation_id; /* May be zero for finding them all */
|
---|
19 | int (*pre)(OSSL_PROVIDER *, int operation_id, int no_store, void *data,
|
---|
20 | int *result);
|
---|
21 | int (*reserve_store)(int no_store, void *data);
|
---|
22 | void (*fn)(OSSL_PROVIDER *, const OSSL_ALGORITHM *, int no_store,
|
---|
23 | void *data);
|
---|
24 | int (*unreserve_store)(void *data);
|
---|
25 | int (*post)(OSSL_PROVIDER *, int operation_id, int no_store, void *data,
|
---|
26 | int *result);
|
---|
27 | void *data;
|
---|
28 | };
|
---|
29 |
|
---|
30 | /*
|
---|
31 | * Process one OSSL_ALGORITHM array, for the operation |cur_operation|,
|
---|
32 | * by constructing methods for all its implementations and adding those
|
---|
33 | * to the appropriate method store.
|
---|
34 | * Which method store is appropriate is given by |no_store| ("permanent"
|
---|
35 | * if 0, temporary if 1) and other data in |data->data|.
|
---|
36 | *
|
---|
37 | * Returns:
|
---|
38 | * -1 to quit adding algorithm implementations immediately
|
---|
39 | * 0 if not successful, but adding should continue
|
---|
40 | * 1 if successful so far, and adding should continue
|
---|
41 | */
|
---|
42 | static int algorithm_do_map(OSSL_PROVIDER *provider, const OSSL_ALGORITHM *map,
|
---|
43 | int cur_operation, int no_store, void *cbdata)
|
---|
44 | {
|
---|
45 | struct algorithm_data_st *data = cbdata;
|
---|
46 | int ret = 0;
|
---|
47 |
|
---|
48 | if (!data->reserve_store(no_store, data->data))
|
---|
49 | /* Error, bail out! */
|
---|
50 | return -1;
|
---|
51 |
|
---|
52 | /* Do we fulfill pre-conditions? */
|
---|
53 | if (data->pre == NULL) {
|
---|
54 | /* If there is no pre-condition function, assume "yes" */
|
---|
55 | ret = 1;
|
---|
56 | } else if (!data->pre(provider, cur_operation, no_store, data->data,
|
---|
57 | &ret)) {
|
---|
58 | /* Error, bail out! */
|
---|
59 | ret = -1;
|
---|
60 | goto end;
|
---|
61 | }
|
---|
62 |
|
---|
63 | /*
|
---|
64 | * If pre-condition not fulfilled don't add this set of implementations,
|
---|
65 | * but do continue with the next. This simply means that another thread
|
---|
66 | * got to it first.
|
---|
67 | */
|
---|
68 | if (ret == 0) {
|
---|
69 | ret = 1;
|
---|
70 | goto end;
|
---|
71 | }
|
---|
72 |
|
---|
73 | if (map != NULL) {
|
---|
74 | const OSSL_ALGORITHM *thismap;
|
---|
75 |
|
---|
76 | for (thismap = map; thismap->algorithm_names != NULL; thismap++)
|
---|
77 | data->fn(provider, thismap, no_store, data->data);
|
---|
78 | }
|
---|
79 |
|
---|
80 | /* Do we fulfill post-conditions? */
|
---|
81 | if (data->post == NULL) {
|
---|
82 | /* If there is no post-condition function, assume "yes" */
|
---|
83 | ret = 1;
|
---|
84 | } else if (!data->post(provider, cur_operation, no_store, data->data,
|
---|
85 | &ret)) {
|
---|
86 | /* Error, bail out! */
|
---|
87 | ret = -1;
|
---|
88 | }
|
---|
89 |
|
---|
90 | end:
|
---|
91 | data->unreserve_store(data->data);
|
---|
92 |
|
---|
93 | return ret;
|
---|
94 | }
|
---|
95 |
|
---|
96 | /*
|
---|
97 | * Given a provider, process one operation given by |data->operation_id|, or
|
---|
98 | * if that's zero, process all known operations.
|
---|
99 | * For each such operation, query the associated OSSL_ALGORITHM array from
|
---|
100 | * the provider, then process that array with |algorithm_do_map()|.
|
---|
101 | */
|
---|
102 | static int algorithm_do_this(OSSL_PROVIDER *provider, void *cbdata)
|
---|
103 | {
|
---|
104 | struct algorithm_data_st *data = cbdata;
|
---|
105 | int first_operation = 1;
|
---|
106 | int last_operation = OSSL_OP__HIGHEST;
|
---|
107 | int cur_operation;
|
---|
108 | int ok = 1;
|
---|
109 |
|
---|
110 | if (data->operation_id != 0)
|
---|
111 | first_operation = last_operation = data->operation_id;
|
---|
112 |
|
---|
113 | for (cur_operation = first_operation;
|
---|
114 | cur_operation <= last_operation;
|
---|
115 | cur_operation++) {
|
---|
116 | int no_store = 0; /* Assume caching is ok */
|
---|
117 | const OSSL_ALGORITHM *map = NULL;
|
---|
118 | int ret = 0;
|
---|
119 |
|
---|
120 | map = ossl_provider_query_operation(provider, cur_operation,
|
---|
121 | &no_store);
|
---|
122 | ret = algorithm_do_map(provider, map, cur_operation, no_store, data);
|
---|
123 | ossl_provider_unquery_operation(provider, cur_operation, map);
|
---|
124 |
|
---|
125 | if (ret < 0)
|
---|
126 | /* Hard error, bail out immediately! */
|
---|
127 | return 0;
|
---|
128 |
|
---|
129 | /* If post-condition not fulfilled, set general failure */
|
---|
130 | if (!ret)
|
---|
131 | ok = 0;
|
---|
132 | }
|
---|
133 |
|
---|
134 | return ok;
|
---|
135 | }
|
---|
136 |
|
---|
137 | void ossl_algorithm_do_all(OSSL_LIB_CTX *libctx, int operation_id,
|
---|
138 | OSSL_PROVIDER *provider,
|
---|
139 | int (*pre)(OSSL_PROVIDER *, int operation_id,
|
---|
140 | int no_store, void *data, int *result),
|
---|
141 | int (*reserve_store)(int no_store, void *data),
|
---|
142 | void (*fn)(OSSL_PROVIDER *provider,
|
---|
143 | const OSSL_ALGORITHM *algo,
|
---|
144 | int no_store, void *data),
|
---|
145 | int (*unreserve_store)(void *data),
|
---|
146 | int (*post)(OSSL_PROVIDER *, int operation_id,
|
---|
147 | int no_store, void *data, int *result),
|
---|
148 | void *data)
|
---|
149 | {
|
---|
150 | struct algorithm_data_st cbdata = { 0, };
|
---|
151 |
|
---|
152 | cbdata.libctx = libctx;
|
---|
153 | cbdata.operation_id = operation_id;
|
---|
154 | cbdata.pre = pre;
|
---|
155 | cbdata.reserve_store = reserve_store;
|
---|
156 | cbdata.fn = fn;
|
---|
157 | cbdata.unreserve_store = unreserve_store;
|
---|
158 | cbdata.post = post;
|
---|
159 | cbdata.data = data;
|
---|
160 |
|
---|
161 | if (provider == NULL) {
|
---|
162 | ossl_provider_doall_activated(libctx, algorithm_do_this, &cbdata);
|
---|
163 | } else {
|
---|
164 | OSSL_LIB_CTX *libctx2 = ossl_provider_libctx(provider);
|
---|
165 |
|
---|
166 | /*
|
---|
167 | * If a provider is given, its library context MUST match the library
|
---|
168 | * context we're passed. If this turns out not to be true, there is
|
---|
169 | * a programming error in the functions up the call stack.
|
---|
170 | */
|
---|
171 | if (!ossl_assert(ossl_lib_ctx_get_concrete(libctx)
|
---|
172 | == ossl_lib_ctx_get_concrete(libctx2)))
|
---|
173 | return;
|
---|
174 |
|
---|
175 | cbdata.libctx = libctx2;
|
---|
176 | algorithm_do_this(provider, &cbdata);
|
---|
177 | }
|
---|
178 | }
|
---|
179 |
|
---|
180 | char *ossl_algorithm_get1_first_name(const OSSL_ALGORITHM *algo)
|
---|
181 | {
|
---|
182 | const char *first_name_end = NULL;
|
---|
183 | size_t first_name_len = 0;
|
---|
184 | char *ret;
|
---|
185 |
|
---|
186 | if (algo->algorithm_names == NULL)
|
---|
187 | return NULL;
|
---|
188 |
|
---|
189 | first_name_end = strchr(algo->algorithm_names, ':');
|
---|
190 | if (first_name_end == NULL)
|
---|
191 | first_name_len = strlen(algo->algorithm_names);
|
---|
192 | else
|
---|
193 | first_name_len = first_name_end - algo->algorithm_names;
|
---|
194 |
|
---|
195 | ret = OPENSSL_strndup(algo->algorithm_names, first_name_len);
|
---|
196 | return ret;
|
---|
197 | }
|
---|