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 http://www.opensolaris.org/os/licensing.
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 digest 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_QUEUED: A request was submitted successfully. The callback
44 * routine will be called when the operation is done.
45 * CRYPTO_MECHANISM_INVALID or CRYPTO_INVALID_MECH_PARAM
46 * for problems with the 'mech'.
47 * CRYPTO_INVALID_DATA for bogus 'data'
48 * CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
49 * CRYPTO_INVALID_CONTEXT: Not a valid context.
50 * CRYPTO_BUSY: Cannot process the request now. Schedule a
51 * crypto_bufcall(), or try later.
52 * CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED:
53 * No provider is capable of a function or a mechanism.
54 */
55
56
57 /*
58 * crypto_digest_prov()
59 *
60 * Arguments:
61 * pd: pointer to the descriptor of the provider to use for this
62 * operation.
63 * sid: provider session id.
64 * mech: crypto_mechanism_t pointer.
65 * mech_type is a valid value previously returned by
66 * crypto_mech2id();
67 * When the mech's parameter is not NULL, its definition depends
68 * on the standard definition of the mechanism.
69 * data: The message to be digested.
70 * digest: Storage for the digest. The length needed depends on the
71 * mechanism.
72 * cr: crypto_call_req_t calling conditions and call back info.
73 *
74 * Description:
75 * Asynchronously submits a request for, or synchronously performs the
76 * digesting operation of 'data' on the specified
77 * provider with the specified session.
78 * When complete and successful, 'digest' will contain the digest value.
79 * The caller should hold a reference on the specified provider
80 * descriptor before calling this function.
81 *
82 * Context:
83 * Process or interrupt, according to the semantics dictated by the 'cr'.
84 *
85 * Returns:
86 * See comment in the beginning of the file.
87 */
88 int
crypto_digest_prov(crypto_provider_t provider,crypto_session_id_t sid,crypto_mechanism_t * mech,crypto_data_t * data,crypto_data_t * digest,crypto_call_req_t * crq)89 crypto_digest_prov(crypto_provider_t provider, crypto_session_id_t sid,
90 crypto_mechanism_t *mech, crypto_data_t *data, crypto_data_t *digest,
91 crypto_call_req_t *crq)
92 {
93 kcf_req_params_t params;
94 kcf_provider_desc_t *pd = provider;
95 kcf_provider_desc_t *real_provider = pd;
96 int rv;
97
98 ASSERT(KCF_PROV_REFHELD(pd));
99
100 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
101 rv = kcf_get_hardware_provider(mech->cm_type,
102 CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq),
103 pd, &real_provider, CRYPTO_FG_DIGEST_ATOMIC);
104
105 if (rv != CRYPTO_SUCCESS)
106 return (rv);
107 }
108 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, sid, mech, NULL,
109 data, digest);
110
111 /* no crypto context to carry between multiple parts. */
112 rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE);
113 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
114 KCF_PROV_REFRELE(real_provider);
115
116 return (rv);
117 }
118
119
120 /*
121 * Same as crypto_digest_prov(), but relies on the KCF scheduler to
122 * choose a provider. See crypto_digest_prov() comments for more information.
123 */
124 int
crypto_digest(crypto_mechanism_t * mech,crypto_data_t * data,crypto_data_t * digest,crypto_call_req_t * crq)125 crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data,
126 crypto_data_t *digest, crypto_call_req_t *crq)
127 {
128 int error;
129 kcf_provider_desc_t *pd;
130 kcf_req_params_t params;
131 kcf_prov_tried_t *list = NULL;
132
133 retry:
134 /* The pd is returned held */
135 if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error, list,
136 CRYPTO_FG_DIGEST_ATOMIC, CHECK_RESTRICT(crq),
137 data->cd_length)) == NULL) {
138 if (list != NULL)
139 kcf_free_triedlist(list);
140 return (error);
141 }
142
143 /* The fast path for SW providers. */
144 if (CHECK_FASTPATH(crq, pd)) {
145 crypto_mechanism_t lmech;
146
147 lmech = *mech;
148 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
149 error = KCF_PROV_DIGEST_ATOMIC(pd, pd->pd_sid, &lmech, data,
150 digest, KCF_SWFP_RHNDL(crq));
151 KCF_PROV_INCRSTATS(pd, error);
152 } else {
153 if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
154 (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
155 (data->cd_length > pd->pd_hash_limit)) {
156 error = CRYPTO_BUFFER_TOO_BIG;
157 } else {
158 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_ATOMIC,
159 pd->pd_sid, mech, NULL, data, digest);
160
161 /* no crypto context to carry between multiple parts. */
162 error = kcf_submit_request(pd, NULL, crq, ¶ms,
163 B_FALSE);
164 }
165 }
166
167 if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
168 IS_RECOVERABLE(error)) {
169 /* Add pd to the linked list of providers tried. */
170 if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
171 goto retry;
172 }
173
174 if (list != NULL)
175 kcf_free_triedlist(list);
176
177 KCF_PROV_REFRELE(pd);
178 return (error);
179 }
180
181 /*
182 * crypto_digest_init_prov()
183 *
184 * pd: pointer to the descriptor of the provider to use for this
185 * operation.
186 * sid: provider session id.
187 * mech: crypto_mechanism_t pointer.
188 * mech_type is a valid value previously returned by
189 * crypto_mech2id();
190 * When the mech's parameter is not NULL, its definition depends
191 * on the standard definition of the mechanism.
192 * ctxp: Pointer to a crypto_context_t.
193 * cr: crypto_call_req_t calling conditions and call back info.
194 *
195 * Description:
196 * Asynchronously submits a request for, or synchronously performs the
197 * initialization of a message digest operation on the specified
198 * provider with the specified session.
199 * When complete and successful, 'ctxp' will contain a crypto_context_t
200 * valid for later calls to digest_update() and digest_final().
201 * The caller should hold a reference on the specified provider
202 * descriptor before calling this function.
203 */
204 int
crypto_digest_init_prov(crypto_provider_t provider,crypto_session_id_t sid,crypto_mechanism_t * mech,crypto_context_t * ctxp,crypto_call_req_t * crq)205 crypto_digest_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
206 crypto_mechanism_t *mech, crypto_context_t *ctxp, crypto_call_req_t *crq)
207 {
208 int error;
209 crypto_ctx_t *ctx;
210 kcf_req_params_t params;
211 kcf_provider_desc_t *pd = provider;
212 kcf_provider_desc_t *real_provider = pd;
213
214 ASSERT(KCF_PROV_REFHELD(pd));
215
216 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
217 error = kcf_get_hardware_provider(mech->cm_type,
218 CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
219 &real_provider, CRYPTO_FG_DIGEST);
220
221 if (error != CRYPTO_SUCCESS)
222 return (error);
223 }
224
225 /* Allocate and initialize the canonical context */
226 if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
227 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
228 KCF_PROV_REFRELE(real_provider);
229 return (CRYPTO_HOST_MEMORY);
230 }
231
232 /* The fast path for SW providers. */
233 if (CHECK_FASTPATH(crq, pd)) {
234 crypto_mechanism_t lmech;
235
236 lmech = *mech;
237 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
238 error = KCF_PROV_DIGEST_INIT(real_provider, ctx, &lmech,
239 KCF_SWFP_RHNDL(crq));
240 KCF_PROV_INCRSTATS(pd, error);
241 } else {
242 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_INIT, sid,
243 mech, NULL, NULL, NULL);
244 error = kcf_submit_request(real_provider, ctx, crq, ¶ms,
245 B_FALSE);
246 }
247
248 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
249 KCF_PROV_REFRELE(real_provider);
250
251 if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED))
252 *ctxp = (crypto_context_t)ctx;
253 else {
254 /* Release the hold done in kcf_new_ctx(). */
255 KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
256 }
257
258 return (error);
259 }
260
261 /*
262 * Same as crypto_digest_init_prov(), but relies on the KCF scheduler
263 * to choose a provider. See crypto_digest_init_prov() comments for
264 * more information.
265 */
266 int
crypto_digest_init(crypto_mechanism_t * mech,crypto_context_t * ctxp,crypto_call_req_t * crq)267 crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp,
268 crypto_call_req_t *crq)
269 {
270 int error;
271 kcf_provider_desc_t *pd;
272 kcf_prov_tried_t *list = NULL;
273
274 retry:
275 /* The pd is returned held */
276 if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error,
277 list, CRYPTO_FG_DIGEST, CHECK_RESTRICT(crq), 0)) == NULL) {
278 if (list != NULL)
279 kcf_free_triedlist(list);
280 return (error);
281 }
282
283 if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
284 (pd->pd_flags & CRYPTO_HASH_NO_UPDATE)) {
285 /*
286 * The hardware provider has limited digest support.
287 * So, we fallback early here to using a software provider.
288 *
289 * XXX - need to enhance to do the fallback later in
290 * crypto_digest_update() if the size of accumulated input data
291 * exceeds the maximum size digestable by hardware provider.
292 */
293 error = CRYPTO_BUFFER_TOO_BIG;
294 } else {
295 error = crypto_digest_init_prov(pd, pd->pd_sid,
296 mech, ctxp, crq);
297 }
298
299 if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
300 IS_RECOVERABLE(error)) {
301 /* Add pd to the linked list of providers tried. */
302 if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
303 goto retry;
304 }
305
306 if (list != NULL)
307 kcf_free_triedlist(list);
308 KCF_PROV_REFRELE(pd);
309 return (error);
310 }
311
312 /*
313 * crypto_digest_update()
314 *
315 * Arguments:
316 * context: A crypto_context_t initialized by digest_init().
317 * data: The part of message to be digested.
318 * cr: crypto_call_req_t calling conditions and call back info.
319 *
320 * Description:
321 * Asynchronously submits a request for, or synchronously performs a
322 * part of a message digest operation.
323 *
324 * Context:
325 * Process or interrupt, according to the semantics dictated by the 'cr'.
326 *
327 * Returns:
328 * See comment in the beginning of the file.
329 */
330 int
crypto_digest_update(crypto_context_t context,crypto_data_t * data,crypto_call_req_t * cr)331 crypto_digest_update(crypto_context_t context, crypto_data_t *data,
332 crypto_call_req_t *cr)
333 {
334 crypto_ctx_t *ctx = (crypto_ctx_t *)context;
335 kcf_context_t *kcf_ctx;
336 kcf_provider_desc_t *pd;
337 int error;
338 kcf_req_params_t params;
339
340 if ((ctx == NULL) ||
341 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
342 ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
343 return (CRYPTO_INVALID_CONTEXT);
344 }
345
346 ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
347
348 /* The fast path for SW providers. */
349 if (CHECK_FASTPATH(cr, pd)) {
350 error = KCF_PROV_DIGEST_UPDATE(pd, ctx, data, NULL);
351 KCF_PROV_INCRSTATS(pd, error);
352 } else {
353 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_UPDATE,
354 ctx->cc_session, NULL, NULL, data, NULL);
355 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
356 }
357
358 return (error);
359 }
360
361 /*
362 * crypto_digest_final()
363 *
364 * Arguments:
365 * context: A crypto_context_t initialized by digest_init().
366 * digest: The storage for the digest.
367 * cr: crypto_call_req_t calling conditions and call back info.
368 *
369 * Description:
370 * Asynchronously submits a request for, or synchronously performs the
371 * final part of a message digest operation.
372 *
373 * Context:
374 * Process or interrupt, according to the semantics dictated by the 'cr'.
375 *
376 * Returns:
377 * See comment in the beginning of the file.
378 */
379 int
crypto_digest_final(crypto_context_t context,crypto_data_t * digest,crypto_call_req_t * cr)380 crypto_digest_final(crypto_context_t context, crypto_data_t *digest,
381 crypto_call_req_t *cr)
382 {
383 crypto_ctx_t *ctx = (crypto_ctx_t *)context;
384 kcf_context_t *kcf_ctx;
385 kcf_provider_desc_t *pd;
386 int error;
387 kcf_req_params_t params;
388
389 if ((ctx == NULL) ||
390 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
391 ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
392 return (CRYPTO_INVALID_CONTEXT);
393 }
394
395 ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
396
397 /* The fast path for SW providers. */
398 if (CHECK_FASTPATH(cr, pd)) {
399 error = KCF_PROV_DIGEST_FINAL(pd, ctx, digest, NULL);
400 KCF_PROV_INCRSTATS(pd, error);
401 } else {
402 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_FINAL,
403 ctx->cc_session, NULL, NULL, NULL, digest);
404 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
405 }
406
407 /* Release the hold done in kcf_new_ctx() during init step. */
408 KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
409 return (error);
410 }
411
412 /*
413 * Performs a digest update on the specified key. Note that there is
414 * no k-API crypto_digest_key() equivalent of this function.
415 */
416 int
crypto_digest_key_prov(crypto_context_t context,crypto_key_t * key,crypto_call_req_t * cr)417 crypto_digest_key_prov(crypto_context_t context, crypto_key_t *key,
418 crypto_call_req_t *cr)
419 {
420 crypto_ctx_t *ctx = (crypto_ctx_t *)context;
421 kcf_context_t *kcf_ctx;
422 kcf_provider_desc_t *pd;
423 int error;
424 kcf_req_params_t params;
425
426 if ((ctx == NULL) ||
427 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
428 ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
429 return (CRYPTO_INVALID_CONTEXT);
430 }
431
432 ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
433
434 /* The fast path for SW providers. */
435 if (CHECK_FASTPATH(cr, pd)) {
436 error = KCF_PROV_DIGEST_KEY(pd, ctx, key, NULL);
437 KCF_PROV_INCRSTATS(pd, error);
438 } else {
439 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_DIGEST_KEY,
440 ctx->cc_session, NULL, key, NULL, NULL);
441 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
442 }
443
444 return (error);
445 }
446
447 /*
448 * See comments for crypto_digest_update() and crypto_digest_final().
449 */
450 int
crypto_digest_single(crypto_context_t context,crypto_data_t * data,crypto_data_t * digest,crypto_call_req_t * cr)451 crypto_digest_single(crypto_context_t context, crypto_data_t *data,
452 crypto_data_t *digest, crypto_call_req_t *cr)
453 {
454 crypto_ctx_t *ctx = (crypto_ctx_t *)context;
455 kcf_context_t *kcf_ctx;
456 kcf_provider_desc_t *pd;
457 int error;
458 kcf_req_params_t params;
459
460 if ((ctx == NULL) ||
461 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
462 ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
463 return (CRYPTO_INVALID_CONTEXT);
464 }
465
466
467 /* The fast path for SW providers. */
468 if (CHECK_FASTPATH(cr, pd)) {
469 error = KCF_PROV_DIGEST(pd, ctx, data, digest, NULL);
470 KCF_PROV_INCRSTATS(pd, error);
471 } else {
472 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_SINGLE, pd->pd_sid,
473 NULL, NULL, data, digest);
474 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
475 }
476
477 /* Release the hold done in kcf_new_ctx() during init step. */
478 KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
479 return (error);
480 }
481
482 #if defined(_KERNEL)
483 EXPORT_SYMBOL(crypto_digest_prov);
484 EXPORT_SYMBOL(crypto_digest);
485 EXPORT_SYMBOL(crypto_digest_init_prov);
486 EXPORT_SYMBOL(crypto_digest_init);
487 EXPORT_SYMBOL(crypto_digest_update);
488 EXPORT_SYMBOL(crypto_digest_final);
489 EXPORT_SYMBOL(crypto_digest_key_prov);
490 EXPORT_SYMBOL(crypto_digest_single);
491 #endif
492