xref: /freebsd/sys/contrib/openzfs/module/icp/api/kcf_mac.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
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