/* * crypto_mac_prov() * * Arguments: * mech: crypto_mechanism_t pointer. * mech_type is a valid value previously returned by * crypto_mech2id(); * When the mech's parameter is not NULL, its definition depends * on the standard definition of the mechanism. * key: pointer to a crypto_key_t structure. * data: The message to compute the MAC for. * mac: Storage for the MAC. The length needed depends on the mechanism. * tmpl: a crypto_ctx_template_t, opaque template of a context of a * MAC with the 'mech' using 'key'. 'tmpl' is created by * a previous call to crypto_create_ctx_template(). * cr: crypto_call_req_t calling conditions and call back info. * * Description: * Asynchronously submits a request for, or synchronously performs a * single-part message authentication of 'data' with the mechanism * 'mech', using * the key 'key', on the specified provider with * the specified session id. * When complete and successful, 'mac' will contain the message * authentication code. * * Context: * Process or interrupt, according to the semantics dictated by the 'crq'. * * Returns: * See comment in the beginning of the file. */ int crypto_mac_prov(crypto_provider_t provider, crypto_session_id_t sid, crypto_mechanism_t *mech, crypto_data_t *data, crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac, crypto_call_req_t *crq) { kcf_req_params_t params; kcf_provider_desc_t *pd = provider; kcf_provider_desc_t *real_provider = pd; int rv; ASSERT(KCF_PROV_REFHELD(pd)); if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { rv = kcf_get_hardware_provider(mech->cm_type, CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd, &real_provider, CRYPTO_FG_MAC_ATOMIC); if (rv != CRYPTO_SUCCESS) return (rv); } KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, sid, mech, key, data, mac, tmpl); rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE); if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) KCF_PROV_REFRELE(real_provider); return (rv); }
/* * See comments for crypto_digest_update(). */ int crypto_sign_update(crypto_context_t context, crypto_data_t *data, crypto_call_req_t *cr) { crypto_ctx_t *ctx = (crypto_ctx_t *)context; kcf_context_t *kcf_ctx; kcf_provider_desc_t *pd; kcf_req_params_t params; int rv; if ((ctx == NULL) || ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || ((pd = kcf_ctx->kc_prov_desc) == NULL)) { return (CRYPTO_INVALID_CONTEXT); } ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); KCF_PROV_REFHOLD(pd); KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_UPDATE, ctx->cc_session, NULL, NULL, data, NULL, NULL); rv = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); KCF_PROV_REFRELE(pd); return (rv); }
/* * crypto_mac_update() * * Arguments: * context: A crypto_context_t initialized by mac_init(). * data: The message part to be MAC'ed * cr: crypto_call_req_t calling conditions and call back info. * * Description: * Asynchronously submits a request for, or synchronously performs a * part of a MAC operation. * * Context: * Process or interrupt, according to the semantics dictated by the 'cr'. * * Returns: * See comment in the beginning of the file. */ int crypto_mac_update(crypto_context_t context, crypto_data_t *data, crypto_call_req_t *cr) { crypto_ctx_t *ctx = (crypto_ctx_t *)context; kcf_context_t *kcf_ctx; kcf_provider_desc_t *pd; kcf_req_params_t params; int rv; if ((ctx == NULL) || ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || ((pd = kcf_ctx->kc_prov_desc) == NULL)) { return (CRYPTO_INVALID_CONTEXT); } ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); /* The fast path for SW providers. */ if (CHECK_FASTPATH(cr, pd)) { rv = KCF_PROV_MAC_UPDATE(pd, ctx, data, NULL); KCF_PROV_INCRSTATS(pd, rv); } else { KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_UPDATE, ctx->cc_session, NULL, NULL, data, NULL, NULL); rv = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); } return (rv); }
/* * See comments for crypto_digest_final(). */ int crypto_sign_final(crypto_context_t context, crypto_data_t *signature, crypto_call_req_t *cr) { crypto_ctx_t *ctx = (crypto_ctx_t *)context; kcf_context_t *kcf_ctx; kcf_provider_desc_t *pd; int rv; kcf_req_params_t params; if ((ctx == NULL) || ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || ((pd = kcf_ctx->kc_prov_desc) == NULL)) { return (CRYPTO_INVALID_CONTEXT); } ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); KCF_PROV_REFHOLD(pd); KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_FINAL, ctx->cc_session, NULL, NULL, NULL, signature, NULL); rv = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); KCF_PROV_REFRELE(pd); /* Release the hold done in kcf_new_ctx() during init step. */ KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx); return (rv); }
/* * crypto_mac_final() * * Arguments: * context: A crypto_context_t initialized by mac_init(). * mac: Storage for the message authentication code. * cr: crypto_call_req_t calling conditions and call back info. * * Description: * Asynchronously submits a request for, or synchronously performs a * part of a message authentication operation. * * Context: * Process or interrupt, according to the semantics dictated by the 'cr'. * * Returns: * See comment in the beginning of the file. */ int crypto_mac_final(crypto_context_t context, crypto_data_t *mac, crypto_call_req_t *cr) { crypto_ctx_t *ctx = (crypto_ctx_t *)context; kcf_context_t *kcf_ctx; kcf_provider_desc_t *pd; kcf_req_params_t params; int rv; if ((ctx == NULL) || ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || ((pd = kcf_ctx->kc_prov_desc) == NULL)) { return (CRYPTO_INVALID_CONTEXT); } ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); /* The fast path for SW providers. */ if (CHECK_FASTPATH(cr, pd)) { rv = KCF_PROV_MAC_FINAL(pd, ctx, mac, NULL); KCF_PROV_INCRSTATS(pd, rv); } else { KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_FINAL, ctx->cc_session, NULL, NULL, NULL, mac, NULL); rv = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); } /* Release the hold done in kcf_new_ctx() during init step. */ KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx); return (rv); }
int crypto_object_find_final(crypto_provider_t provider, void *cookie, crypto_call_req_t *crq) { kcf_req_params_t params; kcf_provider_desc_t *pd = provider; kcf_provider_desc_t *real_provider = pd; int rv; if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { rv = kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET( object_ops), CRYPTO_OBJECT_OFFSET(object_find_final), CHECK_RESTRICT(crq), pd, &real_provider); if (rv != CRYPTO_SUCCESS) return (rv); } if (CHECK_FASTPATH(crq, real_provider)) { rv = KCF_PROV_OBJECT_FIND_FINAL(real_provider, cookie, KCF_SWFP_RHNDL(crq)); KCF_PROV_INCRSTATS(pd, rv); } else { KCF_WRAP_OBJECT_OPS_PARAMS(¶ms, KCF_OP_OBJECT_FIND_FINAL, 0, 0, NULL, 0, NULL, 0, NULL, cookie, 0, NULL); rv = kcf_submit_request(real_provider, NULL, NULL, ¶ms, B_FALSE); } if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) KCF_PROV_REFRELE(real_provider); return (rv); }
int crypto_session_logout(crypto_provider_t provider, crypto_session_id_t sid, crypto_call_req_t *crq) { kcf_req_params_t params; kcf_provider_desc_t *pd = provider; kcf_provider_desc_t *real_provider = pd; int rv; ASSERT(KCF_PROV_REFHELD(pd)); if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { rv = kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET( session_ops), CRYPTO_SESSION_OFFSET(session_logout), pd, &real_provider); if (rv != CRYPTO_SUCCESS) return (rv); } if (CHECK_FASTPATH(crq, real_provider)) { rv = KCF_PROV_SESSION_LOGOUT(real_provider, sid, KCF_SWFP_RHNDL(crq)); KCF_PROV_INCRSTATS(pd, rv); } else { KCF_WRAP_SESSION_OPS_PARAMS(¶ms, KCF_OP_SESSION_LOGOUT, NULL, sid, 0, NULL, 0, real_provider); rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE); } if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) KCF_PROV_REFRELE(real_provider); return (rv); }
/* * crypto_digest_prov() * * Arguments: * pd: pointer to the descriptor of the provider to use for this * operation. * sid: provider session id. * mech: crypto_mechanism_t pointer. * mech_type is a valid value previously returned by * crypto_mech2id(); * When the mech's parameter is not NULL, its definition depends * on the standard definition of the mechanism. * data: The message to be digested. * digest: Storage for the digest. The length needed depends on the * mechanism. * cr: crypto_call_req_t calling conditions and call back info. * * Description: * Asynchronously submits a request for, or synchronously performs the * digesting operation of 'data' on the specified * provider with the specified session. * When complete and successful, 'digest' will contain the digest value. * The caller should hold a reference on the specified provider * descriptor before calling this function. * * Context: * Process or interrupt, according to the semantics dictated by the 'cr'. * * Returns: * See comment in the beginning of the file. */ 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) { kcf_req_params_t params; kcf_provider_desc_t *pd = provider; kcf_provider_desc_t *real_provider = pd; int rv; ASSERT(KCF_PROV_REFHELD(pd)); if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { rv = kcf_get_hardware_provider(mech->cm_type, CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd, &real_provider, CRYPTO_FG_DIGEST_ATOMIC); if (rv != CRYPTO_SUCCESS) return (rv); } KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, sid, mech, NULL, data, digest); /* no crypto context to carry between multiple parts. */ rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE); if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) KCF_PROV_REFRELE(real_provider); return (rv); }
/* * See comments for crypto_mac_update() and crypto_mac_final(). */ int crypto_mac_single(crypto_context_t context, crypto_data_t *data, crypto_data_t *mac, crypto_call_req_t *cr) { crypto_ctx_t *ctx = (crypto_ctx_t *)context; kcf_context_t *kcf_ctx; kcf_provider_desc_t *pd; int error; kcf_req_params_t params; if ((ctx == NULL) || ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || ((pd = kcf_ctx->kc_prov_desc) == NULL)) { return (CRYPTO_INVALID_CONTEXT); } /* The fast path for SW providers. */ if (CHECK_FASTPATH(cr, pd)) { error = KCF_PROV_MAC(pd, ctx, data, mac, NULL); KCF_PROV_INCRSTATS(pd, error); } else { KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_SINGLE, pd->pd_sid, NULL, NULL, data, mac, NULL); error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); } /* Release the hold done in kcf_new_ctx() during init step. */ KCF_CONTEXT_COND_RELEASE(error, kcf_ctx); return (error); }
/* * Performs a digest update on the specified key. Note that there is * no k-API crypto_digest_key() equivalent of this function. */ int crypto_digest_key_prov(crypto_context_t context, crypto_key_t *key, crypto_call_req_t *cr) { crypto_ctx_t *ctx = (crypto_ctx_t *)context; kcf_context_t *kcf_ctx; kcf_provider_desc_t *pd; int error; kcf_req_params_t params; if ((ctx == NULL) || ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || ((pd = kcf_ctx->kc_prov_desc) == NULL)) { return (CRYPTO_INVALID_CONTEXT); } ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); KCF_PROV_REFHOLD(pd); /* The fast path for SW providers. */ if (CHECK_FASTPATH(cr, pd)) { error = KCF_PROV_DIGEST_KEY(pd, ctx, key, NULL); KCF_PROV_INCRSTATS(pd, error); } else { KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_DIGEST_KEY, ctx->cc_session, NULL, key, NULL, NULL); error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); } KCF_PROV_REFRELE(pd); return (error); }
int crypto_sign_recover_single(crypto_context_t context, crypto_data_t *data, crypto_data_t *signature, crypto_call_req_t *cr) { crypto_ctx_t *ctx = (crypto_ctx_t *)context; kcf_context_t *kcf_ctx; kcf_provider_desc_t *pd; int error; kcf_req_params_t params; if ((ctx == NULL) || ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || ((pd = kcf_ctx->kc_prov_desc) == NULL)) { return (CRYPTO_INVALID_CONTEXT); } KCF_PROV_REFHOLD(pd); KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_SIGN_RECOVER, 0, NULL, NULL, data, signature, NULL); error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); KCF_PROV_REFRELE(pd); /* Release the hold done in kcf_new_ctx() during init step. */ KCF_CONTEXT_COND_RELEASE(error, kcf_ctx); return (error); }
/* * crypto_mac_init_prov() * * Arguments: * pd: pointer to the descriptor of the provider to use for this * operation. * sid: provider session id. * mech: crypto_mechanism_t pointer. * mech_type is a valid value previously returned by * crypto_mech2id(); * When the mech's parameter is not NULL, its definition depends * on the standard definition of the mechanism. * key: pointer to a crypto_key_t structure. * tmpl: a crypto_ctx_template_t, opaque template of a context of a * MAC with the 'mech' using 'key'. 'tmpl' is created by * a previous call to crypto_create_ctx_template(). * ctxp: Pointer to a crypto_context_t. * cr: crypto_call_req_t calling conditions and call back info. * * Description: * Asynchronously submits a request for, or synchronously performs the * initialization of a MAC operation on the specified provider with * the specified session. * When possible and applicable, will internally use the pre-computed MAC * context from the context template, tmpl. * When complete and successful, 'ctxp' will contain a crypto_context_t * valid for later calls to mac_update() and mac_final(). * The caller should hold a reference on the specified provider * descriptor before calling this function. * * Context: * Process or interrupt, according to the semantics dictated by the 'cr'. * * Returns: * See comment in the beginning of the file. */ int crypto_mac_init_prov(crypto_provider_t provider, crypto_session_id_t sid, crypto_mechanism_t *mech, crypto_key_t *key, crypto_spi_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *crq) { int rv; crypto_ctx_t *ctx; kcf_req_params_t params; kcf_provider_desc_t *pd = provider; kcf_provider_desc_t *real_provider = pd; ASSERT(KCF_PROV_REFHELD(pd)); if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { rv = kcf_get_hardware_provider(mech->cm_type, CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd, &real_provider, CRYPTO_FG_MAC); if (rv != CRYPTO_SUCCESS) return (rv); } /* Allocate and initialize the canonical context */ if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) { if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) KCF_PROV_REFRELE(real_provider); return (CRYPTO_HOST_MEMORY); } /* The fast path for SW providers. */ if (CHECK_FASTPATH(crq, pd)) { crypto_mechanism_t lmech; lmech = *mech; KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech); rv = KCF_PROV_MAC_INIT(real_provider, ctx, &lmech, key, tmpl, KCF_SWFP_RHNDL(crq)); KCF_PROV_INCRSTATS(pd, rv); } else { KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_INIT, sid, mech, key, NULL, NULL, tmpl); rv = kcf_submit_request(real_provider, ctx, crq, ¶ms, B_FALSE); } if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) KCF_PROV_REFRELE(real_provider); if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED)) *ctxp = (crypto_context_t)ctx; else { /* Release the hold done in kcf_new_ctx(). */ KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private); } return (rv); }
/* * This routine is called for blocking reads. * * The argument is_taskq_thr indicates whether the caller is * the taskq thread dispatched by the timeout handler routine. * In this case, we cycle through all the providers * submitting a request to each provider to generate random numbers. * * For other cases, we pick a provider and submit a request to generate * random numbers. We retry using another provider if we get an error. * * Returns the number of bytes that are written to 'ptr'. Returns -1 * if no provider is found. ptr and need are unchanged. */ static int rngprov_getbytes(uint8_t *ptr, size_t need, boolean_t is_taskq_thr) { int rv; int prov_cnt = 0; int total_bytes = 0; kcf_provider_desc_t *pd; kcf_req_params_t params; kcf_prov_tried_t *list = NULL; while ((pd = kcf_get_mech_provider(rngmech_type, NULL, NULL, &rv, list, CRYPTO_FG_RANDOM, 0)) != NULL) { prov_cnt++; KCF_WRAP_RANDOM_OPS_PARAMS(¶ms, KCF_OP_RANDOM_GENERATE, pd->pd_sid, ptr, need, 0, 0); rv = kcf_submit_request(pd, NULL, NULL, ¶ms, B_FALSE); ASSERT(rv != CRYPTO_QUEUED); if (rv == CRYPTO_SUCCESS) { total_bytes += need; if (is_taskq_thr) rndc_addbytes(ptr, need); else { KCF_PROV_REFRELE(pd); break; } } if (is_taskq_thr || rv != CRYPTO_SUCCESS) { /* Add pd to the linked list of providers tried. */ if (kcf_insert_triedlist(&list, pd, KM_SLEEP) == NULL) { KCF_PROV_REFRELE(pd); break; } } } if (list != NULL) kcf_free_triedlist(list); if (prov_cnt == 0) { /* no provider could be found. */ rng_prov_found = B_FALSE; return (-1); } else { rng_prov_found = B_TRUE; /* See comments in kcf_rngprov_check() */ rng_ok_to_log = B_TRUE; } return (total_bytes); }
/* * Same as crypto_digest_prov(), but relies on the KCF scheduler to * choose a provider. See crypto_digest_prov() comments for more information. */ int crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data, crypto_data_t *digest, crypto_call_req_t *crq) { int error; kcf_provider_desc_t *pd; kcf_req_params_t params; kcf_prov_tried_t *list = NULL; retry: /* The pd is returned held */ if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error, list, CRYPTO_FG_DIGEST_ATOMIC, CHECK_RESTRICT(crq), data->cd_length)) == NULL) { if (list != NULL) kcf_free_triedlist(list); return (error); } /* The fast path for SW providers. */ if (CHECK_FASTPATH(crq, pd)) { crypto_mechanism_t lmech; lmech = *mech; KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech); error = KCF_PROV_DIGEST_ATOMIC(pd, pd->pd_sid, &lmech, data, digest, KCF_SWFP_RHNDL(crq)); KCF_PROV_INCRSTATS(pd, error); } else { KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, pd->pd_sid, mech, NULL, data, digest); /* no crypto context to carry between multiple parts. */ error = kcf_submit_request(pd, NULL, crq, ¶ms, B_FALSE); } if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED && IS_RECOVERABLE(error)) { /* Add pd to the linked list of providers tried. */ if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL) goto retry; } if (list != NULL) kcf_free_triedlist(list); KCF_PROV_REFRELE(pd); return (error); }
int crypto_sign_recover_init_prov(crypto_provider_t provider, crypto_session_id_t sid, crypto_mechanism_t *mech, crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *crq) { int rv; crypto_ctx_t *ctx; kcf_req_params_t params; kcf_provider_desc_t *pd = provider; kcf_provider_desc_t *real_provider = pd; ASSERT(KCF_PROV_REFHELD(pd)); if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { rv = kcf_get_hardware_provider(mech->cm_type, CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd, &real_provider, CRYPTO_FG_SIGN_RECOVER); if (rv != CRYPTO_SUCCESS) return (rv); } /* Allocate and initialize the canonical context */ if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) { if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) KCF_PROV_REFRELE(real_provider); return (CRYPTO_HOST_MEMORY); } KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_SIGN_RECOVER_INIT, sid, mech, key, NULL, NULL, tmpl); rv = kcf_submit_request(real_provider, ctx, crq, ¶ms, B_FALSE); if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) KCF_PROV_REFRELE(real_provider); if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED)) *ctxp = (crypto_context_t)ctx; else { /* Release the hold done in kcf_new_ctx(). */ KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private); } return (rv); }
int crypto_object_find_init(crypto_provider_t provider, crypto_session_id_t sid, crypto_object_attribute_t *attrs, uint_t count, void **cookie, crypto_call_req_t *crq) { kcf_req_params_t params; kcf_provider_desc_t *pd = provider; kcf_provider_desc_t *real_provider = pd; int rv; ASSERT(KCF_PROV_REFHELD(pd)); if (cookie == NULL) { return (CRYPTO_ARGUMENTS_BAD); } if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { rv = kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET( object_ops), CRYPTO_OBJECT_OFFSET(object_find_init), CHECK_RESTRICT(crq), pd, &real_provider); if (rv != CRYPTO_SUCCESS) return (rv); } if (CHECK_FASTPATH(crq, real_provider)) { rv = KCF_PROV_OBJECT_FIND_INIT(real_provider, sid, attrs, count, cookie, KCF_SWFP_RHNDL(crq)); KCF_PROV_INCRSTATS(pd, rv); } else { KCF_WRAP_OBJECT_OPS_PARAMS(¶ms, KCF_OP_OBJECT_FIND_INIT, sid, 0, attrs, count, NULL, 0, cookie, NULL, 0, NULL); rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE); } if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) KCF_PROV_REFRELE(real_provider); return (rv); }
int crypto_session_open(crypto_provider_t provider, crypto_session_id_t *sidp, crypto_call_req_t *crq) { kcf_req_params_t params; kcf_provider_desc_t *real_provider; kcf_provider_desc_t *pd = provider; ASSERT(KCF_PROV_REFHELD(pd)); /* find a provider that supports session ops */ (void) kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET(session_ops), CRYPTO_SESSION_OFFSET(session_open), pd, &real_provider); if (real_provider != NULL) { int rv; ASSERT(real_provider == pd || pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER); if (CHECK_FASTPATH(crq, pd)) { rv = KCF_PROV_SESSION_OPEN(real_provider, sidp, KCF_SWFP_RHNDL(crq), pd); KCF_PROV_INCRSTATS(pd, rv); } else { KCF_WRAP_SESSION_OPS_PARAMS(¶ms, KCF_OP_SESSION_OPEN, sidp, 0, CRYPTO_USER, NULL, 0, pd); rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE); } KCF_PROV_REFRELE(real_provider); if (rv != CRYPTO_SUCCESS) { return (rv); } } return (CRYPTO_SUCCESS); }
int crypto_session_close(crypto_provider_t provider, crypto_session_id_t sid, crypto_call_req_t *crq) { int rv; kcf_req_params_t params; kcf_provider_desc_t *real_provider; kcf_provider_desc_t *pd = provider; if (pd == NULL) return (CRYPTO_ARGUMENTS_BAD); ASSERT(KCF_PROV_REFHELD(pd)); /* find a provider that supports session ops */ (void) kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET(session_ops), CRYPTO_SESSION_OFFSET(session_close), pd, &real_provider); ASSERT(real_provider == pd || pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER); /* edge case is where the logical provider has no members */ if (real_provider != NULL) { /* The fast path for SW providers. */ if (CHECK_FASTPATH(crq, pd)) { rv = KCF_PROV_SESSION_CLOSE(real_provider, sid, KCF_SWFP_RHNDL(crq), pd); KCF_PROV_INCRSTATS(pd, rv); } else { KCF_WRAP_SESSION_OPS_PARAMS(¶ms, KCF_OP_SESSION_CLOSE, NULL, sid, CRYPTO_USER, NULL, 0, pd); rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE); } KCF_PROV_REFRELE(real_provider); } return (CRYPTO_SUCCESS); }
int crypto_object_set_attribute_value(crypto_provider_t provider, crypto_session_id_t sid, crypto_object_id_t object_handle, crypto_object_attribute_t *attrs, uint_t count, crypto_call_req_t *crq) { kcf_req_params_t params; kcf_provider_desc_t *pd = provider; kcf_provider_desc_t *real_provider = pd; int rv; ASSERT(KCF_PROV_REFHELD(pd)); if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { rv = kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET( object_ops), CRYPTO_OBJECT_OFFSET(object_set_attribute_value), CHECK_RESTRICT(crq), pd, &real_provider); if (rv != CRYPTO_SUCCESS) return (rv); } if (CHECK_FASTPATH(crq, real_provider)) { rv = KCF_PROV_OBJECT_SET_ATTRIBUTE_VALUE(real_provider, sid, object_handle, attrs, count, KCF_SWFP_RHNDL(crq)); KCF_PROV_INCRSTATS(pd, rv); } else { KCF_WRAP_OBJECT_OPS_PARAMS(¶ms, KCF_OP_OBJECT_SET_ATTRIBUTE_VALUE, sid, object_handle, attrs, count, NULL, 0, NULL, NULL, 0, NULL); rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE); } if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) KCF_PROV_REFRELE(real_provider); return (rv); }
static int sign_sr_atomic_common(crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature, crypto_call_req_t *crq, crypto_func_group_t fg) { int error; kcf_mech_entry_t *me; kcf_provider_desc_t *pd; kcf_req_params_t params; kcf_prov_tried_t *list = NULL; kcf_ctx_template_t *ctx_tmpl; crypto_spi_ctx_template_t spi_ctx_tmpl = NULL; retry: /* The pd is returned held */ if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error, list, fg, CHECK_RESTRICT(crq), data->cd_length)) == NULL) { if (list != NULL) kcf_free_triedlist(list); return (error); } /* * For SW providers, check the validity of the context template * It is very rare that the generation number mis-matches, so * it is acceptable to fail here, and let the consumer recover by * freeing this tmpl and create a new one for the key and new SW * provider. */ if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) && ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) { if (ctx_tmpl->ct_generation != me->me_gen_swprov) { if (list != NULL) kcf_free_triedlist(list); KCF_PROV_REFRELE(pd); return (CRYPTO_OLD_CTX_TEMPLATE); } else { spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl; } } /* The fast path for SW providers. */ if (CHECK_FASTPATH(crq, pd)) { crypto_mechanism_t lmech; lmech = *mech; KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech); if (fg == CRYPTO_FG_SIGN_ATOMIC) error = KCF_PROV_SIGN_ATOMIC(pd, pd->pd_sid, &lmech, key, data, spi_ctx_tmpl, signature, KCF_SWFP_RHNDL(crq)); else error = KCF_PROV_SIGN_RECOVER_ATOMIC(pd, pd->pd_sid, &lmech, key, data, spi_ctx_tmpl, signature, KCF_SWFP_RHNDL(crq)); KCF_PROV_INCRSTATS(pd, error); } else { kcf_op_type_t op = ((fg == CRYPTO_FG_SIGN_ATOMIC) ? KCF_OP_ATOMIC : KCF_OP_SIGN_RECOVER_ATOMIC); KCF_WRAP_SIGN_OPS_PARAMS(¶ms, op, pd->pd_sid, mech, key, data, signature, spi_ctx_tmpl); /* no crypto context to carry between multiple parts. */ error = kcf_submit_request(pd, NULL, crq, ¶ms, B_FALSE); } if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED && IS_RECOVERABLE(error)) { /* Add pd to the linked list of providers tried. */ if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL) goto retry; } if (list != NULL) kcf_free_triedlist(list); KCF_PROV_REFRELE(pd); return (error); }
/* * Cycle through all the providers submitting a request to each provider * to generate random numbers. This is called for the modes - NONBLOCK_EXTRACT * and ALWAYS_EXTRACT. * * Returns the number of bytes that are written to 'ptr'. Returns -1 * if no provider is found. ptr and len are unchanged. */ static int rngprov_getbytes_nblk(uint8_t *ptr, size_t len) { int rv, total_bytes; size_t blen; uchar_t *rndbuf; kcf_provider_desc_t *pd; kcf_req_params_t params; crypto_call_req_t req; kcf_prov_tried_t *list = NULL; int prov_cnt = 0; blen = 0; total_bytes = 0; req.cr_flag = CRYPTO_SKIP_REQID; req.cr_callback_func = notify_done; while ((pd = kcf_get_mech_provider(rngmech_type, NULL, NULL, &rv, list, CRYPTO_FG_RANDOM, 0)) != NULL) { prov_cnt ++; switch (pd->pd_prov_type) { case CRYPTO_HW_PROVIDER: /* * We have to allocate a buffer here as we can not * assume that the input buffer will remain valid * when the callback comes. We use a fixed size buffer * to simplify the book keeping. */ rndbuf = kmem_alloc(MINEXTRACTBYTES, KM_NOSLEEP); if (rndbuf == NULL) { KCF_PROV_REFRELE(pd); if (list != NULL) kcf_free_triedlist(list); return (total_bytes); } req.cr_callback_arg = rndbuf; KCF_WRAP_RANDOM_OPS_PARAMS(¶ms, KCF_OP_RANDOM_GENERATE, pd->pd_sid, rndbuf, MINEXTRACTBYTES, 0, 0); break; case CRYPTO_SW_PROVIDER: /* * We do not need to allocate a buffer in the software * provider case as there is no callback involved. We * avoid any extra data copy by directly passing 'ptr'. */ KCF_WRAP_RANDOM_OPS_PARAMS(¶ms, KCF_OP_RANDOM_GENERATE, pd->pd_sid, ptr, len, 0, 0); break; } rv = kcf_submit_request(pd, NULL, &req, ¶ms, B_FALSE); if (rv == CRYPTO_SUCCESS) { switch (pd->pd_prov_type) { case CRYPTO_HW_PROVIDER: /* * Since we have the input buffer handy, * we directly copy to it rather than * adding to the pool. */ blen = min(MINEXTRACTBYTES, len); bcopy(rndbuf, ptr, blen); if (len < MINEXTRACTBYTES) rndc_addbytes(rndbuf + len, MINEXTRACTBYTES - len); ptr += blen; len -= blen; total_bytes += blen; break; case CRYPTO_SW_PROVIDER: total_bytes += len; len = 0; break; } } /* * We free the buffer in the callback routine * for the CRYPTO_QUEUED case. */ if (pd->pd_prov_type == CRYPTO_HW_PROVIDER && rv != CRYPTO_QUEUED) { bzero(rndbuf, MINEXTRACTBYTES); kmem_free(rndbuf, MINEXTRACTBYTES); } if (len == 0) { KCF_PROV_REFRELE(pd); break; } if (rv != CRYPTO_SUCCESS) { /* Add pd to the linked list of providers tried. */ if (kcf_insert_triedlist(&list, pd, KM_NOSLEEP) == NULL) { KCF_PROV_REFRELE(pd); break; } } } if (list != NULL) { kcf_free_triedlist(list); } if (prov_cnt == 0) { /* no provider could be found. */ rng_prov_found = B_FALSE; return (-1); } else { rng_prov_found = B_TRUE; /* See comments in kcf_rngprov_check() */ rng_ok_to_log = B_TRUE; } return (total_bytes); }
/* * This routine is used to add cryptographic providers to the KEF framework. * Providers pass a crypto_provider_info structure to crypto_register_provider() * and get back a handle. The crypto_provider_info structure contains a * list of mechanisms supported by the provider and an ops vector containing * provider entry points. Hardware providers call this routine in their attach * routines. Software providers call this routine in their _init() routine. */ int crypto_register_provider(crypto_provider_info_t *info, crypto_kcf_provider_handle_t *handle) { char ks_name[KSTAT_STRLEN]; kcf_provider_desc_t *prov_desc = NULL; int ret = CRYPTO_ARGUMENTS_BAD; if (info->pi_interface_version > CRYPTO_SPI_VERSION_3) return (CRYPTO_VERSION_MISMATCH); /* * Check provider type, must be software, hardware, or logical. */ if (info->pi_provider_type != CRYPTO_HW_PROVIDER && info->pi_provider_type != CRYPTO_SW_PROVIDER && info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) return (CRYPTO_ARGUMENTS_BAD); /* * Allocate and initialize a new provider descriptor. We also * hold it and release it when done. */ prov_desc = kcf_alloc_provider_desc(info); KCF_PROV_REFHOLD(prov_desc); prov_desc->pd_prov_type = info->pi_provider_type; /* provider-private handle, opaque to KCF */ prov_desc->pd_prov_handle = info->pi_provider_handle; /* copy provider description string */ if (info->pi_provider_description != NULL) { /* * pi_provider_descriptor is a string that can contain * up to CRYPTO_PROVIDER_DESCR_MAX_LEN + 1 characters * INCLUDING the terminating null character. A bcopy() * is necessary here as pd_description should not have * a null character. See comments in kcf_alloc_provider_desc() * for details on pd_description field. */ bcopy(info->pi_provider_description, prov_desc->pd_description, MIN(strlen(info->pi_provider_description), (size_t)CRYPTO_PROVIDER_DESCR_MAX_LEN)); } if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) { if (info->pi_ops_vector == NULL) { goto bail; } copy_ops_vector_v1(info->pi_ops_vector, prov_desc->pd_ops_vector); if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2) { copy_ops_vector_v2(info->pi_ops_vector, prov_desc->pd_ops_vector); prov_desc->pd_flags = info->pi_flags; } if (info->pi_interface_version == CRYPTO_SPI_VERSION_3) { copy_ops_vector_v3(info->pi_ops_vector, prov_desc->pd_ops_vector); } } /* object_ops and nostore_key_ops are mutually exclusive */ if (prov_desc->pd_ops_vector->co_object_ops && prov_desc->pd_ops_vector->co_nostore_key_ops) { goto bail; } /* process the mechanisms supported by the provider */ if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS) goto bail; /* * Add provider to providers tables, also sets the descriptor * pd_prov_id field. */ if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) { undo_register_provider(prov_desc, B_FALSE); goto bail; } /* * We create a taskq only for a hardware provider. The global * software queue is used for software providers. We handle ordering * of multi-part requests in the taskq routine. So, it is safe to * have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag * to keep some entries cached to improve performance. */ if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER) prov_desc->pd_sched_info.ks_taskq = taskq_create("kcf_taskq", crypto_taskq_threads, minclsyspri, crypto_taskq_minalloc, crypto_taskq_maxalloc, TASKQ_PREPOPULATE); else prov_desc->pd_sched_info.ks_taskq = NULL; /* no kernel session to logical providers */ if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) { /* * Open a session for session-oriented providers. This session * is used for all kernel consumers. This is fine as a provider * is required to support multiple thread access to a session. * We can do this only after the taskq has been created as we * do a kcf_submit_request() to open the session. */ if (KCF_PROV_SESSION_OPS(prov_desc) != NULL) { kcf_req_params_t params; KCF_WRAP_SESSION_OPS_PARAMS(¶ms, KCF_OP_SESSION_OPEN, &prov_desc->pd_sid, 0, CRYPTO_USER, NULL, 0, prov_desc); ret = kcf_submit_request(prov_desc, NULL, NULL, ¶ms, B_FALSE); if (ret != CRYPTO_SUCCESS) { undo_register_provider(prov_desc, B_TRUE); ret = CRYPTO_FAILED; goto bail; } } } if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) { /* * Create the kstat for this provider. There is a kstat * installed for each successfully registered provider. * This kstat is deleted, when the provider unregisters. */ if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) { (void) snprintf(ks_name, KSTAT_STRLEN, "%s_%s", "NONAME", "provider_stats"); } else { (void) snprintf(ks_name, KSTAT_STRLEN, "%s_%d_%u_%s", "NONAME", 0, prov_desc->pd_prov_id, "provider_stats"); } prov_desc->pd_kstat = kstat_create("kcf", 0, ks_name, "crypto", KSTAT_TYPE_NAMED, sizeof (kcf_prov_stats_t) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL); if (prov_desc->pd_kstat != NULL) { bcopy(&kcf_stats_ks_data_template, &prov_desc->pd_ks_data, sizeof (kcf_stats_ks_data_template)); prov_desc->pd_kstat->ks_data = &prov_desc->pd_ks_data; KCF_PROV_REFHOLD(prov_desc); KCF_PROV_IREFHOLD(prov_desc); prov_desc->pd_kstat->ks_private = prov_desc; prov_desc->pd_kstat->ks_update = kcf_prov_kstat_update; kstat_install(prov_desc->pd_kstat); } } if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER) process_logical_providers(info, prov_desc); mutex_enter(&prov_desc->pd_lock); prov_desc->pd_state = KCF_PROV_READY; mutex_exit(&prov_desc->pd_lock); kcf_do_notify(prov_desc, B_TRUE); *handle = prov_desc->pd_kcf_prov_handle; ret = CRYPTO_SUCCESS; bail: KCF_PROV_REFRELE(prov_desc); return (ret); }
/* * Same as crypto_mac_verify_prov(), but relies on the KCF scheduler to choose * a provider. See crypto_mac_verify_prov() comments for more information. */ int crypto_mac_verify(crypto_mechanism_t *mech, crypto_data_t *data, crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac, crypto_call_req_t *crq) { int error; kcf_mech_entry_t *me; kcf_req_params_t params; kcf_provider_desc_t *pd; kcf_ctx_template_t *ctx_tmpl; crypto_spi_ctx_template_t spi_ctx_tmpl = NULL; kcf_prov_tried_t *list = NULL; retry: /* The pd is returned held */ if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error, list, CRYPTO_FG_MAC_ATOMIC, CHECK_RESTRICT(crq), data->cd_length)) == NULL) { if (list != NULL) kcf_free_triedlist(list); return (error); } /* * For SW providers, check the validity of the context template * It is very rare that the generation number mis-matches, so * is acceptable to fail here, and let the consumer recover by * freeing this tmpl and create a new one for the key and new SW * provider */ if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) && ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) { if (ctx_tmpl->ct_generation != me->me_gen_swprov) { if (list != NULL) kcf_free_triedlist(list); KCF_PROV_REFRELE(pd); return (CRYPTO_OLD_CTX_TEMPLATE); } else { spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl; } } /* The fast path for SW providers. */ if (CHECK_FASTPATH(crq, pd)) { crypto_mechanism_t lmech; lmech = *mech; KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech); error = KCF_PROV_MAC_VERIFY_ATOMIC(pd, pd->pd_sid, &lmech, key, data, mac, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq)); KCF_PROV_INCRSTATS(pd, error); } else { if (pd->pd_prov_type == CRYPTO_HW_PROVIDER && (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) && (data->cd_length > pd->pd_hash_limit)) { /* see comments in crypto_mac() */ error = CRYPTO_BUFFER_TOO_BIG; } else { KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_MAC_VERIFY_ATOMIC, pd->pd_sid, mech, key, data, mac, spi_ctx_tmpl); error = kcf_submit_request(pd, NULL, crq, ¶ms, KCF_ISDUALREQ(crq)); } } if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED && IS_RECOVERABLE(error)) { /* Add pd to the linked list of providers tried. */ if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL) goto retry; } if (list != NULL) kcf_free_triedlist(list); KCF_PROV_REFRELE(pd); return (error); }