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