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