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