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