fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
fec509a05ddbf645268fe2e537314def7d1b67c8gm * CDDL HEADER START
fec509a05ddbf645268fe2e537314def7d1b67c8gm *
fec509a05ddbf645268fe2e537314def7d1b67c8gm * The contents of this file are subject to the terms of the
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Common Development and Distribution License (the "License").
fec509a05ddbf645268fe2e537314def7d1b67c8gm * You may not use this file except in compliance with the License.
fec509a05ddbf645268fe2e537314def7d1b67c8gm *
fec509a05ddbf645268fe2e537314def7d1b67c8gm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fec509a05ddbf645268fe2e537314def7d1b67c8gm * or http://www.opensolaris.org/os/licensing.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * See the License for the specific language governing permissions
fec509a05ddbf645268fe2e537314def7d1b67c8gm * and limitations under the License.
fec509a05ddbf645268fe2e537314def7d1b67c8gm *
fec509a05ddbf645268fe2e537314def7d1b67c8gm * When distributing Covered Code, include this CDDL HEADER in each
fec509a05ddbf645268fe2e537314def7d1b67c8gm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * If applicable, add the following below this CDDL HEADER, with the
fec509a05ddbf645268fe2e537314def7d1b67c8gm * fields enclosed by brackets "[]" replaced with your own identifying
fec509a05ddbf645268fe2e537314def7d1b67c8gm * information: Portions Copyright [yyyy] [name of copyright owner]
fec509a05ddbf645268fe2e537314def7d1b67c8gm *
fec509a05ddbf645268fe2e537314def7d1b67c8gm * CDDL HEADER END
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Use is subject to license terms.
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm#pragma ident "%Z%%M% %I% %E% SMI"
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/types.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/uio.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/stream.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/ddi.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/sunddi.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/strsun.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/kmem.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/atomic.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/random.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/crypto/common.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/crypto/spi.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/n2rng.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define IDENT_N2RNG "SUNW_N2_Random_Number_Generator"
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define N2RNG_PROVIDER2N2RNG(x) (((n2rng_provider_private_t *)x)->mp_n2rng)
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic void n2rng_provider_status(crypto_provider_handle_t, uint_t *);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic int n2rng_random_number(crypto_provider_handle_t, crypto_session_id_t,
fec509a05ddbf645268fe2e537314def7d1b67c8gm uchar_t *, size_t, crypto_req_handle_t);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic int ext_info(crypto_provider_handle_t, crypto_provider_ext_info_t *,
fec509a05ddbf645268fe2e537314def7d1b67c8gm crypto_req_handle_t);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmvoid n2rng_ksinit(n2rng_t *n2rng);
fec509a05ddbf645268fe2e537314def7d1b67c8gmvoid n2rng_ksdeinit(n2rng_t *n2rng);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic int fips_init(n2rng_t *n2rng);
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic void fips_fini(n2rng_t *n2rng);
fec509a05ddbf645268fe2e537314def7d1b67c8gmint fips_random(n2rng_t *n2rng, uint8_t *out, size_t nbytes);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic crypto_control_ops_t n2rng_control_ops = {
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_provider_status
fec509a05ddbf645268fe2e537314def7d1b67c8gm};
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic crypto_random_number_ops_t n2rng_rng_ops = {
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* seed_random */
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_random_number
fec509a05ddbf645268fe2e537314def7d1b67c8gm};
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic crypto_provider_management_ops_t n2rng_extinfo_op = {
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info, /* ext_info */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* init_token */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* init_pin */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* set_pin */
fec509a05ddbf645268fe2e537314def7d1b67c8gm};
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic crypto_ops_t n2rng_ops = {
fec509a05ddbf645268fe2e537314def7d1b67c8gm &n2rng_control_ops,
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* digest_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* cipher_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* mac_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* sign_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* verify_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* dual_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* cipher_mac_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm &n2rng_rng_ops, /* rng_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* session_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* object_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* key_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm &n2rng_extinfo_op, /* management_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* ctx_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL /* mech_ops */
fec509a05ddbf645268fe2e537314def7d1b67c8gm};
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic crypto_provider_info_t n2rng_prov_info = {
fec509a05ddbf645268fe2e537314def7d1b67c8gm CRYPTO_SPI_VERSION_2,
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* pi_provider_description */
fec509a05ddbf645268fe2e537314def7d1b67c8gm CRYPTO_HW_PROVIDER,
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* pi_provider_dev */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* pi_provider_handle */
fec509a05ddbf645268fe2e537314def7d1b67c8gm &n2rng_ops,
fec509a05ddbf645268fe2e537314def7d1b67c8gm 0, /* number of mechanisms */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL, /* mechanism table */
fec509a05ddbf645268fe2e537314def7d1b67c8gm 0, /* pi_logical_provider_count */
fec509a05ddbf645268fe2e537314def7d1b67c8gm NULL /* pi_logical_providers */
fec509a05ddbf645268fe2e537314def7d1b67c8gm};
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic void
fec509a05ddbf645268fe2e537314def7d1b67c8gmstrncpy_spacepad(uchar_t *s1, char *s2, int n)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm int s2len = strlen(s2);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm (void) strncpy((char *)s1, s2, n);
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (s2len < n)
fec509a05ddbf645268fe2e537314def7d1b67c8gm (void) memset(s1 + s2len, ' ', n - s2len);
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*ARGSUSED*/
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic int
fec509a05ddbf645268fe2e537314def7d1b67c8gmext_info(crypto_provider_handle_t prov, crypto_provider_ext_info_t *ext_info,
fec509a05ddbf645268fe2e537314def7d1b67c8gm crypto_req_handle_t cfreq)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define BUFSZ 64
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_t *n2rng = (n2rng_t *)prov;
fec509a05ddbf645268fe2e537314def7d1b67c8gm char buf[BUFSZ];
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* handle info common to logical and hardware provider */
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* Manufacturer ID */
fec509a05ddbf645268fe2e537314def7d1b67c8gm strncpy_spacepad(ext_info->ei_manufacturerID, N2RNG_MANUFACTURER_ID,
fec509a05ddbf645268fe2e537314def7d1b67c8gm CRYPTO_EXT_SIZE_MANUF);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* Model */
fec509a05ddbf645268fe2e537314def7d1b67c8gm strncpy_spacepad(ext_info->ei_model, "0", CRYPTO_EXT_SIZE_MODEL);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* Token flags */
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_flags = CRYPTO_EXTF_RNG | CRYPTO_EXTF_SO_PIN_LOCKED |
fec509a05ddbf645268fe2e537314def7d1b67c8gm CRYPTO_EXTF_WRITE_PROTECTED;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_max_session_count = CRYPTO_EFFECTIVELY_INFINITE;
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_max_pin_len = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_min_pin_len = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO;
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO;
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO;
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_free_private_memory = CRYPTO_UNAVAILABLE_INFO;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* Time. No need to be supplied for token without a clock */
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_time[0] = '\000';
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* handle hardware provider specific fields */
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* Token label */
fec509a05ddbf645268fe2e537314def7d1b67c8gm (void) snprintf(buf, BUFSZ, "%s/%d SUNW_N2_RNG",
fec509a05ddbf645268fe2e537314def7d1b67c8gm ddi_driver_name(n2rng->n_dip),
fec509a05ddbf645268fe2e537314def7d1b67c8gm ddi_get_instance(n2rng->n_dip));
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* Serial number */
fec509a05ddbf645268fe2e537314def7d1b67c8gm strncpy_spacepad(ext_info->ei_serial_number,
fec509a05ddbf645268fe2e537314def7d1b67c8gm "0",
fec509a05ddbf645268fe2e537314def7d1b67c8gm CRYPTO_EXT_SIZE_SERIAL);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* Version info */
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_hardware_version.cv_major = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_hardware_version.cv_minor = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_firmware_version.cv_major = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm ext_info->ei_firmware_version.cv_minor = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm buf[BUFSZ - 1] = '\000';
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* set the token label */
fec509a05ddbf645268fe2e537314def7d1b67c8gm strncpy_spacepad(ext_info->ei_label, buf, CRYPTO_EXT_SIZE_LABEL);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm#undef BUFSZ
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (CRYPTO_SUCCESS);
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelkestatic void
741c280d5486676df48cd5d5e8ed8d92eac714a8twelkeunregister_task(void *targ)
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke{
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_t *n2rng = (n2rng_t *)targ;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Unregister provider without checking result */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke (void) n2rng_unregister_provider(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke}
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke/*
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * Register with KCF if not already registered
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelkeint
741c280d5486676df48cd5d5e8ed8d92eac714a8twelken2rng_register_provider(n2rng_t *n2rng)
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke{
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke int ret;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (n2rng_isregistered(n2rng)) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider already "
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "registered");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke return (DDI_SUCCESS);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke } else {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke ret = crypto_register_provider(&n2rng_prov_info,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke &n2rng->n_prov);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (ret == CRYPTO_SUCCESS) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider "
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "registered");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke } else {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke cmn_err(CE_WARN,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "crypto_register_provider() failed (%d)", ret);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng->n_prov = NULL;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke return (DDI_FAILURE);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_setregistered(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke crypto_provider_notification(n2rng->n_prov, CRYPTO_PROVIDER_READY);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke return (DDI_SUCCESS);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke}
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke/*
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * Unregister with KCF if not already registered
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelkeint
741c280d5486676df48cd5d5e8ed8d92eac714a8twelken2rng_unregister_provider(n2rng_t *n2rng)
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke{
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (!n2rng_isregistered(n2rng)) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider already "
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "unregistered");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke } else {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (crypto_unregister_provider(n2rng->n_prov) ==
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke CRYPTO_SUCCESS) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider "
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "unregistered");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke } else {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_error(n2rng, "unable to unregister from kcf");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke return (DDI_FAILURE);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng->n_prov = NULL;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_clrregistered(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke return (DDI_SUCCESS);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke}
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke/*
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * Set state to failed for all rngs if in control domain and dispatch a task
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * to unregister from kcf
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelkevoid
741c280d5486676df48cd5d5e8ed8d92eac714a8twelken2rng_failure(n2rng_t *n2rng)
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke{
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke int rngid;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_entry_t *rng;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke mutex_enter(&n2rng->n_lock);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Check if error has already been detected */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (n2rng_isfailed(n2rng)) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke mutex_exit(&n2rng->n_lock);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke return;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke cmn_err(CE_WARN, "n2rng: hardware failure detected");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_setfailed(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Set each rng to failed if running in control domain */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (n2rng_iscontrol(n2rng)) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke for (rngid = 0; rngid < n2rng->n_ctl_data->n_num_rngs;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rngid++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng = &n2rng->n_ctl_data->n_rngs[rngid];
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng->n_rng_state = CTL_STATE_ERROR;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke mutex_exit(&n2rng->n_lock);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Dispatch task to unregister from kcf */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (ddi_taskq_dispatch(n2rng->n_taskq, unregister_task,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke (void *)n2rng, DDI_SLEEP) != DDI_SUCCESS) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke cmn_err(CE_WARN, "n2rng: ddi_taskq_dispatch() failed");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke}
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke/*
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * Set state to unconfigured for all rngs if in control domain and dispatch a
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * task to unregister from kcf.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelkevoid
741c280d5486676df48cd5d5e8ed8d92eac714a8twelken2rng_unconfigured(n2rng_t *n2rng)
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke{
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke int rngid;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_entry_t *rng;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke mutex_enter(&n2rng->n_lock);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Check if unconfigured state has already been detected */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (!n2rng_isconfigured(n2rng)) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke mutex_exit(&n2rng->n_lock);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke return;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke cmn_err(CE_WARN, "n2rng: no longer generating entropy");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_clrconfigured(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Set each rng to unconfigured if running in control domain */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (n2rng_iscontrol(n2rng)) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke for (rngid = 0; rngid < n2rng->n_ctl_data->n_num_rngs;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rngid++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng = &n2rng->n_ctl_data->n_rngs[rngid];
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng->n_rng_state = CTL_STATE_UNCONFIGURED;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke mutex_exit(&n2rng->n_lock);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Dispatch task to unregister from kcf */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (ddi_taskq_dispatch(n2rng->n_taskq, unregister_task,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke (void *)n2rng, DDI_SLEEP) != DDI_SUCCESS) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke cmn_err(CE_WARN, "n2rng: ddi_taskq_dispatch() failed");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke } else {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Schedule a configuration retry */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_config_retry(n2rng, RNG_CFG_RETRY_SECS);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Setup and also register to kCF
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gmint
fec509a05ddbf645268fe2e537314def7d1b67c8gmn2rng_init(n2rng_t *n2rng)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm int ret;
fec509a05ddbf645268fe2e537314def7d1b67c8gm char ID[64];
fec509a05ddbf645268fe2e537314def7d1b67c8gm dev_info_t *dip;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm dip = n2rng->n_dip;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Initialize data structures if not already done */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (!n2rng_isinitialized(n2rng)) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* initialize kstats */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_ksinit(n2rng);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* initialize the FIPS data and mutexes */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke ret = fips_init(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (ret) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_ksdeinit(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke return (DDI_FAILURE);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /*
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * Register with crypto framework if not already registered.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * Be careful not to exceed 32 characters.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke */
fec509a05ddbf645268fe2e537314def7d1b67c8gm (void) sprintf(ID, "%s/%d %s",
fec509a05ddbf645268fe2e537314def7d1b67c8gm ddi_driver_name(dip), ddi_get_instance(dip),
fec509a05ddbf645268fe2e537314def7d1b67c8gm IDENT_N2RNG);
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_prov_info.pi_provider_description = ID;
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_prov_info.pi_provider_dev.pd_hw = dip;
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_prov_info.pi_provider_handle = n2rng;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_setinitialized(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke ret = n2rng_register_provider(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (ret != DDI_SUCCESS) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm fips_fini(n2rng);
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_ksdeinit(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_clrinitialized(n2rng);
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (DDI_FAILURE);
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (DDI_SUCCESS);
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Unregister from kCF and cleanup
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gmint
fec509a05ddbf645268fe2e537314def7d1b67c8gmn2rng_uninit(n2rng_t *n2rng)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Un-initialize data structures if they exist */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (n2rng_isinitialized(n2rng)) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /*
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * Unregister from kCF.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * This needs to be done at the beginning of detach.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (n2rng_unregister_provider(n2rng) != DDI_SUCCESS) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (DDI_FAILURE);
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke fips_fini(n2rng);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* deinitialize kstats */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_ksdeinit(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke n2rng_clrinitialized(n2rng);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (DDI_SUCCESS);
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
fec509a05ddbf645268fe2e537314def7d1b67c8gm * At this time there are no periodic health checks. If the health
fec509a05ddbf645268fe2e537314def7d1b67c8gm * check done at attrach time fails, the driver does not even attach.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * So there are no failure conditions to report, and this provider is
fec509a05ddbf645268fe2e537314def7d1b67c8gm * never busy.
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gm/* ARGSUSED */
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic void
fec509a05ddbf645268fe2e537314def7d1b67c8gmn2rng_provider_status(crypto_provider_handle_t provider, uint_t *status)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm *status = CRYPTO_PROVIDER_READY;
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*ARGSUSED*/
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic int
fec509a05ddbf645268fe2e537314def7d1b67c8gmn2rng_random_number(crypto_provider_handle_t provider,
fec509a05ddbf645268fe2e537314def7d1b67c8gm crypto_session_id_t sess, unsigned char *buf, size_t buflen,
fec509a05ddbf645268fe2e537314def7d1b67c8gm crypto_req_handle_t cfreq)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_t *n2rng = (n2rng_t *)provider;
fec509a05ddbf645268fe2e537314def7d1b67c8gm int rv;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm rv = fips_random(n2rng, buf, buflen);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm atomic_add_64(&n2rng->n_stats[DS_RNGBYTES], buflen);
fec509a05ddbf645268fe2e537314def7d1b67c8gm atomic_inc_64(&n2rng->n_stats[DS_RNGJOBS]);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic int
fec509a05ddbf645268fe2e537314def7d1b67c8gmfips_init(n2rng_t *n2rng)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm int i;
fec509a05ddbf645268fe2e537314def7d1b67c8gm int rv;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng->n_frs.fips_round_robin_j = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (i = 0; i < N2RNG_FIPS_INSTANCES; i++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm rv = n2rng_fips_random_init(n2rng, &n2rng->n_frs.fipsarray[i]);
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (rv) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* finalize all the FIPS structures allocated so far */
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (--i; i >= 0; --i) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_fips_random_fini(
fec509a05ddbf645268fe2e537314def7d1b67c8gm &n2rng->n_frs.fipsarray[i]);
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (0);
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic void
fec509a05ddbf645268fe2e537314def7d1b67c8gmfips_fini(n2rng_t *n2rng)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm int i;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (i = 0; i < N2RNG_FIPS_INSTANCES; i++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_fips_random_fini(&n2rng->n_frs.fipsarray[i]);
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm}