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
crypto_mac(crypto_mechanism_t * mech,crypto_data_t * data,crypto_key_t * key,crypto_ctx_template_t tmpl,crypto_data_t * mac)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
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)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
crypto_mac_init(crypto_mechanism_t * mech,crypto_key_t * key,crypto_ctx_template_t tmpl,crypto_context_t * ctxp)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
crypto_mac_update(crypto_context_t context,crypto_data_t * data)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
crypto_mac_final(crypto_context_t context,crypto_data_t * mac)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