]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - module/icp/api/kcf_digest.c
Vendor import of openzfs master @ 184df27eef0abdc7ab2105b21257f753834b936b
[FreeBSD/FreeBSD.git] / module / icp / api / kcf_digest.c
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
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(&params, 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, &params, 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
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(&params, 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, &params,
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
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(&params, KCF_OP_INIT, sid,
243                     mech, NULL, NULL, NULL);
244                 error = kcf_submit_request(real_provider, ctx, crq, &params,
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
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
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(&params, KCF_OP_UPDATE,
354                     ctx->cc_session, NULL, NULL, data, NULL);
355                 error = kcf_submit_request(pd, ctx, cr, &params, 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
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(&params, KCF_OP_FINAL,
403                     ctx->cc_session, NULL, NULL, NULL, digest);
404                 error = kcf_submit_request(pd, ctx, cr, &params, 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
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(&params, KCF_OP_DIGEST_KEY,
440                     ctx->cc_session, NULL, key, NULL, NULL);
441                 error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
442         }
443
444         return (error);
445 }
446
447 /*
448  * See comments for crypto_digest_update() and crypto_digest_final().
449  */
450 int
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(&params, KCF_OP_SINGLE, pd->pd_sid,
473                     NULL, NULL, data, digest);
474                 error = kcf_submit_request(pd, ctx, cr, &params, 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