/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * This file contains routines which call into a provider's * entry points and do other related work. */ #include #include #include #include #include #include #include #include /* * Return B_TRUE if the specified entry point is NULL. We rely on the * caller to provide, with offset_1 and offset_2, information to calculate * the location of the entry point. The ops argument is a temporary local * variable defined as caddr_t *. */ #define KCF_PROV_NULL_ENTRY_POINT(pd, o1, o2, ops) \ (ops = (caddr_t *)(void *)((caddr_t)(pd)->pd_ops_vector + (o1)), \ (*ops == NULL || *(caddr_t *)(void *)((caddr_t)(*ops) + (o2)) == NULL)) static int kcf_emulate_dual(kcf_provider_desc_t *, crypto_ctx_t *, kcf_req_params_t *); void kcf_free_triedlist(kcf_prov_tried_t *list) { kcf_prov_tried_t *l; while ((l = list) != NULL) { list = list->pt_next; KCF_PROV_REFRELE(l->pt_pd); kmem_free(l, sizeof (kcf_prov_tried_t)); } } /* * The typical caller of this routine does a kcf_get_mech_provider() * which holds the provider and then calls this routine. So, for the * common case (no KCF_HOLD_PROV flag) we skip doing a KCF_PROV_REFHOLD. */ kcf_prov_tried_t * kcf_insert_triedlist(kcf_prov_tried_t **list, kcf_provider_desc_t *pd, int flags) { kcf_prov_tried_t *l; l = kmem_alloc(sizeof (kcf_prov_tried_t), flags & (KM_SLEEP | KM_NOSLEEP)); if (l == NULL) return (NULL); if (flags & KCF_HOLD_PROV) KCF_PROV_REFHOLD(pd); l->pt_pd = pd; l->pt_next = *list; *list = l; return (l); } static boolean_t is_in_triedlist(kcf_provider_desc_t *pd, kcf_prov_tried_t *triedl) { while (triedl != NULL) { if (triedl->pt_pd == pd) return (B_TRUE); triedl = triedl->pt_next; }; return (B_FALSE); } /* * Check if the key/attribute length is within the limits of given provider * and mechanism. Return 0 if the key length is off the limits, 1 otherwise. * In the latter case, this either means the key length is within the limits * or we are not able to perform check for a key type. */ static int kcf_check_prov_mech_keylen(kcf_provider_desc_t *provider, crypto_mech_type_t mech_type, crypto_key_t *key) { crypto_mech_info_t *mech_info = NULL; size_t keylen = 0; ssize_t attr_len; uchar_t *attr; mech_info = &(KCF_TO_PROV_MECHINFO(provider, mech_type)); switch (key->ck_format) { case CRYPTO_KEY_RAW: /* ck_length is always in bits */ if (mech_info->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BYTES) keylen = CRYPTO_BITS2BYTES(key->ck_length); else keylen = key->ck_length; break; case CRYPTO_KEY_ATTR_LIST: /* Check modulus for RSA operations. */ if ((crypto_get_key_attr(key, SUN_CKA_MODULUS, &attr, &attr_len)) == CRYPTO_SUCCESS) { /* modulus length is returned in bytes */ if (mech_info->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BITS) keylen = CRYPTO_BYTES2BITS(attr_len); else keylen = attr_len; /* Check prime for DH/DSA operations. */ } else if ((crypto_get_key_attr(key, SUN_CKA_PRIME, &attr, &attr_len)) == CRYPTO_SUCCESS) { /* prime length is returned in bytes */ if (mech_info->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BITS) keylen = CRYPTO_BYTES2BITS(attr_len); else keylen = attr_len; } /* * If the attribute is not found we cannot do * the check so return with success and let * the actual provider do the check. */ if (keylen == 0) return (1); break; default: /* * We are not able to check CRYPTO_KEY_REFERENCE * or other key types here. */ return (1); } DTRACE_PROBE4(keylen__check, crypto_mech_type_t, mech_type, size_t, keylen, ssize_t, mech_info->cm_min_key_length, ssize_t, mech_info->cm_max_key_length); /* Do the actual check. */ if ((keylen > mech_info->cm_max_key_length) || (keylen < mech_info->cm_min_key_length)) { return (0); } return (1); } /* * Search a mech entry's hardware provider list for the specified * provider. Return true if found. */ static boolean_t is_valid_provider_for_mech(kcf_provider_desc_t *pd, kcf_mech_entry_t *me, crypto_func_group_t fg) { kcf_prov_mech_desc_t *prov_chain; prov_chain = me->me_hw_prov_chain; if (prov_chain != NULL) { ASSERT(me->me_num_hwprov > 0); for (; prov_chain != NULL; prov_chain = prov_chain->pm_next) { if (prov_chain->pm_prov_desc == pd && IS_FG_SUPPORTED(prov_chain, fg)) { return (B_TRUE); } } } return (B_FALSE); } /* * This routine, given a logical provider, returns the least loaded * provider belonging to the logical provider. The provider must be * able to do the specified mechanism, i.e. check that the mechanism * hasn't been disabled. In addition, just in case providers are not * entirely equivalent, the provider's entry point is checked for * non-nullness. This is accomplished by having the caller pass, as * arguments, the offset of the function group (offset_1), and the * offset of the function within the function group (offset_2). * * If a non-NULL key structure is supplied, the provider will be checked * to see if the key length falls into the limits of given mechanism * for that provider. This is done for both key structures and mechanisms. * * Returns NULL if no provider can be found. */ int kcf_get_hardware_provider(crypto_mech_type_t mech_type_1, crypto_key_t *key1, crypto_mech_type_t mech_type_2, crypto_key_t *key2, kcf_provider_desc_t *old, kcf_provider_desc_t **new, crypto_func_group_t fg) { kcf_provider_desc_t *provider, *real_pd = old; kcf_provider_desc_t *gpd = NULL; /* good provider */ kcf_provider_desc_t *bpd = NULL; /* busy provider */ kcf_provider_list_t *p; kcf_ops_class_t class; kcf_mech_entry_t *me; kcf_mech_entry_tab_t *me_tab; int index, len, gqlen = INT_MAX, rv = CRYPTO_SUCCESS; kcf_lock_withpad_t *mp; /* get the mech entry for the specified mechanism */ class = KCF_MECH2CLASS(mech_type_1); if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) { return (CRYPTO_MECHANISM_INVALID); } me_tab = &kcf_mech_tabs_tab[class]; index = KCF_MECH2INDEX(mech_type_1); if ((index < 0) || (index >= me_tab->met_size)) { return (CRYPTO_MECHANISM_INVALID); } me = &((me_tab->met_tab)[index]); mp = &me_mutexes[CPU_SEQID]; mutex_enter(&mp->kl_lock); /* * We assume the provider descriptor will not go away because * it is being held somewhere, i.e. its reference count has been * incremented. In the case of the crypto module, the provider * descriptor is held by the session structure. */ if (old->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { if (old->pd_provider_list == NULL) { real_pd = NULL; rv = CRYPTO_DEVICE_ERROR; goto out; } /* * Find the least loaded real provider. KCF_PROV_LOAD gives * the load (number of pending requests) of the provider. */ mutex_enter(&old->pd_lock); p = old->pd_provider_list; while (p != NULL) { provider = p->pl_provider; ASSERT(provider->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); if (!is_valid_provider_for_mech(provider, me, fg)) { p = p->pl_next; continue; } if ((key1 != NULL) && !kcf_check_prov_mech_keylen(provider, mech_type_1, key1)) { p = p->pl_next; rv = CRYPTO_KEY_SIZE_RANGE; continue; } /* provider does second mech */ if (mech_type_2 != CRYPTO_MECH_INVALID) { int i; i = KCF_TO_PROV_MECH_INDX(provider, mech_type_2); if (i == KCF_INVALID_INDX) { p = p->pl_next; continue; } if ((key2 != NULL) && !kcf_check_prov_mech_keylen(provider, mech_type_2, key2)) { p = p->pl_next; rv = CRYPTO_KEY_SIZE_RANGE; continue; } } if (provider->pd_state != KCF_PROV_READY) { /* choose BUSY if no READY providers */ if (provider->pd_state == KCF_PROV_BUSY) bpd = provider; p = p->pl_next; continue; } /* Do load calculation only if needed */ if ((p = p->pl_next) == NULL && gpd == NULL) { gpd = provider; } else { len = KCF_PROV_LOAD(provider); if (len < gqlen) { gqlen = len; gpd = provider; } } } if (gpd != NULL) { real_pd = gpd; rv = CRYPTO_SUCCESS; KCF_PROV_REFHOLD(real_pd); } else if (bpd != NULL) { real_pd = bpd; rv = CRYPTO_SUCCESS; KCF_PROV_REFHOLD(real_pd); } else { /* can't find provider */ real_pd = NULL; if (rv == CRYPTO_SUCCESS) rv = CRYPTO_MECHANISM_INVALID; } mutex_exit(&old->pd_lock); } else { if (!KCF_IS_PROV_USABLE(old)) { real_pd = NULL; rv = CRYPTO_DEVICE_ERROR; goto out; } if (!is_valid_provider_for_mech(old, me, fg)) { real_pd = NULL; rv = CRYPTO_MECHANISM_INVALID; goto out; } if ((key1 != NULL) && !kcf_check_prov_mech_keylen(old, mech_type_1, key1)) { real_pd = NULL; rv = CRYPTO_KEY_SIZE_RANGE; goto out; } KCF_PROV_REFHOLD(real_pd); } out: mutex_exit(&mp->kl_lock); *new = real_pd; return (rv); } /* * This routine, given a logical provider, returns the least loaded * provider belonging to the logical provider. Just in case providers * are not entirely equivalent, the provider's entry point is checked * for non-nullness. This is accomplished by having the caller pass, as * arguments, the offset of the function group (offset_1), and the * offset of the function within the function group (offset_2). * Returns NULL if no provider can be found. */ int kcf_get_hardware_provider_nomech(offset_t offset_1, offset_t offset_2, kcf_provider_desc_t *old, kcf_provider_desc_t **new) { kcf_provider_desc_t *provider, *real_pd = old; kcf_provider_desc_t *gpd = NULL; /* good provider */ kcf_provider_desc_t *bpd = NULL; /* busy provider */ kcf_provider_list_t *p; caddr_t *ops; int len, gqlen = INT_MAX, rv = CRYPTO_SUCCESS; /* * We assume the provider descriptor will not go away because * it is being held somewhere, i.e. its reference count has been * incremented. In the case of the crypto module, the provider * descriptor is held by the session structure. */ if (old->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { if (old->pd_provider_list == NULL) { real_pd = NULL; rv = CRYPTO_DEVICE_ERROR; goto out; } /* * Find the least loaded real provider. KCF_PROV_LOAD gives * the load (number of pending requests) of the provider. */ mutex_enter(&old->pd_lock); p = old->pd_provider_list; while (p != NULL) { provider = p->pl_provider; ASSERT(provider->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); if (KCF_PROV_NULL_ENTRY_POINT(provider, offset_1, offset_2, ops)) { p = p->pl_next; continue; } if (provider->pd_state != KCF_PROV_READY) { /* choose BUSY if no READY providers */ if (provider->pd_state == KCF_PROV_BUSY) bpd = provider; p = p->pl_next; continue; } /* Do load calculation only if needed */ if ((p = p->pl_next) == NULL && gpd == NULL) { gpd = provider; } else { len = KCF_PROV_LOAD(provider); if (len < gqlen) { gqlen = len; gpd = provider; } } } mutex_exit(&old->pd_lock); if (gpd != NULL) { real_pd = gpd; KCF_PROV_REFHOLD(real_pd); } else if (bpd != NULL) { real_pd = bpd; KCF_PROV_REFHOLD(real_pd); } else { /* can't find provider */ real_pd = NULL; rv = CRYPTO_DEVICE_ERROR; } } else { if (!KCF_IS_PROV_USABLE(old)) { real_pd = NULL; rv = CRYPTO_DEVICE_ERROR; goto out; } if (KCF_PROV_NULL_ENTRY_POINT(old, offset_1, offset_2, ops)) { real_pd = NULL; rv = CRYPTO_NOT_SUPPORTED; goto out; } KCF_PROV_REFHOLD(real_pd); } out: *new = real_pd; return (rv); } /* * Return the next member of a logical provider, given the previous * member. The function returns true if the next member is found and * bumps its refcnt before returning. */ boolean_t kcf_get_next_logical_provider_member(kcf_provider_desc_t *logical_provider, kcf_provider_desc_t *prev, kcf_provider_desc_t **pd) { kcf_provider_list_t *p; kcf_provider_desc_t *next; ASSERT(MUTEX_HELD(&logical_provider->pd_lock)); p = logical_provider->pd_provider_list; while (p != NULL) { /* start the search */ if (prev == NULL) { next = p->pl_provider; goto found; } else { /* find where we were before */ if (p->pl_provider == prev) { if (p->pl_next != NULL) { next = p->pl_next->pl_provider; goto found; } } } p = p->pl_next; } return (B_FALSE); found: KCF_PROV_REFHOLD(next); *pd = next; return (B_TRUE); } /* * Return the best provider for the specified mechanism. The provider * is held and it is the caller's responsibility to release it when done. * The fg input argument is used as a search criterion to pick a provider. * A provider has to support this function group to be picked. If a non-NULL * key structure is supplied, the provider will be checked to see if the key * length falls into the limits of given mechanism for that provider. * * Find the least loaded provider in the list of providers. We do a linear * search to find one. This is fine as we assume there are only a few * number of providers in this list. If this assumption ever changes, * we should revisit this. * */ kcf_provider_desc_t * kcf_get_mech_provider(crypto_mech_type_t mech_type, crypto_key_t *key, kcf_mech_entry_t **mepp, int *error, kcf_prov_tried_t *triedl, crypto_func_group_t fg, size_t data_size) { kcf_provider_desc_t *pd = NULL, *gpd = NULL; kcf_prov_mech_desc_t *prov_chain, *mdesc; int len, gqlen = INT_MAX; kcf_ops_class_t class; int index; kcf_mech_entry_t *me; kcf_mech_entry_tab_t *me_tab; kcf_lock_withpad_t *mp; int error_val = CRYPTO_MECH_NOT_SUPPORTED; /* default error value */ class = KCF_MECH2CLASS(mech_type); if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) { *error = CRYPTO_MECHANISM_INVALID; return (NULL); } me_tab = &kcf_mech_tabs_tab[class]; index = KCF_MECH2INDEX(mech_type); if ((index < 0) || (index >= me_tab->met_size)) { *error = CRYPTO_MECHANISM_INVALID; return (NULL); } me = &((me_tab->met_tab)[index]); if (mepp != NULL) *mepp = me; mp = &me_mutexes[CPU_SEQID]; mutex_enter(&mp->kl_lock); prov_chain = me->me_hw_prov_chain; /* * We check for the threshold for using a hardware provider for * this amount of data. If there is no software provider available * for the mechanism, then the threshold is ignored. */ if ((prov_chain != NULL) && ((data_size == 0) || (me->me_threshold == 0) || (data_size >= me->me_threshold) || ((mdesc = me->me_sw_prov) == NULL) || (!IS_FG_SUPPORTED(mdesc, fg)) || (!KCF_IS_PROV_USABLE(mdesc->pm_prov_desc)))) { ASSERT(me->me_num_hwprov > 0); /* there is at least one provider */ /* * Find the least loaded real provider. KCF_PROV_LOAD gives * the load (number of pending requests) of the provider. */ while (prov_chain != NULL) { pd = prov_chain->pm_prov_desc; if (!IS_FG_SUPPORTED(prov_chain, fg) || !KCF_IS_PROV_USABLE(pd) || IS_PROVIDER_TRIED(pd, triedl)) { prov_chain = prov_chain->pm_next; continue; } if ((key != NULL) && !kcf_check_prov_mech_keylen(pd, mech_type, key)) { prov_chain = prov_chain->pm_next; error_val = CRYPTO_KEY_SIZE_RANGE; continue; } /* Do load calculation only if needed */ if ((prov_chain = prov_chain->pm_next) == NULL && gpd == NULL) { gpd = pd; } else { len = KCF_PROV_LOAD(pd); if (len < gqlen) { gqlen = len; gpd = pd; } } } pd = gpd; } /* No HW provider for this mech, is there a SW provider? */ if (pd == NULL && (mdesc = me->me_sw_prov) != NULL) { pd = mdesc->pm_prov_desc; if (!IS_FG_SUPPORTED(mdesc, fg) || !KCF_IS_PROV_USABLE(pd) || IS_PROVIDER_TRIED(pd, triedl)) pd = NULL; } /* No provider found */ if (pd == NULL) { /* * We do not want to report CRYPTO_MECH_NOT_SUPPORTED, when * we are in the "fallback to the next provider" case. Rather * we preserve the error, so that the client gets the right * error code. */ if (triedl == NULL) *error = error_val; } else { KCF_PROV_REFHOLD(pd); } mutex_exit(&mp->kl_lock); return (pd); } /* * Very similar to kcf_get_mech_provider(). Finds the best provider capable of * a dual operation with both me1 and me2. * * If a non-NULL key structure is supplied, the provider will be checked * to see if the key length falls into the limits of given mechanism * for that provider. This is done for both key structures and mechanisms. * * When no dual-ops capable providers are available, return the best provider * for me1 only, and sets *prov_mt2 to CRYPTO_INVALID_MECHID; * We assume/expect that a slower HW capable of the dual is still * faster than the 2 fastest providers capable of the individual ops * separately. */ kcf_provider_desc_t * kcf_get_dual_provider(crypto_mechanism_t *mech1, crypto_key_t *key1, crypto_mechanism_t *mech2, crypto_key_t *key2, kcf_mech_entry_t **mepp, crypto_mech_type_t *prov_mt1, crypto_mech_type_t *prov_mt2, int *error, kcf_prov_tried_t *triedl, crypto_func_group_t fg1, crypto_func_group_t fg2, size_t data_size) { kcf_provider_desc_t *pd = NULL, *pdm1 = NULL, *pdm1m2 = NULL; kcf_prov_mech_desc_t *prov_chain, *mdesc; int len, gqlen = INT_MAX, dgqlen = INT_MAX; crypto_mech_info_list_t *mil; crypto_mech_type_t m2id = mech2->cm_type; kcf_mech_entry_t *me; kcf_lock_withpad_t *mp; int error_val = CRYPTO_MECH_NOT_SUPPORTED; /* default error value */ /* when mech is a valid mechanism, me will be its mech_entry */ if (kcf_get_mech_entry(mech1->cm_type, &me) != KCF_SUCCESS) { *error = CRYPTO_MECHANISM_INVALID; return (NULL); } *prov_mt2 = CRYPTO_MECH_INVALID; if (mepp != NULL) *mepp = me; mp = &me_mutexes[CPU_SEQID]; mutex_enter(&mp->kl_lock); prov_chain = me->me_hw_prov_chain; /* * We check the threshold for using a hardware provider for * this amount of data. If there is no software provider available * for the first mechanism, then the threshold is ignored. */ if ((prov_chain != NULL) && ((data_size == 0) || (me->me_threshold == 0) || (data_size >= me->me_threshold) || ((mdesc = me->me_sw_prov) == NULL) || (!IS_FG_SUPPORTED(mdesc, fg1)) || (!KCF_IS_PROV_USABLE(mdesc->pm_prov_desc)))) { /* there is at least one provider */ ASSERT(me->me_num_hwprov > 0); /* * Find the least loaded provider capable of the combo * me1 + me2, and save a pointer to the least loaded * provider capable of me1 only. */ while (prov_chain != NULL) { pd = prov_chain->pm_prov_desc; if (!IS_FG_SUPPORTED(prov_chain, fg1) || !KCF_IS_PROV_USABLE(pd) || IS_PROVIDER_TRIED(pd, triedl)) { prov_chain = prov_chain->pm_next; continue; } if ((key1 != NULL) && !kcf_check_prov_mech_keylen(pd, mech1->cm_type, key1)) { prov_chain = prov_chain->pm_next; error_val = CRYPTO_KEY_SIZE_RANGE; continue; } #define PMD_MECH_NUM(pmdp) (pmdp)->pm_mech_info.cm_mech_number /* Do load calculation only if needed */ if (prov_chain->pm_next == NULL && pdm1 == NULL) { *prov_mt1 = PMD_MECH_NUM(prov_chain); pdm1 = pd; } else { len = KCF_PROV_LOAD(pd); /* Save the best provider capable of m1 */ if (len < gqlen) { *prov_mt1 = PMD_MECH_NUM(prov_chain); gqlen = len; pdm1 = pd; } } /* See if pd can do me2 too */ for (mil = prov_chain->pm_mi_list; mil != NULL; mil = mil->ml_next) { if ((mil->ml_mech_info.cm_func_group_mask & fg2) == 0) continue; if ((key2 != NULL) && !kcf_check_prov_mech_keylen(pd, mech2->cm_type, key2)) { error_val = CRYPTO_KEY_SIZE_RANGE; continue; } #define MIL_MECH_NUM(mil) (mil)->ml_mech_info.cm_mech_number if (mil->ml_kcf_mechid == m2id) { /* Bingo! */ /* Do load calculation only if needed */ if (prov_chain->pm_next == NULL && pdm1m2 == NULL) { pdm1m2 = pd; *prov_mt2 = MIL_MECH_NUM(mil); } else { if (len < dgqlen) { dgqlen = len; pdm1m2 = pd; *prov_mt2 = MIL_MECH_NUM(mil); } } break; } } prov_chain = prov_chain->pm_next; } pd = (pdm1m2 != NULL) ? pdm1m2 : pdm1; } /* no HW provider for this mech, is there a SW provider? */ if (pd == NULL && (mdesc = me->me_sw_prov) != NULL) { pd = mdesc->pm_prov_desc; if (!IS_FG_SUPPORTED(mdesc, fg1) || !KCF_IS_PROV_USABLE(pd) || IS_PROVIDER_TRIED(pd, triedl)) pd = NULL; else { /* See if pd can do me2 too */ for (mil = me->me_sw_prov->pm_mi_list; mil != NULL; mil = mil->ml_next) { if ((mil->ml_mech_info.cm_func_group_mask & fg2) == 0) continue; if (mil->ml_kcf_mechid == m2id) { /* Bingo! */ *prov_mt2 = mil->ml_mech_info.cm_mech_number; break; } } *prov_mt1 = me->me_sw_prov->pm_mech_info.cm_mech_number; } } /* No provider found */ if (pd == NULL) { /* * We do not want to report CRYPTO_MECH_NOT_SUPPORTED, when * we are in the "fallback to the next provider" case. Rather * we preserve the error, so that the client gets the right * error code. */ if (triedl == NULL) *error = error_val; } else KCF_PROV_REFHOLD(pd); mutex_exit(&mp->kl_lock); return (pd); } /* * Do the actual work of calling the provider routines. * * pd - Provider structure * ctx - Context for this operation * params - Parameters for this operation * rhndl - Request handle to use for notification * * The return values are the same as that of the respective SPI. */ int common_submit_request(kcf_provider_desc_t *pd, crypto_ctx_t *ctx, kcf_req_params_t *params, crypto_req_handle_t rhndl) { int err = CRYPTO_ARGUMENTS_BAD; kcf_op_type_t optype; optype = params->rp_optype; switch (params->rp_opgrp) { case KCF_OG_DIGEST: { kcf_digest_ops_params_t *dops = ¶ms->rp_u.digest_params; switch (optype) { case KCF_OP_INIT: /* * We should do this only here and not in KCF_WRAP_* * macros. This is because we may want to try other * providers, in case we recover from a failure. */ KCF_SET_PROVIDER_MECHNUM(dops->do_framework_mechtype, pd, &dops->do_mech); err = KCF_PROV_DIGEST_INIT(pd, ctx, &dops->do_mech, rhndl); break; case KCF_OP_SINGLE: err = KCF_PROV_DIGEST(pd, ctx, dops->do_data, dops->do_digest, rhndl); break; case KCF_OP_UPDATE: err = KCF_PROV_DIGEST_UPDATE(pd, ctx, dops->do_data, rhndl); break; case KCF_OP_FINAL: err = KCF_PROV_DIGEST_FINAL(pd, ctx, dops->do_digest, rhndl); break; case KCF_OP_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM(dops->do_framework_mechtype, pd, &dops->do_mech); err = KCF_PROV_DIGEST_ATOMIC(pd, dops->do_sid, &dops->do_mech, dops->do_data, dops->do_digest, rhndl); break; case KCF_OP_DIGEST_KEY: err = KCF_PROV_DIGEST_KEY(pd, ctx, dops->do_digest_key, rhndl); break; default: break; } break; } case KCF_OG_MAC: { kcf_mac_ops_params_t *mops = ¶ms->rp_u.mac_params; switch (optype) { case KCF_OP_INIT: KCF_SET_PROVIDER_MECHNUM(mops->mo_framework_mechtype, pd, &mops->mo_mech); err = KCF_PROV_MAC_INIT(pd, ctx, &mops->mo_mech, mops->mo_key, mops->mo_templ, rhndl); break; case KCF_OP_SINGLE: err = KCF_PROV_MAC(pd, ctx, mops->mo_data, mops->mo_mac, rhndl); break; case KCF_OP_UPDATE: err = KCF_PROV_MAC_UPDATE(pd, ctx, mops->mo_data, rhndl); break; case KCF_OP_FINAL: err = KCF_PROV_MAC_FINAL(pd, ctx, mops->mo_mac, rhndl); break; case KCF_OP_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM(mops->mo_framework_mechtype, pd, &mops->mo_mech); err = KCF_PROV_MAC_ATOMIC(pd, mops->mo_sid, &mops->mo_mech, mops->mo_key, mops->mo_data, mops->mo_mac, mops->mo_templ, rhndl); break; case KCF_OP_MAC_VERIFY_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM(mops->mo_framework_mechtype, pd, &mops->mo_mech); err = KCF_PROV_MAC_VERIFY_ATOMIC(pd, mops->mo_sid, &mops->mo_mech, mops->mo_key, mops->mo_data, mops->mo_mac, mops->mo_templ, rhndl); break; default: break; } break; } case KCF_OG_ENCRYPT: { kcf_encrypt_ops_params_t *eops = ¶ms->rp_u.encrypt_params; switch (optype) { case KCF_OP_INIT: KCF_SET_PROVIDER_MECHNUM(eops->eo_framework_mechtype, pd, &eops->eo_mech); err = KCF_PROV_ENCRYPT_INIT(pd, ctx, &eops->eo_mech, eops->eo_key, eops->eo_templ, rhndl); break; case KCF_OP_SINGLE: err = KCF_PROV_ENCRYPT(pd, ctx, eops->eo_plaintext, eops->eo_ciphertext, rhndl); break; case KCF_OP_UPDATE: err = KCF_PROV_ENCRYPT_UPDATE(pd, ctx, eops->eo_plaintext, eops->eo_ciphertext, rhndl); break; case KCF_OP_FINAL: err = KCF_PROV_ENCRYPT_FINAL(pd, ctx, eops->eo_ciphertext, rhndl); break; case KCF_OP_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM(eops->eo_framework_mechtype, pd, &eops->eo_mech); err = KCF_PROV_ENCRYPT_ATOMIC(pd, eops->eo_sid, &eops->eo_mech, eops->eo_key, eops->eo_plaintext, eops->eo_ciphertext, eops->eo_templ, rhndl); break; default: break; } break; } case KCF_OG_DECRYPT: { kcf_decrypt_ops_params_t *dcrops = ¶ms->rp_u.decrypt_params; switch (optype) { case KCF_OP_INIT: KCF_SET_PROVIDER_MECHNUM(dcrops->dop_framework_mechtype, pd, &dcrops->dop_mech); err = KCF_PROV_DECRYPT_INIT(pd, ctx, &dcrops->dop_mech, dcrops->dop_key, dcrops->dop_templ, rhndl); break; case KCF_OP_SINGLE: err = KCF_PROV_DECRYPT(pd, ctx, dcrops->dop_ciphertext, dcrops->dop_plaintext, rhndl); break; case KCF_OP_UPDATE: err = KCF_PROV_DECRYPT_UPDATE(pd, ctx, dcrops->dop_ciphertext, dcrops->dop_plaintext, rhndl); break; case KCF_OP_FINAL: err = KCF_PROV_DECRYPT_FINAL(pd, ctx, dcrops->dop_plaintext, rhndl); break; case KCF_OP_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM(dcrops->dop_framework_mechtype, pd, &dcrops->dop_mech); err = KCF_PROV_DECRYPT_ATOMIC(pd, dcrops->dop_sid, &dcrops->dop_mech, dcrops->dop_key, dcrops->dop_ciphertext, dcrops->dop_plaintext, dcrops->dop_templ, rhndl); break; default: break; } break; } case KCF_OG_SIGN: { kcf_sign_ops_params_t *sops = ¶ms->rp_u.sign_params; switch (optype) { case KCF_OP_INIT: KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype, pd, &sops->so_mech); err = KCF_PROV_SIGN_INIT(pd, ctx, &sops->so_mech, sops->so_key, sops->so_templ, rhndl); break; case KCF_OP_SIGN_RECOVER_INIT: KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype, pd, &sops->so_mech); err = KCF_PROV_SIGN_RECOVER_INIT(pd, ctx, &sops->so_mech, sops->so_key, sops->so_templ, rhndl); break; case KCF_OP_SINGLE: err = KCF_PROV_SIGN(pd, ctx, sops->so_data, sops->so_signature, rhndl); break; case KCF_OP_SIGN_RECOVER: err = KCF_PROV_SIGN_RECOVER(pd, ctx, sops->so_data, sops->so_signature, rhndl); break; case KCF_OP_UPDATE: err = KCF_PROV_SIGN_UPDATE(pd, ctx, sops->so_data, rhndl); break; case KCF_OP_FINAL: err = KCF_PROV_SIGN_FINAL(pd, ctx, sops->so_signature, rhndl); break; case KCF_OP_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype, pd, &sops->so_mech); err = KCF_PROV_SIGN_ATOMIC(pd, sops->so_sid, &sops->so_mech, sops->so_key, sops->so_data, sops->so_templ, sops->so_signature, rhndl); break; case KCF_OP_SIGN_RECOVER_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype, pd, &sops->so_mech); err = KCF_PROV_SIGN_RECOVER_ATOMIC(pd, sops->so_sid, &sops->so_mech, sops->so_key, sops->so_data, sops->so_templ, sops->so_signature, rhndl); break; default: break; } break; } case KCF_OG_VERIFY: { kcf_verify_ops_params_t *vops = ¶ms->rp_u.verify_params; switch (optype) { case KCF_OP_INIT: KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype, pd, &vops->vo_mech); err = KCF_PROV_VERIFY_INIT(pd, ctx, &vops->vo_mech, vops->vo_key, vops->vo_templ, rhndl); break; case KCF_OP_VERIFY_RECOVER_INIT: KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype, pd, &vops->vo_mech); err = KCF_PROV_VERIFY_RECOVER_INIT(pd, ctx, &vops->vo_mech, vops->vo_key, vops->vo_templ, rhndl); break; case KCF_OP_SINGLE: err = KCF_PROV_VERIFY(pd, ctx, vops->vo_data, vops->vo_signature, rhndl); break; case KCF_OP_VERIFY_RECOVER: err = KCF_PROV_VERIFY_RECOVER(pd, ctx, vops->vo_signature, vops->vo_data, rhndl); break; case KCF_OP_UPDATE: err = KCF_PROV_VERIFY_UPDATE(pd, ctx, vops->vo_data, rhndl); break; case KCF_OP_FINAL: err = KCF_PROV_VERIFY_FINAL(pd, ctx, vops->vo_signature, rhndl); break; case KCF_OP_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype, pd, &vops->vo_mech); err = KCF_PROV_VERIFY_ATOMIC(pd, vops->vo_sid, &vops->vo_mech, vops->vo_key, vops->vo_data, vops->vo_templ, vops->vo_signature, rhndl); break; case KCF_OP_VERIFY_RECOVER_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype, pd, &vops->vo_mech); err = KCF_PROV_VERIFY_RECOVER_ATOMIC(pd, vops->vo_sid, &vops->vo_mech, vops->vo_key, vops->vo_signature, vops->vo_templ, vops->vo_data, rhndl); break; default: break; } break; } case KCF_OG_ENCRYPT_MAC: { kcf_encrypt_mac_ops_params_t *eops = ¶ms->rp_u.encrypt_mac_params; kcf_context_t *kcf_secondctx; switch (optype) { case KCF_OP_INIT: kcf_secondctx = ((kcf_context_t *) (ctx->cc_framework_private))->kc_secondctx; if (kcf_secondctx != NULL) { err = kcf_emulate_dual(pd, ctx, params); break; } KCF_SET_PROVIDER_MECHNUM( eops->em_framework_encr_mechtype, pd, &eops->em_encr_mech); KCF_SET_PROVIDER_MECHNUM( eops->em_framework_mac_mechtype, pd, &eops->em_mac_mech); err = KCF_PROV_ENCRYPT_MAC_INIT(pd, ctx, &eops->em_encr_mech, eops->em_encr_key, &eops->em_mac_mech, eops->em_mac_key, eops->em_encr_templ, eops->em_mac_templ, rhndl); break; case KCF_OP_SINGLE: err = KCF_PROV_ENCRYPT_MAC(pd, ctx, eops->em_plaintext, eops->em_ciphertext, eops->em_mac, rhndl); break; case KCF_OP_UPDATE: kcf_secondctx = ((kcf_context_t *) (ctx->cc_framework_private))->kc_secondctx; if (kcf_secondctx != NULL) { err = kcf_emulate_dual(pd, ctx, params); break; } err = KCF_PROV_ENCRYPT_MAC_UPDATE(pd, ctx, eops->em_plaintext, eops->em_ciphertext, rhndl); break; case KCF_OP_FINAL: kcf_secondctx = ((kcf_context_t *) (ctx->cc_framework_private))->kc_secondctx; if (kcf_secondctx != NULL) { err = kcf_emulate_dual(pd, ctx, params); break; } err = KCF_PROV_ENCRYPT_MAC_FINAL(pd, ctx, eops->em_ciphertext, eops->em_mac, rhndl); break; case KCF_OP_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM( eops->em_framework_encr_mechtype, pd, &eops->em_encr_mech); KCF_SET_PROVIDER_MECHNUM( eops->em_framework_mac_mechtype, pd, &eops->em_mac_mech); err = KCF_PROV_ENCRYPT_MAC_ATOMIC(pd, eops->em_sid, &eops->em_encr_mech, eops->em_encr_key, &eops->em_mac_mech, eops->em_mac_key, eops->em_plaintext, eops->em_ciphertext, eops->em_mac, eops->em_encr_templ, eops->em_mac_templ, rhndl); break; default: break; } break; } case KCF_OG_MAC_DECRYPT: { kcf_mac_decrypt_ops_params_t *dops = ¶ms->rp_u.mac_decrypt_params; kcf_context_t *kcf_secondctx; switch (optype) { case KCF_OP_INIT: kcf_secondctx = ((kcf_context_t *) (ctx->cc_framework_private))->kc_secondctx; if (kcf_secondctx != NULL) { err = kcf_emulate_dual(pd, ctx, params); break; } KCF_SET_PROVIDER_MECHNUM( dops->md_framework_mac_mechtype, pd, &dops->md_mac_mech); KCF_SET_PROVIDER_MECHNUM( dops->md_framework_decr_mechtype, pd, &dops->md_decr_mech); err = KCF_PROV_MAC_DECRYPT_INIT(pd, ctx, &dops->md_mac_mech, dops->md_mac_key, &dops->md_decr_mech, dops->md_decr_key, dops->md_mac_templ, dops->md_decr_templ, rhndl); break; case KCF_OP_SINGLE: err = KCF_PROV_MAC_DECRYPT(pd, ctx, dops->md_ciphertext, dops->md_mac, dops->md_plaintext, rhndl); break; case KCF_OP_UPDATE: kcf_secondctx = ((kcf_context_t *) (ctx->cc_framework_private))->kc_secondctx; if (kcf_secondctx != NULL) { err = kcf_emulate_dual(pd, ctx, params); break; } err = KCF_PROV_MAC_DECRYPT_UPDATE(pd, ctx, dops->md_ciphertext, dops->md_plaintext, rhndl); break; case KCF_OP_FINAL: kcf_secondctx = ((kcf_context_t *) (ctx->cc_framework_private))->kc_secondctx; if (kcf_secondctx != NULL) { err = kcf_emulate_dual(pd, ctx, params); break; } err = KCF_PROV_MAC_DECRYPT_FINAL(pd, ctx, dops->md_mac, dops->md_plaintext, rhndl); break; case KCF_OP_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM( dops->md_framework_mac_mechtype, pd, &dops->md_mac_mech); KCF_SET_PROVIDER_MECHNUM( dops->md_framework_decr_mechtype, pd, &dops->md_decr_mech); err = KCF_PROV_MAC_DECRYPT_ATOMIC(pd, dops->md_sid, &dops->md_mac_mech, dops->md_mac_key, &dops->md_decr_mech, dops->md_decr_key, dops->md_ciphertext, dops->md_mac, dops->md_plaintext, dops->md_mac_templ, dops->md_decr_templ, rhndl); break; case KCF_OP_MAC_VERIFY_DECRYPT_ATOMIC: ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM( dops->md_framework_mac_mechtype, pd, &dops->md_mac_mech); KCF_SET_PROVIDER_MECHNUM( dops->md_framework_decr_mechtype, pd, &dops->md_decr_mech); err = KCF_PROV_MAC_VERIFY_DECRYPT_ATOMIC(pd, dops->md_sid, &dops->md_mac_mech, dops->md_mac_key, &dops->md_decr_mech, dops->md_decr_key, dops->md_ciphertext, dops->md_mac, dops->md_plaintext, dops->md_mac_templ, dops->md_decr_templ, rhndl); break; default: break; } break; } case KCF_OG_KEY: { kcf_key_ops_params_t *kops = ¶ms->rp_u.key_params; ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM(kops->ko_framework_mechtype, pd, &kops->ko_mech); switch (optype) { case KCF_OP_KEY_GENERATE: err = KCF_PROV_KEY_GENERATE(pd, kops->ko_sid, &kops->ko_mech, kops->ko_key_template, kops->ko_key_attribute_count, kops->ko_key_object_id_ptr, rhndl); break; case KCF_OP_KEY_GENERATE_PAIR: err = KCF_PROV_KEY_GENERATE_PAIR(pd, kops->ko_sid, &kops->ko_mech, kops->ko_key_template, kops->ko_key_attribute_count, kops->ko_private_key_template, kops->ko_private_key_attribute_count, kops->ko_key_object_id_ptr, kops->ko_private_key_object_id_ptr, rhndl); break; case KCF_OP_KEY_WRAP: err = KCF_PROV_KEY_WRAP(pd, kops->ko_sid, &kops->ko_mech, kops->ko_key, kops->ko_key_object_id_ptr, kops->ko_wrapped_key, kops->ko_wrapped_key_len_ptr, rhndl); break; case KCF_OP_KEY_UNWRAP: err = KCF_PROV_KEY_UNWRAP(pd, kops->ko_sid, &kops->ko_mech, kops->ko_key, kops->ko_wrapped_key, kops->ko_wrapped_key_len_ptr, kops->ko_key_template, kops->ko_key_attribute_count, kops->ko_key_object_id_ptr, rhndl); break; case KCF_OP_KEY_DERIVE: err = KCF_PROV_KEY_DERIVE(pd, kops->ko_sid, &kops->ko_mech, kops->ko_key, kops->ko_key_template, kops->ko_key_attribute_count, kops->ko_key_object_id_ptr, rhndl); break; default: break; } break; } case KCF_OG_RANDOM: { kcf_random_number_ops_params_t *rops = ¶ms->rp_u.random_number_params; ASSERT(ctx == NULL); switch (optype) { case KCF_OP_RANDOM_SEED: err = KCF_PROV_SEED_RANDOM(pd, rops->rn_sid, rops->rn_buf, rops->rn_buflen, rops->rn_entropy_est, rops->rn_flags, rhndl); break; case KCF_OP_RANDOM_GENERATE: err = KCF_PROV_GENERATE_RANDOM(pd, rops->rn_sid, rops->rn_buf, rops->rn_buflen, rhndl); break; default: break; } break; } case KCF_OG_SESSION: { kcf_session_ops_params_t *sops = ¶ms->rp_u.session_params; ASSERT(ctx == NULL); switch (optype) { case KCF_OP_SESSION_OPEN: /* * so_pd may be a logical provider, in which case * we need to check whether it has been removed. */ if (KCF_IS_PROV_REMOVED(sops->so_pd)) { err = CRYPTO_DEVICE_ERROR; break; } err = KCF_PROV_SESSION_OPEN(pd, sops->so_sid_ptr, rhndl, sops->so_pd); break; case KCF_OP_SESSION_CLOSE: /* * so_pd may be a logical provider, in which case * we need to check whether it has been removed. */ if (KCF_IS_PROV_REMOVED(sops->so_pd)) { err = CRYPTO_DEVICE_ERROR; break; } err = KCF_PROV_SESSION_CLOSE(pd, sops->so_sid, rhndl, sops->so_pd); break; case KCF_OP_SESSION_LOGIN: err = KCF_PROV_SESSION_LOGIN(pd, sops->so_sid, sops->so_user_type, sops->so_pin, sops->so_pin_len, rhndl); break; case KCF_OP_SESSION_LOGOUT: err = KCF_PROV_SESSION_LOGOUT(pd, sops->so_sid, rhndl); break; default: break; } break; } case KCF_OG_OBJECT: { kcf_object_ops_params_t *jops = ¶ms->rp_u.object_params; ASSERT(ctx == NULL); switch (optype) { case KCF_OP_OBJECT_CREATE: err = KCF_PROV_OBJECT_CREATE(pd, jops->oo_sid, jops->oo_template, jops->oo_attribute_count, jops->oo_object_id_ptr, rhndl); break; case KCF_OP_OBJECT_COPY: err = KCF_PROV_OBJECT_COPY(pd, jops->oo_sid, jops->oo_object_id, jops->oo_template, jops->oo_attribute_count, jops->oo_object_id_ptr, rhndl); break; case KCF_OP_OBJECT_DESTROY: err = KCF_PROV_OBJECT_DESTROY(pd, jops->oo_sid, jops->oo_object_id, rhndl); break; case KCF_OP_OBJECT_GET_SIZE: err = KCF_PROV_OBJECT_GET_SIZE(pd, jops->oo_sid, jops->oo_object_id, jops->oo_object_size, rhndl); break; case KCF_OP_OBJECT_GET_ATTRIBUTE_VALUE: err = KCF_PROV_OBJECT_GET_ATTRIBUTE_VALUE(pd, jops->oo_sid, jops->oo_object_id, jops->oo_template, jops->oo_attribute_count, rhndl); break; case KCF_OP_OBJECT_SET_ATTRIBUTE_VALUE: err = KCF_PROV_OBJECT_SET_ATTRIBUTE_VALUE(pd, jops->oo_sid, jops->oo_object_id, jops->oo_template, jops->oo_attribute_count, rhndl); break; case KCF_OP_OBJECT_FIND_INIT: err = KCF_PROV_OBJECT_FIND_INIT(pd, jops->oo_sid, jops->oo_template, jops->oo_attribute_count, jops->oo_find_init_pp_ptr, rhndl); break; case KCF_OP_OBJECT_FIND: err = KCF_PROV_OBJECT_FIND(pd, jops->oo_find_pp, jops->oo_object_id_ptr, jops->oo_max_object_count, jops->oo_object_count_ptr, rhndl); break; case KCF_OP_OBJECT_FIND_FINAL: err = KCF_PROV_OBJECT_FIND_FINAL(pd, jops->oo_find_pp, rhndl); break; default: break; } break; } case KCF_OG_PROVMGMT: { kcf_provmgmt_ops_params_t *pops = ¶ms->rp_u.provmgmt_params; ASSERT(ctx == NULL); switch (optype) { case KCF_OP_MGMT_EXTINFO: /* * po_pd may be a logical provider, in which case * we need to check whether it has been removed. */ if (KCF_IS_PROV_REMOVED(pops->po_pd)) { err = CRYPTO_DEVICE_ERROR; break; } err = KCF_PROV_EXT_INFO(pd, pops->po_ext_info, rhndl, pops->po_pd); break; case KCF_OP_MGMT_INITTOKEN: err = KCF_PROV_INIT_TOKEN(pd, pops->po_pin, pops->po_pin_len, pops->po_label, rhndl); break; case KCF_OP_MGMT_INITPIN: err = KCF_PROV_INIT_PIN(pd, pops->po_sid, pops->po_pin, pops->po_pin_len, rhndl); break; case KCF_OP_MGMT_SETPIN: err = KCF_PROV_SET_PIN(pd, pops->po_sid, pops->po_old_pin, pops->po_old_pin_len, pops->po_pin, pops->po_pin_len, rhndl); break; default: break; } break; } case KCF_OG_NOSTORE_KEY: { kcf_key_ops_params_t *kops = ¶ms->rp_u.key_params; ASSERT(ctx == NULL); KCF_SET_PROVIDER_MECHNUM(kops->ko_framework_mechtype, pd, &kops->ko_mech); switch (optype) { case KCF_OP_KEY_GENERATE: err = KCF_PROV_NOSTORE_KEY_GENERATE(pd, kops->ko_sid, &kops->ko_mech, kops->ko_key_template, kops->ko_key_attribute_count, kops->ko_out_template1, kops->ko_out_attribute_count1, rhndl); break; case KCF_OP_KEY_GENERATE_PAIR: err = KCF_PROV_NOSTORE_KEY_GENERATE_PAIR(pd, kops->ko_sid, &kops->ko_mech, kops->ko_key_template, kops->ko_key_attribute_count, kops->ko_private_key_template, kops->ko_private_key_attribute_count, kops->ko_out_template1, kops->ko_out_attribute_count1, kops->ko_out_template2, kops->ko_out_attribute_count2, rhndl); break; case KCF_OP_KEY_DERIVE: err = KCF_PROV_NOSTORE_KEY_DERIVE(pd, kops->ko_sid, &kops->ko_mech, kops->ko_key, kops->ko_key_template, kops->ko_key_attribute_count, kops->ko_out_template1, kops->ko_out_attribute_count1, rhndl); break; default: break; } break; } default: break; } /* end of switch(params->rp_opgrp) */ KCF_PROV_INCRSTATS(pd, err); return (err); } /* * Emulate the call for a multipart dual ops with 2 single steps. * This routine is always called in the context of a working thread * running kcf_svc_do_run(). * The single steps are submitted in a pure synchronous way (blocking). * When this routine returns, kcf_svc_do_run() will call kcf_aop_done() * so the originating consumer's callback gets invoked. kcf_aop_done() * takes care of freeing the operation context. So, this routine does * not free the operation context. * * The provider descriptor is assumed held by the callers. */ static int kcf_emulate_dual(kcf_provider_desc_t *pd, crypto_ctx_t *ctx, kcf_req_params_t *params) { int err = CRYPTO_ARGUMENTS_BAD; kcf_op_type_t optype; size_t save_len; off_t save_offset; optype = params->rp_optype; switch (params->rp_opgrp) { case KCF_OG_ENCRYPT_MAC: { kcf_encrypt_mac_ops_params_t *cmops = ¶ms->rp_u.encrypt_mac_params; kcf_context_t *encr_kcf_ctx; crypto_ctx_t *mac_ctx; kcf_req_params_t encr_params; encr_kcf_ctx = (kcf_context_t *)(ctx->cc_framework_private); switch (optype) { case KCF_OP_INIT: { encr_kcf_ctx->kc_secondctx = NULL; KCF_WRAP_ENCRYPT_OPS_PARAMS(&encr_params, KCF_OP_INIT, pd->pd_sid, &cmops->em_encr_mech, cmops->em_encr_key, NULL, NULL, cmops->em_encr_templ); err = kcf_submit_request(pd, ctx, NULL, &encr_params, B_FALSE); /* It can't be CRYPTO_QUEUED */ if (err != CRYPTO_SUCCESS) { break; } err = crypto_mac_init(&cmops->em_mac_mech, cmops->em_mac_key, cmops->em_mac_templ, (crypto_context_t *)&mac_ctx, NULL); if (err == CRYPTO_SUCCESS) { encr_kcf_ctx->kc_secondctx = (kcf_context_t *) mac_ctx->cc_framework_private; KCF_CONTEXT_REFHOLD((kcf_context_t *) mac_ctx->cc_framework_private); } break; } case KCF_OP_UPDATE: { crypto_dual_data_t *ct = cmops->em_ciphertext; crypto_data_t *pt = cmops->em_plaintext; kcf_context_t *mac_kcf_ctx = encr_kcf_ctx->kc_secondctx; crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx; KCF_WRAP_ENCRYPT_OPS_PARAMS(&encr_params, KCF_OP_UPDATE, pd->pd_sid, NULL, NULL, pt, (crypto_data_t *)ct, NULL); err = kcf_submit_request(pd, ctx, NULL, &encr_params, B_FALSE); /* It can't be CRYPTO_QUEUED */ if (err != CRYPTO_SUCCESS) { break; } save_offset = ct->dd_offset1; save_len = ct->dd_len1; if (ct->dd_len2 == 0) { /* * The previous encrypt step was an * accumulation only and didn't produce any * partial output */ if (ct->dd_len1 == 0) break; } else { ct->dd_offset1 = ct->dd_offset2; ct->dd_len1 = ct->dd_len2; } err = crypto_mac_update((crypto_context_t)mac_ctx, (crypto_data_t *)ct, NULL); ct->dd_offset1 = save_offset; ct->dd_len1 = save_len; break; } case KCF_OP_FINAL: { crypto_dual_data_t *ct = cmops->em_ciphertext; crypto_data_t *mac = cmops->em_mac; kcf_context_t *mac_kcf_ctx = encr_kcf_ctx->kc_secondctx; crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx; crypto_context_t mac_context = mac_ctx; KCF_WRAP_ENCRYPT_OPS_PARAMS(&encr_params, KCF_OP_FINAL, pd->pd_sid, NULL, NULL, NULL, (crypto_data_t *)ct, NULL); err = kcf_submit_request(pd, ctx, NULL, &encr_params, B_FALSE); /* It can't be CRYPTO_QUEUED */ if (err != CRYPTO_SUCCESS) { crypto_cancel_ctx(mac_context); break; } if (ct->dd_len2 > 0) { save_offset = ct->dd_offset1; save_len = ct->dd_len1; ct->dd_offset1 = ct->dd_offset2; ct->dd_len1 = ct->dd_len2; err = crypto_mac_update(mac_context, (crypto_data_t *)ct, NULL); ct->dd_offset1 = save_offset; ct->dd_len1 = save_len; if (err != CRYPTO_SUCCESS) { crypto_cancel_ctx(mac_context); return (err); } } /* and finally, collect the MAC */ err = crypto_mac_final(mac_context, mac, NULL); break; } default: break; } KCF_PROV_INCRSTATS(pd, err); break; } case KCF_OG_MAC_DECRYPT: { kcf_mac_decrypt_ops_params_t *mdops = ¶ms->rp_u.mac_decrypt_params; kcf_context_t *decr_kcf_ctx; crypto_ctx_t *mac_ctx; kcf_req_params_t decr_params; decr_kcf_ctx = (kcf_context_t *)(ctx->cc_framework_private); switch (optype) { case KCF_OP_INIT: { decr_kcf_ctx->kc_secondctx = NULL; err = crypto_mac_init(&mdops->md_mac_mech, mdops->md_mac_key, mdops->md_mac_templ, (crypto_context_t *)&mac_ctx, NULL); /* It can't be CRYPTO_QUEUED */ if (err != CRYPTO_SUCCESS) { break; } KCF_WRAP_DECRYPT_OPS_PARAMS(&decr_params, KCF_OP_INIT, pd->pd_sid, &mdops->md_decr_mech, mdops->md_decr_key, NULL, NULL, mdops->md_decr_templ); err = kcf_submit_request(pd, ctx, NULL, &decr_params, B_FALSE); /* It can't be CRYPTO_QUEUED */ if (err != CRYPTO_SUCCESS) { crypto_cancel_ctx((crypto_context_t)mac_ctx); break; } decr_kcf_ctx->kc_secondctx = (kcf_context_t *) mac_ctx->cc_framework_private; KCF_CONTEXT_REFHOLD((kcf_context_t *) mac_ctx->cc_framework_private); break; } case KCF_OP_UPDATE: { crypto_dual_data_t *ct = mdops->md_ciphertext; crypto_data_t *pt = mdops->md_plaintext; kcf_context_t *mac_kcf_ctx = decr_kcf_ctx->kc_secondctx; crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx; err = crypto_mac_update((crypto_context_t)mac_ctx, (crypto_data_t *)ct, NULL); if (err != CRYPTO_SUCCESS) break; save_offset = ct->dd_offset1; save_len = ct->dd_len1; /* zero ct->dd_len2 means decrypt everything */ if (ct->dd_len2 > 0) { ct->dd_offset1 = ct->dd_offset2; ct->dd_len1 = ct->dd_len2; } err = crypto_decrypt_update((crypto_context_t)ctx, (crypto_data_t *)ct, pt, NULL); ct->dd_offset1 = save_offset; ct->dd_len1 = save_len; break; } case KCF_OP_FINAL: { crypto_data_t *pt = mdops->md_plaintext; crypto_data_t *mac = mdops->md_mac; kcf_context_t *mac_kcf_ctx = decr_kcf_ctx->kc_secondctx; crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx; err = crypto_mac_final((crypto_context_t)mac_ctx, mac, NULL); if (err != CRYPTO_SUCCESS) { crypto_cancel_ctx(ctx); break; } /* Get the last chunk of plaintext */ KCF_CONTEXT_REFHOLD(decr_kcf_ctx); err = crypto_decrypt_final((crypto_context_t)ctx, pt, NULL); break; } } break; } default: break; } /* end of switch(params->rp_opgrp) */ return (err); }