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.
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.
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]
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/errno.h>
26 #include <sys/types.h>
28 #include <sys/sysmacros.h>
29 #include <sys/crypto/common.h>
30 #include <sys/crypto/impl.h>
31 #include <sys/crypto/api.h>
32 #include <sys/crypto/spi.h>
33 #include <sys/crypto/sched_impl.h>
35 #define CRYPTO_OPS_OFFSET(f) offsetof(crypto_ops_t, co_##f)
36 #define CRYPTO_MAC_OFFSET(f) offsetof(crypto_mac_ops_t, f)
39 * Message authentication codes routines.
43 * The following are the possible returned values common to all the routines
44 * below. The applicability of some of these return values depends on the
45 * presence of the arguments.
47 * CRYPTO_SUCCESS: The operation completed successfully.
48 * CRYPTO_QUEUED: A request was submitted successfully. The callback
49 * routine will be called when the operation is done.
50 * CRYPTO_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or
51 * CRYPTO_INVALID_MECH for problems with the 'mech'.
52 * CRYPTO_INVALID_DATA for bogus 'data'
53 * CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
54 * CRYPTO_INVALID_CONTEXT: Not a valid context.
55 * CRYPTO_BUSY: Cannot process the request now. Schedule a
56 * crypto_bufcall(), or try later.
57 * CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: No provider is
58 * capable of a function or a mechanism.
59 * CRYPTO_INVALID_KEY: bogus 'key' argument.
60 * CRYPTO_INVALID_MAC: bogus 'mac' argument.
67 * mech: crypto_mechanism_t pointer.
68 * mech_type is a valid value previously returned by
70 * When the mech's parameter is not NULL, its definition depends
71 * on the standard definition of the mechanism.
72 * key: pointer to a crypto_key_t structure.
73 * data: The message to compute the MAC for.
74 * mac: Storage for the MAC. The length needed depends on the mechanism.
75 * tmpl: a crypto_ctx_template_t, opaque template of a context of a
76 * MAC with the 'mech' using 'key'. 'tmpl' is created by
77 * a previous call to crypto_create_ctx_template().
78 * cr: crypto_call_req_t calling conditions and call back info.
81 * Asynchronously submits a request for, or synchronously performs a
82 * single-part message authentication of 'data' with the mechanism
83 * 'mech', using * the key 'key', on the specified provider with
84 * the specified session id.
85 * When complete and successful, 'mac' will contain the message
86 * authentication code.
89 * Process or interrupt, according to the semantics dictated by the 'crq'.
92 * See comment in the beginning of the file.
95 crypto_mac_prov(crypto_provider_t provider
, crypto_session_id_t sid
,
96 crypto_mechanism_t
*mech
, crypto_data_t
*data
, crypto_key_t
*key
,
97 crypto_ctx_template_t tmpl
, crypto_data_t
*mac
, crypto_call_req_t
*crq
)
99 kcf_req_params_t params
;
100 kcf_provider_desc_t
*pd
= provider
;
101 kcf_provider_desc_t
*real_provider
= pd
;
104 ASSERT(KCF_PROV_REFHELD(pd
));
106 if (pd
->pd_prov_type
== CRYPTO_LOGICAL_PROVIDER
) {
107 rv
= kcf_get_hardware_provider(mech
->cm_type
, key
,
108 CRYPTO_MECH_INVALID
, NULL
, pd
, &real_provider
,
109 CRYPTO_FG_MAC_ATOMIC
);
111 if (rv
!= CRYPTO_SUCCESS
)
115 KCF_WRAP_MAC_OPS_PARAMS(¶ms
, KCF_OP_ATOMIC
, sid
, mech
, key
,
117 rv
= kcf_submit_request(real_provider
, NULL
, crq
, ¶ms
, B_FALSE
);
118 if (pd
->pd_prov_type
== CRYPTO_LOGICAL_PROVIDER
)
119 KCF_PROV_REFRELE(real_provider
);
125 * Same as crypto_mac_prov(), but relies on the KCF scheduler to choose
126 * a provider. See crypto_mac() comments for more information.
129 crypto_mac(crypto_mechanism_t
*mech
, crypto_data_t
*data
,
130 crypto_key_t
*key
, crypto_ctx_template_t tmpl
, crypto_data_t
*mac
,
131 crypto_call_req_t
*crq
)
134 kcf_mech_entry_t
*me
;
135 kcf_req_params_t params
;
136 kcf_provider_desc_t
*pd
;
137 kcf_ctx_template_t
*ctx_tmpl
;
138 crypto_spi_ctx_template_t spi_ctx_tmpl
= NULL
;
139 kcf_prov_tried_t
*list
= NULL
;
142 /* The pd is returned held */
143 if ((pd
= kcf_get_mech_provider(mech
->cm_type
, key
, &me
, &error
,
144 list
, CRYPTO_FG_MAC_ATOMIC
, data
->cd_length
)) == NULL
) {
146 kcf_free_triedlist(list
);
151 * For SW providers, check the validity of the context template
152 * It is very rare that the generation number mis-matches, so
153 * is acceptable to fail here, and let the consumer recover by
154 * freeing this tmpl and create a new one for the key and new SW
157 if ((pd
->pd_prov_type
== CRYPTO_SW_PROVIDER
) &&
158 ((ctx_tmpl
= (kcf_ctx_template_t
*)tmpl
) != NULL
)) {
159 if (ctx_tmpl
->ct_generation
!= me
->me_gen_swprov
) {
161 kcf_free_triedlist(list
);
162 KCF_PROV_REFRELE(pd
);
163 return (CRYPTO_OLD_CTX_TEMPLATE
);
165 spi_ctx_tmpl
= ctx_tmpl
->ct_prov_tmpl
;
169 /* The fast path for SW providers. */
170 if (CHECK_FASTPATH(crq
, pd
)) {
171 crypto_mechanism_t lmech
;
174 KCF_SET_PROVIDER_MECHNUM(mech
->cm_type
, pd
, &lmech
);
176 error
= KCF_PROV_MAC_ATOMIC(pd
, pd
->pd_sid
, &lmech
, key
, data
,
177 mac
, spi_ctx_tmpl
, KCF_SWFP_RHNDL(crq
));
178 KCF_PROV_INCRSTATS(pd
, error
);
180 if (pd
->pd_prov_type
== CRYPTO_HW_PROVIDER
&&
181 (pd
->pd_flags
& CRYPTO_HMAC_NO_UPDATE
) &&
182 (data
->cd_length
> pd
->pd_hmac_limit
)) {
184 * XXX - We need a check to see if this is indeed
185 * a HMAC. So far, all kernel clients use
186 * this interface only for HMAC. So, this is fine
189 error
= CRYPTO_BUFFER_TOO_BIG
;
191 KCF_WRAP_MAC_OPS_PARAMS(¶ms
, KCF_OP_ATOMIC
,
192 pd
->pd_sid
, mech
, key
, data
, mac
, spi_ctx_tmpl
);
194 error
= kcf_submit_request(pd
, NULL
, crq
, ¶ms
,
199 if (error
!= CRYPTO_SUCCESS
&& error
!= CRYPTO_QUEUED
&&
200 IS_RECOVERABLE(error
)) {
201 /* Add pd to the linked list of providers tried. */
202 if (kcf_insert_triedlist(&list
, pd
, KCF_KMFLAG(crq
)) != NULL
)
207 kcf_free_triedlist(list
);
209 KCF_PROV_REFRELE(pd
);
214 * Single part operation to compute the MAC corresponding to the specified
215 * 'data' and to verify that it matches the MAC specified by 'mac'.
216 * The other arguments are the same as the function crypto_mac_prov().
219 crypto_mac_verify_prov(crypto_provider_t provider
, crypto_session_id_t sid
,
220 crypto_mechanism_t
*mech
, crypto_data_t
*data
, crypto_key_t
*key
,
221 crypto_ctx_template_t tmpl
, crypto_data_t
*mac
, crypto_call_req_t
*crq
)
223 kcf_req_params_t params
;
224 kcf_provider_desc_t
*pd
= provider
;
225 kcf_provider_desc_t
*real_provider
= pd
;
228 ASSERT(KCF_PROV_REFHELD(pd
));
230 if (pd
->pd_prov_type
== CRYPTO_LOGICAL_PROVIDER
) {
231 rv
= kcf_get_hardware_provider(mech
->cm_type
, key
,
232 CRYPTO_MECH_INVALID
, NULL
, pd
, &real_provider
,
233 CRYPTO_FG_MAC_ATOMIC
);
235 if (rv
!= CRYPTO_SUCCESS
)
239 KCF_WRAP_MAC_OPS_PARAMS(¶ms
, KCF_OP_MAC_VERIFY_ATOMIC
, sid
, mech
,
240 key
, data
, mac
, tmpl
);
241 rv
= kcf_submit_request(real_provider
, NULL
, crq
, ¶ms
, B_FALSE
);
242 if (pd
->pd_prov_type
== CRYPTO_LOGICAL_PROVIDER
)
243 KCF_PROV_REFRELE(real_provider
);
249 * Same as crypto_mac_verify_prov(), but relies on the KCF scheduler to choose
250 * a provider. See crypto_mac_verify_prov() comments for more information.
253 crypto_mac_verify(crypto_mechanism_t
*mech
, crypto_data_t
*data
,
254 crypto_key_t
*key
, crypto_ctx_template_t tmpl
, crypto_data_t
*mac
,
255 crypto_call_req_t
*crq
)
258 kcf_mech_entry_t
*me
;
259 kcf_req_params_t params
;
260 kcf_provider_desc_t
*pd
;
261 kcf_ctx_template_t
*ctx_tmpl
;
262 crypto_spi_ctx_template_t spi_ctx_tmpl
= NULL
;
263 kcf_prov_tried_t
*list
= NULL
;
266 /* The pd is returned held */
267 if ((pd
= kcf_get_mech_provider(mech
->cm_type
, key
, &me
, &error
,
268 list
, CRYPTO_FG_MAC_ATOMIC
, data
->cd_length
)) == NULL
) {
270 kcf_free_triedlist(list
);
275 * For SW providers, check the validity of the context template
276 * It is very rare that the generation number mis-matches, so
277 * is acceptable to fail here, and let the consumer recover by
278 * freeing this tmpl and create a new one for the key and new SW
281 if ((pd
->pd_prov_type
== CRYPTO_SW_PROVIDER
) &&
282 ((ctx_tmpl
= (kcf_ctx_template_t
*)tmpl
) != NULL
)) {
283 if (ctx_tmpl
->ct_generation
!= me
->me_gen_swprov
) {
285 kcf_free_triedlist(list
);
286 KCF_PROV_REFRELE(pd
);
287 return (CRYPTO_OLD_CTX_TEMPLATE
);
289 spi_ctx_tmpl
= ctx_tmpl
->ct_prov_tmpl
;
293 /* The fast path for SW providers. */
294 if (CHECK_FASTPATH(crq
, pd
)) {
295 crypto_mechanism_t lmech
;
298 KCF_SET_PROVIDER_MECHNUM(mech
->cm_type
, pd
, &lmech
);
300 error
= KCF_PROV_MAC_VERIFY_ATOMIC(pd
, pd
->pd_sid
, &lmech
, key
,
301 data
, mac
, spi_ctx_tmpl
, KCF_SWFP_RHNDL(crq
));
302 KCF_PROV_INCRSTATS(pd
, error
);
304 if (pd
->pd_prov_type
== CRYPTO_HW_PROVIDER
&&
305 (pd
->pd_flags
& CRYPTO_HMAC_NO_UPDATE
) &&
306 (data
->cd_length
> pd
->pd_hmac_limit
)) {
307 /* see comments in crypto_mac() */
308 error
= CRYPTO_BUFFER_TOO_BIG
;
310 KCF_WRAP_MAC_OPS_PARAMS(¶ms
,
311 KCF_OP_MAC_VERIFY_ATOMIC
, pd
->pd_sid
, mech
,
312 key
, data
, mac
, spi_ctx_tmpl
);
314 error
= kcf_submit_request(pd
, NULL
, crq
, ¶ms
,
319 if (error
!= CRYPTO_SUCCESS
&& error
!= CRYPTO_QUEUED
&&
320 IS_RECOVERABLE(error
)) {
321 /* Add pd to the linked list of providers tried. */
322 if (kcf_insert_triedlist(&list
, pd
, KCF_KMFLAG(crq
)) != NULL
)
327 kcf_free_triedlist(list
);
329 KCF_PROV_REFRELE(pd
);
335 * crypto_mac_init_prov()
338 * pd: pointer to the descriptor of the provider to use for this
340 * sid: provider session id.
341 * mech: crypto_mechanism_t pointer.
342 * mech_type is a valid value previously returned by
344 * When the mech's parameter is not NULL, its definition depends
345 * on the standard definition of the mechanism.
346 * key: pointer to a crypto_key_t structure.
347 * tmpl: a crypto_ctx_template_t, opaque template of a context of a
348 * MAC with the 'mech' using 'key'. 'tmpl' is created by
349 * a previous call to crypto_create_ctx_template().
350 * ctxp: Pointer to a crypto_context_t.
351 * cr: crypto_call_req_t calling conditions and call back info.
354 * Asynchronously submits a request for, or synchronously performs the
355 * initialization of a MAC operation on the specified provider with
356 * the specified session.
357 * When possible and applicable, will internally use the pre-computed MAC
358 * context from the context template, tmpl.
359 * When complete and successful, 'ctxp' will contain a crypto_context_t
360 * valid for later calls to mac_update() and mac_final().
361 * The caller should hold a reference on the specified provider
362 * descriptor before calling this function.
365 * Process or interrupt, according to the semantics dictated by the 'cr'.
368 * See comment in the beginning of the file.
371 crypto_mac_init_prov(crypto_provider_t provider
, crypto_session_id_t sid
,
372 crypto_mechanism_t
*mech
, crypto_key_t
*key
, crypto_spi_ctx_template_t tmpl
,
373 crypto_context_t
*ctxp
, crypto_call_req_t
*crq
)
377 kcf_req_params_t params
;
378 kcf_provider_desc_t
*pd
= provider
;
379 kcf_provider_desc_t
*real_provider
= pd
;
381 ASSERT(KCF_PROV_REFHELD(pd
));
383 if (pd
->pd_prov_type
== CRYPTO_LOGICAL_PROVIDER
) {
384 rv
= kcf_get_hardware_provider(mech
->cm_type
, key
,
385 CRYPTO_MECH_INVALID
, NULL
, pd
, &real_provider
,
388 if (rv
!= CRYPTO_SUCCESS
)
392 /* Allocate and initialize the canonical context */
393 if ((ctx
= kcf_new_ctx(crq
, real_provider
, sid
)) == NULL
) {
394 if (pd
->pd_prov_type
== CRYPTO_LOGICAL_PROVIDER
)
395 KCF_PROV_REFRELE(real_provider
);
396 return (CRYPTO_HOST_MEMORY
);
399 /* The fast path for SW providers. */
400 if (CHECK_FASTPATH(crq
, pd
)) {
401 crypto_mechanism_t lmech
;
404 KCF_SET_PROVIDER_MECHNUM(mech
->cm_type
, real_provider
, &lmech
);
405 rv
= KCF_PROV_MAC_INIT(real_provider
, ctx
, &lmech
, key
, tmpl
,
406 KCF_SWFP_RHNDL(crq
));
407 KCF_PROV_INCRSTATS(pd
, rv
);
409 KCF_WRAP_MAC_OPS_PARAMS(¶ms
, KCF_OP_INIT
, sid
, mech
, key
,
411 rv
= kcf_submit_request(real_provider
, ctx
, crq
, ¶ms
,
415 if (pd
->pd_prov_type
== CRYPTO_LOGICAL_PROVIDER
)
416 KCF_PROV_REFRELE(real_provider
);
418 if ((rv
== CRYPTO_SUCCESS
) || (rv
== CRYPTO_QUEUED
))
419 *ctxp
= (crypto_context_t
)ctx
;
421 /* Release the hold done in kcf_new_ctx(). */
422 KCF_CONTEXT_REFRELE((kcf_context_t
*)ctx
->cc_framework_private
);
429 * Same as crypto_mac_init_prov(), but relies on the KCF scheduler to
430 * choose a provider. See crypto_mac_init_prov() comments for more
434 crypto_mac_init(crypto_mechanism_t
*mech
, crypto_key_t
*key
,
435 crypto_ctx_template_t tmpl
, crypto_context_t
*ctxp
,
436 crypto_call_req_t
*crq
)
439 kcf_mech_entry_t
*me
;
440 kcf_provider_desc_t
*pd
;
441 kcf_ctx_template_t
*ctx_tmpl
;
442 crypto_spi_ctx_template_t spi_ctx_tmpl
= NULL
;
443 kcf_prov_tried_t
*list
= NULL
;
446 /* The pd is returned held */
447 if ((pd
= kcf_get_mech_provider(mech
->cm_type
, key
, &me
, &error
,
448 list
, CRYPTO_FG_MAC
, 0)) == NULL
) {
450 kcf_free_triedlist(list
);
455 * For SW providers, check the validity of the context template
456 * It is very rare that the generation number mis-matches, so
457 * is acceptable to fail here, and let the consumer recover by
458 * freeing this tmpl and create a new one for the key and new SW
462 if ((pd
->pd_prov_type
== CRYPTO_SW_PROVIDER
) &&
463 ((ctx_tmpl
= (kcf_ctx_template_t
*)tmpl
) != NULL
)) {
464 if (ctx_tmpl
->ct_generation
!= me
->me_gen_swprov
) {
466 kcf_free_triedlist(list
);
467 KCF_PROV_REFRELE(pd
);
468 return (CRYPTO_OLD_CTX_TEMPLATE
);
470 spi_ctx_tmpl
= ctx_tmpl
->ct_prov_tmpl
;
474 if (pd
->pd_prov_type
== CRYPTO_HW_PROVIDER
&&
475 (pd
->pd_flags
& CRYPTO_HMAC_NO_UPDATE
)) {
477 * The hardware provider has limited HMAC support.
478 * So, we fallback early here to using a software provider.
480 * XXX - need to enhance to do the fallback later in
481 * crypto_mac_update() if the size of accumulated input data
482 * exceeds the maximum size digestable by hardware provider.
484 error
= CRYPTO_BUFFER_TOO_BIG
;
486 error
= crypto_mac_init_prov(pd
, pd
->pd_sid
, mech
, key
,
487 spi_ctx_tmpl
, ctxp
, crq
);
489 if (error
!= CRYPTO_SUCCESS
&& error
!= CRYPTO_QUEUED
&&
490 IS_RECOVERABLE(error
)) {
491 /* Add pd to the linked list of providers tried. */
492 if (kcf_insert_triedlist(&list
, pd
, KCF_KMFLAG(crq
)) != NULL
)
497 kcf_free_triedlist(list
);
499 KCF_PROV_REFRELE(pd
);
504 * crypto_mac_update()
507 * context: A crypto_context_t initialized by mac_init().
508 * data: The message part to be MAC'ed
509 * cr: crypto_call_req_t calling conditions and call back info.
512 * Asynchronously submits a request for, or synchronously performs a
513 * part of a MAC operation.
516 * Process or interrupt, according to the semantics dictated by the 'cr'.
519 * See comment in the beginning of the file.
522 crypto_mac_update(crypto_context_t context
, crypto_data_t
*data
,
523 crypto_call_req_t
*cr
)
525 crypto_ctx_t
*ctx
= (crypto_ctx_t
*)context
;
526 kcf_context_t
*kcf_ctx
;
527 kcf_provider_desc_t
*pd
;
528 kcf_req_params_t params
;
532 ((kcf_ctx
= (kcf_context_t
*)ctx
->cc_framework_private
) == NULL
) ||
533 ((pd
= kcf_ctx
->kc_prov_desc
) == NULL
)) {
534 return (CRYPTO_INVALID_CONTEXT
);
537 ASSERT(pd
->pd_prov_type
!= CRYPTO_LOGICAL_PROVIDER
);
539 /* The fast path for SW providers. */
540 if (CHECK_FASTPATH(cr
, pd
)) {
541 rv
= KCF_PROV_MAC_UPDATE(pd
, ctx
, data
, NULL
);
542 KCF_PROV_INCRSTATS(pd
, rv
);
544 KCF_WRAP_MAC_OPS_PARAMS(¶ms
, KCF_OP_UPDATE
,
545 ctx
->cc_session
, NULL
, NULL
, data
, NULL
, NULL
);
546 rv
= kcf_submit_request(pd
, ctx
, cr
, ¶ms
, B_FALSE
);
556 * context: A crypto_context_t initialized by mac_init().
557 * mac: Storage for the message authentication code.
558 * cr: crypto_call_req_t calling conditions and call back info.
561 * Asynchronously submits a request for, or synchronously performs a
562 * part of a message authentication operation.
565 * Process or interrupt, according to the semantics dictated by the 'cr'.
568 * See comment in the beginning of the file.
571 crypto_mac_final(crypto_context_t context
, crypto_data_t
*mac
,
572 crypto_call_req_t
*cr
)
574 crypto_ctx_t
*ctx
= (crypto_ctx_t
*)context
;
575 kcf_context_t
*kcf_ctx
;
576 kcf_provider_desc_t
*pd
;
577 kcf_req_params_t params
;
581 ((kcf_ctx
= (kcf_context_t
*)ctx
->cc_framework_private
) == NULL
) ||
582 ((pd
= kcf_ctx
->kc_prov_desc
) == NULL
)) {
583 return (CRYPTO_INVALID_CONTEXT
);
586 ASSERT(pd
->pd_prov_type
!= CRYPTO_LOGICAL_PROVIDER
);
588 /* The fast path for SW providers. */
589 if (CHECK_FASTPATH(cr
, pd
)) {
590 rv
= KCF_PROV_MAC_FINAL(pd
, ctx
, mac
, NULL
);
591 KCF_PROV_INCRSTATS(pd
, rv
);
593 KCF_WRAP_MAC_OPS_PARAMS(¶ms
, KCF_OP_FINAL
,
594 ctx
->cc_session
, NULL
, NULL
, NULL
, mac
, NULL
);
595 rv
= kcf_submit_request(pd
, ctx
, cr
, ¶ms
, B_FALSE
);
598 /* Release the hold done in kcf_new_ctx() during init step. */
599 KCF_CONTEXT_COND_RELEASE(rv
, kcf_ctx
);
604 * See comments for crypto_mac_update() and crypto_mac_final().
607 crypto_mac_single(crypto_context_t context
, crypto_data_t
*data
,
608 crypto_data_t
*mac
, crypto_call_req_t
*cr
)
610 crypto_ctx_t
*ctx
= (crypto_ctx_t
*)context
;
611 kcf_context_t
*kcf_ctx
;
612 kcf_provider_desc_t
*pd
;
614 kcf_req_params_t params
;
618 ((kcf_ctx
= (kcf_context_t
*)ctx
->cc_framework_private
) == NULL
) ||
619 ((pd
= kcf_ctx
->kc_prov_desc
) == NULL
)) {
620 return (CRYPTO_INVALID_CONTEXT
);
624 /* The fast path for SW providers. */
625 if (CHECK_FASTPATH(cr
, pd
)) {
626 error
= KCF_PROV_MAC(pd
, ctx
, data
, mac
, NULL
);
627 KCF_PROV_INCRSTATS(pd
, error
);
629 KCF_WRAP_MAC_OPS_PARAMS(¶ms
, KCF_OP_SINGLE
, pd
->pd_sid
,
630 NULL
, NULL
, data
, mac
, NULL
);
631 error
= kcf_submit_request(pd
, ctx
, cr
, ¶ms
, B_FALSE
);
634 /* Release the hold done in kcf_new_ctx() during init step. */
635 KCF_CONTEXT_COND_RELEASE(error
, kcf_ctx
);