static int gencert_pkcs11(KMF_HANDLE_T kmfhandle, char *token, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, char *certlabel, KMF_KEY_ALG keyAlg, KMF_ALGORITHM_INDEX sigAlg, int keylen, uint32_t ltime, KMF_BIGINT *serial, uint16_t kubits, int kucrit, KMF_CREDENTIAL *tokencred, EKU_LIST *ekulist, KMF_OID *curveoid) { KMF_RETURN kmfrv = KMF_OK; KMF_KEY_HANDLE pubk, prik; KMF_X509_CERTIFICATE signedCert; KMF_X509_NAME certSubject; KMF_X509_NAME certIssuer; KMF_DATA x509DER; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; KMF_KEY_ALG keytype; uint32_t keylength; (void) memset(&signedCert, 0, sizeof (signedCert)); (void) memset(&certSubject, 0, sizeof (certSubject)); (void) memset(&certIssuer, 0, sizeof (certIssuer)); (void) memset(&x509DER, 0, sizeof (x509DER)); /* If the subject name cannot be parsed, flag it now and exit */ if (kmf_dn_parser(subject, &certSubject) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed.\n")); return (PK_ERR_USAGE); } /* For a self-signed cert, the issuser and subject are the same */ if (kmf_dn_parser(subject, &certIssuer) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed.\n")); return (PK_ERR_USAGE); } keylength = keylen; /* bits */ keytype = keyAlg; /* Select a PKCS11 token */ kmfrv = select_token(kmfhandle, token, FALSE); if (kmfrv != KMF_OK) { return (kmfrv); } /* * Share the "genkeypair" routine for creating the keypair. */ kmfrv = genkeypair_pkcs11(kmfhandle, token, certlabel, keytype, keylength, tokencred, curveoid, &prik, &pubk); if (kmfrv != KMF_OK) return (kmfrv); SET_VALUE(kmf_set_cert_pubkey(kmfhandle, &pubk, &signedCert), "keypair"); SET_VALUE(kmf_set_cert_version(&signedCert, 2), "version number"); SET_VALUE(kmf_set_cert_serial(&signedCert, serial), "serial number"); SET_VALUE(kmf_set_cert_validity(&signedCert, NULL, ltime), "validity time"); SET_VALUE(kmf_set_cert_sig_alg(&signedCert, sigAlg), "signature algorithm"); SET_VALUE(kmf_set_cert_subject(&signedCert, &certSubject), "subject name"); SET_VALUE(kmf_set_cert_issuer(&signedCert, &certIssuer), "issuer name"); if (altname != NULL) SET_VALUE(kmf_set_cert_subject_altname(&signedCert, altcrit, alttype, altname), "subjectAltName"); if (kubits != 0) SET_VALUE(kmf_set_cert_ku(&signedCert, kucrit, kubits), "KeyUsage"); if (ekulist != NULL) { int i; for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { SET_VALUE(kmf_add_cert_eku(&signedCert, &ekulist->ekulist[i], ekulist->critlist[i]), "Extended Key Usage"); } } /* * Construct attributes for the kmf_sign_cert operation. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE_ATTR)); numattr++; /* cert data that is to be signed */ kmf_set_attr_at_index(attrlist, numattr, KMF_X509_CERTIFICATE_ATTR, &signedCert, sizeof (KMF_X509_CERTIFICATE)); numattr++; /* output buffer for the signed cert */ kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &x509DER, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ALGORITHM_INDEX_ATTR, &sigAlg, sizeof (sigAlg)); numattr++; if ((kmfrv = kmf_sign_cert(kmfhandle, numattr, attrlist)) != KMF_OK) { goto cleanup; } /* * Store the cert in the DB. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &x509DER, sizeof (KMF_DATA)); numattr++; if (certlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel)); numattr++; } kmfrv = kmf_store_cert(kmfhandle, numattr, attrlist); cleanup: kmf_free_data(&x509DER); kmf_free_dn(&certSubject); kmf_free_dn(&certIssuer); /* * If kmf_sign_cert or kmf_store_cert failed, then we need to clean up * the key pair from the token. */ if (kmfrv != KMF_OK) { /* delete the public key */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); numattr++; if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } (void) kmf_delete_key_from_keystore(kmfhandle, numattr, attrlist); /* delete the private key */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); numattr++; if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } (void) kmf_delete_key_from_keystore(kmfhandle, numattr, attrlist); } return (kmfrv); }
/* * The top level function for the "cryptoadm list" subcommand and options. */ static int do_list(int argc, char **argv) { boolean_t mflag = B_FALSE; boolean_t pflag = B_FALSE; boolean_t vflag = B_FALSE; char ch; cryptoadm_provider_t *prov = NULL; int rc = SUCCESS; if ((argc == 3) && (strncmp(argv[2], FIPS_KEYWORD, strlen(FIPS_KEYWORD))) == 0) { /* * cryptoadm list fips-140 */ rc = do_fips_actions(FIPS140_STATUS, NOT_REFRESH); return (rc); } argc -= 1; argv += 1; if (argc == 1) { rc = list_simple_for_all(B_FALSE); goto out; } /* * cryptoadm list [-v] [-m] [-p] [provider=<>] [mechanism=<>] */ if (argc > 5) { usage(); return (rc); } while ((ch = getopt(argc, argv, "mpv")) != EOF) { switch (ch) { case 'm': mflag = B_TRUE; if (pflag) { rc = ERROR_USAGE; } break; case 'p': pflag = B_TRUE; if (mflag || vflag) { rc = ERROR_USAGE; } break; case 'v': vflag = B_TRUE; if (pflag) rc = ERROR_USAGE; break; default: rc = ERROR_USAGE; break; } } if (rc == ERROR_USAGE) { usage(); return (rc); } if ((rc = process_feature_operands(argc, argv)) != SUCCESS) { goto out; } prov = get_provider(argc, argv); if (mflag || vflag) { if (argc > 0) { rc = process_mech_operands(argc, argv, B_TRUE); if (rc == FAILURE) goto out; /* "-m" is implied when a mechanism list is given */ if (mecharglist != NULL || allflag) mflag = B_TRUE; } } if (prov == NULL) { if (mflag) { rc = list_mechlist_for_all(vflag); } else if (pflag) { rc = list_policy_for_all(); } else if (vflag) { rc = list_simple_for_all(vflag); } } else if (prov->cp_type == METASLOT) { if ((!mflag) && (!vflag) && (!pflag)) { /* no flag is specified, just list metaslot status */ rc = list_metaslot_info(mflag, vflag, mecharglist); } else if (mflag || vflag) { rc = list_metaslot_info(mflag, vflag, mecharglist); } else if (pflag) { rc = list_metaslot_policy(); } else { /* error message */ usage(); rc = ERROR_USAGE; } } else if (prov->cp_type == PROV_BADNAME) { usage(); rc = ERROR_USAGE; goto out; } else { /* do the listing for a provider only */ char *provname = prov->cp_name; if (mflag || vflag) { if (vflag) (void) printf(gettext("Provider: %s\n"), provname); switch (prov->cp_type) { case PROV_UEF_LIB: rc = list_mechlist_for_lib(provname, mecharglist, NULL, B_FALSE, vflag, mflag); break; case PROV_KEF_SOFT: rc = list_mechlist_for_soft(provname, NULL, NULL); break; case PROV_KEF_HARD: rc = list_mechlist_for_hard(provname); break; default: /* should not come here */ rc = FAILURE; break; } } else if (pflag) { switch (prov->cp_type) { case PROV_UEF_LIB: rc = list_policy_for_lib(provname); break; case PROV_KEF_SOFT: if (getzoneid() == GLOBAL_ZONEID) { rc = list_policy_for_soft(provname, NULL, NULL); } else { /* * TRANSLATION_NOTE * "global" is keyword and not to * be translated. */ cryptoerror(LOG_STDERR, gettext( "policy information for kernel " "providers is available " "in the %s zone only"), "global"); rc = FAILURE; } break; case PROV_KEF_HARD: if (getzoneid() == GLOBAL_ZONEID) { rc = list_policy_for_hard( provname, NULL, NULL, NULL); } else { /* * TRANSLATION_NOTE * "global" is keyword and not to * be translated. */ cryptoerror(LOG_STDERR, gettext( "policy information for kernel " "providers is available " "in the %s zone only"), "global"); rc = FAILURE; } break; default: /* should not come here */ rc = FAILURE; break; } } else { /* error message */ usage(); rc = ERROR_USAGE; } } out: if (prov != NULL) free(prov); if (mecharglist != NULL) free_mechlist(mecharglist); return (rc); }
/* * The top level function for the "cryptoadm install" subcommand. */ static int do_install(int argc, char **argv) { cryptoadm_provider_t *prov = NULL; int rc; if (argc < 3) { usage(); return (ERROR_USAGE); } prov = get_provider(argc, argv); if (prov == NULL || prov->cp_type == PROV_BADNAME || prov->cp_type == PROV_KEF_HARD) { /* * TRANSLATION_NOTE * "install" could be either a literal keyword and hence * not to be translated, or a verb and translatable. A * choice was made to view it as a literal keyword. */ cryptoerror(LOG_STDERR, gettext("bad provider name for %s."), "install"); rc = FAILURE; goto out; } if (prov->cp_type == PROV_UEF_LIB) { rc = install_uef_lib(prov->cp_name); goto out; } /* It is the PROV_KEF_SOFT type now */ /* check if there are mechanism operands */ if (argc < 4) { /* * TRANSLATION_NOTE * "mechanism" could be either a literal keyword and hence * not to be translated, or a descriptive word and * translatable. A choice was made to view it as a literal * keyword. */ cryptoerror(LOG_STDERR, gettext("need %s operands for installing a" " kernel software provider."), "mechanism"); rc = ERROR_USAGE; goto out; } if ((rc = process_mech_operands(argc, argv, B_FALSE)) != SUCCESS) { goto out; } if (allflag == B_TRUE) { /* * TRANSLATION_NOTE * "all", "mechanism", and "install" are all keywords and * not to be translated. */ cryptoerror(LOG_STDERR, gettext("can not use the %1$s keyword for %2$s " "in the %3$s subcommand."), "all", "mechanism", "install"); rc = ERROR_USAGE; goto out; } if (getzoneid() == GLOBAL_ZONEID) { rc = install_kef(prov->cp_name, mecharglist); } else { /* * TRANSLATION_NOTE * "install" could be either a literal keyword and hence * not to be translated, or a verb and translatable. A * choice was made to view it as a literal keyword. * "global" is keyword and not to be translated. */ cryptoerror(LOG_STDERR, gettext("%1$s for kernel providers " "is supported in the %2$s zone only"), "install", "global"); rc = FAILURE; } out: free(prov); return (rc); }
/* * List all the providers. And for each provider, list the mechanism list. * Called for "cryptoadm list -m" or "cryptoadm list -mv" . */ static int list_mechlist_for_all(boolean_t verbose) { crypto_get_dev_list_t *pdevlist_kernel = NULL; uentrylist_t *pliblist = NULL; uentrylist_t *plibptr = NULL; entry_t *pent = NULL; mechlist_t *pmechlist = NULL; char provname[MAXNAMELEN]; char devname[MAXNAMELEN]; int inst_num; int count; int i; int rv; int rc = SUCCESS; /* get user-level providers */ (void) printf(gettext("\nUser-level providers:\n")); /* * TRANSLATION_NOTE * Strictly for appearance's sake, this line should be as long as * the length of the translated text above. */ (void) printf(gettext("=====================\n")); if (get_pkcs11conf_info(&pliblist) != SUCCESS) { cryptoerror(LOG_STDERR, gettext("failed to retrieve " "the list of user-level providers.\n")); rc = FAILURE; } plibptr = pliblist; while (plibptr != NULL) { /* skip metaslot and fips-140 entry */ if ((strcmp(plibptr->puent->name, METASLOT_KEYWORD) != 0) && (strcmp(plibptr->puent->name, FIPS_KEYWORD) != 0)) { (void) printf(gettext("\nProvider: %s\n"), plibptr->puent->name); rv = list_mechlist_for_lib(plibptr->puent->name, mecharglist, NULL, B_FALSE, verbose, B_TRUE); if (rv == FAILURE) { rc = FAILURE; } } plibptr = plibptr->next; } free_uentrylist(pliblist); /* get kernel software providers */ (void) printf(gettext("\nKernel software providers:\n")); /* * TRANSLATION_NOTE * Strictly for appearance's sake, this line should be as long as * the length of the translated text above. */ (void) printf(gettext("==========================\n")); if (getzoneid() == GLOBAL_ZONEID) { /* get kernel software providers from kernel ioctl */ crypto_get_soft_list_t *psoftlist_kernel = NULL; uint_t sl_soft_count; char *psoftname; int i; entrylist_t *pdevlist_conf = NULL; entrylist_t *psoftlist_conf = NULL; if (get_soft_list(&psoftlist_kernel) == FAILURE) { cryptoerror(LOG_ERR, gettext("Failed to retrieve the " "software provider list from kernel.")); return (FAILURE); } sl_soft_count = psoftlist_kernel->sl_soft_count; if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf) == FAILURE) { cryptoerror(LOG_ERR, "failed to retrieve the providers' " "information from file kcf.conf - %s.", _PATH_KCF_CONF); free(psoftlist_kernel); return (FAILURE); } for (i = 0, psoftname = psoftlist_kernel->sl_soft_names; i < sl_soft_count; ++i, psoftname += strlen(psoftname) + 1) { pent = getent_kef(psoftname, pdevlist_conf, psoftlist_conf); if ((pent == NULL) || (pent->load)) { rv = list_mechlist_for_soft(psoftname, NULL, NULL); if (rv == FAILURE) { rc = FAILURE; } } else { (void) printf(gettext("%s: (inactive)\n"), psoftname); } } free(psoftlist_kernel); free_entrylist(pdevlist_conf); free_entrylist(psoftlist_conf); } else { /* kcf.conf not there in non-global zone, use /dev/cryptoadm */ entrylist_t *pdevlist_zone = NULL; entrylist_t *psoftlist_zone = NULL; entrylist_t *ptr; if (get_admindev_info(&pdevlist_zone, &psoftlist_zone) != SUCCESS) { cryptoerror(LOG_STDERR, gettext("failed to retrieve " "the list of kernel software providers.\n")); rc = FAILURE; } for (ptr = psoftlist_zone; ptr != NULL; ptr = ptr->next) { rv = list_mechlist_for_soft(ptr->pent->name, pdevlist_zone, psoftlist_zone); if (rv == FAILURE) { (void) printf(gettext( "%s: failed to get the mechanism list.\n"), ptr->pent->name); rc = FAILURE; } } free_entrylist(pdevlist_zone); free_entrylist(psoftlist_zone); } /* Get kernel hardware providers and their mechanism lists */ (void) printf(gettext("\nKernel hardware providers:\n")); /* * TRANSLATION_NOTE * Strictly for appearance's sake, this line should be as long as * the length of the translated text above. */ (void) printf(gettext("==========================\n")); if (get_dev_list(&pdevlist_kernel) != SUCCESS) { cryptoerror(LOG_STDERR, gettext("failed to retrieve " "the list of hardware providers.\n")); return (FAILURE); } for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) { (void) strlcpy(devname, pdevlist_kernel->dl_devs[i].le_dev_name, MAXNAMELEN); inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance; count = pdevlist_kernel->dl_devs[i].le_mechanism_count; (void) snprintf(provname, sizeof (provname), "%s/%d", devname, inst_num); if (get_dev_info(devname, inst_num, count, &pmechlist) == SUCCESS) { (void) filter_mechlist(&pmechlist, RANDOM); print_mechlist(provname, pmechlist); free_mechlist(pmechlist); } else { (void) printf(gettext("%s: failed to get the mechanism" " list.\n"), provname); rc = FAILURE; } } free(pdevlist_kernel); return (rc); }
/* * Get the provider structure. This function returns NULL if no valid * provider= is found in argv[], otherwise a cryptoadm_provider_t is returned. * If provider= is found but has no argument, then a cryptoadm_provider_t * with cp_type = PROV_BADNAME is returned. */ static cryptoadm_provider_t * get_provider(int argc, char **argv) { int c = 0; boolean_t found = B_FALSE; cryptoadm_provider_t *provider = NULL; char *provstr = NULL, *savstr; boolean_t is_metaslot = B_FALSE; while (!found && ++c < argc) { if (strncmp(argv[c], METASLOT_KEYWORD, strlen(METASLOT_KEYWORD)) == 0) { is_metaslot = B_TRUE; found = B_TRUE; } else if (strncmp(argv[c], KN_PROVIDER, strlen(KN_PROVIDER)) == 0 && strlen(argv[c]) > strlen(KN_PROVIDER)) { if ((provstr = strdup(argv[c])) == NULL) { int err = errno; /* * TRANSLATION_NOTE * "get_provider" is a function name and should * not be translated. */ cryptoerror(LOG_STDERR, "get_provider: %s.", strerror(err)); return (NULL); } found = B_TRUE; } } if (!found) return (NULL); provider = malloc(sizeof (cryptoadm_provider_t)); if (provider == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); if (provstr) { free(provstr); } return (NULL); } if (is_metaslot) { (void) strlcpy(provider->cp_name, METASLOT_KEYWORD, strlen(METASLOT_KEYWORD)); provider->cp_type = METASLOT; } else { savstr = provstr; (void) strtok(provstr, "="); provstr = strtok(NULL, "="); if (provstr == NULL) { cryptoerror(LOG_STDERR, gettext("bad provider name.")); provider->cp_type = PROV_BADNAME; free(savstr); return (provider); } (void) strlcpy(provider->cp_name, provstr, sizeof (provider->cp_name)); provider->cp_type = get_provider_type(provider->cp_name); free(savstr); } return (provider); }
/* * For each provider found in pkcs11.conf: expand $ISA if necessary, * verify the module is signed, load the provider, find all of its * slots, and store the function list and disabled policy. * * This function requires that the uentrylist_t and pkcs11_slottable_t * already have memory allocated, and that the uentrylist_t is already * populated with provider and policy information. * * pInitArgs can be set to NULL, but is normally the same value * the framework's C_Initialize() was called with. * * Unless metaslot is explicitly disabled, it is setup when all other * providers are loaded. */ CK_RV pkcs11_slot_mapping(uentrylist_t *pplist, CK_VOID_PTR pInitArgs) { CK_RV rv = CKR_OK; CK_RV prov_rv; /* Provider's return code */ CK_INFO prov_info; CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR); CK_FUNCTION_LIST_PTR prov_funcs = NULL; /* Provider's function list */ CK_ULONG prov_slot_count; /* Number of slots */ CK_SLOT_ID slot_id; /* slotID assigned for framework */ CK_SLOT_ID_PTR prov_slots = NULL; /* Provider's slot list */ /* Enabled or Disabled policy */ CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL; void *dldesc = NULL; char *isa, *fullpath = NULL, *dl_error; uentrylist_t *phead; uint_t prov_count = 0; pkcs11_slot_t *cur_slot; CK_ULONG i; size_t len; uentry_t *metaslot_entry = NULL; /* number of slots in the framework, not including metaslot */ uint_t slot_count = 0; ELFsign_status_t estatus = ELFSIGN_UNKNOWN; char *estatus_str = NULL; int kcfdfd = -1; door_arg_t darg; kcf_door_arg_t *kda = NULL; kcf_door_arg_t *rkda = NULL; int r; phead = pplist; /* Loop through all of the provider listed in pkcs11.conf */ while (phead != NULL) { if (!strcasecmp(phead->puent->name, "metaslot")) { /* * Skip standard processing for metaslot * entry since it is not an actual library * that can be dlopened. * It will be initialized later. */ if (metaslot_entry != NULL) { cryptoerror(LOG_ERR, "libpkcs11: multiple entries for metaslot " "detected. All but the first entry will " "be ignored"); } else { metaslot_entry = phead->puent; } goto contparse; } /* Check for Instruction Set Architecture indicator */ if ((isa = strstr(phead->puent->name, PKCS11_ISA)) != NULL) { /* Substitute the architecture dependent path */ len = strlen(phead->puent->name) - strlen(PKCS11_ISA) + strlen(PKCS11_ISA_DIR) + 1; if ((fullpath = (char *)malloc(len)) == NULL) { cryptoerror(LOG_ERR, "libpksc11: parsing %s, out of memory. " "Cannot continue parsing.", _PATH_PKCS11_CONF); rv = CKR_HOST_MEMORY; goto conferror; } *isa = '\000'; isa += strlen(PKCS11_ISA); (void) snprintf(fullpath, len, "%s%s%s", phead->puent->name, PKCS11_ISA_DIR, isa); } else if ((fullpath = strdup(phead->puent->name)) == 0) { cryptoerror(LOG_ERR, "libpkcs11: parsing %s, out of memory. " "Cannot continue parsing.", _PATH_PKCS11_CONF); rv = CKR_HOST_MEMORY; goto conferror; } /* * Open the provider. Use RTLD_NOW to make sure we * will not encounter symbol referencing errors later. * Use RTLD_GROUP to limit the provider to it's own * symbols, which prevents it from mistakenly accessing * the framework's C_* functions. */ dldesc = dlopen(fullpath, RTLD_NOW|RTLD_GROUP); /* * If we failed to load it, we will just skip this * provider and move on to the next one. */ if (dldesc == NULL) { dl_error = dlerror(); cryptoerror(LOG_ERR, "libpkcs11: Cannot load PKCS#11 library %s. " "dlerror: %s. %s", fullpath, dl_error != NULL ? dl_error : "Unknown", conf_err); goto contparse; } /* Get the pointer to provider's C_GetFunctionList() */ Tmp_C_GetFunctionList = (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList"); /* * If we failed to get the pointer to C_GetFunctionList(), * skip this provider and continue to the next one. */ if (Tmp_C_GetFunctionList == NULL) { cryptoerror(LOG_ERR, "libpkcs11: Could not dlsym() C_GetFunctionList() " "for %s. May not be a PKCS#11 library. %s", fullpath, conf_err); (void) dlclose(dldesc); goto contparse; } /* Get the provider's function list */ prov_rv = Tmp_C_GetFunctionList(&prov_funcs); /* * If we failed to get the provider's function list, * skip this provider and continue to the next one. */ if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Could not get function list for %s. " "%s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) dlclose(dldesc); goto contparse; } /* Initialize this provider */ prov_rv = prov_funcs->C_Initialize(pInitArgs); /* * If we failed to initialize this provider, * skip this provider and continue to the next one. */ if ((prov_rv != CKR_OK) && (prov_rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { cryptoerror(LOG_ERR, "libpkcs11: Could not initialize %s. " "%s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) dlclose(dldesc); goto contparse; } /* * Make sure this provider is implementing the same * major version, and at least the same minor version * that we are. */ prov_rv = prov_funcs->C_GetInfo(&prov_info); /* * If we can't verify that we are implementing the * same major version, or if it is definitely not the same * version, we need to skip this provider. */ if ((prov_rv != CKR_OK) || (prov_info.cryptokiVersion.major != CRYPTOKI_VERSION_MAJOR)) { if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Could not verify version of " "%s. %s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); } else { cryptoerror(LOG_ERR, "libpkcs11: Only CRYPTOKI major version " "%d is supported. %s is major " "version %d. %s", CRYPTOKI_VERSION_MAJOR, fullpath, prov_info.cryptokiVersion.major, conf_err); } (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } /* * Warn the administrator (at debug) that a provider with * a significantly older or newer version of * CRYPTOKI is being used. It should not cause * problems, but logging a warning makes it easier * to debug later. */ if ((prov_info.cryptokiVersion.minor < CRYPTOKI_VERSION_WARN_MINOR) || (prov_info.cryptokiVersion.minor > CRYPTOKI_VERSION_MINOR)) { cryptoerror(LOG_DEBUG, "libpkcs11: %s CRYPTOKI minor version, %d, may " "not be compatible with minor version %d.", fullpath, prov_info.cryptokiVersion.minor, CRYPTOKI_VERSION_MINOR); } /* * Find out how many slots this provider has, * call with tokenPresent set to FALSE so all * potential slots are returned. */ prov_rv = prov_funcs->C_GetSlotList(FALSE, NULL, &prov_slot_count); /* * If the call failed, or if no slots are returned, * then skip this provider and continue to next one. */ if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpksc11: Could not get slot list from %s. " "%s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } if (prov_slot_count == 0) { cryptodebug("libpkcs11: No slots presented from %s. " "Skipping this plug-in at this time.\n", fullpath); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } /* * Verify that the module is signed correctly. * * NOTE: there is a potential race condition here, * since the module is verified well after we have * opened the provider via dlopen(). This could be * resolved by a variant of dlopen() that would take a * file descriptor as an argument and by changing the * kcfd libelfsign door protocol to use and fd instead * of a path - but that wouldn't work in the kernel case. */ while ((kcfdfd = open(_PATH_KCFD_DOOR, O_RDONLY)) == -1) { if (!(errno == EINTR || errno == EAGAIN)) break; } if (kcfdfd == -1) { cryptoerror(LOG_ERR, "libpkcs11: open %s: %s", _PATH_KCFD_DOOR, strerror(errno)); goto verifycleanup; } /* Mark the door "close on exec" */ (void) fcntl(kcfdfd, F_SETFD, FD_CLOEXEC); if ((kda = malloc(sizeof (kcf_door_arg_t))) == NULL) { cryptoerror(LOG_ERR, "libpkcs11: malloc of kda " "failed: %s", strerror(errno)); goto verifycleanup; } kda->da_version = KCF_KCFD_VERSION1; kda->da_iskernel = B_FALSE; (void) strlcpy(kda->da_u.filename, fullpath, strlen(fullpath) + 1); darg.data_ptr = (char *)kda; darg.data_size = sizeof (kcf_door_arg_t); darg.desc_ptr = NULL; darg.desc_num = 0; darg.rbuf = (char *)kda; darg.rsize = sizeof (kcf_door_arg_t); while ((r = door_call(kcfdfd, &darg)) != 0) { if (!(errno == EINTR || errno == EAGAIN)) break; } if (r != 0) { cryptoerror(LOG_ERR, "libpkcs11: Unable to contact kcfd: %s", strerror(errno)); goto verifycleanup; } /*LINTED*/ rkda = (kcf_door_arg_t *)darg.rbuf; if (rkda->da_version != KCF_KCFD_VERSION1) { cryptoerror(LOG_ERR, "libpkcs11: kcfd and libelfsign versions " "don't match: got %d expected %d", rkda->da_version, KCF_KCFD_VERSION1); goto verifycleanup; } estatus = rkda->da_u.result.status; verifycleanup: if (kcfdfd != -1) { (void) close(kcfdfd); } if (rkda != NULL && rkda != kda) (void) munmap((char *)rkda, darg.rsize); if (kda != NULL) { bzero(kda, sizeof (kda)); free(kda); kda = NULL; rkda = NULL; /* rkda is an alias of kda */ } switch (estatus) { case ELFSIGN_SUCCESS: case ELFSIGN_RESTRICTED: break; case ELFSIGN_NOTSIGNED: estatus_str = strdup("not a signed provider."); break; case ELFSIGN_FAILED: estatus_str = strdup("signature verification failed."); break; default: estatus_str = strdup("unexpected failure in ELF " "signature verification. " "System may have been tampered with."); } if (estatus_str != NULL) { cryptoerror(LOG_ERR, "libpkcs11: %s %s %s", fullpath, estatus_str ? estatus_str : "", estatus == ELFSIGN_UNKNOWN ? "Cannot continue parsing " _PATH_PKCS11_CONF: conf_err); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); free(estatus_str); estatus_str = NULL; if (estatus == ELFSIGN_UNKNOWN) { prov_funcs = NULL; dldesc = NULL; rv = CKR_GENERAL_ERROR; goto conferror; } goto contparse; } /* Allocate memory for the slot list */ prov_slots = calloc(prov_slot_count, sizeof (CK_SLOT_ID)); if (prov_slots == NULL) { cryptoerror(LOG_ERR, "libpkcs11: Could not allocate memory for " "plug-in slots. Cannot continue parsing %s\n", _PATH_PKCS11_CONF); rv = CKR_HOST_MEMORY; goto conferror; } /* Get slot list from provider */ prov_rv = prov_funcs->C_GetSlotList(FALSE, prov_slots, &prov_slot_count); /* if second call fails, drop this provider */ if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Second call to C_GetSlotList() for %s " "failed. %s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } /* * Parse the list of disabled or enabled mechanisms, will * apply to each of the provider's slots. */ if (phead->puent->count > 0) { rv = pkcs11_mech_parse(phead->puent->policylist, &prov_pol_mechs, phead->puent->count); if (rv == CKR_HOST_MEMORY) { cryptoerror(LOG_ERR, "libpkcs11: Could not parse configuration," "out of memory. Cannot continue parsing " "%s.", _PATH_PKCS11_CONF); goto conferror; } else if (rv == CKR_MECHANISM_INVALID) { /* * Configuration file is corrupted for this * provider. */ cryptoerror(LOG_ERR, "libpkcs11: Policy invalid or corrupted " "for %s. Use cryptoadm(1M) to fix " "this. Skipping this plug-in.", fullpath); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } } /* Allocate memory in our slottable for these slots */ rv = pkcs11_slottable_increase(prov_slot_count); /* * If any error is returned, it will be memory related, * so we need to abort the attempt at filling the * slottable. */ if (rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: slottable could not increase. " "Cannot continue parsing %s.", _PATH_PKCS11_CONF); goto conferror; } /* Configure information for each new slot */ for (i = 0; i < prov_slot_count; i++) { /* allocate slot in framework */ rv = pkcs11_slot_allocate(&slot_id); if (rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Could not allocate " "new slot. Cannot continue parsing %s.", _PATH_PKCS11_CONF); goto conferror; } slot_count++; cur_slot = slottable->st_slots[slot_id]; (void) pthread_mutex_lock(&cur_slot->sl_mutex); cur_slot->sl_id = prov_slots[i]; cur_slot->sl_func_list = prov_funcs; cur_slot->sl_enabledpol = phead->puent->flag_enabledlist; cur_slot->sl_pol_mechs = prov_pol_mechs; cur_slot->sl_pol_count = phead->puent->count; cur_slot->sl_norandom = phead->puent->flag_norandom; cur_slot->sl_dldesc = dldesc; cur_slot->sl_prov_id = prov_count + 1; (void) pthread_mutex_unlock(&cur_slot->sl_mutex); } /* Set and reset values to process next provider */ prov_count++; contparse: prov_slot_count = 0; Tmp_C_GetFunctionList = NULL; prov_funcs = NULL; dldesc = NULL; if (fullpath != NULL) { free(fullpath); fullpath = NULL; } if (prov_slots != NULL) { free(prov_slots); prov_slots = NULL; } phead = phead->next; } if (slot_count == 0) { /* * there's no other slot in the framework, * there is nothing to do */ goto config_complete; } /* determine if metaslot should be enabled */ /* * Check to see if any environment variable is defined * by the user for configuring metaslot. Users' * setting always take precedence over the system wide * setting. So, we will first check for any user's * defined env variables before looking at the system-wide * configuration. */ get_user_metaslot_config(); /* no metaslot entry in /etc/crypto/pkcs11.conf */ if (!metaslot_entry) { /* * If user env variable indicates metaslot should be enabled, * but there's no entry in /etc/crypto/pkcs11.conf for * metaslot at all, will respect the user's defined value */ if ((metaslot_config.enabled_specified) && (metaslot_config.enabled)) { metaslot_enabled = B_TRUE; } } else { if (!metaslot_config.enabled_specified) { /* * take system wide value if * it is not specified by user */ metaslot_enabled = metaslot_entry->flag_metaslot_enabled; } else { metaslot_enabled = metaslot_config.enabled; } } /* * * As long as the user or system configuration file does not * disable metaslot, it will be enabled regardless of the * number of slots plugged into the framework. Therefore, * metaslot is enabled even when there's only one slot * plugged into the framework. This is necessary for * presenting a consistent token label view to applications. * * However, for the case where there is only 1 slot plugged into * the framework, we can use "fastpath". * * "fastpath" will pass all of the application's requests * directly to the underlying provider. Only when policy is in * effect will we need to keep slotID around. * * When metaslot is enabled, and fastpath is enabled, * all the metaslot processing will be skipped. * When there is only 1 slot, there's * really not much metaslot can do in terms of combining functionality * of different slots, and object migration. * */ /* check to see if fastpath can be used */ if (slottable->st_last == slottable->st_first) { cur_slot = slottable->st_slots[slottable->st_first]; (void) pthread_mutex_lock(&cur_slot->sl_mutex); if ((cur_slot->sl_pol_count == 0) && (!cur_slot->sl_enabledpol) && (!cur_slot->sl_norandom)) { /* No policy is in effect, don't need slotid */ fast_funcs = cur_slot->sl_func_list; purefastpath = B_TRUE; } else { fast_funcs = cur_slot->sl_func_list; fast_slot = slottable->st_first; policyfastpath = B_TRUE; } (void) pthread_mutex_unlock(&cur_slot->sl_mutex); } if ((purefastpath || policyfastpath) && (!metaslot_enabled)) { goto config_complete; } /* * If we get here, there are more than 2 slots in the framework, * we need to set up metaslot if it is enabled */ if (metaslot_enabled) { rv = setup_metaslot(metaslot_entry); if (rv != CKR_OK) { goto conferror; } } config_complete: return (CKR_OK); conferror: /* * This cleanup code is only exercised when a major, * unrecoverable error like "out of memory" occurs. */ if (prov_funcs != NULL) { (void) prov_funcs->C_Finalize(NULL); } if (dldesc != NULL) { (void) dlclose(dldesc); } if (fullpath != NULL) { free(fullpath); fullpath = NULL; } if (prov_slots != NULL) { free(prov_slots); prov_slots = NULL; } return (rv); }
/* * The top level function for the "cryptoadm unload" subcommand. */ static int do_unload(int argc, char **argv) { cryptoadm_provider_t *prov = NULL; entry_t *pent = NULL; boolean_t in_kernel = B_FALSE; int rc = SUCCESS; char *provname = NULL; if (argc != 3) { usage(); return (ERROR_USAGE); } /* check if it is a kernel software provider */ prov = get_provider(argc, argv); if (prov == NULL) { cryptoerror(LOG_STDERR, gettext("unable to determine provider name.")); goto out; } provname = prov->cp_name; if (prov->cp_type != PROV_KEF_SOFT) { cryptoerror(LOG_STDERR, gettext("%s is not a valid kernel software provider."), provname); rc = FAILURE; goto out; } if (getzoneid() != GLOBAL_ZONEID) { /* * TRANSLATION_NOTE * "unload" could be either a literal keyword and hence * not to be translated, or a verb and translatable. * A choice was made to view it as a literal keyword. * "global" is keyword and not to be translated. */ cryptoerror(LOG_STDERR, gettext("%1$s for kernel providers " "is supported in the %2$s zone only"), "unload", "global"); rc = FAILURE; goto out; } if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) { cryptodebug("internal error"); rc = FAILURE; goto out; } else if (in_kernel == B_FALSE) { cryptoerror(LOG_STDERR, gettext("provider %s is not loaded or does not exist."), provname); rc = FAILURE; goto out; } /* Get kcf.conf entry. If none, build a new entry */ if ((pent = getent_kef(provname, NULL, NULL)) == NULL) { if ((pent = create_entry(provname)) == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); rc = FAILURE; goto out; } } /* If it is unloaded already, return */ if (!pent->load) { /* unloaded already */ cryptoerror(LOG_STDERR, gettext("failed to unload %s."), provname); rc = FAILURE; goto out; } else if (unload_kef_soft(provname) != FAILURE) { /* Mark as unloaded in kcf.conf */ pent->load = B_FALSE; rc = update_kcfconf(pent, MODIFY_MODE); } else { cryptoerror(LOG_STDERR, gettext("failed to unload %s."), provname); rc = FAILURE; } out: free(prov); free_entry(pent); return (rc); }
/* * Display the policy information for a kernel hardware provider. * This implements part of the "cryptoadm list -p" command. * * Parameters phardlist and psoftlist are supplied by getent_kef(). * If NULL, this function obtains it by calling get_kcfconf_info() via * getent_kef() internally. * Parameter pdevlist is supplied by check_kernel_for_hard(). * If NULL, this function obtains it by calling get_dev_list() via * check_kernel_for_hard() internally. */ int list_policy_for_hard(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist, crypto_get_dev_list_t *pdevlist) { entry_t *pent = NULL; boolean_t in_kernel; mechlist_t *pmechlist = NULL; char devname[MAXNAMELEN]; int inst_num; int count; int rc = SUCCESS; boolean_t has_random = B_FALSE; boolean_t has_mechs = B_FALSE; if (provname == NULL) { return (FAILURE); } /* * Check if the provider is valid. If it is valid, get the number of * mechanisms also. */ if (check_hardware_provider(provname, devname, &inst_num, &count) == FAILURE) { return (FAILURE); } /* Get the mechanism list for the kernel hardware provider */ if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) == SUCCESS) { has_random = filter_mechlist(&pmechlist, RANDOM); if (pmechlist != NULL) { has_mechs = B_TRUE; free_mechlist(pmechlist); } } else { cryptoerror(LOG_STDERR, gettext( "failed to retrieve the mechanism list for %s."), devname); return (rc); } /* * If the hardware provider has an entry in the kcf.conf file, * some of its mechanisms must have been disabled. Print out * the disabled list from the config file entry. Otherwise, * if it is active, then all the mechanisms for it are enabled. */ if ((pent = getent_kef(provname, phardlist, psoftlist)) != NULL) { print_kef_policy(provname, pent, has_random, has_mechs); free_entry(pent); return (SUCCESS); } else { if (check_kernel_for_hard(provname, pdevlist, &in_kernel) == FAILURE) { return (FAILURE); } else if (in_kernel == B_TRUE) { (void) printf(gettext( "%s: all mechanisms are enabled."), provname); if (has_random) /* * TRANSLATION_NOTE * "random" is a keyword and not to be * translated. */ (void) printf(gettext(" %s is enabled.\n"), "random"); else (void) printf("\n"); return (SUCCESS); } else { cryptoerror(LOG_STDERR, gettext("%s does not exist."), provname); return (FAILURE); } } }
/* * Disable a kernel hardware provider. * This implements the "cryptoadm disable" command for * kernel hardware providers. */ int disable_kef_hardware(char *provname, boolean_t rndflag, boolean_t allflag, mechlist_t *dislist) { crypto_load_dev_disabled_t *pload_dev_dis = NULL; mechlist_t *infolist = NULL; entry_t *pent = NULL; boolean_t new_dev_entry = B_FALSE; char devname[MAXNAMELEN]; int inst_num; int count; int fd = -1; int rc = SUCCESS; if (provname == NULL) { return (FAILURE); } /* * Check if the provider is valid. If it is valid, get the number of * mechanisms also. */ if (check_hardware_provider(provname, devname, &inst_num, &count) == FAILURE) { return (FAILURE); } /* Get the mechanism list for the kernel hardware provider */ if (get_dev_info(devname, inst_num, count, &infolist) == FAILURE) { return (FAILURE); } /* * Get the entry of this hardware provider from the config file. * If there is no entry yet, create one for it. */ if ((pent = getent_kef(provname, NULL, NULL)) == NULL) { if ((pent = create_entry(provname)) == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); free_mechlist(infolist); return (FAILURE); } new_dev_entry = B_TRUE; } /* * kCF treats random as an internal mechanism. So, we need to * filter it from the mechanism list here, if we are NOT disabling * or enabling the random feature. Note that we map random feature at * cryptoadm(1M) level to the "random" mechanism in kCF. */ if (!rndflag) { (void) filter_mechlist(&dislist, RANDOM); } /* Calculate the new disabled list */ if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) { free_mechlist(infolist); free_entry(pent); return (FAILURE); } free_mechlist(infolist); /* If no mechanisms are to be disabled, return */ if (pent->dis_count == 0) { free_entry(pent); return (SUCCESS); } /* Update the config file with the new entry or the updated entry */ if (new_dev_entry) { rc = update_kcfconf(pent, ADD_MODE); } else { rc = update_kcfconf(pent, MODIFY_MODE); } if (rc == FAILURE) { free_entry(pent); return (FAILURE); } /* Inform kernel about the new disabled mechanism list */ if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) { free_entry(pent); return (FAILURE); } free_entry(pent); if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); free(pload_dev_dis); return (FAILURE); } if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) { cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: %s", strerror(errno)); free(pload_dev_dis); (void) close(fd); return (FAILURE); } if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl return_value = " "%d", pload_dev_dis->dd_return_value); free(pload_dev_dis); (void) close(fd); return (FAILURE); } free(pload_dev_dis); (void) close(fd); return (SUCCESS); }
/* * Implement the "cryptoadm refresh" command for global zones. * That is, send the current contents of kcf.conf to the kernel via ioctl(). */ int refresh(void) { crypto_load_soft_config_t *pload_soft_conf = NULL; crypto_load_soft_disabled_t *pload_soft_dis = NULL; crypto_load_dev_disabled_t *pload_dev_dis = NULL; entrylist_t *pdevlist = NULL; entrylist_t *psoftlist = NULL; entrylist_t *ptr; int fd = -1; int rc = SUCCESS; int err; if (get_kcfconf_info(&pdevlist, &psoftlist) == FAILURE) { cryptoerror(LOG_ERR, "failed to retrieve the providers' " "information from the configuration file - %s.", _PATH_KCF_CONF); return (FAILURE); } if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(err)); free(psoftlist); free(pdevlist); return (FAILURE); } /* * For each software provider module, pass two sets of information to * the kernel: the supported list and the disabled list. */ for (ptr = psoftlist; ptr != NULL; ptr = ptr->next) { entry_t *pent = ptr->pent; /* load the supported list */ if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) { cryptodebug("setup_soft_conf() failed"); rc = FAILURE; break; } if (!pent->load) { /* unloaded--mark as loaded */ pent->load = B_TRUE; rc = update_kcfconf(pent, MODIFY_MODE); if (rc != SUCCESS) { free(pload_soft_conf); break; } } if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s", strerror(errno)); free(pload_soft_conf); rc = FAILURE; break; } if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl " "return_value = %d", pload_soft_conf->sc_return_value); free(pload_soft_conf); rc = FAILURE; break; } free(pload_soft_conf); /* load the disabled list */ if (ptr->pent->dis_count != 0) { pload_soft_dis = setup_soft_dis(ptr->pent); if (pload_soft_dis == NULL) { cryptodebug("setup_soft_dis() failed"); free(pload_soft_dis); rc = FAILURE; break; } if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl " "failed: %s", strerror(errno)); free(pload_soft_dis); rc = FAILURE; break; } if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl " "return_value = %d", pload_soft_dis->sd_return_value); free(pload_soft_dis); rc = FAILURE; break; } free(pload_soft_dis); } } if (rc != SUCCESS) { (void) close(fd); return (rc); } /* * For each hardware provider module, pass the disabled list * information to the kernel. */ for (ptr = pdevlist; ptr != NULL; ptr = ptr->next) { /* load the disabled list */ if (ptr->pent->dis_count != 0) { pload_dev_dis = setup_dev_dis(ptr->pent); if (pload_dev_dis == NULL) { rc = FAILURE; break; } if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) { cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl " "failed: %s", strerror(errno)); free(pload_dev_dis); rc = FAILURE; break; } if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl " "return_value = %d", pload_dev_dis->dd_return_value); free(pload_dev_dis); rc = FAILURE; break; } free(pload_dev_dis); } } /* * handle fips_status=enabled|disabled */ { int pkcs11_fips_mode = 0; /* Get FIPS-140 status from pkcs11.conf */ fips_status_pkcs11conf(&pkcs11_fips_mode); if (pkcs11_fips_mode == CRYPTO_FIPS_MODE_ENABLED) { rc = do_fips_actions(FIPS140_ENABLE, REFRESH); } else { rc = do_fips_actions(FIPS140_DISABLE, REFRESH); } } (void) close(fd); return (rc); }
/* * Unload the kernel software provider. Before calling this function, the * caller should check to see if the provider is in the kernel. * * This routine makes 2 ioctl calls to remove it completely from the kernel: * CRYPTO_UNLOAD_SOFT_MODULE - does a modunload of the KCF module * CRYPTO_LOAD_SOFT_DISABLED - updates kernel disabled mechanism list * * This implements part of "cryptoadm unload" and "cryptoadm uninstall". */ int unload_kef_soft(char *provname) { crypto_unload_soft_module_t *punload_soft = NULL; crypto_load_soft_disabled_t *pload_soft_dis = NULL; entry_t *pent = NULL; int fd = -1; int err; if (provname == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } pent = getent_kef(provname, NULL, NULL); if (pent == NULL) { /* not in kcf.conf */ /* Construct an entry using the provname */ pent = create_entry(provname); if (pent == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); return (FAILURE); } } /* Open the admin_ioctl_device */ if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(err)); free_entry(pent); return (FAILURE); } /* Inform kernel to unload this software module */ if ((punload_soft = setup_unload_soft(pent)) == NULL) { free_entry(pent); (void) close(fd); return (FAILURE); } if (ioctl(fd, CRYPTO_UNLOAD_SOFT_MODULE, punload_soft) == -1) { cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl failed: %s", strerror(errno)); free_entry(pent); free(punload_soft); (void) close(fd); return (FAILURE); } if (punload_soft->sm_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl return_value = " "%d", punload_soft->sm_return_value); /* * If the return value is CRYPTO_UNKNOWN_PROVIDER, it means * that the provider is not registered yet. Should just * continue. */ if (punload_soft->sm_return_value != CRYPTO_UNKNOWN_PROVIDER) { free_entry(pent); free(punload_soft); (void) close(fd); return (FAILURE); } } free(punload_soft); /* Inform kernel to remove the disabled entries if any */ if (pent->dis_count == 0) { free_entry(pent); (void) close(fd); return (SUCCESS); } else { free_mechlist(pent->dislist); pent->dislist = NULL; pent->dis_count = 0; } if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) { free_entry(pent); (void) close(fd); return (FAILURE); } /* pent is no longer needed; free it */ free_entry(pent); if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s", strerror(errno)); free(pload_soft_dis); (void) close(fd); return (FAILURE); } if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = " "%d", pload_soft_dis->sd_return_value); free(pload_soft_dis); (void) close(fd); return (FAILURE); } free(pload_soft_dis); (void) close(fd); return (SUCCESS); }
int pk_gencsr(int argc, char *argv[]) { KMF_RETURN rv; int opt; extern int optind_av; extern char *optarg_av; KMF_KEYSTORE_TYPE kstype = 0; char *subject = NULL; char *tokenname = NULL; char *dir = NULL; char *prefix = NULL; int keylen = PK_DEFAULT_KEYLENGTH; char *certlabel = NULL; char *outcsr = NULL; char *outkey = NULL; char *format = NULL; char *altname = NULL; char *kustr = NULL; char *ekustr = NULL; char *hashname = NULL; uint16_t kubits = 0; char *keytype = PK_DEFAULT_KEYTYPE; KMF_HANDLE_T kmfhandle = NULL; KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1; KMF_KEY_ALG keyAlg = KMF_RSA; KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_SHA1WithRSA; boolean_t interactive = B_FALSE; char *subname = NULL; KMF_CREDENTIAL tokencred = {NULL, 0}; KMF_GENERALNAMECHOICES alttype = 0; int altcrit = 0, kucrit = 0; EKU_LIST *ekulist = NULL; KMF_OID *curveoid = NULL; /* ECC */ KMF_OID *hashoid = NULL; int y_flag = 0; while ((opt = getopt_av(argc, argv, "ik:(keystore)s:(subject)n:(nickname)A:(altname)" "u:(keyusage)T:(token)d:(dir)p:(prefix)t:(keytype)" "y:(keylen)l:(label)c:(outcsr)e:(eku)C:(curve)" "K:(outkey)F:(format)E(listcurves)h:(hash)")) != EOF) { switch (opt) { case 'A': altname = optarg_av; break; case 'i': if (interactive) return (PK_ERR_USAGE); else if (subject) { cryptoerror(LOG_STDERR, gettext("Interactive (-i) and " "subject options are mutually " "exclusive.\n")); return (PK_ERR_USAGE); } else interactive = B_TRUE; break; case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 's': if (subject) return (PK_ERR_USAGE); else if (interactive) { cryptoerror(LOG_STDERR, gettext("Interactive (-i) and " "subject options are mutually " "exclusive.\n")); return (PK_ERR_USAGE); } else subject = optarg_av; break; case 'l': case 'n': if (certlabel) return (PK_ERR_USAGE); certlabel = optarg_av; break; case 'T': if (tokenname) return (PK_ERR_USAGE); tokenname = optarg_av; break; case 'd': dir = optarg_av; break; case 'p': if (prefix) return (PK_ERR_USAGE); prefix = optarg_av; break; case 't': keytype = optarg_av; break; case 'u': kustr = optarg_av; break; case 'y': if (sscanf(optarg_av, "%d", &keylen) != 1) { cryptoerror(LOG_STDERR, gettext("Unrecognized " "key length (%s)\n"), optarg_av); return (PK_ERR_USAGE); } y_flag++; break; case 'c': if (outcsr) return (PK_ERR_USAGE); outcsr = optarg_av; break; case 'K': if (outkey) return (PK_ERR_USAGE); outkey = optarg_av; break; case 'F': if (format) return (PK_ERR_USAGE); format = optarg_av; break; case 'e': ekustr = optarg_av; break; case 'C': curveoid = ecc_name_to_oid(optarg_av); if (curveoid == NULL) { cryptoerror(LOG_STDERR, gettext("Unrecognized ECC " "curve.\n")); return (PK_ERR_USAGE); } break; case 'E': /* * This argument is only to be used * by itself, no other options should * be present. */ if (argc != 2) { cryptoerror(LOG_STDERR, gettext("listcurves has no other " "options.\n")); return (PK_ERR_USAGE); } show_ecc_curves(); return (0); case 'h': hashname = optarg_av; hashoid = ecc_name_to_oid(optarg_av); if (hashoid == NULL) { cryptoerror(LOG_STDERR, gettext("Unrecognized hash.\n")); return (PK_ERR_USAGE); } break; default: cryptoerror(LOG_STDERR, gettext( "unrecognized gencsr option '%s'\n"), argv[optind_av]); return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) { return (PK_ERR_USAGE); } /* Assume keystore = PKCS#11 if not specified. */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; DIR_OPTION_CHECK(kstype, dir); if (EMPTYSTRING(outcsr) && interactive) { (void) get_filename("CSR", &outcsr); } if (EMPTYSTRING(outcsr)) { (void) printf(gettext("A filename must be specified to hold" "the final certificate request data.\n")); return (PK_ERR_USAGE); } /* * verify that the outcsr file does not already exist * and that it can be created. */ rv = verify_file(outcsr); if (rv == KMF_ERR_OPEN_FILE) { cryptoerror(LOG_STDERR, gettext("Warning: file \"%s\" exists, " "will be overwritten."), outcsr); if (yesno(gettext("Continue with gencsr? "), gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { return (0); } else { /* remove the file */ (void) unlink(outcsr); } } else if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Warning: error accessing \"%s\""), outcsr); return (rv); } if ((kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN)) { if (EMPTYSTRING(certlabel) && interactive) (void) get_certlabel(&certlabel); if (EMPTYSTRING(certlabel)) { cryptoerror(LOG_STDERR, gettext("A label must be " "specified to create a certificate request.\n")); return (PK_ERR_USAGE); } } else if (kstype == KMF_KEYSTORE_OPENSSL) { if (EMPTYSTRING(outkey) && interactive) (void) get_filename("private key", &outkey); if (EMPTYSTRING(outkey)) { cryptoerror(LOG_STDERR, gettext("A key filename " "must be specified to create a certificate " "request.\n")); return (PK_ERR_USAGE); } } if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) { cryptoerror(LOG_STDERR, gettext("Error parsing format string (%s).\n"), format); return (PK_ERR_USAGE); } if (format && fmt != KMF_FORMAT_ASN1 && fmt != KMF_FORMAT_PEM) { cryptoerror(LOG_STDERR, gettext("CSR must be DER or PEM format.\n")); return (PK_ERR_USAGE); } /* * Check the subject name. * If interactive is true, get it now interactively. */ if (interactive) { if (get_subname(&subname) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Failed to get the " "subject name interactively.\n")); return (PK_ERR_USAGE); } } else { if (EMPTYSTRING(subject)) { cryptoerror(LOG_STDERR, gettext("A subject name or " "-i must be specified to create a certificate " "request.\n")); return (PK_ERR_USAGE); } else { subname = strdup(subject); if (subname == NULL) { cryptoerror(LOG_STDERR, gettext("Out of memory.\n")); return (PK_ERR_SYSTEM); } } } if (altname != NULL) { rv = verify_altname(altname, &alttype, &altcrit); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject AltName " "must be specified as a name=value pair. " "See the man page for details.")); goto end; } else { /* advance the altname past the '=' sign */ char *p = strchr(altname, '='); if (p != NULL) altname = p + 1; } } if (kustr != NULL) { rv = verify_keyusage(kustr, &kubits, &kucrit); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("KeyUsage " "must be specified as a comma-separated list. " "See the man page for details.")); goto end; } } if (ekustr != NULL) { rv = verify_ekunames(ekustr, &ekulist); if (rv != KMF_OK) { (void) fprintf(stderr, gettext("EKUs must " "be specified as a comma-separated list. " "See the man page for details.\n")); rv = PK_ERR_USAGE; goto end; } } if ((rv = Str2KeyType(keytype, hashoid, &keyAlg, &sigAlg)) != 0) { cryptoerror(LOG_STDERR, gettext("Unsupported key/hash combination (%s/%s).\n"), keytype, (hashname ? hashname : "none")); goto end; } if (curveoid != NULL && keyAlg != KMF_ECDSA) { cryptoerror(LOG_STDERR, gettext("EC curves are only " "valid for EC keytypes.\n")); return (PK_ERR_USAGE); } if (keyAlg == KMF_ECDSA && curveoid == NULL) { cryptoerror(LOG_STDERR, gettext("A curve must be " "specifed when using EC keys.\n")); return (PK_ERR_USAGE); } if (keyAlg == KMF_ECDSA && kstype == KMF_KEYSTORE_OPENSSL) { (void) fprintf(stderr, gettext("ECC certificates are" "only supported with the pkcs11 and nss keystores\n")); rv = PK_ERR_USAGE; goto end; } /* Adjust default keylength for NSS and DSA */ if (keyAlg == KMF_DSA && !y_flag && kstype == KMF_KEYSTORE_NSS) keylen = 1024; if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) { if (tokenname == NULL || !strlen(tokenname)) { if (kstype == KMF_KEYSTORE_NSS) { tokenname = "internal"; } else { tokenname = PK_DEFAULT_PK11TOKEN; } } (void) get_token_password(kstype, tokenname, &tokencred); } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); return (PK_ERR_USAGE); } if (kstype == KMF_KEYSTORE_NSS) { if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; rv = gencsr_nss(kmfhandle, tokenname, subname, altname, alttype, altcrit, certlabel, dir, prefix, keyAlg, keylen, kubits, kucrit, fmt, outcsr, &tokencred, ekulist, sigAlg, curveoid); } else if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = gencsr_pkcs11(kmfhandle, tokenname, subname, altname, alttype, altcrit, certlabel, keyAlg, keylen, kubits, kucrit, fmt, outcsr, &tokencred, ekulist, sigAlg, curveoid); } else if (kstype == KMF_KEYSTORE_OPENSSL) { rv = gencsr_file(kmfhandle, keyAlg, keylen, fmt, subname, altname, alttype, altcrit, kubits, kucrit, outcsr, outkey, ekulist, sigAlg); } end: if (rv != KMF_OK) { display_error(kmfhandle, rv, gettext("Error creating CSR or keypair")); if (rv == KMF_ERR_RDN_PARSER) { cryptoerror(LOG_STDERR, gettext("subject or " "issuer name must be in proper DN format.\n")); } } if (ekulist != NULL) free_eku_list(ekulist); if (subname) free(subname); if (tokencred.cred != NULL) free(tokencred.cred); (void) kmf_finalize(kmfhandle); if (rv != KMF_OK) return (PK_ERR_USAGE); return (0); }
static KMF_RETURN gencsr_file(KMF_HANDLE_T kmfhandle, KMF_KEY_ALG keyAlg, int keylen, KMF_ENCODE_FORMAT fmt, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, uint16_t kubits, int kucrit, char *outcsr, char *outkey, EKU_LIST *ekulist, KMF_ALGORITHM_INDEX sigAlg) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; KMF_X509_NAME csrSubject; KMF_CSR_DATA csr; KMF_DATA signedCsr = {NULL, 0}; char *fullcsrpath = NULL; char *fullkeypath = NULL; (void) memset(&csr, 0, sizeof (csr)); (void) memset(&csrSubject, 0, sizeof (csrSubject)); if (EMPTYSTRING(outcsr) || EMPTYSTRING(outkey)) { cryptoerror(LOG_STDERR, gettext("No output file was specified for " "the csr or key\n")); return (KMF_ERR_BAD_PARAMETER); } fullcsrpath = strdup(outcsr); if (verify_file(fullcsrpath)) { cryptoerror(LOG_STDERR, gettext("Cannot write the indicated output " "certificate file (%s).\n"), fullcsrpath); free(fullcsrpath); return (PK_ERR_USAGE); } /* If the subject name cannot be parsed, flag it now and exit */ if ((kmfrv = kmf_dn_parser(subject, &csrSubject)) != KMF_OK) { return (kmfrv); } /* * Share the "genkeypair" routine for creating the keypair. */ kmfrv = genkeypair_file(kmfhandle, keyAlg, keylen, fmt, outkey, &prik, &pubk); if (kmfrv != KMF_OK) return (kmfrv); SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "SetCSRPubKey"); SET_VALUE(kmf_set_csr_version(&csr, 2), "SetCSRVersion"); SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), "kmf_set_csr_subject"); SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "kmf_set_csr_sig_alg"); if (altname != NULL) { SET_VALUE(kmf_set_csr_subject_altname(&csr, altname, altcrit, alttype), "kmf_set_csr_subject_altname"); } if (kubits != NULL) { SET_VALUE(kmf_set_csr_ku(&csr, kucrit, kubits), "kmf_set_csr_ku"); } if (ekulist != NULL) { int i; for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { SET_VALUE(kmf_add_csr_eku(&csr, &ekulist->ekulist[i], ekulist->critlist[i]), "Extended Key Usage"); } } if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) == KMF_OK) { kmfrv = kmf_create_csr_file(&signedCsr, fmt, fullcsrpath); } cleanup: if (fullkeypath) free(fullkeypath); if (fullcsrpath) free(fullcsrpath); kmf_free_data(&signedCsr); kmf_free_kmf_key(kmfhandle, &prik); kmf_free_signed_csr(&csr); return (kmfrv); }
int pk_gencert(int argc, char *argv[]) { int rv; int opt; extern int optind_av; extern char *optarg_av; KMF_KEYSTORE_TYPE kstype = 0; char *subject = NULL; char *tokenname = NULL; char *dir = NULL; char *prefix = NULL; char *keytype = PK_DEFAULT_KEYTYPE; int keylen = PK_DEFAULT_KEYLENGTH; char *trust = NULL; char *lifetime = NULL; char *certlabel = NULL; char *outcert = NULL; char *outkey = NULL; char *format = NULL; char *serstr = NULL; char *altname = NULL; char *keyusagestr = NULL; char *ekustr = NULL; char *hashname = NULL; KMF_GENERALNAMECHOICES alttype = 0; KMF_BIGINT serial = { NULL, 0 }; uint32_t ltime; KMF_HANDLE_T kmfhandle = NULL; KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1; KMF_KEY_ALG keyAlg = KMF_RSA; KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_SHA1WithRSA; boolean_t interactive = B_FALSE; char *subname = NULL; KMF_CREDENTIAL tokencred = { NULL, 0 }; uint16_t kubits = 0; int altcrit = 0, kucrit = 0; EKU_LIST *ekulist = NULL; KMF_OID *curveoid = NULL; /* ECC */ KMF_OID *hashoid = NULL; int y_flag = 0; while ((opt = getopt_av(argc, argv, "ik:(keystore)s:(subject)n:(nickname)A:(altname)" "T:(token)d:(dir)p:(prefix)t:(keytype)y:(keylen)" "r:(trust)L:(lifetime)l:(label)c:(outcert)e:(eku)" "K:(outkey)S:(serial)F:(format)u:(keyusage)C:(curve)" "E(listcurves)h:(hash)")) != EOF) { if (opt != 'i' && opt != 'E' && EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'A': altname = optarg_av; break; case 'i': if (interactive || subject) return (PK_ERR_USAGE); else interactive = B_TRUE; break; case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 's': if (interactive || subject) return (PK_ERR_USAGE); else subject = optarg_av; break; case 'l': case 'n': if (certlabel) return (PK_ERR_USAGE); certlabel = optarg_av; break; case 'T': if (tokenname) return (PK_ERR_USAGE); tokenname = optarg_av; break; case 'd': if (dir) return (PK_ERR_USAGE); dir = optarg_av; break; case 'p': if (prefix) return (PK_ERR_USAGE); prefix = optarg_av; break; case 't': keytype = optarg_av; break; case 'u': keyusagestr = optarg_av; break; case 'y': if (sscanf(optarg_av, "%d", &keylen) != 1) { cryptoerror(LOG_STDERR, gettext("key length must be" "a numeric value (%s)\n"), optarg_av); return (PK_ERR_USAGE); } y_flag++; break; case 'r': if (trust) return (PK_ERR_USAGE); trust = optarg_av; break; case 'L': if (lifetime) return (PK_ERR_USAGE); lifetime = optarg_av; break; case 'c': if (outcert) return (PK_ERR_USAGE); outcert = optarg_av; break; case 'K': if (outkey) return (PK_ERR_USAGE); outkey = optarg_av; break; case 'S': serstr = optarg_av; break; case 'F': if (format) return (PK_ERR_USAGE); format = optarg_av; break; case 'e': ekustr = optarg_av; break; case 'C': curveoid = ecc_name_to_oid(optarg_av); if (curveoid == NULL) { cryptoerror(LOG_STDERR, gettext("Unrecognized ECC " "curve.\n")); return (PK_ERR_USAGE); } break; case 'E': /* * This argument is only to be used * by itself, no other options should * be present. */ if (argc != 2) { cryptoerror(LOG_STDERR, gettext("listcurves has no other " "options.\n")); return (PK_ERR_USAGE); } show_ecc_curves(); return (0); case 'h': hashname = optarg_av; hashoid = ecc_name_to_oid(optarg_av); if (hashoid == NULL) { cryptoerror(LOG_STDERR, gettext("Unrecognized hash.\n")); return (PK_ERR_USAGE); } break; default: return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) { return (PK_ERR_USAGE); } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); return (PK_ERR_USAGE); } /* Assume keystore = PKCS#11 if not specified. */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; if ((kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN)) { if (interactive && EMPTYSTRING(certlabel)) { (void) get_certlabel(&certlabel); } /* It better not be empty now */ if (EMPTYSTRING(certlabel)) { cryptoerror(LOG_STDERR, gettext("A label must be " "specified to create a self-signed certificate." "\n")); return (PK_ERR_USAGE); } } else if (kstype == KMF_KEYSTORE_OPENSSL && EMPTYSTRING(outcert)) { cryptoerror(LOG_STDERR, gettext("A certificate filename must " "be specified to create a self-signed certificate.\n")); return (PK_ERR_USAGE); } DIR_OPTION_CHECK(kstype, dir); if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) { cryptoerror(LOG_STDERR, gettext("Error parsing format string (%s).\n"), format); return (PK_ERR_USAGE); } if (Str2Lifetime(lifetime, <ime) != 0) { cryptoerror(LOG_STDERR, gettext("Error parsing lifetime string\n")); return (PK_ERR_USAGE); } if (Str2KeyType(keytype, hashoid, &keyAlg, &sigAlg) != 0) { cryptoerror(LOG_STDERR, gettext("Unsupported key/hash combination (%s/%s).\n"), keytype, (hashname ? hashname : "none")); return (PK_ERR_USAGE); } if (curveoid != NULL && keyAlg != KMF_ECDSA) { cryptoerror(LOG_STDERR, gettext("EC curves are only " "valid for EC keytypes.\n")); return (PK_ERR_USAGE); } if (keyAlg == KMF_ECDSA && curveoid == NULL) { cryptoerror(LOG_STDERR, gettext("A curve must be " "specifed when using EC keys.\n")); return (PK_ERR_USAGE); } /* Adjust default keylength for NSS and DSA */ if (keyAlg == KMF_DSA && !y_flag && kstype == KMF_KEYSTORE_NSS) keylen = 1024; /* * Check the subject name. * If interactive is true, get it now interactively. */ if (interactive) { subname = NULL; if (get_subname(&subname) != KMF_OK || subname == NULL) { cryptoerror(LOG_STDERR, gettext("Failed to get the " "subject name interactively.\n")); return (PK_ERR_USAGE); } if (serstr == NULL) { (void) get_serial(&serstr); } } else { if (EMPTYSTRING(subject)) { cryptoerror(LOG_STDERR, gettext("A subject name or " "-i must be specified to create a self-signed " "certificate.\n")); return (PK_ERR_USAGE); } else { subname = strdup(subject); if (subname == NULL) { cryptoerror(LOG_STDERR, gettext("Out of memory.\n")); return (PK_ERR_SYSTEM); } } } if (serstr == NULL) { (void) fprintf(stderr, gettext("A serial number " "must be specified as a hex number when creating" " a self-signed certificate " "(ex: serial=0x0102030405feedface)\n")); rv = PK_ERR_USAGE; goto end; } else { uchar_t *bytes = NULL; size_t bytelen; rv = kmf_hexstr_to_bytes((uchar_t *)serstr, &bytes, &bytelen); if (rv != KMF_OK || bytes == NULL) { (void) fprintf(stderr, gettext("serial number " "must be specified as a hex number " "(ex: 0x0102030405ffeeddee)\n")); rv = PK_ERR_USAGE; goto end; } serial.val = bytes; serial.len = bytelen; } if (altname != NULL) { rv = verify_altname(altname, &alttype, &altcrit); if (rv != KMF_OK) { (void) fprintf(stderr, gettext("Subject AltName " "must be specified as a name=value pair. " "See the man page for details.\n")); rv = PK_ERR_USAGE; goto end; } else { /* advance the altname past the '=' sign */ char *p = strchr(altname, '='); if (p != NULL) altname = p + 1; } } if (keyusagestr != NULL) { rv = verify_keyusage(keyusagestr, &kubits, &kucrit); if (rv != KMF_OK) { (void) fprintf(stderr, gettext("KeyUsage " "must be specified as a comma-separated list. " "See the man page for details.\n")); rv = PK_ERR_USAGE; goto end; } } if (ekustr != NULL) { rv = verify_ekunames(ekustr, &ekulist); if (rv != KMF_OK) { (void) fprintf(stderr, gettext("EKUs must " "be specified as a comma-separated list. " "See the man page for details.\n")); rv = PK_ERR_USAGE; goto end; } } if (keyAlg == KMF_ECDSA && kstype == KMF_KEYSTORE_OPENSSL) { (void) fprintf(stderr, gettext("ECC certificates are" "only supported with the pkcs11 and nss keystores\n")); rv = PK_ERR_USAGE; goto end; } if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) { if (tokenname == NULL || !strlen(tokenname)) { if (kstype == KMF_KEYSTORE_NSS) { tokenname = "internal"; } else { tokenname = PK_DEFAULT_PK11TOKEN; } } (void) get_token_password(kstype, tokenname, &tokencred); } if (kstype == KMF_KEYSTORE_NSS) { if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; rv = gencert_nss(kmfhandle, tokenname, subname, altname, alttype, altcrit, certlabel, dir, prefix, keyAlg, sigAlg, keylen, trust, ltime, &serial, kubits, kucrit, &tokencred, ekulist, curveoid); } else if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = gencert_pkcs11(kmfhandle, tokenname, subname, altname, alttype, altcrit, certlabel, keyAlg, sigAlg, keylen, ltime, &serial, kubits, kucrit, &tokencred, ekulist, curveoid); } else if (kstype == KMF_KEYSTORE_OPENSSL) { rv = gencert_file(kmfhandle, keyAlg, sigAlg, keylen, fmt, ltime, subname, altname, alttype, altcrit, &serial, kubits, kucrit, outcert, outkey, ekulist); } if (rv != KMF_OK) display_error(kmfhandle, rv, gettext("Error creating certificate and keypair")); end: if (ekulist != NULL) free_eku_list(ekulist); if (subname) free(subname); if (tokencred.cred != NULL) free(tokencred.cred); if (serial.val != NULL) free(serial.val); (void) kmf_finalize(kmfhandle); return (rv); }
/* * enable metaslot and some of its configuration options * * If mechlist==NULL, and the other flags are false, or not specified, * just enable the metaslot feature. * * token: if specified, indicate label of token to be used as keystore. * slot: if specified, indicate slot to be used as keystore. * use_default: if true, indicate to use the default keystore. It should * not be specified if either token or slot is specified. * mechlist: list of mechanisms to enable * allflag: if true, indicates all mechanisms should be enabled. * auto_key_migrate_flag: if true, indicates auto key migrate should be enabled */ int enable_metaslot(char *token, char *slot, boolean_t use_default, mechlist_t *mechlist, boolean_t allflag, boolean_t auto_key_migrate_flag) { uentry_t *puent; int rc = SUCCESS; if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) { cryptoerror(LOG_STDERR, gettext("metaslot entry doesn't exist.")); return (FAILURE); } puent->flag_metaslot_enabled = B_TRUE; if (auto_key_migrate_flag) { /* need to enable auto_key_migrate */ puent->flag_metaslot_auto_key_migrate = B_TRUE; } if (allflag) { /* * If enabling all, what needs to be done are cleaning up the * policylist and setting the "flag_enabledlist" flag to * B_FALSE. */ free_umechlist(puent->policylist); puent->policylist = NULL; puent->count = 0; puent->flag_enabledlist = B_FALSE; rc = SUCCESS; } else { if (mechlist) { if (puent->flag_enabledlist == B_TRUE) { /* * The current default policy mode of this * library is "all are disabled, except ...", * so if a specified mechanism is not in the * exception list (policylist), add it. */ rc = update_policylist(puent, mechlist, ADD_MODE); } else { /* * The current default policy mode of this * library is "all are enabled, except", so if * a specified mechanism is in the exception * list (policylist), delete it. */ rc = update_policylist(puent, mechlist, DELETE_MODE); } } } if (rc != SUCCESS) { goto finish; } if (!use_default && !token && !slot) { /* no need to change metaslot keystore */ goto write_to_file; } (void) bzero((char *)puent->metaslot_ks_token, TOKEN_LABEL_SIZE); (void) bzero((char *)puent->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE); if (use_default) { (void) strlcpy((char *)puent->metaslot_ks_token, SOFT_TOKEN_LABEL, TOKEN_LABEL_SIZE); (void) strlcpy((char *)puent->metaslot_ks_slot, SOFT_SLOT_DESCRIPTION, SLOT_DESCRIPTION_SIZE); } else { if (token) { (void) strlcpy((char *)puent->metaslot_ks_token, token, TOKEN_LABEL_SIZE); } if (slot) { (void) strlcpy((char *)puent->metaslot_ks_slot, slot, SLOT_DESCRIPTION_SIZE); } } write_to_file: rc = update_pkcs11conf(puent); finish: free_uentry(puent); return (rc); }
/* * Disable a kernel software provider. * This implements the "cryptoadm disable" command for * kernel software providers. */ int disable_kef_software(char *provname, boolean_t rndflag, boolean_t allflag, mechlist_t *dislist) { crypto_load_soft_disabled_t *pload_soft_dis = NULL; mechlist_t *infolist = NULL; entry_t *pent = NULL; entrylist_t *phardlist = NULL; entrylist_t *psoftlist = NULL; boolean_t in_kernel = B_FALSE; int fd = -1; int rc = SUCCESS; if (provname == NULL) { return (FAILURE); } /* * Check if the kernel software provider is currently unloaded. * If it is unloaded, return FAILURE, because the disable subcommand * can not perform on inactive (unloaded) providers. */ if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) { return (FAILURE); } else if (in_kernel == B_FALSE) { cryptoerror(LOG_STDERR, gettext("%s is not loaded or does not exist."), provname); return (FAILURE); } if (get_kcfconf_info(&phardlist, &psoftlist) == FAILURE) { cryptoerror(LOG_ERR, "failed to retrieve the providers' " "information from the configuration file - %s.", _PATH_KCF_CONF); return (FAILURE); } /* * Get the entry of this provider from the kcf.conf file, if any. * Otherwise, create a new kcf.conf entry for writing back to the file. */ pent = getent_kef(provname, phardlist, psoftlist); if (pent == NULL) { /* create a new entry */ pent = create_entry(provname); if (pent == NULL) { cryptodebug("out of memory."); rc = FAILURE; goto out; } } /* Get the mechanism list for the software provider from the kernel */ if (get_soft_info(provname, &infolist, phardlist, psoftlist) == FAILURE) { rc = FAILURE; goto out; } if ((infolist != NULL) && (infolist->name[0] != '\0')) { /* * Replace the supportedlist from kcf.conf with possibly * more-up-to-date list from the kernel. This is the case * for default software providers that had more mechanisms * added in the current version of the kernel. */ free_mechlist(pent->suplist); pent->suplist = infolist; } /* * kCF treats random as an internal mechanism. So, we need to * filter it from the mechanism list here, if we are NOT disabling * or enabling the random feature. Note that we map random feature at * cryptoadm(1M) level to the "random" mechanism in kCF. */ if (!rndflag) { (void) filter_mechlist(&infolist, RANDOM); } /* Calculate the new disabled list */ if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) { rc = FAILURE; goto out; } /* Update the kcf.conf file with the updated entry */ if (update_kcfconf(pent, MODIFY_MODE) == FAILURE) { rc = FAILURE; goto out; } /* Setup argument to inform kernel about the new disabled list. */ if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) { rc = FAILURE; goto out; } if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s for RW: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); rc = FAILURE; goto out; } /* Inform kernel about the new disabled list. */ if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s", strerror(errno)); rc = FAILURE; goto out; } if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = " "%d", pload_soft_dis->sd_return_value); rc = FAILURE; goto out; } out: free_entrylist(phardlist); free_entrylist(psoftlist); free_mechlist(infolist); free_entry(pent); free(pload_soft_dis); if (fd != -1) (void) close(fd); return (rc); }
int list_metaslot_info(boolean_t show_mechs, boolean_t verbose, mechlist_t *mechlist) { int rc = SUCCESS; CK_RV rv; CK_SLOT_INFO slot_info; CK_TOKEN_INFO token_info; CK_MECHANISM_TYPE_PTR pmech_list = NULL; CK_ULONG mech_count; int i; CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR); CK_FUNCTION_LIST_PTR funcs; void *dldesc = NULL; boolean_t lib_initialized = B_FALSE; uentry_t *puent; char buf[128]; /* * Display the system-wide metaslot settings as specified * in pkcs11.conf file. */ if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) { cryptoerror(LOG_STDERR, gettext("metaslot entry doesn't exist.")); return (FAILURE); } (void) printf(gettext("System-wide Meta Slot Configuration:\n")); /* * TRANSLATION_NOTE * Strictly for appearance's sake, this line should be as long as * the length of the translated text above. */ (void) printf(gettext("------------------------------------\n")); (void) printf(gettext("Status: %s\n"), puent->flag_metaslot_enabled ? gettext("enabled") : gettext("disabled")); (void) printf(gettext("Sensitive Token Object Automatic Migrate: %s\n"), puent->flag_metaslot_auto_key_migrate ? gettext("enabled") : gettext("disabled")); bzero(buf, sizeof (buf)); if (memcmp(puent->metaslot_ks_slot, buf, SLOT_DESCRIPTION_SIZE) != 0) { (void) printf(gettext("Persistent object store slot: %s\n"), puent->metaslot_ks_slot); } if (memcmp(puent->metaslot_ks_token, buf, TOKEN_LABEL_SIZE) != 0) { (void) printf(gettext("Persistent object store token: %s\n"), puent->metaslot_ks_token); } if ((!verbose) && (!show_mechs)) { return (SUCCESS); } if (verbose) { (void) printf(gettext("\nDetailed Meta Slot Information:\n")); /* * TRANSLATION_NOTE * Strictly for appearance's sake, this line should be as * long as the length of the translated text above. */ (void) printf(gettext("-------------------------------\n")); } /* * Need to actually make calls to libpkcs11.so to get * information about metaslot. */ dldesc = dlopen(UEF_FRAME_LIB, RTLD_NOW); if (dldesc == NULL) { char *dl_error; dl_error = dlerror(); cryptodebug("Cannot load PKCS#11 framework library. " "dlerror:%s", dl_error); return (FAILURE); } /* Get the pointer to library's C_GetFunctionList() */ Tmp_C_GetFunctionList = (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList"); if (Tmp_C_GetFunctionList == NULL) { cryptodebug("Cannot get the address of the C_GetFunctionList " "from framework"); rc = FAILURE; goto finish; } /* Get the provider's function list */ rv = Tmp_C_GetFunctionList(&funcs); if (rv != CKR_OK) { cryptodebug("failed to call C_GetFunctionList in " "framework library"); rc = FAILURE; goto finish; } /* Initialize this provider */ rv = funcs->C_Initialize(NULL_PTR); if (rv != CKR_OK) { cryptodebug("C_Initialize failed with error code 0x%x\n", rv); rc = FAILURE; goto finish; } else { lib_initialized = B_TRUE; } /* * We know for sure that metaslot is slot 0 in the framework, * so, we will do a C_GetSlotInfo() trying to see if it works. * If it fails with CKR_SLOT_ID_INVALID, we know that metaslot * is not really enabled. */ rv = funcs->C_GetSlotInfo(METASLOT_ID, &slot_info); if (rv == CKR_SLOT_ID_INVALID) { (void) printf(gettext("actual status: disabled.\n")); /* * Even if the -m and -v flag is supplied, there's nothing * interesting to display about metaslot since it is disabled, * so, just stop right here. */ goto finish; } if (rv != CKR_OK) { cryptodebug("C_GetSlotInfo failed with error " "code 0x%x\n", rv); rc = FAILURE; goto finish; } if (!verbose) { goto display_mechs; } (void) printf(gettext("actual status: enabled.\n")); (void) printf(gettext("Description: %.64s\n"), slot_info.slotDescription); (void) printf(gettext("Token Present: %s\n"), (slot_info.flags & CKF_TOKEN_PRESENT ? gettext("True") : gettext("False"))); rv = funcs->C_GetTokenInfo(METASLOT_ID, &token_info); if (rv != CKR_OK) { cryptodebug("C_GetTokenInfo failed with error " "code 0x%x\n", rv); rc = FAILURE; goto finish; } (void) printf(gettext("Token Label: %.32s\n" "Manufacturer ID: %.32s\n" "Model: %.16s\n" "Serial Number: %.16s\n" "Hardware Version: %d.%d\n" "Firmware Version: %d.%d\n" "UTC Time: %.16s\n" "PIN Min Length: %d\n" "PIN Max Length: %d\n"), token_info.label, token_info.manufacturerID, token_info.model, token_info.serialNumber, token_info.hardwareVersion.major, token_info.hardwareVersion.minor, token_info.firmwareVersion.major, token_info.firmwareVersion.minor, token_info.utcTime, token_info.ulMinPinLen, token_info.ulMaxPinLen); display_token_flags(token_info.flags); if (!show_mechs) { goto finish; } display_mechs: if (mechlist == NULL) { rv = funcs->C_GetMechanismList(METASLOT_ID, NULL_PTR, &mech_count); if (rv != CKR_OK) { cryptodebug("C_GetMechanismList failed with error " "code 0x%x\n", rv); rc = FAILURE; goto finish; } if (mech_count > 0) { pmech_list = malloc(mech_count * sizeof (CK_MECHANISM_TYPE)); if (pmech_list == NULL) { cryptodebug("out of memory"); rc = FAILURE; goto finish; } rv = funcs->C_GetMechanismList(METASLOT_ID, pmech_list, &mech_count); if (rv != CKR_OK) { cryptodebug("C_GetMechanismList failed with " "error code 0x%x\n", rv); rc = FAILURE; goto finish; } } } else { rc = convert_mechlist(&pmech_list, &mech_count, mechlist); if (rc != SUCCESS) { goto finish; } } (void) printf(gettext("Mechanisms:\n")); if (mech_count == 0) { /* should never be this case */ (void) printf(gettext("No mechanisms\n")); goto finish; } if (verbose) { display_verbose_mech_header(); } for (i = 0; i < mech_count; i++) { CK_MECHANISM_TYPE mech = pmech_list[i]; if (mech >= CKM_VENDOR_DEFINED) { (void) printf("%#lx", mech); } else { (void) printf("%-29s", pkcs11_mech2str(mech)); } if (verbose) { CK_MECHANISM_INFO mech_info; rv = funcs->C_GetMechanismInfo(METASLOT_ID, mech, &mech_info); if (rv != CKR_OK) { cryptodebug("C_GetMechanismInfo failed with " "error code 0x%x\n", rv); rc = FAILURE; goto finish; } display_mech_info(&mech_info); } (void) printf("\n"); } finish: if ((rc == FAILURE) && (show_mechs)) { (void) printf(gettext( "metaslot: failed to retrieve the mechanism list.\n")); } if (lib_initialized) { (void) funcs->C_Finalize(NULL_PTR); } if (dldesc != NULL) { (void) dlclose(dldesc); } if (pmech_list != NULL) { (void) free(pmech_list); } return (rc); }
/* * Enable a kernel software or hardware provider. * This implements the "cryptoadm enable" command for kernel providers. */ int enable_kef(char *provname, boolean_t rndflag, boolean_t allflag, mechlist_t *mlist) { crypto_load_soft_disabled_t *pload_soft_dis = NULL; crypto_load_dev_disabled_t *pload_dev_dis = NULL; entry_t *pent = NULL; boolean_t redo_flag = B_FALSE; boolean_t in_kernel = B_FALSE; int fd = -1; int rc = SUCCESS; /* Get the entry of this provider from the kcf.conf file, if any. */ pent = getent_kef(provname, NULL, NULL); if (is_device(provname)) { if (pent == NULL) { /* * This device doesn't have an entry in the config * file, therefore nothing is disabled. */ cryptoerror(LOG_STDERR, gettext( "all mechanisms are enabled already for %s."), provname); free_entry(pent); return (SUCCESS); } } else { /* a software module */ if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) { free_entry(pent); return (FAILURE); } else if (in_kernel == B_FALSE) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), provname); free_entry(pent); return (FAILURE); } else if ((pent == NULL) || (pent->dis_count == 0)) { /* nothing to be enabled. */ cryptoerror(LOG_STDERR, gettext( "all mechanisms are enabled already for %s."), provname); free_entry(pent); return (SUCCESS); } } /* * kCF treats random as an internal mechanism. So, we need to * filter it from the mechanism list here, if we are NOT disabling * or enabling the random feature. Note that we map random feature at * cryptoadm(1M) level to the "random" mechanism in kCF. */ if (!rndflag) { redo_flag = filter_mechlist(&pent->dislist, RANDOM); if (redo_flag) pent->dis_count--; } /* Update the entry by enabling mechanisms for this provider */ if ((rc = enable_mechs(&pent, allflag, mlist)) != SUCCESS) { free_entry(pent); return (rc); } if (redo_flag) { mechlist_t *tmp; if ((tmp = create_mech(RANDOM)) == NULL) { free_entry(pent); return (FAILURE); } tmp->next = pent->dislist; pent->dislist = tmp; pent->dis_count++; } /* * Update the kcf.conf file with the updated entry. * For a hardware provider, if there is no more disabled mechanism, * remove the entire kcf.conf entry. */ if (is_device(pent->name) && (pent->dis_count == 0)) { rc = update_kcfconf(pent, DELETE_MODE); } else { rc = update_kcfconf(pent, MODIFY_MODE); } if (rc == FAILURE) { free_entry(pent); return (FAILURE); } /* Inform Kernel about the policy change */ if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); free_entry(pent); return (FAILURE); } if (is_device(provname)) { /* LOAD_DEV_DISABLED */ if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) { free_entry(pent); return (FAILURE); } if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) { cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: " "%s", strerror(errno)); free_entry(pent); free(pload_dev_dis); (void) close(fd); return (FAILURE); } if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl " "return_value = %d", pload_dev_dis->dd_return_value); free_entry(pent); free(pload_dev_dis); (void) close(fd); return (FAILURE); } } else { /* a software module */ /* LOAD_SOFT_DISABLED */ if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) { free_entry(pent); return (FAILURE); } if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: " "%s", strerror(errno)); free_entry(pent); free(pload_soft_dis); (void) close(fd); return (FAILURE); } if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl " "return_value = %d", pload_soft_dis->sd_return_value); free_entry(pent); free(pload_soft_dis); (void) close(fd); return (FAILURE); } } free_entry(pent); free(pload_soft_dis); (void) close(fd); return (SUCCESS); }
/* * Set up metaslot for the framework using either user configuration * or system wide configuration options * * Also sets up the global "slottable" to have the first slot be metaslot. */ static CK_RV setup_metaslot(uentry_t *metaslot_entry) { CK_RV rv; CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL; pkcs11_slot_t *cur_slot; /* process policies for mechanisms */ if ((metaslot_entry) && (metaslot_entry->count > 0)) { rv = pkcs11_mech_parse(metaslot_entry->policylist, &prov_pol_mechs, metaslot_entry->count); if (rv == CKR_HOST_MEMORY) { cryptoerror(LOG_ERR, "libpkcs11: Could not parse configuration," "out of memory. Cannot continue parsing " "%s.\n", _PATH_PKCS11_CONF); return (rv); } else if (rv == CKR_MECHANISM_INVALID) { /* * Configuration file is corrupted for metaslot */ cryptoerror(LOG_ERR, "libpkcs11: Policy invalid or corrupted " "for metaslot. Use cryptoadm(1M) to fix " "this. Disabling metaslot functionality.\n"); metaslot_enabled = B_FALSE; return (rv); } } /* * Check for metaslot policy. If all mechanisms are * disabled, disable metaslot since there is nothing * interesting for it to do */ if ((metaslot_entry) && (metaslot_entry->flag_enabledlist) && (prov_pol_mechs == NULL)) { metaslot_enabled = B_FALSE; return (rv); } /* * save system wide value for metaslot's keystore. * If either slot description or token label is specified by * the user, the system wide value for both is ignored. */ if ((metaslot_entry) && (!metaslot_config.keystore_token_specified) && (!metaslot_config.keystore_slot_specified)) { /* * blank_str is used for comparing with token label, * and slot description, make sure it is better than * the larger of both */ char blank_str[TOKEN_LABEL_SIZE + SLOT_DESCRIPTION_SIZE]; bzero(blank_str, sizeof (blank_str)); if (memcmp(metaslot_entry->metaslot_ks_token, blank_str, TOKEN_LABEL_SIZE) != 0) { metaslot_config.keystore_token_specified = B_TRUE; (void) strlcpy( (char *)metaslot_config.keystore_token, (const char *)metaslot_entry->metaslot_ks_token, TOKEN_LABEL_SIZE); } if (memcmp(metaslot_entry->metaslot_ks_slot, blank_str, SLOT_DESCRIPTION_SIZE) != 0) { metaslot_config.keystore_slot_specified = B_TRUE; (void) strlcpy( (char *)metaslot_config.keystore_slot, (const char *)metaslot_entry->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE); } } /* check system-wide value for auto_key_migrate */ if (metaslot_config.auto_key_migrate_specified) { /* take user's specified value */ metaslot_auto_key_migrate = metaslot_config.auto_key_migrate; } else { if (metaslot_entry) { /* use system-wide default */ metaslot_auto_key_migrate = metaslot_entry->flag_metaslot_auto_key_migrate; } else { /* * there's no system wide metaslot entry, * default auto_key_migrate to true */ metaslot_auto_key_migrate = B_TRUE; } } /* Make first slotID be 0, for metaslot. */ slottable->st_first = 0; /* Set up the slottable entry for metaslot */ slottable->st_slots[0] = NULL; cur_slot = calloc(1, sizeof (pkcs11_slot_t)); if (cur_slot == NULL) { rv = CKR_HOST_MEMORY; return (rv); } cur_slot->sl_wfse_state = WFSE_CLEAR; cur_slot->sl_enabledpol = B_FALSE; cur_slot->sl_no_wfse = B_FALSE; (void) pthread_mutex_init(&cur_slot->sl_mutex, NULL); /* * The metaslot entry was prealloc'd by * pkcs11_slottable_increase() */ (void) pthread_mutex_lock(&slottable->st_mutex); slottable->st_slots[0] = cur_slot; (void) pthread_mutex_unlock(&slottable->st_mutex); (void) pthread_mutex_lock(&cur_slot->sl_mutex); cur_slot->sl_id = METASLOT_SLOTID; cur_slot->sl_func_list = &metaslot_functionList; if (metaslot_entry) { cur_slot->sl_enabledpol = metaslot_entry->flag_enabledlist; cur_slot->sl_pol_count = metaslot_entry->count; } else { /* if no metaslot entry, assume all mechs are enabled */ cur_slot->sl_enabledpol = B_FALSE; cur_slot->sl_pol_count = 0; } cur_slot->sl_pol_mechs = prov_pol_mechs; cur_slot->sl_dldesc = NULL; /* not applicable */ cur_slot->sl_prov_id = 0; (void) pthread_mutex_unlock(&cur_slot->sl_mutex); /* Call the meta_Initialize() to initialize metaslot */ rv = meta_Initialize(NULL); if (rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Can't initialize metaslot (%s)", pkcs11_strerror(rv)); goto cleanup; } return (CKR_OK); cleanup: metaslot_enabled = B_FALSE; slottable->st_slots[0] = NULL; if (cur_slot) { (void) pthread_mutex_destroy(&cur_slot->sl_mutex); free(cur_slot); } return (rv); }
/* * Install a software module with the specified mechanism list into the system. * This routine adds an entry into the config file for this software module * first, then makes a CRYPTO_LOAD_SOFT_CONFIG ioctl call to inform kernel * about the new addition. */ int install_kef(char *provname, mechlist_t *mlist) { crypto_load_soft_config_t *pload_soft_conf = NULL; boolean_t found; entry_t *pent = NULL; FILE *pfile = NULL; FILE *pfile_tmp = NULL; char tmpfile_name[MAXPATHLEN]; char *ptr; char *str; char *name; char buffer[BUFSIZ]; char buffer2[BUFSIZ]; int found_count; int fd = -1; int rc = SUCCESS; int err; if ((provname == NULL) || (mlist == NULL)) { return (FAILURE); } /* Check if the provider already exists */ if ((pent = getent_kef(provname, NULL, NULL)) != NULL) { cryptoerror(LOG_STDERR, gettext("%s exists already."), provname); free_entry(pent); return (FAILURE); } /* Create an entry with provname and mlist. */ if ((pent = create_entry(provname)) == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); return (FAILURE); } pent->sup_count = get_mech_count(mlist); pent->suplist = mlist; /* Append an entry for this software module to the kcf.conf file. */ if ((str = ent2str(pent)) == NULL) { free_entry(pent); return (FAILURE); } if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to open %s for write.", _PATH_KCF_CONF); free_entry(pent); return (FAILURE); } if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to lock the configuration - %s"), strerror(err)); free_entry(pent); (void) fclose(pfile); return (FAILURE); } /* * Create a temporary file in the /etc/crypto directory. */ (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); if (mkstemp(tmpfile_name) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to create a temporary file - %s"), strerror(err)); free_entry(pent); (void) fclose(pfile); return (FAILURE); } if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), tmpfile_name, strerror(err)); free_entry(pent); (void) fclose(pfile); return (FAILURE); } /* * Loop thru the config file. If the provider was reserved within a * package bracket, just uncomment it. Otherwise, append it at * the end. The resulting file will be saved in the temp file first. */ found_count = 0; rc = SUCCESS; while (fgets(buffer, BUFSIZ, pfile) != NULL) { found = B_FALSE; if (buffer[0] == '#') { (void) strlcpy(buffer2, buffer, BUFSIZ); ptr = buffer2; ptr++; if ((name = strtok(ptr, SEP_COLON)) == NULL) { rc = FAILURE; break; } else if (strcmp(provname, name) == 0) { found = B_TRUE; found_count++; } } if (found == B_FALSE) { if (fputs(buffer, pfile_tmp) == EOF) { rc = FAILURE; } } else { if (found_count == 1) { if (fputs(str, pfile_tmp) == EOF) { rc = FAILURE; } } else { /* * Found a second entry with #libname. * Should not happen. The kcf.conf file * is corrupted. Give a warning and skip * this entry. */ cryptoerror(LOG_STDERR, gettext( "(Warning) Found an additional reserved " "entry for %s."), provname); } } if (rc == FAILURE) { break; } } (void) fclose(pfile); if (rc == FAILURE) { cryptoerror(LOG_STDERR, gettext("write error.")); (void) fclose(pfile_tmp); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } free_entry(pent); return (FAILURE); } if (found_count == 0) { /* * This libname was not in package before, append it to the * end of the temp file. */ if (fputs(str, pfile_tmp) == EOF) { cryptoerror(LOG_STDERR, gettext( "failed to write to %s: %s"), tmpfile_name, strerror(errno)); (void) fclose(pfile_tmp); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } free_entry(pent); return (FAILURE); } } if (fclose(pfile_tmp) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to close %s: %s"), tmpfile_name, strerror(err)); free_entry(pent); return (FAILURE); } if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to rename %s to %s: %s", tmpfile_name, _PATH_KCF_CONF, strerror(err)); rc = FAILURE; } else if (chmod(_PATH_KCF_CONF, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF, strerror(err)); rc = FAILURE; } else { rc = SUCCESS; } if (rc == FAILURE) { if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } free_entry(pent); return (FAILURE); } /* Inform kernel of this new software module. */ if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) { free_entry(pent); return (FAILURE); } if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); free_entry(pent); free(pload_soft_conf); return (FAILURE); } if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s", strerror(errno)); free_entry(pent); free(pload_soft_conf); (void) close(fd); return (FAILURE); } if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed, " "return_value = %d", pload_soft_conf->sc_return_value); free_entry(pent); free(pload_soft_conf); (void) close(fd); return (FAILURE); } free_entry(pent); free(pload_soft_conf); (void) close(fd); return (SUCCESS); }
/* * Print a list all the the providers. * Called for "cryptoadm list" or "cryptoadm list -v" (no -m or -p). */ static int list_simple_for_all(boolean_t verbose) { uentrylist_t *pliblist = NULL; uentrylist_t *plibptr = NULL; entry_t *pent = NULL; crypto_get_dev_list_t *pdevlist_kernel = NULL; int rc = SUCCESS; int i; /* get user-level providers */ (void) printf(gettext("\nUser-level providers:\n")); if (get_pkcs11conf_info(&pliblist) != SUCCESS) { cryptoerror(LOG_STDERR, gettext( "failed to retrieve the list of user-level providers.")); rc = FAILURE; } for (plibptr = pliblist; plibptr != NULL; plibptr = plibptr->next) { /* skip metaslot and fips-140 entry */ if ((strcmp(plibptr->puent->name, METASLOT_KEYWORD) != 0) && (strcmp(plibptr->puent->name, FIPS_KEYWORD) != 0)) { (void) printf(gettext("Provider: %s\n"), plibptr->puent->name); if (verbose) { (void) list_mechlist_for_lib( plibptr->puent->name, mecharglist, NULL, B_FALSE, verbose, B_FALSE); (void) printf("\n"); } } } free_uentrylist(pliblist); /* get kernel software providers */ (void) printf(gettext("\nKernel software providers:\n")); if (getzoneid() == GLOBAL_ZONEID) { /* get kernel software providers from kernel ioctl */ crypto_get_soft_list_t *psoftlist_kernel = NULL; uint_t sl_soft_count; char *psoftname; entrylist_t *pdevlist_conf = NULL; entrylist_t *psoftlist_conf = NULL; if (get_soft_list(&psoftlist_kernel) == FAILURE) { cryptoerror(LOG_ERR, gettext("Failed to retrieve the " "software provider list from kernel.")); rc = FAILURE; } else { sl_soft_count = psoftlist_kernel->sl_soft_count; if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf) == FAILURE) { cryptoerror(LOG_ERR, "failed to retrieve the providers' " "information from file kcf.conf - %s.", _PATH_KCF_CONF); free(psoftlist_kernel); rc = FAILURE; } else { for (i = 0, psoftname = psoftlist_kernel->sl_soft_names; i < sl_soft_count; ++i, psoftname += strlen(psoftname) + 1) { pent = getent_kef(psoftname, pdevlist_conf, psoftlist_conf); (void) printf("\t%s%s\n", psoftname, (pent == NULL) || (pent->load) ? "" : gettext(" (inactive)")); } free_entrylist(pdevlist_conf); free_entrylist(psoftlist_conf); } free(psoftlist_kernel); } } else { /* kcf.conf not there in non-global zone, use /dev/cryptoadm */ entrylist_t *pdevlist_zone = NULL; entrylist_t *psoftlist_zone = NULL; entrylist_t *ptr; if (get_admindev_info(&pdevlist_zone, &psoftlist_zone) != SUCCESS) { cryptoerror(LOG_STDERR, gettext("failed to retrieve the " "list of kernel software providers.\n")); rc = FAILURE; } ptr = psoftlist_zone; while (ptr != NULL) { (void) printf("\t%s\n", ptr->pent->name); ptr = ptr->next; } free_entrylist(pdevlist_zone); free_entrylist(psoftlist_zone); } /* get kernel hardware providers */ (void) printf(gettext("\nKernel hardware providers:\n")); if (get_dev_list(&pdevlist_kernel) == FAILURE) { cryptoerror(LOG_STDERR, gettext("failed to retrieve " "the list of kernel hardware providers.\n")); rc = FAILURE; } else { for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) { (void) printf("\t%s/%d\n", pdevlist_kernel->dl_devs[i].le_dev_name, pdevlist_kernel->dl_devs[i].le_dev_instance); } } free(pdevlist_kernel); return (rc); }
/* * Uninstall the software module. This routine first unloads the software * module with 3 ioctl calls, then deletes its entry from the config file. * Removing an entry from the config file needs to be done last to ensure * that there is still an entry if the earlier unload failed for any reason. */ int uninstall_kef(char *provname) { entry_t *pent = NULL; int rc = SUCCESS; boolean_t in_kernel = B_FALSE; boolean_t in_kcfconf = B_FALSE; int fd = -1; crypto_load_soft_config_t *pload_soft_conf = NULL; /* Check to see if the provider exists first. */ if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) { return (FAILURE); } else if (in_kernel == B_FALSE) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), provname); return (FAILURE); } /* * If it is loaded, unload it first. This does 2 ioctl calls: * CRYPTO_UNLOAD_SOFT_MODULE and CRYPTO_LOAD_SOFT_DISABLED. */ if (unload_kef_soft(provname) == FAILURE) { cryptoerror(LOG_STDERR, gettext("failed to unload %s during uninstall.\n"), provname); return (FAILURE); } /* * Inform kernel to remove the configuration of this software module. */ /* Setup ioctl() parameter */ pent = getent_kef(provname, NULL, NULL); if (pent != NULL) { /* in kcf.conf */ in_kcfconf = B_TRUE; free_mechlist(pent->suplist); pent->suplist = NULL; pent->sup_count = 0; } else if ((pent = create_entry(provname)) == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); return (FAILURE); } if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) { free_entry(pent); return (FAILURE); } /* Open the /dev/cryptoadm device */ if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { int err = errno; cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(err)); free_entry(pent); free(pload_soft_conf); return (FAILURE); } if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s", strerror(errno)); free_entry(pent); free(pload_soft_conf); (void) close(fd); return (FAILURE); } if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl = return_value = %d", pload_soft_conf->sc_return_value); free_entry(pent); free(pload_soft_conf); (void) close(fd); return (FAILURE); } /* ioctl cleanup */ free(pload_soft_conf); (void) close(fd); /* Finally, remove entry from kcf.conf, if present */ if (in_kcfconf && (pent != NULL)) { rc = update_kcfconf(pent, DELETE_MODE); } free_entry(pent); return (rc); }
/* * List all the providers. And for each provider, list the policy information. * Called for "cryptoadm list -p". */ static int list_policy_for_all(void) { crypto_get_dev_list_t *pdevlist_kernel = NULL; uentrylist_t *pliblist = NULL; entrylist_t *pdevlist_conf = NULL; entrylist_t *psoftlist_conf = NULL; entrylist_t *ptr = NULL; entrylist_t *phead = NULL; boolean_t found = B_FALSE; char provname[MAXNAMELEN]; int i; int rc = SUCCESS; /* Get user-level providers */ (void) printf(gettext("\nUser-level providers:\n")); /* * TRANSLATION_NOTE * Strictly for appearance's sake, this line should be as long as * the length of the translated text above. */ (void) printf(gettext("=====================\n")); if (get_pkcs11conf_info(&pliblist) == FAILURE) { cryptoerror(LOG_STDERR, gettext("failed to retrieve " "the list of user-level providers.\n")); rc = FAILURE; } else { uentrylist_t *plibptr = pliblist; while (plibptr != NULL) { /* skip metaslot and fips-140 entry */ if ((strcmp(plibptr->puent->name, METASLOT_KEYWORD) != 0) && (strcmp(plibptr->puent->name, FIPS_KEYWORD) != 0)) { if (print_uef_policy(plibptr->puent) == FAILURE) { rc = FAILURE; } } plibptr = plibptr->next; } free_uentrylist(pliblist); } /* kernel software providers */ (void) printf(gettext("\nKernel software providers:\n")); /* * TRANSLATION_NOTE * Strictly for appearance's sake, this line should be as long as * the length of the translated text above. */ (void) printf(gettext("==========================\n")); /* Get all entries from the kernel */ if (getzoneid() == GLOBAL_ZONEID) { /* get kernel software providers from kernel ioctl */ crypto_get_soft_list_t *psoftlist_kernel = NULL; uint_t sl_soft_count; char *psoftname; int i; if (get_soft_list(&psoftlist_kernel) == FAILURE) { cryptoerror(LOG_ERR, gettext("Failed to retrieve the " "software provider list from kernel.")); rc = FAILURE; } else { sl_soft_count = psoftlist_kernel->sl_soft_count; for (i = 0, psoftname = psoftlist_kernel->sl_soft_names; i < sl_soft_count; ++i, psoftname += strlen(psoftname) + 1) { (void) list_policy_for_soft(psoftname, pdevlist_conf, psoftlist_conf); } free(psoftlist_kernel); } } else { /* kcf.conf not there in non-global zone, no policy info */ /* * TRANSLATION_NOTE * "global" is keyword and not to be translated. */ cryptoerror(LOG_STDERR, gettext( "policy information for kernel software providers is " "available in the %s zone only"), "global"); } /* Kernel hardware providers */ (void) printf(gettext("\nKernel hardware providers:\n")); /* * TRANSLATION_NOTE * Strictly for appearance's sake, this line should be as long as * the length of the translated text above. */ (void) printf(gettext("==========================\n")); if (getzoneid() != GLOBAL_ZONEID) { /* * TRANSLATION_NOTE * "global" is keyword and not to be translated. */ cryptoerror(LOG_STDERR, gettext( "policy information for kernel hardware providers is " "available in the %s zone only"), "global"); return (FAILURE); } /* Get the hardware provider list from kernel */ if (get_dev_list(&pdevlist_kernel) != SUCCESS) { cryptoerror(LOG_STDERR, gettext( "failed to retrieve the list of hardware providers.\n")); return (FAILURE); } if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf) == FAILURE) { cryptoerror(LOG_ERR, "failed to retrieve the providers' " "information from file kcf.conf - %s.", _PATH_KCF_CONF); return (FAILURE); } /* * For each hardware provider from kernel, check if it has an entry * in the config file. If it has an entry, print out the policy from * config file and remove the entry from the hardware provider list * of the config file. If it does not have an entry in the config * file, no mechanisms of it have been disabled. But, we still call * list_policy_for_hard() to account for the "random" feature. */ for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) { (void) snprintf(provname, sizeof (provname), "%s/%d", pdevlist_kernel->dl_devs[i].le_dev_name, pdevlist_kernel->dl_devs[i].le_dev_instance); found = B_FALSE; phead = ptr = pdevlist_conf; while (!found && ptr) { if (strcmp(ptr->pent->name, provname) == 0) { found = B_TRUE; } else { phead = ptr; ptr = ptr->next; } } if (found) { (void) list_policy_for_hard(ptr->pent->name, pdevlist_conf, psoftlist_conf, pdevlist_kernel); if (phead == ptr) { pdevlist_conf = pdevlist_conf->next; } else { phead->next = ptr->next; } free_entry(ptr->pent); free(ptr); } else { (void) list_policy_for_hard(provname, pdevlist_conf, psoftlist_conf, pdevlist_kernel); } } /* * If there are still entries left in the pdevlist_conf list from * the config file, these providers must have been detached. * Should print out their policy information also. */ for (ptr = pdevlist_conf; ptr != NULL; ptr = ptr->next) { print_kef_policy(ptr->pent->name, ptr->pent, B_FALSE, B_TRUE); } free_entrylist(pdevlist_conf); free_entrylist(psoftlist_conf); free(pdevlist_kernel); return (rc); }
int pk_inittoken(int argc, char *argv[]) /* ARGSUSED */ { int opt; int rv; extern int optind_av; extern char *optarg_av; char *newlabel = NULL; char *currlabel = NULL; CK_UTF8CHAR_PTR sopin; CK_ULONG sopinlen; KMF_HANDLE_T handle; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "n:(newlabel)" "l:(currlabel)")) != EOF) { switch (opt) { case 'l': /* token specifier */ if (currlabel) return (PK_ERR_USAGE); currlabel = optarg_av; break; case 'n': /* token specifier */ if (newlabel) return (PK_ERR_USAGE); newlabel = optarg_av; break; default: return (PK_ERR_USAGE); break; } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc != 0) return (PK_ERR_USAGE); if ((rv = kmf_initialize(&handle, NULL, NULL)) != KMF_OK) return (rv); if ((rv = get_pin(gettext("Enter SO PIN:"), NULL, &sopin, &sopinlen)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get SO PIN for token")); return (PK_ERR_SYSTEM); } if ((currlabel == NULL || !strlen(currlabel))) { cryptoerror(LOG_STDERR, gettext("The current token is not identified by label.")); return (PK_ERR_SYSTEM); } rv = kmf_pk11_init_token(handle, currlabel, newlabel, sopin, sopinlen); (void) kmf_finalize(handle); free(sopin); if (rv == KMF_ERR_AUTH_FAILED) { cryptoerror(LOG_STDERR, gettext("Incorrect passphrase.")); return (PK_ERR_SYSTEM); } else if (rv != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to initialize token.")); return (PK_ERR_SYSTEM); } else { (void) fprintf(stdout, gettext("Token %s initialized.\n"), (newlabel ? newlabel : currlabel)); } return (0); }
/* * Process the mechanism operands for the disable, enable and install * subcommands. This function sets the static variable allflag to be B_TRUE * if the keyword "all" is specified, otherwise builds a link list of the * mechanism operands and save it in the static variable mecharglist. * * This function returns * ERROR_USAGE: mechanism operand is missing. * FAILURE: out of memory. * SUCCESS: otherwise. */ static int process_mech_operands(int argc, char **argv, boolean_t quiet) { mechlist_t *pmech; mechlist_t *pcur = NULL; mechlist_t *phead = NULL; boolean_t found = B_FALSE; char *mechliststr = NULL; char *curmech = NULL; int c = -1; int rc = SUCCESS; while (!found && ++c < argc) { if ((strncmp(argv[c], KN_MECH, strlen(KN_MECH)) == 0) && strlen(argv[c]) > strlen(KN_MECH)) { found = B_TRUE; } } if (!found) { if (!quiet) /* * TRANSLATION_NOTE * "mechanism" could be either a literal keyword * and hence not to be translated, or a descriptive * word and translatable. A choice was made to * view it as a literal keyword. */ cryptoerror(LOG_STDERR, gettext("the %s operand is missing.\n"), "mechanism"); return (ERROR_USAGE); } (void) strtok(argv[c], "="); mechliststr = strtok(NULL, "="); if (strcmp(mechliststr, "all") == 0) { allflag = B_TRUE; mecharglist = NULL; return (SUCCESS); } curmech = strtok(mechliststr, ","); do { if ((pmech = create_mech(curmech)) == NULL) { rc = FAILURE; break; } else { if (phead == NULL) { phead = pcur = pmech; } else { pcur->next = pmech; pcur = pmech; } } } while ((curmech = strtok(NULL, ",")) != NULL); if (rc == FAILURE) { cryptoerror(LOG_STDERR, gettext("out of memory.")); free_mechlist(phead); } else { mecharglist = phead; rc = SUCCESS; } return (rc); }
/* * MAIN() -- where all the action is */ int main(int argc, char *argv[], char *envp[]) /* ARGSUSED2 */ { int i, found = -1; int rv; int pk_argc = 0; char **pk_argv = NULL; int save_errno = 0; /* Set up for i18n/l10n. */ (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D. */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */ #endif (void) textdomain(TEXT_DOMAIN); init_command_list(); /* Get program base name and move pointer over 0th arg. */ prog = basename(argv[0]); argv++, argc--; /* Set up for debug and error output. */ if (argc == 0) { usage(-1); return (1); } /* Check for help options. For CLIP-compliance. */ if (strcmp(argv[0], "-?") == 0) { return (pk_help(argc, argv)); } else if (strcmp(argv[0], "-f") == 0 && argc == 2) { rv = process_arg_file(argv[1], &pk_argv, &pk_argc); if (rv) return (rv); } else if (argc >= 1 && argv[0][0] == '-') { usage(-1); return (1); } /* Always turns off Metaslot so that we can see softtoken. */ if (setenv("METASLOT_ENABLED", "false", 1) < 0) { save_errno = errno; cryptoerror(LOG_STDERR, gettext("Disabling Metaslot failed (%s)."), strerror(save_errno)); return (1); } /* Begin parsing command line. */ if (pk_argc == 0 && pk_argv == NULL) { pk_argc = argc; pk_argv = argv; } /* Check for valid verb (or an abbreviation of it). */ found = -1; for (i = 0; i < num_cmds; i++) { if (strcmp(cmds[i].verb, pk_argv[0]) == 0) { if (found < 0) { found = i; break; } } } /* Stop here if no valid verb found. */ if (found < 0) { cryptoerror(LOG_STDERR, gettext("Invalid verb: %s"), pk_argv[0]); return (1); } /* Get to work! */ rv = (*cmds[found].action)(pk_argc, pk_argv); switch (rv) { case PK_ERR_NONE: break; /* Command succeeded, do nothing. */ case PK_ERR_USAGE: usage(found); break; case PK_ERR_QUIT: exit(0); /* NOTREACHED */ case PK_ERR_PK11: case PK_ERR_SYSTEM: case PK_ERR_OPENSSL: case PK_ERR_NSS: default: break; } return (rv); }
/* * The top level function for the "cryptoadm enable" subcommand. */ static int do_enable(int argc, char **argv) { cryptoadm_provider_t *prov = NULL; int rc = SUCCESS; char *alt_token = NULL, *alt_slot = NULL; boolean_t use_default = B_FALSE; boolean_t auto_key_migrate_flag = B_FALSE; if ((argc == 3) && (strncmp(argv[2], FIPS_KEYWORD, strlen(FIPS_KEYWORD))) == 0) { /* * cryptoadm enable fips-140 */ rc = do_fips_actions(FIPS140_ENABLE, NOT_REFRESH); return (rc); } if ((argc < 3) || (argc > 6)) { usage(); return (ERROR_USAGE); } prov = get_provider(argc, argv); if (prov == NULL) { usage(); return (ERROR_USAGE); } if ((prov->cp_type != METASLOT) && (argc != 4)) { usage(); return (ERROR_USAGE); } if (prov->cp_type == PROV_BADNAME) { rc = FAILURE; goto out; } if (prov->cp_type == METASLOT) { if ((rc = process_metaslot_operands(argc, argv, &alt_token, &alt_slot, &use_default, &auto_key_migrate_flag)) != SUCCESS) { usage(); goto out; } if ((alt_slot || alt_token) && use_default) { usage(); rc = FAILURE; goto out; } } else { if ((rc = process_feature_operands(argc, argv)) != SUCCESS) { goto out; } /* * If allflag or rndflag has already been set there is * no reason to process mech= */ if (!allflag && !rndflag && (rc = process_mech_operands(argc, argv, B_FALSE)) != SUCCESS) { goto out; } } switch (prov->cp_type) { case METASLOT: rc = enable_metaslot(alt_token, alt_slot, use_default, mecharglist, allflag, auto_key_migrate_flag); break; case PROV_UEF_LIB: rc = enable_uef_lib(prov->cp_name, rndflag, allflag, mecharglist); break; case PROV_KEF_SOFT: case PROV_KEF_HARD: if (rndflag && !allflag) { if ((mecharglist = create_mech(RANDOM)) == NULL) { rc = FAILURE; break; } } if (getzoneid() == GLOBAL_ZONEID) { rc = enable_kef(prov->cp_name, rndflag, allflag, mecharglist); } else { /* * TRANSLATION_NOTE * "enable" could be either a literal keyword * and hence not to be translated, or a verb and * translatable. A choice was made to view it as * a literal keyword. "global" is keyword and not * to be translated. */ cryptoerror(LOG_STDERR, gettext("%1$s for kernel " "providers is supported in the %2$s zone only"), "enable", "global"); rc = FAILURE; } break; default: /* should not come here */ rc = FAILURE; break; } out: free(prov); if (mecharglist != NULL) { free_mechlist(mecharglist); } if (alt_token != NULL) { free(alt_token); } if (alt_slot != NULL) { free(alt_slot); } return (rc); }
/* * disable metaslot and some of its configuration options * * If mechlist==NULL, and the other 2 flags are false, just disabled * the metaslot feature. * * mechlist: list of mechanisms to disable * allflag: if true, indicates all mechanisms should be disabled. * auto_key_migrate_flag: if true, indicates auto key migrate should be disabled */ int disable_metaslot(mechlist_t *mechlist, boolean_t allflag, boolean_t auto_key_migrate_flag) { uentry_t *puent; int rc = SUCCESS; if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) { cryptoerror(LOG_STDERR, gettext("metaslot entry doesn't exist.")); return (FAILURE); } if ((mechlist == NULL) && (!auto_key_migrate_flag) && (!allflag)) { /* disable metaslot */ puent->flag_metaslot_enabled = B_FALSE; goto write_to_file; } if (auto_key_migrate_flag) { /* need to disable auto_key_migrate */ puent->flag_metaslot_auto_key_migrate = B_FALSE; } if ((mechlist == NULL) && (!allflag)) { goto write_to_file; } /* disable specified mechanisms */ if (allflag) { free_umechlist(puent->policylist); puent->policylist = NULL; puent->count = 0; puent->flag_enabledlist = B_TRUE; rc = SUCCESS; } else { if (puent->flag_enabledlist == B_TRUE) { /* * The current default policy mode * is "all are disabled, except ...", so if a * specified mechanism is in the exception list * (the policylist), delete it from the policylist. */ rc = update_policylist(puent, mechlist, DELETE_MODE); } else { /* * The current default policy mode of this library * is "all are enabled", so if a specified mechanism * is not in the exception list (policylist), add * it into the policylist. */ rc = update_policylist(puent, mechlist, ADD_MODE); } } if (rc != SUCCESS) { goto finish; } /* If all mechanisms are disabled, metaslot will be disabled as well */ if ((puent->flag_enabledlist) && (puent->count == 0)) { puent->flag_metaslot_enabled = B_FALSE; } write_to_file: rc = update_pkcs11conf(puent); finish: free_uentry(puent); return (rc); }
/* * Get the device list from kernel. */ int get_dev_list(crypto_get_dev_list_t **ppdevlist) { crypto_get_dev_list_t *pdevlist; int fd; int count = DEFAULT_DEV_NUM; pdevlist = malloc(sizeof (crypto_get_dev_list_t) + sizeof (crypto_dev_list_entry_t) * (count - 1)); if (pdevlist == NULL) { cryptodebug("out of memory."); return (FAILURE); } if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); return (FAILURE); } pdevlist->dl_dev_count = count; if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) { cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s", strerror(errno)); free(pdevlist); (void) close(fd); return (FAILURE); } /* BUFFER is too small, get the number of devices and retry it. */ if (pdevlist->dl_return_value == CRYPTO_BUFFER_TOO_SMALL) { count = pdevlist->dl_dev_count; free(pdevlist); pdevlist = malloc(sizeof (crypto_get_dev_list_t) + sizeof (crypto_dev_list_entry_t) * (count - 1)); if (pdevlist == NULL) { cryptodebug("out of memory."); (void) close(fd); return (FAILURE); } if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) { cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s", strerror(errno)); free(pdevlist); (void) close(fd); return (FAILURE); } } if (pdevlist->dl_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed, " "return_value = %d", pdevlist->dl_return_value); free(pdevlist); (void) close(fd); return (FAILURE); } *ppdevlist = pdevlist; (void) close(fd); return (SUCCESS); }
static KMF_RETURN gencert_nss(KMF_HANDLE_T kmfhandle, char *token, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, char *nickname, char *dir, char *prefix, KMF_KEY_ALG keyAlg, KMF_ALGORITHM_INDEX sigAlg, int keylen, char *trust, uint32_t ltime, KMF_BIGINT *serial, uint16_t kubits, int kucrit, KMF_CREDENTIAL *tokencred, EKU_LIST *ekulist, KMF_OID *curveoid) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; KMF_X509_CERTIFICATE signedCert; KMF_X509_NAME certSubject; KMF_X509_NAME certIssuer; KMF_DATA x509DER; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; if (token == NULL) token = DEFAULT_NSS_TOKEN; kmfrv = configure_nss(kmfhandle, dir, prefix); if (kmfrv != KMF_OK) return (kmfrv); (void) memset(&signedCert, 0, sizeof (signedCert)); (void) memset(&certSubject, 0, sizeof (certSubject)); (void) memset(&certIssuer, 0, sizeof (certIssuer)); (void) memset(&x509DER, 0, sizeof (x509DER)); /* If the subject name cannot be parsed, flag it now and exit */ if (kmf_dn_parser(subject, &certSubject) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed.\n")); return (PK_ERR_USAGE); } /* For a self-signed cert, the issuser and subject are the same */ if (kmf_dn_parser(subject, &certIssuer) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed.\n")); return (PK_ERR_USAGE); } kmfrv = genkeypair_nss(kmfhandle, token, nickname, dir, prefix, keyAlg, keylen, tokencred, curveoid, &prik, &pubk); if (kmfrv != KMF_OK) return (kmfrv); SET_VALUE(kmf_set_cert_pubkey(kmfhandle, &pubk, &signedCert), "keypair"); SET_VALUE(kmf_set_cert_version(&signedCert, 2), "version number"); SET_VALUE(kmf_set_cert_serial(&signedCert, serial), "serial number"); SET_VALUE(kmf_set_cert_validity(&signedCert, NULL, ltime), "validity time"); SET_VALUE(kmf_set_cert_sig_alg(&signedCert, sigAlg), "signature algorithm"); SET_VALUE(kmf_set_cert_subject(&signedCert, &certSubject), "subject name"); SET_VALUE(kmf_set_cert_issuer(&signedCert, &certIssuer), "issuer name"); if (altname != NULL) SET_VALUE(kmf_set_cert_subject_altname(&signedCert, altcrit, alttype, altname), "subjectAltName"); if (kubits) SET_VALUE(kmf_set_cert_ku(&signedCert, kucrit, kubits), "subjectAltName"); if (ekulist != NULL) { int i; for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { SET_VALUE(kmf_add_cert_eku(&signedCert, &ekulist->ekulist[i], ekulist->critlist[i]), "Extended Key Usage"); } } /* * Construct attributes for the kmf_sign_cert operation. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE_ATTR)); numattr++; /* cert data that is to be signed */ kmf_set_attr_at_index(attrlist, numattr, KMF_X509_CERTIFICATE_ATTR, &signedCert, sizeof (KMF_X509_CERTIFICATE)); numattr++; /* output buffer for the signed cert */ kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &x509DER, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ALGORITHM_INDEX_ATTR, &sigAlg, sizeof (sigAlg)); numattr++; if ((kmfrv = kmf_sign_cert(kmfhandle, numattr, attrlist)) != KMF_OK) { goto cleanup; } /* * Store the cert in the DB. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &x509DER, sizeof (KMF_DATA)); numattr++; if (nickname != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, nickname, strlen(nickname)); numattr++; } if (trust != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TRUSTFLAG_ATTR, trust, strlen(trust)); numattr++; } if (token != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } kmfrv = kmf_store_cert(kmfhandle, numattr, attrlist); cleanup: kmf_free_data(&x509DER); kmf_free_dn(&certSubject); kmf_free_dn(&certIssuer); return (kmfrv); }