1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License (the "License").
7 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or https://opensource.org/licenses/CDDL-1.0.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/zfs_context.h>
28 #include <sys/crypto/common.h>
29 #include <sys/crypto/impl.h>
30 #include <sys/crypto/api.h>
31 #include <sys/crypto/spi.h>
32 #include <sys/crypto/sched_impl.h>
33
34 /*
35 * Message authentication codes routines.
36 */
37
38 /*
39 * The following are the possible returned values common to all the routines
40 * below. The applicability of some of these return values depends on the
41 * presence of the arguments.
42 *
43 * CRYPTO_SUCCESS: The operation completed successfully.
44 * CRYPTO_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or
45 * CRYPTO_INVALID_MECH for problems with the 'mech'.
46 * CRYPTO_INVALID_DATA for bogus 'data'
47 * CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
48 * CRYPTO_INVALID_CONTEXT: Not a valid context.
49 * CRYPTO_BUSY: Cannot process the request now. Try later.
50 * CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: No provider is
51 * capable of a function or a mechanism.
52 * CRYPTO_INVALID_KEY: bogus 'key' argument.
53 * CRYPTO_INVALID_MAC: bogus 'mac' argument.
54 */
55
56 /*
57 * crypto_mac_prov()
58 *
59 * Arguments:
60 * mech: crypto_mechanism_t pointer.
61 * mech_type is a valid value previously returned by
62 * crypto_mech2id();
63 * When the mech's parameter is not NULL, its definition depends
64 * on the standard definition of the mechanism.
65 * key: pointer to a crypto_key_t structure.
66 * data: The message to compute the MAC for.
67 * mac: Storage for the MAC. The length needed depends on the mechanism.
68 * tmpl: a crypto_ctx_template_t, opaque template of a context of a
69 * MAC with the 'mech' using 'key'. 'tmpl' is created by
70 * a previous call to crypto_create_ctx_template().
71 *
72 * Description:
73 * Asynchronously submits a request for, or synchronously performs a
74 * single-part message authentication of 'data' with the mechanism
75 * 'mech', using * the key 'key', on the specified provider with
76 * the specified session id.
77 * When complete and successful, 'mac' will contain the message
78 * authentication code.
79 * Relies on the KCF scheduler to choose a provider.
80 *
81 * Returns:
82 * See comment in the beginning of the file.
83 */
84 int
crypto_mac(crypto_mechanism_t * mech,crypto_data_t * data,crypto_key_t * key,crypto_ctx_template_t tmpl,crypto_data_t * mac)85 crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data,
86 crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac)
87 {
88 int error;
89 kcf_mech_entry_t *me;
90 kcf_provider_desc_t *pd;
91 kcf_ctx_template_t *ctx_tmpl;
92 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
93 kcf_prov_tried_t *list = NULL;
94
95 retry:
96 /* The pd is returned held */
97 if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
98 list, CRYPTO_FG_MAC_ATOMIC)) == NULL) {
99 if (list != NULL)
100 kcf_free_triedlist(list);
101 return (error);
102 }
103
104 if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL))
105 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
106
107 crypto_mechanism_t lmech = *mech;
108 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
109 error = KCF_PROV_MAC_ATOMIC(pd, &lmech, key, data,
110 mac, spi_ctx_tmpl);
111
112 if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {
113 /* Add pd to the linked list of providers tried. */
114 if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL)
115 goto retry;
116 }
117
118 if (list != NULL)
119 kcf_free_triedlist(list);
120
121 KCF_PROV_REFRELE(pd);
122 return (error);
123 }
124
125 /*
126 * crypto_mac_init_prov()
127 *
128 * Arguments:
129 * pd: pointer to the descriptor of the provider to use for this
130 * operation.
131 * mech: crypto_mechanism_t pointer.
132 * mech_type is a valid value previously returned by
133 * crypto_mech2id();
134 * When the mech's parameter is not NULL, its definition depends
135 * on the standard definition of the mechanism.
136 * key: pointer to a crypto_key_t structure.
137 * tmpl: a crypto_ctx_template_t, opaque template of a context of a
138 * MAC with the 'mech' using 'key'. 'tmpl' is created by
139 * a previous call to crypto_create_ctx_template().
140 * ctxp: Pointer to a crypto_context_t.
141 *
142 * Description:
143 * Asynchronously submits a request for, or synchronously performs the
144 * initialization of a MAC operation on the specified provider with
145 * the specified session.
146 * When possible and applicable, will internally use the pre-computed MAC
147 * context from the context template, tmpl.
148 * When complete and successful, 'ctxp' will contain a crypto_context_t
149 * valid for later calls to mac_update() and mac_final().
150 * The caller should hold a reference on the specified provider
151 * descriptor before calling this function.
152 *
153 * Returns:
154 * See comment in the beginning of the file.
155 */
156 static int
crypto_mac_init_prov(kcf_provider_desc_t * pd,crypto_mechanism_t * mech,crypto_key_t * key,crypto_spi_ctx_template_t tmpl,crypto_context_t * ctxp)157 crypto_mac_init_prov(kcf_provider_desc_t *pd,
158 crypto_mechanism_t *mech, crypto_key_t *key, crypto_spi_ctx_template_t tmpl,
159 crypto_context_t *ctxp)
160 {
161 int rv;
162 crypto_ctx_t *ctx;
163 kcf_provider_desc_t *real_provider = pd;
164
165 ASSERT(KCF_PROV_REFHELD(pd));
166
167 /* Allocate and initialize the canonical context */
168 if ((ctx = kcf_new_ctx(real_provider)) == NULL)
169 return (CRYPTO_HOST_MEMORY);
170
171 crypto_mechanism_t lmech = *mech;
172 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
173 rv = KCF_PROV_MAC_INIT(real_provider, ctx, &lmech, key, tmpl);
174
175 if (rv == CRYPTO_SUCCESS)
176 *ctxp = (crypto_context_t)ctx;
177 else {
178 /* Release the hold done in kcf_new_ctx(). */
179 KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
180 }
181
182 return (rv);
183 }
184
185 /*
186 * Same as crypto_mac_init_prov(), but relies on the KCF scheduler to
187 * choose a provider. See crypto_mac_init_prov() comments for more
188 * information.
189 */
190 int
crypto_mac_init(crypto_mechanism_t * mech,crypto_key_t * key,crypto_ctx_template_t tmpl,crypto_context_t * ctxp)191 crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key,
192 crypto_ctx_template_t tmpl, crypto_context_t *ctxp)
193 {
194 int error;
195 kcf_mech_entry_t *me;
196 kcf_provider_desc_t *pd;
197 kcf_ctx_template_t *ctx_tmpl;
198 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
199 kcf_prov_tried_t *list = NULL;
200
201 retry:
202 /* The pd is returned held */
203 if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
204 list, CRYPTO_FG_MAC)) == NULL) {
205 if (list != NULL)
206 kcf_free_triedlist(list);
207 return (error);
208 }
209
210 /*
211 * Check the validity of the context template
212 * It is very rare that the generation number mis-matches, so
213 * is acceptable to fail here, and let the consumer recover by
214 * freeing this tmpl and create a new one for the key and new provider
215 */
216
217 if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL))
218 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
219
220 error = crypto_mac_init_prov(pd, mech, key,
221 spi_ctx_tmpl, ctxp);
222 if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {
223 /* Add pd to the linked list of providers tried. */
224 if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL)
225 goto retry;
226 }
227
228 if (list != NULL)
229 kcf_free_triedlist(list);
230
231 KCF_PROV_REFRELE(pd);
232 return (error);
233 }
234
235 /*
236 * crypto_mac_update()
237 *
238 * Arguments:
239 * context: A crypto_context_t initialized by mac_init().
240 * data: The message part to be MAC'ed
241 *
242 * Description:
243 * Synchronously performs a part of a MAC operation.
244 *
245 * Returns:
246 * See comment in the beginning of the file.
247 */
248 int
crypto_mac_update(crypto_context_t context,crypto_data_t * data)249 crypto_mac_update(crypto_context_t context, crypto_data_t *data)
250 {
251 crypto_ctx_t *ctx = (crypto_ctx_t *)context;
252 kcf_context_t *kcf_ctx;
253 kcf_provider_desc_t *pd;
254
255 if ((ctx == NULL) ||
256 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
257 ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
258 return (CRYPTO_INVALID_CONTEXT);
259 }
260
261 return (KCF_PROV_MAC_UPDATE(pd, ctx, data));
262 }
263
264 /*
265 * crypto_mac_final()
266 *
267 * Arguments:
268 * context: A crypto_context_t initialized by mac_init().
269 * mac: Storage for the message authentication code.
270 *
271 * Description:
272 * Synchronously performs a part of a message authentication operation.
273 *
274 * Returns:
275 * See comment in the beginning of the file.
276 */
277 int
crypto_mac_final(crypto_context_t context,crypto_data_t * mac)278 crypto_mac_final(crypto_context_t context, crypto_data_t *mac)
279 {
280 crypto_ctx_t *ctx = (crypto_ctx_t *)context;
281 kcf_context_t *kcf_ctx;
282 kcf_provider_desc_t *pd;
283
284 if ((ctx == NULL) ||
285 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
286 ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
287 return (CRYPTO_INVALID_CONTEXT);
288 }
289
290 int rv = KCF_PROV_MAC_FINAL(pd, ctx, mac);
291
292 /* Release the hold done in kcf_new_ctx() during init step. */
293 KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx);
294 return (rv);
295 }
296
297 #if defined(_KERNEL)
298 EXPORT_SYMBOL(crypto_mac);
299 EXPORT_SYMBOL(crypto_mac_init);
300 EXPORT_SYMBOL(crypto_mac_update);
301 EXPORT_SYMBOL(crypto_mac_final);
302 #endif
303