# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. # include ../Makefile.cmd # Hammerhead: tpmadm removed (requires TPM/TSS headers not on Hammerhead) SUBDIRS1 = \ cryptoadm \ decrypt \ digest \ elfsign \ kmfcfg \ pktool SUBDIRS2 = \ etc \ scripts all: TARGET= all install: TARGET= install clean: TARGET= clean clobber: TARGET= clobber _msg: TARGET= _msg .KEEP_STATE: all clean clobber _msg: $(SUBDIRS1) $($(MACH)_SUBDIRS) install: $(SUBDIRS1) $(SUBDIRS2) $($(MACH)_SUBDIRS) $(SUBDIRS1) $(SUBDIRS2) $($(MACH)_SUBDIRS) : FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. # # Copyright 2010 Nexenta Systems, Inc. All rights reserved. PROG = cryptoadm OBJS = cryptoadm.o \ adm_uef.o \ adm_kef.o \ adm_kef_ioctl.o \ adm_kef_util.o \ adm_util.o \ adm_metaslot.o SRCS = $(OBJS:.o=.c) include ../../Makefile.cmd POFILES = $(OBJS:%.o=%.po) POFILE = $(PROG)_all.po CFLAGS += $(CCVERBOSE) CERRWARN += $(CNOWARN_UNINIT) CERRWARN += -Wno-parentheses # Hammerhead: -ldl for dlopen/dlsym of PKCS#11 provider modules LDLIBS += -lcryptoutil -ldl .KEEP_STATE: all: $(PROG) $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(DYNFLAGS) $(POST_PROCESS) $(POFILE): $(POFILES) $(RM) $@; cat $(POFILES) > $@ install: all $(ROOTSBINPROG) $(RM) $(ROOTUSRSBINPROG) -$(SYMLINK) ../../sbin/$(PROG) $(ROOTUSRSBINPROG) clean: $(RM) -f $(OBJS) $(PROG) lint: lint_SRCS include ../../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "cryptoadm.h" static int check_hardware_provider(char *, char *, int *, int *); /* * Display the mechanism list for a kernel software provider. * This implements part of the "cryptoadm list -m" command. * * Parameters phardlist and psoftlist are supplied by * get_soft_info(). * If NULL, this function obtains it by calling getent_kef() and * then get_kcfconf_info() via get_soft_info() internally. */ int list_mechlist_for_soft(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist) { mechlist_t *pmechlist = NULL; int rc; if (provname == NULL) { return (FAILURE); } rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist); if (rc == SUCCESS) { (void) filter_mechlist(&pmechlist, RANDOM); print_mechlist(provname, pmechlist); free_mechlist(pmechlist); } else { cryptoerror(LOG_STDERR, gettext( "failed to retrieve the mechanism list for %s."), provname); } return (rc); } /* * Display the mechanism list for a kernel hardware provider. * This implements part of the "cryptoadm list -m" command. */ int list_mechlist_for_hard(char *provname) { mechlist_t *pmechlist = NULL; char devname[MAXNAMELEN]; int inst_num; int count; 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 ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) == SUCCESS) { (void) filter_mechlist(&pmechlist, RANDOM); print_mechlist(provname, pmechlist); free_mechlist(pmechlist); } return (rc); } /* * Display the policy information for a kernel software 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. */ int list_policy_for_soft(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist) { int rc; entry_t *pent = NULL; mechlist_t *pmechlist = NULL; boolean_t has_random = B_FALSE; boolean_t has_mechs = B_FALSE; boolean_t in_kernel = B_FALSE; if (provname == NULL) { return (FAILURE); } 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); } pent = getent_kef(provname, phardlist, psoftlist); rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist); if (rc == 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."), provname); return (rc); } print_kef_policy(provname, pent, has_random, has_mechs); free_entry(pent); return (SUCCESS); } /* * 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(8) 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); } /* * 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(8) 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); } /* * 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(8) 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); } /* * 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); } /* * 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); } /* * 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); } } (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); } /* * Check if a hardware provider is valid. If it is valid, returns its device * name, instance number and the number of mechanisms it supports. */ static int check_hardware_provider(char *provname, char *pname, int *pnum, int *pcount) { crypto_get_dev_list_t *dev_list = NULL; int i; if (provname == NULL) { return (FAILURE); } /* First, get the device name and the instance number from provname */ if (split_hw_provname(provname, pname, pnum) == FAILURE) { return (FAILURE); } /* * Get the complete device list from kernel and check if this provider * is in the list. */ if (get_dev_list(&dev_list) == FAILURE) { return (FAILURE); } for (i = 0; i < dev_list->dl_dev_count; i++) { if ((strcmp(dev_list->dl_devs[i].le_dev_name, pname) == 0) && (dev_list->dl_devs[i].le_dev_instance == *pnum)) { break; } } if (i == dev_list->dl_dev_count) { /* didn't find this provider in the kernel device list */ cryptoerror(LOG_STDERR, gettext("%s does not exist."), provname); free(dev_list); return (FAILURE); } /* This provider is valid. Get its mechanism count */ *pcount = dev_list->dl_devs[i].le_mechanism_count; free(dev_list); return (SUCCESS); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2010 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include "cryptoadm.h" #define DEFAULT_DEV_NUM 5 #define DEFAULT_SOFT_NUM 10 static crypto_get_soft_info_t *setup_get_soft_info(char *, int); /* * Prepare the argument for the LOAD_SOFT_CONFIG ioctl call for the * provider pointed by pent. Return NULL if out of memory. */ crypto_load_soft_config_t * setup_soft_conf(entry_t *pent) { crypto_load_soft_config_t *pload_soft_conf; mechlist_t *plist; uint_t sup_count; size_t extra_mech_size = 0; int i; if (pent == NULL) { return (NULL); } sup_count = pent->sup_count; if (sup_count > 1) { extra_mech_size = sizeof (crypto_mech_name_t) * (sup_count - 1); } pload_soft_conf = malloc(sizeof (crypto_load_soft_config_t) + extra_mech_size); if (pload_soft_conf == NULL) { cryptodebug("out of memory."); return (NULL); } (void) strlcpy(pload_soft_conf->sc_name, pent->name, MAXNAMELEN); pload_soft_conf->sc_count = sup_count; i = 0; plist = pent->suplist; while (i < sup_count) { (void) strlcpy(pload_soft_conf->sc_list[i++], plist->name, CRYPTO_MAX_MECH_NAME); plist = plist->next; } return (pload_soft_conf); } /* * Prepare the argument for the LOAD_SOFT_DISABLED ioctl call for the * provider pointed by pent. Return NULL if out of memory. */ crypto_load_soft_disabled_t * setup_soft_dis(entry_t *pent) { crypto_load_soft_disabled_t *pload_soft_dis = NULL; mechlist_t *plist = NULL; size_t extra_mech_size = 0; uint_t dis_count; int i; if (pent == NULL) { return (NULL); } dis_count = pent->dis_count; if (dis_count > 1) { extra_mech_size = sizeof (crypto_mech_name_t) * (dis_count - 1); } pload_soft_dis = malloc(sizeof (crypto_load_soft_disabled_t) + extra_mech_size); if (pload_soft_dis == NULL) { cryptodebug("out of memory."); return (NULL); } (void) strlcpy(pload_soft_dis->sd_name, pent->name, MAXNAMELEN); pload_soft_dis->sd_count = dis_count; i = 0; plist = pent->dislist; while (i < dis_count) { (void) strlcpy(pload_soft_dis->sd_list[i++], plist->name, CRYPTO_MAX_MECH_NAME); plist = plist->next; } return (pload_soft_dis); } /* * Prepare the argument for the LOAD_DEV_DISABLED ioctl call for the * provider pointed by pent. Return NULL if out of memory. */ crypto_load_dev_disabled_t * setup_dev_dis(entry_t *pent) { crypto_load_dev_disabled_t *pload_dev_dis = NULL; mechlist_t *plist = NULL; size_t extra_mech_size = 0; uint_t dis_count; int i; char pname[MAXNAMELEN]; int inst_num; if (pent == NULL) { return (NULL); } /* get the device name and the instance number */ if (split_hw_provname(pent->name, pname, &inst_num) == FAILURE) { return (NULL); } /* allocate space for pload_dev_des */ dis_count = pent->dis_count; if (dis_count > 1) { extra_mech_size = sizeof (crypto_mech_name_t) * (dis_count - 1); } pload_dev_dis = malloc(sizeof (crypto_load_dev_disabled_t) + extra_mech_size); if (pload_dev_dis == NULL) { cryptodebug("out of memory."); return (NULL); } /* set the values for pload_dev_dis */ (void) strlcpy(pload_dev_dis->dd_dev_name, pname, MAXNAMELEN); pload_dev_dis->dd_dev_instance = inst_num; pload_dev_dis->dd_count = dis_count; i = 0; plist = pent->dislist; while (i < dis_count) { (void) strlcpy(pload_dev_dis->dd_list[i++], plist->name, CRYPTO_MAX_MECH_NAME); plist = plist->next; } return (pload_dev_dis); } /* * Prepare the calling argument of the UNLOAD_SOFT_MODULE ioctl call for the * provider pointed by pent. Return NULL if out of memory. */ crypto_unload_soft_module_t * setup_unload_soft(entry_t *pent) { crypto_unload_soft_module_t *punload_soft; if (pent == NULL) { return (NULL); } punload_soft = malloc(sizeof (crypto_unload_soft_module_t)); if (punload_soft == NULL) { cryptodebug("out of memory."); return (NULL); } (void) strlcpy(punload_soft->sm_name, pent->name, MAXNAMELEN); return (punload_soft); } /* * Prepare the calling argument for the GET_SOFT_INFO call for the provider * with the number of mechanisms specified in the second argument. * * Called by get_soft_info(). */ static crypto_get_soft_info_t * setup_get_soft_info(char *provname, int count) { crypto_get_soft_info_t *psoft_info; size_t extra_mech_size = 0; if (provname == NULL) { return (NULL); } if (count > 1) { extra_mech_size = sizeof (crypto_mech_name_t) * (count - 1); } psoft_info = malloc(sizeof (crypto_get_soft_info_t) + extra_mech_size); if (psoft_info == NULL) { cryptodebug("out of memory."); return (NULL); } (void) strlcpy(psoft_info->si_name, provname, MAXNAMELEN); psoft_info->si_count = count; return (psoft_info); } /* * Get the device list from kernel. */ int get_dev_list(crypto_get_dev_list_t **ppdevlist) { crypto_get_dev_list_t *pdevlist; int fd = -1; 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)); free(pdevlist); 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); } /* * Get all the mechanisms supported by the hardware provider. * The result will be stored in the second argument. */ int get_dev_info(char *devname, int inst_num, int count, mechlist_t **ppmechlist) { crypto_get_dev_info_t *dev_info; mechlist_t *phead; mechlist_t *pcur; mechlist_t *pmech; int fd = -1; int i; int rc; if (devname == NULL || count < 1) { cryptodebug("get_dev_info(): devname is NULL or bogus count"); return (FAILURE); } /* Set up the argument for the CRYPTO_GET_DEV_INFO ioctl call */ dev_info = malloc(sizeof (crypto_get_dev_info_t) + sizeof (crypto_mech_name_t) * (count - 1)); if (dev_info == NULL) { cryptodebug("out of memory."); return (FAILURE); } (void) strlcpy(dev_info->di_dev_name, devname, MAXNAMELEN); dev_info->di_dev_instance = inst_num; dev_info->di_count = count; /* Open the ioctl device */ if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); free(dev_info); return (FAILURE); } if (ioctl(fd, CRYPTO_GET_DEV_INFO, dev_info) == -1) { cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed: %s", strerror(errno)); free(dev_info); (void) close(fd); return (FAILURE); } if (dev_info->di_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed, " "return_value = %d", dev_info->di_return_value); free(dev_info); (void) close(fd); return (FAILURE); } phead = pcur = NULL; rc = SUCCESS; for (i = 0; i < dev_info->di_count; i++) { pmech = create_mech(&dev_info->di_list[i][0]); if (pmech == NULL) { rc = FAILURE; break; } else { if (phead == NULL) { phead = pcur = pmech; } else { pcur->next = pmech; pcur = pmech; } } } if (rc == SUCCESS) { *ppmechlist = phead; } else { free_mechlist(phead); } free(dev_info); (void) close(fd); return (rc); } /* * Get the supported mechanism list of the software provider from kernel. * * Parameters phardlist and psoftlist are supplied by get_kcfconf_info(). * If NULL, this function calls get_kcfconf_info() internally. */ int get_soft_info(char *provname, mechlist_t **ppmechlist, entrylist_t *phardlist, entrylist_t *psoftlist) { boolean_t in_kernel = B_FALSE; crypto_get_soft_info_t *psoft_info; mechlist_t *phead; mechlist_t *pmech; mechlist_t *pcur; entry_t *pent = NULL; int count; int fd = -1; int rc; int i; if (provname == NULL) { return (FAILURE); } if (getzoneid() == GLOBAL_ZONEID) { /* use kcf.conf for kernel software providers in global zone */ if ((pent = getent_kef(provname, phardlist, psoftlist)) == NULL) { /* No kcf.conf entry for this provider */ 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); } /* * Set mech count to 1. It will be reset to the * correct value later if the setup buffer is too small. */ count = 1; } else { count = pent->sup_count; free_entry(pent); } } else { /* * kcf.conf not there in non-global zone: set mech count to 1. * It will be reset to the correct value later if the setup * buffer is too small. */ count = 1; } if ((psoft_info = setup_get_soft_info(provname, count)) == NULL) { 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)); free(psoft_info); return (FAILURE); } /* make GET_SOFT_INFO ioctl call */ if ((rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info)) == -1) { cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed: %s", strerror(errno)); (void) close(fd); free(psoft_info); return (FAILURE); } /* BUFFER is too small, get the number of mechanisms and retry it. */ if (psoft_info->si_return_value == CRYPTO_BUFFER_TOO_SMALL) { count = psoft_info->si_count; free(psoft_info); if ((psoft_info = setup_get_soft_info(provname, count)) == NULL) { (void) close(fd); return (FAILURE); } else { rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info); if (rc == -1) { cryptodebug("CRYPTO_GET_SOFT_INFO ioctl " "failed: %s", strerror(errno)); (void) close(fd); free(psoft_info); return (FAILURE); } } } (void) close(fd); if (psoft_info->si_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed, " "return_value = %d", psoft_info->si_return_value); free(psoft_info); return (FAILURE); } /* Build the mechanism linked list and return it */ rc = SUCCESS; phead = pcur = NULL; for (i = 0; i < psoft_info->si_count; i++) { pmech = create_mech(&psoft_info->si_list[i][0]); if (pmech == NULL) { rc = FAILURE; break; } else { if (phead == NULL) { phead = pcur = pmech; } else { pcur->next = pmech; pcur = pmech; } } } if (rc == FAILURE) { free_mechlist(phead); } else { *ppmechlist = phead; } free(psoft_info); return (rc); } /* * Get the kernel software provider list from kernel. */ int get_soft_list(crypto_get_soft_list_t **ppsoftlist) { crypto_get_soft_list_t *psoftlist = NULL; int count = DEFAULT_SOFT_NUM; int len; int fd = -1; 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); } len = MAXNAMELEN * count; psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len); if (psoftlist == NULL) { cryptodebug("out of memory."); (void) close(fd); return (FAILURE); } psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1); psoftlist->sl_soft_count = count; psoftlist->sl_soft_len = len; if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) { cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed: %s", strerror(errno)); free(psoftlist); (void) close(fd); return (FAILURE); } /* * if BUFFER is too small, get the number of software providers and * the minimum length needed for names and length and retry it. */ if (psoftlist->sl_return_value == CRYPTO_BUFFER_TOO_SMALL) { count = psoftlist->sl_soft_count; len = psoftlist->sl_soft_len; free(psoftlist); psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len); if (psoftlist == NULL) { cryptodebug("out of memory."); (void) close(fd); return (FAILURE); } psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1); psoftlist->sl_soft_count = count; psoftlist->sl_soft_len = len; if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) { cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed:" "%s", strerror(errno)); free(psoftlist); (void) close(fd); return (FAILURE); } } if (psoftlist->sl_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed, " "return_value = %d", psoftlist->sl_return_value); free(psoftlist); (void) close(fd); return (FAILURE); } *ppsoftlist = psoftlist; (void) close(fd); return (SUCCESS); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include "cryptoadm.h" static int err; /* To store errno which may be overwritten by gettext() */ static int build_entrylist(entry_t *pent, entrylist_t **pplist); static entry_t *dup_entry(entry_t *pent1); static mechlist_t *dup_mechlist(mechlist_t *plist); static entry_t *getent(char *provname, entrylist_t *entrylist); static int interpret(char *buf, entry_t **ppent); static int parse_sup_dis_list(const char *buf, entry_t *pent); /* * Duplicate the mechanism list. A null pointer is returned if the storage * space available is insufficient or the input argument is NULL. */ static mechlist_t * dup_mechlist(mechlist_t *plist) { mechlist_t *pres = NULL; mechlist_t *pcur; mechlist_t *ptmp; int rc = SUCCESS; while (plist != NULL) { if (!(ptmp = create_mech(plist->name))) { rc = FAILURE; break; } if (pres == NULL) { pres = pcur = ptmp; } else { pcur->next = ptmp; pcur = pcur->next; } plist = plist->next; } if (rc != SUCCESS) { free_mechlist(pres); return (NULL); } return (pres); } /* * Get the number of mechanisms in the mechanism list. */ int get_mech_count(mechlist_t *plist) { int count = 0; while (plist != NULL) { count++; plist = plist->next; } return (count); } /* * Create one item of type entry_t with the provider name. * Return NULL if there's not enough memory or provname is NULL. */ entry_t * create_entry(char *provname) { entry_t *pent = NULL; if (provname == NULL) { return (NULL); } pent = calloc(1, sizeof (entry_t)); if (pent == NULL) { cryptodebug("out of memory."); return (NULL); } (void) strlcpy(pent->name, provname, MAXNAMELEN); pent->suplist = NULL; pent->sup_count = 0; pent->dislist = NULL; pent->dis_count = 0; pent->load = B_TRUE; return (pent); } /* * Duplicate an entry for a provider from kcf.conf. * Return NULL if memory is insufficient or the input argument is NULL. * Called by getent(). */ static entry_t * dup_entry(entry_t *pent1) { entry_t *pent2 = NULL; if (pent1 == NULL) { return (NULL); } if ((pent2 = create_entry(pent1->name)) == NULL) { cryptodebug("out of memory."); return (NULL); } pent2->sup_count = pent1->sup_count; pent2->dis_count = pent1->dis_count; pent2->load = pent1->load; if (pent1->suplist != NULL) { pent2->suplist = dup_mechlist(pent1->suplist); if (pent2->suplist == NULL) { free_entry(pent2); return (NULL); } } if (pent1->dislist != NULL) { pent2->dislist = dup_mechlist(pent1->dislist); if (pent2->dislist == NULL) { free_entry(pent2); return (NULL); } } return (pent2); } /* * This routine parses the disabledlist or the supportedlist of an entry * in the kcf.conf configuration file. * * Arguments: * buf: an input argument which is a char string with the format of * "disabledlist=m1,m2,..." or "supportedlist=m1,m2,..." * pent: the entry for the disabledlist. This is an IN/OUT argument. * * Return value: SUCCESS or FAILURE. */ static int parse_sup_dis_list(const char *buf, entry_t *pent) { mechlist_t *pmech = NULL; mechlist_t *phead = NULL; char *next_token; char *value; int count; int supflag = B_FALSE; int disflag = B_FALSE; int rc = SUCCESS; if (strncmp(buf, EF_SUPPORTED, strlen(EF_SUPPORTED)) == 0) { supflag = B_TRUE; } else if (strncmp(buf, EF_DISABLED, strlen(EF_DISABLED)) == 0) { disflag = B_TRUE; } else { /* should not come here */ return (FAILURE); } if (value = strpbrk(buf, SEP_EQUAL)) { value++; /* get rid of = */ } else { cryptodebug("failed to parse the kcf.conf file."); return (FAILURE); } if ((next_token = strtok(value, SEP_COMMA)) == NULL) { cryptodebug("failed to parse the kcf.conf file."); return (FAILURE); } if ((pmech = create_mech(next_token)) == NULL) { return (FAILURE); } if (supflag) { if (pent->suplist != NULL) { cryptodebug("multiple supportedlist entries " "for a mechanism in file kcf.conf."); return (FAILURE); } else { pent->suplist = phead = pmech; } } else if (disflag) { if (pent->dislist != NULL) { cryptodebug("multiple disabledlist entries " "for a mechanism in file kcf.conf."); return (FAILURE); } else { pent->dislist = phead = pmech; } } count = 1; while (next_token) { if (next_token = strtok(NULL, SEP_COMMA)) { if ((pmech = create_mech(next_token)) == NULL) { rc = FAILURE; break; } count++; phead->next = pmech; phead = phead->next; } } if (rc == SUCCESS) { if (supflag) { pent->sup_count = count; } else if (disflag) { pent->dis_count = count; } } else { free_mechlist(phead); } return (rc); } /* * Convert a char string containing a line about a provider * from kcf.conf into an entry_t structure. * * Note: the input string, buf, may be modified by this function. * * See ent2str(), the reverse of this function, for the format of * kcf.conf lines. */ static int interpret(char *buf, entry_t **ppent) { entry_t *pent = NULL; char *token1; char *token2; char *token3; int rc; /* Get provider name */ if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */ return (FAILURE); }; pent = create_entry(token1); if (pent == NULL) { cryptodebug("out of memory."); return (FAILURE); } if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) { /* The entry contains a provider name only */ free_entry(pent); return (FAILURE); } if (strncmp(token2, EF_UNLOAD, strlen(EF_UNLOAD)) == 0) { pent->load = B_FALSE; /* cryptoadm unload */ token2 = strtok(NULL, SEP_SEMICOLON); /* * If token2 is NULL, the entry contains a * provider name:unload only */ } if (token2 != NULL) { /* * Either supportedlist or disabledlist or both are present. * Need to call strtok() to get token3 first, as function * parse_sup_dis_list() makes strtok() calls on the * token2 substring. */ token3 = strtok(NULL, SEP_SEMICOLON); /* optional */ /* parse supportedlist (or disabledlist if no supportedlist) */ if ((rc = parse_sup_dis_list(token2, pent)) != SUCCESS) { free_entry(pent); return (rc); } /* parse disabledlist (if there's a supportedlist) */ if ((token3 != NULL) && ((rc = parse_sup_dis_list(token3, pent)) != SUCCESS)) { free_entry(pent); return (rc); } } *ppent = pent; return (SUCCESS); } /* * Add an entry about a provider from kcf.conf to the end of an entry list. * If the entry list pplist is NULL, create the linked list with pent as the * first element. */ static int build_entrylist(entry_t *pent, entrylist_t **pplist) { entrylist_t *pentlist; entrylist_t *pcur = NULL; pentlist = malloc(sizeof (entrylist_t)); if (pentlist == NULL) { cryptodebug("out of memory."); return (FAILURE); } pentlist->pent = pent; pentlist->next = NULL; if (*pplist) { pcur = *pplist; while (pcur->next != NULL) pcur = pcur->next; pcur->next = pentlist; } else { /* empty list */ *pplist = pentlist; } return (SUCCESS); } /* * Find the entry with the "provname" name from the entry list and duplicate * it. Called by getent_kef(). */ static entry_t * getent(char *provname, entrylist_t *entrylist) { boolean_t found = B_FALSE; entry_t *pent1 = NULL; if ((provname == NULL) || (entrylist == NULL)) { return (NULL); } while (!found && entrylist) { if (strcmp(entrylist->pent->name, provname) == 0) { found = B_TRUE; pent1 = entrylist->pent; } else { entrylist = entrylist->next; } } if (!found) { return (NULL); } /* duplicate the entry to be returned */ return (dup_entry(pent1)); } /* * Free memory in entry_t. * That is, the supported and disabled lists for a provider * from kcf.conf. */ void free_entry(entry_t *pent) { if (pent == NULL) { return; } else { free_mechlist(pent->suplist); free_mechlist(pent->dislist); free(pent); } } /* * Free elements in a entrylist_t linked list, * which lists providers in kcf.conf. */ void free_entrylist(entrylist_t *entrylist) { entrylist_t *pnext; while (entrylist != NULL) { pnext = entrylist->next; free_entry(entrylist->pent); entrylist = pnext; } } /* * Convert an entry_t to a kcf.conf line string. Build a string to insert * as a line in file kcf.conf. Based on the content of an entry_t, * the result string is one of these 8 forms: * - name:supportedlist=m1,m2,...,mj * - name:disabledlist=m1,m2,...,mj * - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk * * - name:unload * - name:unload;supportedlist=m1,m2,...,mj * - name:unload;disabledlist=m1,m2,...,mj * - name:unload;supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk * * - (NUL character or 0-length string) * * Return a 0-length empty string if no keyword is present (that is, * supportedlist, disabledlist, or unload). A kcf.conf line with just the * provider name with no keyword is invalid. * * Note that the caller is responsible for freeing the returned string * (with free_entry()). * See interpret() for the reverse of this function: converting a string * to an entry_t. */ char * ent2str(entry_t *pent) { char *buf; mechlist_t *pcur = NULL; boolean_t keyword_already_present = B_FALSE; if (pent == NULL) { return (NULL); } if ((buf = malloc(BUFSIZ)) == NULL) { return (NULL); } /* convert the provider name */ if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (!pent->load) { /* add "unload" keyword */ if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_UNLOAD, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } keyword_already_present = B_TRUE; } /* convert the supported list if any */ pcur = pent->suplist; if (pcur != NULL) { if (strlcat(buf, keyword_already_present ? SEP_SEMICOLON : SEP_COLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } while (pcur != NULL) { if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } pcur = pcur->next; if (pcur != NULL) { if (strlcat(buf, SEP_COMMA, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } } keyword_already_present = B_TRUE; } /* convert the disabled list if any */ pcur = pent->dislist; if (pcur != NULL) { if (strlcat(buf, keyword_already_present ? SEP_SEMICOLON : SEP_COLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } while (pcur != NULL) { if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } pcur = pcur->next; if (pcur != NULL) { if (strlcat(buf, SEP_COMMA, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } } keyword_already_present = B_TRUE; } if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (!keyword_already_present) { /* Only the provider name, without a keyword, is on the line */ buf[0] = '\0'; } return (buf); } /* * Enable the mechanisms for the provider pointed by *ppent. If allflag is * TRUE, enable all. Otherwise, enable the mechanisms specified in the 3rd * argument "mlist". The result will be stored in ppent also. */ int enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist) { entry_t *pent; mechlist_t *phead; /* the current and resulting disabled list */ mechlist_t *ptr = NULL; mechlist_t *pcur = NULL; boolean_t found; pent = *ppent; if (pent == NULL) { return (FAILURE); } if (allflag) { free_mechlist(pent->dislist); pent->dis_count = 0; pent->dislist = NULL; return (SUCCESS); } /* * for each mechanism in the to-be-enabled mechanism list, * - check if it is in the current disabled list * - if found, delete it from the disabled list * otherwise, give a warning. */ ptr = mlist; while (ptr != NULL) { found = B_FALSE; phead = pcur = pent->dislist; while (!found && pcur) { if (strcmp(pcur->name, ptr->name) == 0) { found = B_TRUE; } else { phead = pcur; pcur = pcur->next; } } if (found) { if (phead == pcur) { pent->dislist = pent->dislist->next; free(pcur); } else { phead->next = pcur->next; free(pcur); } pent->dis_count--; } else { cryptoerror(LOG_STDERR, gettext( "(Warning) %1$s is either enabled already or not " "a valid mechanism for %2$s"), ptr->name, pent->name); } ptr = ptr->next; } if (pent->dis_count == 0) { pent->dislist = NULL; } return (SUCCESS); } /* * Determine if the kernel provider name, path, is a device * (that is, it contains a slash character (e.g., "mca/0"). * If so, it is a hardware provider; otherwise it is a software provider. */ boolean_t is_device(char *path) { if (strchr(path, SEP_SLASH) != NULL) { return (B_TRUE); } else { return (B_FALSE); } } /* * Split a hardware provider name with the "name/inst_num" format into * a name and a number (e.g., split "mca/0" into "mca" instance 0). */ int split_hw_provname(char *provname, char *pname, int *inst_num) { char name[MAXNAMELEN]; char *inst_str; if (provname == NULL) { return (FAILURE); } (void) strlcpy(name, provname, MAXNAMELEN); if (strtok(name, "/") == NULL) { return (FAILURE); } if ((inst_str = strtok(NULL, "/")) == NULL) { return (FAILURE); } (void) strlcpy(pname, name, MAXNAMELEN); *inst_num = atoi(inst_str); return (SUCCESS); } /* * Retrieve information from kcf.conf and build a hardware device entry list * and a software entry list of kernel crypto providers. * * This list is usually incomplete, as kernel crypto providers only have to * be listed in kcf.conf if a mechanism is disabled (by cryptoadm) or * if the kernel provider module is not one of the default kernel providers. * * The kcf.conf file is available only in the global zone. */ int get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist) { FILE *pfile = NULL; char buffer[BUFSIZ]; int len; entry_t *pent = NULL; int rc = SUCCESS; if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) { cryptodebug("failed to open the kcf.conf file for read only"); return (FAILURE); } *ppdevlist = NULL; *ppsoftlist = NULL; while (fgets(buffer, BUFSIZ, pfile) != NULL) { if (buffer[0] == '#' || buffer[0] == ' ' || buffer[0] == '\n'|| buffer[0] == '\t') { continue; /* ignore comment lines */ } len = strlen(buffer); if (buffer[len - 1] == '\n') { /* get rid of trailing '\n' */ len--; } buffer[len] = '\0'; if ((rc = interpret(buffer, &pent)) == SUCCESS) { if (is_device(pent->name)) { rc = build_entrylist(pent, ppdevlist); } else { rc = build_entrylist(pent, ppsoftlist); } } else { cryptoerror(LOG_STDERR, gettext( "failed to parse configuration.")); } if (rc != SUCCESS) { free_entrylist(*ppdevlist); free_entrylist(*ppsoftlist); free_entry(pent); break; } } (void) fclose(pfile); return (rc); } /* * Retrieve information from admin device and build a device entry list and * a software entry list. This is used where there is no kcf.conf, e.g., the * non-global zone. */ int get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist) { crypto_get_dev_list_t *pdevlist_kernel = NULL; crypto_get_soft_list_t *psoftlist_kernel = NULL; char *devname; int inst_num; int mcount; mechlist_t *pmech = NULL; entry_t *pent_dev = NULL, *pent_soft = NULL; int i; char *psoftname; entrylist_t *tmp_pdev = NULL; entrylist_t *tmp_psoft = NULL; entrylist_t *phardlist = NULL, *psoftlist = NULL; /* * Get hardware providers */ if (get_dev_list(&pdevlist_kernel) != SUCCESS) { cryptodebug("failed to get hardware provider list from kernel"); return (FAILURE); } for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) { devname = pdevlist_kernel->dl_devs[i].le_dev_name; inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance; mcount = pdevlist_kernel->dl_devs[i].le_mechanism_count; pmech = NULL; if (get_dev_info(devname, inst_num, mcount, &pmech) != SUCCESS) { cryptodebug( "failed to retrieve the mechanism list for %s/%d.", devname, inst_num); goto fail_out; } if ((pent_dev = create_entry(devname)) == NULL) { cryptodebug("out of memory."); free_mechlist(pmech); goto fail_out; } pent_dev->suplist = pmech; pent_dev->sup_count = mcount; if (build_entrylist(pent_dev, &tmp_pdev) != SUCCESS) { goto fail_out; } } free(pdevlist_kernel); pdevlist_kernel = NULL; /* * Get software providers */ if (getzoneid() == GLOBAL_ZONEID) { if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) { goto fail_out; } } if (get_soft_list(&psoftlist_kernel) != SUCCESS) { cryptodebug("failed to get software provider list from kernel"); goto fail_out; } for (i = 0, psoftname = psoftlist_kernel->sl_soft_names; i < psoftlist_kernel->sl_soft_count; i++, psoftname = psoftname + strlen(psoftname) + 1) { pmech = NULL; if (get_soft_info(psoftname, &pmech, phardlist, psoftlist) != SUCCESS) { cryptodebug( "failed to retrieve the mechanism list for %s.", psoftname); goto fail_out; } if ((pent_soft = create_entry(psoftname)) == NULL) { cryptodebug("out of memory."); free_mechlist(pmech); goto fail_out; } pent_soft->suplist = pmech; pent_soft->sup_count = get_mech_count(pmech); if (build_entrylist(pent_soft, &tmp_psoft) != SUCCESS) { goto fail_out; } } free(psoftlist_kernel); psoftlist_kernel = NULL; *ppdevlist = tmp_pdev; *ppsoftlist = tmp_psoft; return (SUCCESS); fail_out: if (pent_dev != NULL) free_entry(pent_dev); if (pent_soft != NULL) free_entry(pent_soft); free_entrylist(tmp_pdev); free_entrylist(tmp_psoft); if (pdevlist_kernel != NULL) free(pdevlist_kernel); if (psoftlist_kernel != NULL) free(psoftlist_kernel); return (FAILURE); } /* * Return configuration information for a kernel provider from kcf.conf. * For kernel software providers return a enabled list and disabled list. * For kernel hardware providers return just a disabled list. * * Parameters phardlist and psoftlist are supplied by get_kcfconf_info(). * If NULL, this function calls get_kcfconf_info() internally. */ entry_t * getent_kef(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist) { entry_t *pent = NULL; boolean_t memory_allocated = B_FALSE; if ((phardlist == NULL) || (psoftlist == NULL)) { if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) { return (NULL); } memory_allocated = B_TRUE; } if (is_device(provname)) { pent = getent(provname, phardlist); } else { pent = getent(provname, psoftlist); } if (memory_allocated) { free_entrylist(phardlist); free_entrylist(psoftlist); } return (pent); } /* * Print out the provider name and the mechanism list. */ void print_mechlist(char *provname, mechlist_t *pmechlist) { mechlist_t *ptr = NULL; if (provname == NULL) { return; } (void) printf("%s: ", provname); if (pmechlist == NULL) { (void) printf(gettext("No mechanisms presented.\n")); return; } ptr = pmechlist; while (ptr != NULL) { (void) printf("%s", ptr->name); ptr = ptr->next; if (ptr == NULL) { (void) printf("\n"); } else { (void) printf(","); } } } /* * Update the kcf.conf file based on the update mode: * - If update_mode is MODIFY_MODE, modify the entry with the same name. * If not found, append a new entry to the kcf.conf file. * - If update_mode is DELETE_MODE, delete the entry with the same name. * - If update_mode is ADD_MODE, append a new entry to the kcf.conf file. */ int update_kcfconf(entry_t *pent, int update_mode) { boolean_t add_it = B_FALSE; boolean_t delete_it = B_FALSE; boolean_t this_entry_matches = B_FALSE; boolean_t found_entry = B_FALSE; FILE *pfile = NULL; FILE *pfile_tmp = NULL; char buffer[BUFSIZ]; char buffer2[BUFSIZ]; char tmpfile_name[MAXPATHLEN]; char *name; char *new_str = NULL; int rc = SUCCESS; if (pent == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } /* Check the update_mode */ switch (update_mode) { case ADD_MODE: add_it = B_TRUE; /* FALLTHROUGH */ case MODIFY_MODE: /* Convert the entry a string to add to kcf.conf */ if ((new_str = ent2str(pent)) == NULL) { return (FAILURE); } if (strlen(new_str) == 0) { free(new_str); delete_it = B_TRUE; } break; case DELETE_MODE: delete_it = B_TRUE; break; default: cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } /* Open the kcf.conf file */ 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); return (FAILURE); } /* Lock the kcf.conf file */ if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); (void) fclose(pfile); return (FAILURE); } /* * Create a temporary file in the /etc/crypto directory to save * updated configuration file first. */ (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)); (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)); (void) fclose(pfile); return (FAILURE); } /* * Loop thru the entire kcf.conf file, insert, modify or delete * an entry. */ while (fgets(buffer, BUFSIZ, pfile) != NULL) { if (add_it) { if (fputs(buffer, pfile_tmp) == EOF) { err = errno; cryptoerror(LOG_STDERR, gettext( "failed to write to a temp file: %s."), strerror(err)); rc = FAILURE; break; } } else { /* modify or delete */ this_entry_matches = B_FALSE; if (!(buffer[0] == '#' || buffer[0] == ' ' || buffer[0] == '\n'|| buffer[0] == '\t')) { /* * Get the provider name from this line and * check if this is the entry to be updated * or deleted. Note: can not use "buffer" * directly because strtok will change its * value. */ (void) strlcpy(buffer2, buffer, BUFSIZ); if ((name = strtok(buffer2, SEP_COLON)) == NULL) { rc = FAILURE; break; } if (strcmp(pent->name, name) == 0) { this_entry_matches = B_TRUE; found_entry = B_TRUE; } } if (!this_entry_matches || !delete_it) { /* write this entry */ if (this_entry_matches) { /* * Modify this entry: get the * updated string and place into buffer. */ (void) strlcpy(buffer, new_str, BUFSIZ); free(new_str); } /* write the (unchanged or modified) entry */ if (fputs(buffer, pfile_tmp) == EOF) { err = errno; cryptoerror(LOG_STDERR, gettext( "failed to write to a temp file: " "%s."), strerror(err)); rc = FAILURE; break; } } } } if ((!delete_it) && (rc != FAILURE)) { if (add_it || !found_entry) { /* append new entry to end of file */ if (fputs(new_str, pfile_tmp) == EOF) { err = errno; cryptoerror(LOG_STDERR, gettext( "failed to write to a temp file: %s."), strerror(err)); rc = FAILURE; } free(new_str); } } (void) fclose(pfile); if (fclose(pfile_tmp) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to close %s: %s"), tmpfile_name, strerror(err)); return (FAILURE); } /* Copy the temporary file to the kcf.conf file */ 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, _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) && (unlink(tmpfile_name) != 0)) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } return (rc); } /* * Disable the mechanisms for the provider pointed by *ppent. If allflag is * TRUE, disable all. Otherwise, disable the mechanisms specified in the * dislist argument. The "infolist" argument contains the mechanism list * supported by this provider. */ int disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag, mechlist_t *dislist) { entry_t *pent; mechlist_t *plist = NULL; mechlist_t *phead = NULL; mechlist_t *pmech = NULL; int rc = SUCCESS; pent = *ppent; if (pent == NULL) { return (FAILURE); } if (allflag) { free_mechlist(pent->dislist); pent->dis_count = get_mech_count(infolist); if (!(pent->dislist = dup_mechlist(infolist))) { return (FAILURE); } else { return (SUCCESS); } } /* * Not disable all. Now loop thru the mechanisms specified in the * dislist. If the mechanism is not supported by the provider, * ignore it with a warning. If the mechanism is disabled already, * do nothing. Otherwise, prepend it to the beginning of the disabled * list of the provider. */ plist = dislist; while (plist != NULL) { if (!is_in_list(plist->name, infolist)) { cryptoerror(LOG_STDERR, gettext("(Warning) " "%1$s is not a valid mechanism for %2$s."), plist->name, pent->name); } else if (!is_in_list(plist->name, pent->dislist)) { /* Add this mechanism into the disabled list */ if ((pmech = create_mech(plist->name)) == NULL) { rc = FAILURE; break; } if (pent->dislist == NULL) { pent->dislist = pmech; } else { phead = pent->dislist; pent->dislist = pmech; pmech->next = phead; } pent->dis_count++; } plist = plist->next; } return (rc); } /* * Remove the mechanism passed, specified by mech, from the list of * mechanisms, if present in the list. Else, do nothing. * * Returns B_TRUE if mechanism is present in the list. */ boolean_t filter_mechlist(mechlist_t **pmechlist, const char *mech) { int cnt = 0; mechlist_t *ptr, *pptr; boolean_t mech_present = B_FALSE; ptr = pptr = *pmechlist; while (ptr != NULL) { if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) { mech_present = B_TRUE; if (ptr == *pmechlist) { pptr = *pmechlist = ptr->next; free(ptr); ptr = pptr; } else { pptr->next = ptr->next; free(ptr); ptr = pptr->next; } } else { pptr = ptr; ptr = ptr->next; cnt++; } } /* Only one entry is present */ if (cnt == 0) *pmechlist = NULL; return (mech_present); } /* * Print out the mechanism policy for a kernel provider that has an entry * in the kcf.conf file. * * The flag has_random is set to B_TRUE if the provider does random * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider * has some mechanisms. * * If pent is NULL, the provider doesn't have a kcf.conf entry. */ void print_kef_policy(char *provname, entry_t *pent, boolean_t has_random, boolean_t has_mechs) { mechlist_t *ptr = NULL; boolean_t rnd_disabled = B_FALSE; if (pent != NULL) { rnd_disabled = filter_mechlist(&pent->dislist, RANDOM); ptr = pent->dislist; } (void) printf("%s:", provname); if (has_mechs == B_TRUE) { /* * TRANSLATION_NOTE * This code block may need to be modified a bit to avoid * constructing the text message on the fly. */ (void) printf(gettext(" all mechanisms are enabled")); if (ptr != NULL) (void) printf(gettext(", except ")); while (ptr != NULL) { (void) printf("%s", ptr->name); ptr = ptr->next; if (ptr != NULL) (void) printf(","); } if (ptr == NULL) (void) printf("."); } /* * TRANSLATION_NOTE * "random" is a keyword and not to be translated. */ if (rnd_disabled) (void) printf(gettext(" %s is disabled."), "random"); else if (has_random) (void) printf(gettext(" %s is enabled."), "random"); (void) printf("\n"); } /* * Check if a kernel software provider is in the kernel. * * Parameters: * provname Provider name * psoftlist_kernel Optional software provider list. If NULL, it will be * obtained from get_soft_list(). * in_kernel Set to B_TRUE if device is in the kernel, else B_FALSE */ int check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel, boolean_t *in_kernel) { char *ptr; int i; boolean_t psoftlist_allocated = B_FALSE; if (provname == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } if (psoftlist_kernel == NULL) { if (get_soft_list(&psoftlist_kernel) == FAILURE) { cryptodebug("failed to get the software provider list" " from kernel."); return (FAILURE); } psoftlist_allocated = B_TRUE; } *in_kernel = B_FALSE; ptr = psoftlist_kernel->sl_soft_names; for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) { if (strcmp(provname, ptr) == 0) { *in_kernel = B_TRUE; break; } ptr = ptr + strlen(ptr) + 1; } if (psoftlist_allocated) free(psoftlist_kernel); return (SUCCESS); } /* * Check if a kernel hardware provider is in the kernel. * * Parameters: * provname Provider name * pdevlist Optional Hardware Crypto Device List. If NULL, it will be * obtained from get_dev_list(). * in_kernel Set to B_TRUE if device is in the kernel, otherwise B_FALSE */ int check_kernel_for_hard(char *provname, crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel) { char devname[MAXNAMELEN]; int inst_num; int i; boolean_t dev_list_allocated = B_FALSE; if (provname == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } if (split_hw_provname(provname, devname, &inst_num) == FAILURE) { return (FAILURE); } if (pdevlist == NULL) { if (get_dev_list(&pdevlist) == FAILURE) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } dev_list_allocated = B_TRUE; } *in_kernel = B_FALSE; for (i = 0; i < pdevlist->dl_dev_count; i++) { if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) && (pdevlist->dl_devs[i].le_dev_instance == inst_num)) { *in_kernel = B_TRUE; break; } } if (dev_list_allocated) free(pdevlist); return (SUCCESS); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Administration for metaslot * * All the "list" operations will call functions in libpkcs11.so * Normally, it doesn't make sense to call functions in libpkcs11.so directly * because libpkcs11.so depends on the configuration file (pkcs11.conf) the * cryptoadm command is trying to administer. However, since metaslot * is part of the framework, it is not possible to get information about * it without actually calling functions in libpkcs11.so. * * So, for the listing operation, which won't modify the value of pkcs11.conf * it is safe to call libpkcs11.so. * * For other operations that modifies the pkcs11.conf file, libpkcs11.so * will not be called. * */ #include #include #include #include #include #include #include #include #include "cryptoadm.h" #define METASLOT_ID 0 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); } int list_metaslot_policy() { uentry_t *puent; int rc; if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) { cryptoerror(LOG_STDERR, gettext("metaslot entry doesn't exist.")); return (FAILURE); } rc = display_policy(puent); (void) printf("\n"); free_uentry(puent); 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); } /* * 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); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2010 Nexenta Systems, Inc. All rights resrved. * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cryptoadm.h" #define HDR1 " P\n" #define HDR2 " S V K a U D\n" #define HDR3 " i e e i n e\n" #define HDR4 " S g V r y r W w r\n" #define HDR5 " E D D i n e i G G r r i\n" #define HDR6 " H n e i g + r + e e a a v E\n" #define HDR7 "min max W c c g n R i R n n p p e C\n" static int err; /* To store errno which may be overwritten by gettext() */ static boolean_t is_in_policylist(midstr_t, umechlist_t *); static char *uent2str(uentry_t *); static boolean_t check_random(CK_SLOT_ID, CK_FUNCTION_LIST_PTR); static void display_slot_flags(CK_FLAGS flags) { (void) printf(gettext("Slot Flags: ")); if (flags & CKF_TOKEN_PRESENT) (void) printf("CKF_TOKEN_PRESENT "); if (flags & CKF_REMOVABLE_DEVICE) (void) printf("CKF_REMOVABLE_DEVICE "); if (flags & CKF_HW_SLOT) (void) printf("CKF_HW_SLOT "); (void) printf("\n"); } void display_token_flags(CK_FLAGS flags) { (void) printf(gettext("Flags: ")); if (flags & CKF_RNG) (void) printf("CKF_RNG "); if (flags & CKF_WRITE_PROTECTED) (void) printf("CKF_WRITE_PROTECTED "); if (flags & CKF_LOGIN_REQUIRED) (void) printf("CKF_LOGIN_REQUIRED "); if (flags & CKF_USER_PIN_INITIALIZED) (void) printf("CKF_USER_PIN_INITIALIZED "); if (flags & CKF_RESTORE_KEY_NOT_NEEDED) (void) printf("CKF_RESTORE_KEY_NOT_NEEDED "); if (flags & CKF_CLOCK_ON_TOKEN) (void) printf("CKF_CLOCK_ON_TOKEN "); if (flags & CKF_PROTECTED_AUTHENTICATION_PATH) (void) printf("CKF_PROTECTED_AUTHENTICATION_PATH "); if (flags & CKF_DUAL_CRYPTO_OPERATIONS) (void) printf("CKF_DUAL_CRYPTO_OPERATIONS "); if (flags & CKF_TOKEN_INITIALIZED) (void) printf("CKF_TOKEN_INITIALIZED "); if (flags & CKF_SECONDARY_AUTHENTICATION) (void) printf("CKF_SECONDARY_AUTHENTICATION "); if (flags & CKF_USER_PIN_COUNT_LOW) (void) printf("CKF_USER_PIN_COUNT_LOW "); if (flags & CKF_USER_PIN_FINAL_TRY) (void) printf("CKF_USER_PIN_FINAL_TRY "); if (flags & CKF_USER_PIN_LOCKED) (void) printf("CKF_USER_PIN_LOCKED "); if (flags & CKF_USER_PIN_TO_BE_CHANGED) (void) printf("CKF_USER_PIN_TO_BE_CHANGED "); if (flags & CKF_SO_PIN_COUNT_LOW) (void) printf("CKF_SO_PIN_COUNT_LOW "); if (flags & CKF_SO_PIN_FINAL_TRY) (void) printf("CKF_SO_PIN_FINAL_TRY "); if (flags & CKF_SO_PIN_LOCKED) (void) printf("CKF_SO_PIN_LOCKED "); if (flags & CKF_SO_PIN_TO_BE_CHANGED) (void) printf("CKF_SO_PIN_TO_BE_CHANGED "); if (flags & CKF_SO_PIN_TO_BE_CHANGED) (void) printf("CKF_SO_PIN_TO_BE_CHANGED "); (void) printf("\n"); } void display_mech_info(CK_MECHANISM_INFO *mechInfo) { CK_FLAGS ec_flags = CKF_EC_F_P | CKF_EC_F_2M | CKF_EC_ECPARAMETERS | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS; (void) printf("%-4ld %-4ld ", mechInfo->ulMinKeySize, mechInfo->ulMaxKeySize); (void) printf("%s %s %s %s %s %s %s %s %s %s %s %s " "%s %s", (mechInfo->flags & CKF_HW) ? "X" : ".", (mechInfo->flags & CKF_ENCRYPT) ? "X" : ".", (mechInfo->flags & CKF_DECRYPT) ? "X" : ".", (mechInfo->flags & CKF_DIGEST) ? "X" : ".", (mechInfo->flags & CKF_SIGN) ? "X" : ".", (mechInfo->flags & CKF_SIGN_RECOVER) ? "X" : ".", (mechInfo->flags & CKF_VERIFY) ? "X" : ".", (mechInfo->flags & CKF_VERIFY_RECOVER) ? "X" : ".", (mechInfo->flags & CKF_GENERATE) ? "X" : ".", (mechInfo->flags & CKF_GENERATE_KEY_PAIR) ? "X" : ".", (mechInfo->flags & CKF_WRAP) ? "X" : ".", (mechInfo->flags & CKF_UNWRAP) ? "X" : ".", (mechInfo->flags & CKF_DERIVE) ? "X" : ".", (mechInfo->flags & ec_flags) ? "X" : "."); } /* * Converts the provided list of mechanism names in their string format to * their corresponding PKCS#11 mechanism IDs. * * The list of mechanism names to be converted is provided in the * "mlist" argument. The list of converted mechanism IDs is returned * in the "pmech_list" argument. * * This function is called by list_metaslot_info() and * list_mechlist_for_lib() functions. */ int convert_mechlist(CK_MECHANISM_TYPE **pmech_list, CK_ULONG *mech_count, mechlist_t *mlist) { int i, n = 0; mechlist_t *p = mlist; while (p != NULL) { p = p->next; n++; } *pmech_list = malloc(n * sizeof (CK_MECHANISM_TYPE)); if (*pmech_list == NULL) { cryptodebug("out of memory"); return (FAILURE); } p = mlist; for (i = 0; i < n; i++) { if (pkcs11_str2mech(p->name, &(*pmech_list[i])) != CKR_OK) { free(*pmech_list); return (FAILURE); } p = p->next; } *mech_count = n; return (SUCCESS); } /* * Display the mechanism list for a user-level library */ int list_mechlist_for_lib(char *libname, mechlist_t *mlist, flag_val_t *rng_flag, boolean_t no_warn, boolean_t verbose, boolean_t show_mechs) { CK_RV rv = CKR_OK; CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR); CK_FUNCTION_LIST_PTR prov_funcs; /* Provider's function list */ CK_SLOT_ID_PTR prov_slots = NULL; /* Provider's slot list */ CK_MECHANISM_TYPE_PTR pmech_list = NULL; /* mech list for a slot */ CK_SLOT_INFO slotinfo; CK_ULONG slot_count; CK_ULONG mech_count; uentry_t *puent = NULL; boolean_t lib_initialized = B_FALSE; void *dldesc = NULL; char *dl_error; const char *mech_name; char *isa; char libpath[MAXPATHLEN]; char buf[MAXPATHLEN]; int i, j; int rc = SUCCESS; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("list_mechlist_for_lib() - libname is NULL."); return (FAILURE); } /* Check if the library is in the pkcs11.conf file */ if ((puent = getent_uef(libname)) == NULL) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), libname); return (FAILURE); } free_uentry(puent); /* Remove $ISA from the library name */ if (strlcpy(buf, libname, sizeof (buf)) >= sizeof (buf)) { (void) printf(gettext("%s: the provider name is too long."), libname); return (FAILURE); } if ((isa = strstr(buf, PKCS11_ISA)) != NULL) { *isa = '\000'; isa += strlen(PKCS11_ISA); (void) snprintf(libpath, MAXPATHLEN, "%s%s%s", buf, "/", isa); } else { (void) strlcpy(libpath, libname, sizeof (libpath)); } /* * Open the provider. Use RTLD_NOW here, as a way to * catch any providers with incomplete symbols that * might otherwise cause problems during libpkcs11's * execution. */ dldesc = dlopen(libpath, RTLD_NOW); if (dldesc == NULL) { dl_error = dlerror(); cryptodebug("Cannot load PKCS#11 library %s. dlerror: %s", libname, dl_error != NULL ? dl_error : "Unknown"); rc = FAILURE; goto clean_exit; } /* Get the pointer to provider'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 %s", libname); rc = FAILURE; goto clean_exit; } /* Get the provider's function list */ rv = Tmp_C_GetFunctionList(&prov_funcs); if (rv != CKR_OK) { cryptodebug("failed to call C_GetFunctionList from %s", libname); rc = FAILURE; goto clean_exit; } /* Initialize this provider */ rv = prov_funcs->C_Initialize(NULL_PTR); if (rv != CKR_OK) { cryptodebug("failed to call C_Initialize from %s, " "return code = %d", libname, rv); rc = FAILURE; goto clean_exit; } else { lib_initialized = B_TRUE; } /* * Find out how many slots this provider has, call with tokenPresent * set to FALSE so all potential slots are returned. */ rv = prov_funcs->C_GetSlotList(FALSE, NULL_PTR, &slot_count); if (rv != CKR_OK) { cryptodebug("failed to get the slotlist from %s.", libname); rc = FAILURE; goto clean_exit; } else if (slot_count == 0) { if (!no_warn) (void) printf(gettext("%s: no slots presented.\n"), libname); rc = SUCCESS; goto clean_exit; } /* Allocate memory for the slot list */ prov_slots = malloc(slot_count * sizeof (CK_SLOT_ID)); if (prov_slots == NULL) { cryptodebug("out of memory."); rc = FAILURE; goto clean_exit; } /* Get the slot list from provider */ rv = prov_funcs->C_GetSlotList(FALSE, prov_slots, &slot_count); if (rv != CKR_OK) { cryptodebug("failed to call C_GetSlotList() from %s.", libname); rc = FAILURE; goto clean_exit; } if (verbose) { (void) printf(gettext("Number of slots: %d\n"), slot_count); } /* Get the mechanism list for each slot */ for (i = 0; i < slot_count; i++) { if (verbose) /* * TRANSLATION_NOTE * In some languages, the # symbol should be * converted to "no", an "n" followed by a * superscript "o".. */ (void) printf(gettext("\nSlot #%d\n"), i+1); if ((rng_flag != NULL) && (*rng_flag == NO_RNG)) { if (check_random(prov_slots[i], prov_funcs)) { *rng_flag = HAS_RNG; rc = SUCCESS; goto clean_exit; } else continue; } rv = prov_funcs->C_GetSlotInfo(prov_slots[i], &slotinfo); if (rv != CKR_OK) { cryptodebug("failed to get slotinfo from %s", libname); rc = FAILURE; break; } if (verbose) { CK_TOKEN_INFO tokeninfo; (void) printf(gettext("Description: %.64s\n" "Manufacturer: %.32s\n" "PKCS#11 Version: %d.%d\n"), slotinfo.slotDescription, slotinfo.manufacturerID, prov_funcs->version.major, prov_funcs->version.minor); (void) printf(gettext("Hardware Version: %d.%d\n" "Firmware Version: %d.%d\n"), slotinfo.hardwareVersion.major, slotinfo.hardwareVersion.minor, slotinfo.firmwareVersion.major, slotinfo.firmwareVersion.minor); (void) printf(gettext("Token Present: %s\n"), (slotinfo.flags & CKF_TOKEN_PRESENT ? gettext("True") : gettext("False"))); display_slot_flags(slotinfo.flags); rv = prov_funcs->C_GetTokenInfo(prov_slots[i], &tokeninfo); if (rv != CKR_OK) { cryptodebug("Failed to get " "token info from %s", libname); rc = FAILURE; break; } (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"), tokeninfo.label, tokeninfo.manufacturerID, tokeninfo.model, tokeninfo.serialNumber, tokeninfo.hardwareVersion.major, tokeninfo.hardwareVersion.minor, tokeninfo.firmwareVersion.major, tokeninfo.firmwareVersion.minor, tokeninfo.utcTime, tokeninfo.ulMinPinLen, tokeninfo.ulMaxPinLen); display_token_flags(tokeninfo.flags); } if (mlist == NULL) { rv = prov_funcs->C_GetMechanismList(prov_slots[i], NULL_PTR, &mech_count); if (rv != CKR_OK) { cryptodebug( "failed to call C_GetMechanismList() " "from %s.", libname); rc = FAILURE; break; } if (mech_count == 0) { /* no mechanisms in this slot */ continue; } pmech_list = malloc(mech_count * sizeof (CK_MECHANISM_TYPE)); if (pmech_list == NULL) { cryptodebug("out of memory"); rc = FAILURE; break; } /* Get the actual mechanism list */ rv = prov_funcs->C_GetMechanismList(prov_slots[i], pmech_list, &mech_count); if (rv != CKR_OK) { cryptodebug( "failed to call C_GetMechanismList() " "from %s.", libname); free(pmech_list); rc = FAILURE; break; } } else { /* use the mechanism list passed in */ rc = convert_mechlist(&pmech_list, &mech_count, mlist); if (rc != SUCCESS) { goto clean_exit; } } if (show_mechs) (void) printf(gettext("Mechanisms:\n")); if (verbose && show_mechs) { display_verbose_mech_header(); } /* * Merge the current mechanism list into the returning * mechanism list. */ for (j = 0; show_mechs && j < mech_count; j++) { CK_MECHANISM_TYPE mech = pmech_list[j]; CK_MECHANISM_INFO mech_info; rv = prov_funcs->C_GetMechanismInfo( prov_slots[i], mech, &mech_info); if (rv != CKR_OK) { cryptodebug( "failed to call " "C_GetMechanismInfo() from %s.", libname); free(pmech_list); pmech_list = NULL; rc = FAILURE; break; } if (mech >= CKM_VENDOR_DEFINED) { (void) printf("%#lx", mech); } else { mech_name = pkcs11_mech2str(mech); (void) printf("%-29s", mech_name); } if (verbose) { display_mech_info(&mech_info); } (void) printf("\n"); } if (pmech_list) free(pmech_list); if (rc == FAILURE) { break; } } if (rng_flag != NULL || rc == FAILURE) { goto clean_exit; } clean_exit: if (rc == FAILURE) { (void) printf(gettext( "%s: failed to retrieve the mechanism list.\n"), libname); } if (lib_initialized) { (void) prov_funcs->C_Finalize(NULL_PTR); } if (dldesc != NULL) { (void) dlclose(dldesc); } if (prov_slots != NULL) { free(prov_slots); } return (rc); } /* * Display the mechanism policy for a user-level library */ int list_policy_for_lib(char *libname) { uentry_t *puent = NULL; int rc; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("list_policy_for_lib() - libname is NULL."); return (FAILURE); } /* Get the library entry from the pkcs11.conf file */ if ((puent = getent_uef(libname)) == NULL) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), libname); return (FAILURE); } /* Print the policy for this library */ rc = print_uef_policy(puent); free_uentry(puent); return (rc); } /* * Disable mechanisms for a user-level library */ int disable_uef_lib(char *libname, boolean_t rndflag, boolean_t allflag, mechlist_t *marglist) { uentry_t *puent; int rc; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("disable_uef_lib() - libname is NULL."); return (FAILURE); } /* Get the provider entry from the pkcs11.conf file */ if ((puent = getent_uef(libname)) == NULL) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), libname); return (FAILURE); } /* * Update the mechanism policy of this library entry, based on * the current policy mode of the library and the mechanisms specified * in CLI. */ if (allflag) { /* * If disabling all, just need to clean up the policylist and * set the flag_enabledlist flag to be B_TRUE. */ free_umechlist(puent->policylist); puent->policylist = NULL; puent->count = 0; puent->flag_enabledlist = B_TRUE; rc = SUCCESS; } else if (marglist != NULL) { 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 in the exception list * (the policylist), delete it from the policylist. */ rc = update_policylist(puent, marglist, 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, marglist, ADD_MODE); } } else if (!rndflag) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("disable_uef_lib() - wrong arguments."); return (FAILURE); } if (rndflag) puent->flag_norandom = B_TRUE; if (rc == FAILURE) { free_uentry(puent); return (FAILURE); } /* Update the pkcs11.conf file with the updated entry */ rc = update_pkcs11conf(puent); free_uentry(puent); return (rc); } /* * Enable disabled mechanisms for a user-level library. */ int enable_uef_lib(char *libname, boolean_t rndflag, boolean_t allflag, mechlist_t *marglist) { uentry_t *puent; int rc = SUCCESS; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("enable_uef_lib() - libname is NULL."); return (FAILURE); } /* Get the provider entry from the pkcs11.conf file */ if ((puent = getent_uef(libname)) == NULL) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), libname); return (FAILURE); } /* * Update the mechanism policy of this library entry, based on * the current policy mode of the library and the mechanisms * specified in CLI. */ 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 (marglist != NULL) { 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, marglist, 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, marglist, DELETE_MODE); } } else if (!rndflag) { /* should not come here */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("enable_uef_lib() - wrong arguments."); return (FAILURE); } if (rndflag) puent->flag_norandom = B_FALSE; if (rc == FAILURE) { free_uentry(puent); return (FAILURE); } /* Update the pkcs11.conf file with the updated entry */ rc = update_pkcs11conf(puent); free_uentry(puent); return (rc); } /* * Install a user-level library. */ int install_uef_lib(char *libname) { uentry_t *puent; struct stat statbuf; char libpath[MAXPATHLEN]; char libbuf[MAXPATHLEN]; char *isa; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("install_uef_lib() - libname is NULL."); return (FAILURE); } /* Check if the provider already exists in the framework */ if ((puent = getent_uef(libname)) != NULL) { cryptoerror(LOG_STDERR, gettext("%s exists already."), libname); free_uentry(puent); return (FAILURE); } /* * Check if the library exists in the system. if $ISA is in the * path, only check the 32bit version. */ if (strlcpy(libbuf, libname, MAXPATHLEN) >= MAXPATHLEN) { cryptoerror(LOG_STDERR, gettext("the provider name is too long - %s"), libname); return (FAILURE); } if ((isa = strstr(libbuf, PKCS11_ISA)) != NULL) { *isa = '\000'; isa += strlen(PKCS11_ISA); (void) snprintf(libpath, sizeof (libpath), "%s%s%s", libbuf, "/", isa); } else { (void) strlcpy(libpath, libname, sizeof (libpath)); } /* Check if it is same as the framework library */ if (strcmp(libpath, UEF_FRAME_LIB) == 0) { cryptoerror(LOG_STDERR, gettext( "The framework library %s can not be installed."), libname); return (FAILURE); } if (stat(libpath, &statbuf) != 0) { cryptoerror(LOG_STDERR, gettext("%s not found"), libname); return (FAILURE); } /* Need to add "\n" to libname for adding into the config file */ if (strlcat(libname, "\n", MAXPATHLEN) >= MAXPATHLEN) { cryptoerror(LOG_STDERR, gettext( "can not install %s; the name is too long."), libname); return (FAILURE); } return (update_conf(_PATH_PKCS11_CONF, libname)); } /* * Uninstall a user-level library. */ int uninstall_uef_lib(char *libname) { uentry_t *puent; FILE *pfile; FILE *pfile_tmp; char buffer[BUFSIZ]; char buffer2[BUFSIZ]; char tmpfile_name[MAXPATHLEN]; char *name; boolean_t found; boolean_t in_package; int len; int rc = SUCCESS; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("uninstall_uef_lib() - libname is NULL."); return (FAILURE); } /* Check if the provider exists */ if ((puent = getent_uef(libname)) == NULL) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), libname); return (FAILURE); } free_uentry(puent); /* Open the pkcs11.conf file and lock it */ if ((pfile = fopen(_PATH_PKCS11_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_PKCS11_CONF); return (FAILURE); } if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to lock the configuration - %s"), strerror(err)); (void) fclose(pfile); return (FAILURE); } /* * Create a temporary file in the /etc/crypto directory to save * the new configuration file first. */ (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)); (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)); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } (void) fclose(pfile); return (FAILURE); } /* * Loop thru the config file. If the library to be uninstalled * is in a package, just comment it off. */ in_package = B_FALSE; while (fgets(buffer, BUFSIZ, pfile) != NULL) { found = B_FALSE; if (!(buffer[0] == ' ' || buffer[0] == '\n' || buffer[0] == '\t')) { if (strstr(buffer, " Start ") != NULL) { in_package = B_TRUE; } else if (strstr(buffer, " End ") != NULL) { in_package = B_FALSE; } else if (buffer[0] != '#') { (void) strlcpy(buffer2, buffer, BUFSIZ); /* get rid of trailing '\n' */ len = strlen(buffer2); if (buffer2[len-1] == '\n') { len--; } buffer2[len] = '\0'; if ((name = strtok(buffer2, SEP_COLON)) == NULL) { rc = FAILURE; break; } else if (strcmp(libname, name) == 0) { found = B_TRUE; } } } if (found) { if (in_package) { (void) snprintf(buffer2, sizeof (buffer2), "%s%s%s", "#", libname, "\n"); if (fputs(buffer2, pfile_tmp) == EOF) { rc = FAILURE; } } } else { if (fputs(buffer, pfile_tmp) == EOF) { rc = FAILURE; } } if (rc == FAILURE) { break; } } if (rc == FAILURE) { cryptoerror(LOG_STDERR, gettext("write error.")); (void) fclose(pfile); (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)); } return (FAILURE); } (void) fclose(pfile); if (fclose(pfile_tmp) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to close a temporary file - %s"), strerror(err)); return (FAILURE); } /* Now update the real config file */ if (rename(tmpfile_name, _PATH_PKCS11_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, _PATH_PKCS11_CONF, strerror(err)); rc = FAILURE; } else if (chmod(_PATH_PKCS11_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_PKCS11_CONF, strerror(err)); rc = FAILURE; } else { rc = SUCCESS; } if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } return (rc); } int display_policy(uentry_t *puent) { CK_MECHANISM_TYPE mech_id; const char *mech_name; umechlist_t *ptr; if (puent == NULL) { return (SUCCESS); } if (puent->flag_enabledlist == B_FALSE) { (void) printf(gettext("%s: all mechanisms are enabled"), puent->name); ptr = puent->policylist; if (ptr == NULL) { (void) printf("."); } else { (void) printf(gettext(", except ")); while (ptr != NULL) { mech_id = strtoul(ptr->name, NULL, 0); if (mech_id & CKO_VENDOR_DEFINED) { /* vendor defined mechanism */ (void) printf("%s", ptr->name); } else { if (mech_id >= CKM_VENDOR_DEFINED) { (void) printf("%#lx", mech_id); } else { mech_name = pkcs11_mech2str( mech_id); if (mech_name == NULL) { return (FAILURE); } (void) printf("%s", mech_name); } } ptr = ptr->next; if (ptr == NULL) { (void) printf("."); } else { (void) printf(","); } } } } else { /* puent->flag_enabledlist == B_TRUE */ (void) printf(gettext("%s: all mechanisms are disabled"), puent->name); ptr = puent->policylist; if (ptr == NULL) { (void) printf("."); } else { (void) printf(gettext(", except ")); while (ptr != NULL) { mech_id = strtoul(ptr->name, NULL, 0); if (mech_id & CKO_VENDOR_DEFINED) { /* vendor defined mechanism */ (void) printf("%s", ptr->name); } else { mech_name = pkcs11_mech2str(mech_id); if (mech_name == NULL) { return (FAILURE); } (void) printf("%s", mech_name); } ptr = ptr->next; if (ptr == NULL) { (void) printf("."); } else { (void) printf(","); } } } } return (SUCCESS); } /* * Print out the mechanism policy for a user-level provider pointed by puent. */ int print_uef_policy(uentry_t *puent) { flag_val_t rng_flag; if (puent == NULL) { return (FAILURE); } rng_flag = NO_RNG; if (list_mechlist_for_lib(puent->name, NULL, &rng_flag, B_TRUE, B_FALSE, B_FALSE) != SUCCESS) { cryptoerror(LOG_STDERR, gettext("%s internal error."), puent->name); return (FAILURE); } if (display_policy(puent) != SUCCESS) { goto failed_exit; } if (puent->flag_norandom == B_TRUE) /* * TRANSLATION_NOTE * "random" is a keyword and not to be translated. */ (void) printf(gettext(" %s is disabled."), "random"); else { if (rng_flag == HAS_RNG) /* * TRANSLATION_NOTE * "random" is a keyword and not to be translated. */ (void) printf(gettext(" %s is enabled."), "random"); } (void) printf("\n"); return (SUCCESS); failed_exit: (void) printf(gettext("\nout of memory.\n")); return (FAILURE); } /* * Check if the mechanism is in the mechanism list. */ static boolean_t is_in_policylist(midstr_t mechname, umechlist_t *plist) { boolean_t found = B_FALSE; if (mechname == NULL) { return (B_FALSE); } while (plist != NULL) { if (strcmp(plist->name, mechname) == 0) { found = B_TRUE; break; } plist = plist->next; } return (found); } /* * Update the pkcs11.conf file with the updated entry. */ int update_pkcs11conf(uentry_t *puent) { FILE *pfile; FILE *pfile_tmp; char buffer[BUFSIZ]; char buffer2[BUFSIZ]; char tmpfile_name[MAXPATHLEN]; char *name; char *str; int len; int rc = SUCCESS; boolean_t found; if (puent == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } /* Open the pkcs11.conf file */ if ((pfile = fopen(_PATH_PKCS11_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_PKCS11_CONF); return (FAILURE); } /* Lock the pkcs11.conf file */ if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); (void) fclose(pfile); return (FAILURE); } /* * Create a temporary file in the /etc/crypto directory to save * updated configuration file first. */ (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)); (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)); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } (void) fclose(pfile); return (FAILURE); } /* * Loop thru entire pkcs11.conf file, update the entry to be * updated and save the updated file to the temporary file first. */ while (fgets(buffer, BUFSIZ, pfile) != NULL) { found = B_FALSE; if (!(buffer[0] == '#' || buffer[0] == ' ' || buffer[0] == '\n'|| buffer[0] == '\t')) { /* * Get the provider name from this line and check if * this is the entry to be updated. Note: can not use * "buffer" directly because strtok will change its * value. */ (void) strlcpy(buffer2, buffer, BUFSIZ); /* get rid of trailing '\n' */ len = strlen(buffer2); if (buffer2[len-1] == '\n') { len--; } buffer2[len] = '\0'; if ((name = strtok(buffer2, SEP_COLON)) == NULL) { rc = FAILURE; break; } else if (strcmp(puent->name, name) == 0) { found = B_TRUE; } } if (found) { /* * This is the entry to be modified, get the updated * string. */ if ((str = uent2str(puent)) == NULL) { rc = FAILURE; break; } else { (void) strlcpy(buffer, str, BUFSIZ); free(str); } } if (fputs(buffer, pfile_tmp) == EOF) { err = errno; cryptoerror(LOG_STDERR, gettext( "failed to write to a temp file: %s."), strerror(err)); rc = FAILURE; break; } } if (rc == FAILURE) { (void) fclose(pfile); (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)); } return (FAILURE); } (void) fclose(pfile); if (fclose(pfile_tmp) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to close %s: %s"), tmpfile_name, strerror(err)); return (FAILURE); } /* Copy the temporary file to the pkcs11.conf file */ if (rename(tmpfile_name, _PATH_PKCS11_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_PKCS11_CONF, strerror(err)); rc = FAILURE; } else if (chmod(_PATH_PKCS11_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_PKCS11_CONF, strerror(err)); rc = FAILURE; } else { rc = SUCCESS; } if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } return (rc); } /* * Convert an uentry to a character string */ static char * uent2str(uentry_t *puent) { umechlist_t *phead; boolean_t tok1_present = B_FALSE; char *buf; char blank_buf[128]; if (puent == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (NULL); } buf = malloc(BUFSIZ); if (buf == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); return (NULL); } /* convert the library name */ if (strlcpy(buf, puent->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } /* convert the enabledlist or the disabledlist */ if (puent->flag_enabledlist == B_TRUE) { if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_ENABLED, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } phead = puent->policylist; while (phead != NULL) { if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } phead = phead->next; if (phead != NULL) { if (strlcat(buf, SEP_COMMA, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } } tok1_present = B_TRUE; } else if (puent->policylist != NULL) { if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } phead = puent->policylist; while (phead != NULL) { if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } phead = phead->next; if (phead != NULL) { if (strlcat(buf, SEP_COMMA, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } } tok1_present = B_TRUE; } if (puent->flag_norandom == B_TRUE) { if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_NORANDOM, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } if (strcmp(puent->name, METASLOT_KEYWORD) == 0) { /* write the metaslot_status= value */ if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, METASLOT_STATUS, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (puent->flag_metaslot_enabled) { if (strlcat(buf, ENABLED_KEYWORD, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } else { if (strlcat(buf, DISABLED_KEYWORD, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } if (!tok1_present) { tok1_present = B_TRUE; } if (strlcat(buf, SEP_SEMICOLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, METASLOT_AUTO_KEY_MIGRATE, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (puent->flag_metaslot_auto_key_migrate) { if (strlcat(buf, ENABLED_KEYWORD, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } else { if (strlcat(buf, DISABLED_KEYWORD, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } bzero(blank_buf, sizeof (blank_buf)); /* write metaslot_token= if specified */ if (memcmp(puent->metaslot_ks_token, blank_buf, TOKEN_LABEL_SIZE) != 0) { /* write the metaslot_status= value */ if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, METASLOT_TOKEN, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, (const char *)puent->metaslot_ks_token, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } /* write metaslot_slot= if specified */ if (memcmp(puent->metaslot_ks_slot, blank_buf, SLOT_DESCRIPTION_SIZE) != 0) { /* write the metaslot_status= value */ if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, METASLOT_SLOT, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, (const char *)puent->metaslot_ks_slot, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } } if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } return (buf); } /* * This function updates the default policy mode and the policy exception list * for a user-level provider based on the mechanism specified in the disable * or enable subcommand and the update mode. This function is called by the * enable_uef_lib() or disable_uef_lib(). */ int update_policylist(uentry_t *puent, mechlist_t *marglist, int update_mode) { CK_MECHANISM_TYPE mech_type; midstr_t midname; umechlist_t *phead; umechlist_t *pcur; umechlist_t *pumech; boolean_t found; int rc = SUCCESS; if ((puent == NULL) || (marglist == NULL)) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("update_policylist()- puent or marglist is NULL."); return (FAILURE); } if ((update_mode != ADD_MODE) && (update_mode != DELETE_MODE)) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("update_policylist() - update_mode is incorrect."); return (FAILURE); } /* * For each mechanism operand, get its mechanism type first. * If fails to get the mechanism type, the mechanism operand must be * invalid, gives an warning and ignore it. Otherwise, * - convert the mechanism type to the internal representation (hex) * in the pkcs11.conf file * - If update_mode == DELETE_MODE, * If the mechanism is in the policy list, delete it. * If the mechanism is not in the policy list, do nothing. * - If update_mode == ADD_MODE, * If the mechanism is not in the policy list, add it. * If the mechanism is in the policy list already, do nothing. */ while (marglist) { if (pkcs11_str2mech(marglist->name, &mech_type) != CKR_OK) { /* * This mechanism is not a valid PKCS11 mechanism, * give warning and ignore it. */ cryptoerror(LOG_STDERR, gettext( "(Warning) %s is not a valid PKCS#11 mechanism."), marglist->name); rc = FAILURE; } else { (void) snprintf(midname, sizeof (midname), "%#010x", (int)mech_type); if (update_mode == DELETE_MODE) { found = B_FALSE; phead = pcur = puent->policylist; while (!found && pcur) { if (strcmp(pcur->name, midname) == 0) { found = B_TRUE; } else { phead = pcur; pcur = pcur->next; } } if (found) { if (phead == pcur) { puent->policylist = puent->policylist->next; free(pcur); } else { phead->next = pcur->next; free(pcur); } puent->count--; if (puent->count == 0) { puent->policylist = NULL; } } } else if (update_mode == ADD_MODE) { if (!is_in_policylist(midname, puent->policylist)) { pumech = create_umech(midname); if (pumech == NULL) { rc = FAILURE; break; } phead = puent->policylist; puent->policylist = pumech; pumech->next = phead; puent->count++; } } } marglist = marglist->next; } return (rc); } /* * Open a session to the given slot and check if we can do * random numbers by asking for one byte. */ static boolean_t check_random(CK_SLOT_ID slot_id, CK_FUNCTION_LIST_PTR prov_funcs) { CK_RV rv; CK_SESSION_HANDLE hSession; CK_BYTE test_byte; CK_BYTE_PTR test_byte_ptr = &test_byte; rv = prov_funcs->C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL, &hSession); if (rv != CKR_OK) return (B_FALSE); /* We care only about the return value */ rv = prov_funcs->C_GenerateRandom(hSession, test_byte_ptr, sizeof (test_byte)); (void) prov_funcs->C_CloseSession(hSession); /* * These checks are purely to determine whether the slot can do * random numbers. So, we don't check whether the routine * succeeds. The reason we check for CKR_RANDOM_NO_RNG also is that * this error effectively means CKR_FUNCTION_NOT_SUPPORTED. */ if (rv != CKR_FUNCTION_NOT_SUPPORTED && rv != CKR_RANDOM_NO_RNG) return (B_TRUE); else return (B_FALSE); } void display_verbose_mech_header() { (void) printf("%28s %s", " ", HDR1); (void) printf("%28s %s", " ", HDR2); (void) printf("%28s %s", " ", HDR3); (void) printf("%28s %s", " ", HDR4); (void) printf("%28s %s", " ", HDR5); (void) printf("%28s %s", " ", HDR6); (void) printf("%-28.28s %s", gettext("mechanism name"), HDR7); /* * TRANSLATION_NOTE * Strictly for appearance's sake, the first header line should be * as long as the length of the translated text above. The format * lengths should all match too. */ (void) printf("%28s ---- ---- " "- - - - - - - - - - - - - -\n", gettext("----------------------------")); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include "cryptoadm.h" #include /* * Create one item of type mechlist_t with the mechanism name. A null is * returned to indicate that the storage space available is insufficient. */ mechlist_t * create_mech(char *name) { mechlist_t *pres = NULL; char *first, *last; if (name == NULL) { return (NULL); } pres = malloc(sizeof (mechlist_t)); if (pres == NULL) { cryptodebug("out of memory."); return (NULL); } first = name; while (isspace(*first)) /* nuke leading whitespace */ first++; (void) strlcpy(pres->name, first, sizeof (pres->name)); last = strrchr(pres->name, '\0'); last--; while (isspace(*last)) /* nuke trailing whitespace */ *last-- = '\0'; pres->next = NULL; return (pres); } void free_mechlist(mechlist_t *plist) { mechlist_t *pnext; while (plist != NULL) { pnext = plist->next; free(plist); plist = pnext; } } /* * Check if the mechanism is in the mechanism list. */ boolean_t is_in_list(char *mechname, mechlist_t *plist) { boolean_t found = B_FALSE; if (mechname == NULL) { return (B_FALSE); } while (plist != NULL) { if (strcmp(plist->name, mechname) == 0) { found = B_TRUE; break; } plist = plist->next; } return (found); } int update_conf(char *conf_file, char *entry) { boolean_t found; boolean_t fips_entry = B_FALSE; FILE *pfile; FILE *pfile_tmp; char tmpfile_name[MAXPATHLEN]; char *ptr; char *name; char buffer[BUFSIZ]; char buffer2[BUFSIZ]; int found_count; int rc = SUCCESS; int err; if ((pfile = fopen(conf_file, "r+")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to open %s for write.", conf_file); return (FAILURE); } if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to lock the configuration - %s"), strerror(err)); (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)); (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)); (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 (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) { if (buffer[0] == '#') { ptr = buffer; ptr++; if (strcmp(entry, ptr) == 0) { found = B_TRUE; found_count++; } } else { (void) strlcpy(buffer2, buffer, BUFSIZ); ptr = buffer2; if ((name = strtok(ptr, SEP_COLON)) == NULL) { rc = FAILURE; break; } else if (strcmp(FIPS_KEYWORD, name) == 0) { found = B_TRUE; found_count++; fips_entry = B_TRUE; } } } else { /* _PATH_KCF_CONF */ if (buffer[0] == '#') { (void) strlcpy(buffer2, buffer, BUFSIZ); ptr = buffer2; ptr++; /* skip # */ if ((name = strtok(ptr, SEP_COLON)) == NULL) { rc = FAILURE; break; } } else { (void) strlcpy(buffer2, buffer, BUFSIZ); ptr = buffer2; if ((name = strtok(ptr, SEP_COLON)) == NULL) { rc = FAILURE; break; } } } if (found == B_FALSE) { if (fputs(buffer, pfile_tmp) == EOF) { rc = FAILURE; } } else { if (found_count == 1) { if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) { if (fips_entry == B_TRUE) { if (fputs(entry, pfile_tmp) == EOF) { rc = FAILURE; } fips_entry = B_FALSE; } else { if (fputs(ptr, pfile_tmp) == EOF) { rc = FAILURE; } } } else { if (fputs(entry, pfile_tmp) == EOF) { rc = FAILURE; } } } else { /* * Found a second entry with same tag name. * Should not happen. The config file * is corrupted. Give a warning and skip * this entry. */ cryptoerror(LOG_STDERR, gettext( "(Warning) Found an additional reserved " "entry for %s."), entry); } } 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)); } return (FAILURE); } if (found_count == 0) { /* * The entry was not in config file before, append it to the * end of the temp file. */ if (fputs(entry, 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)); } return (FAILURE); } } if (fclose(pfile_tmp) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to close %s: %s"), tmpfile_name, strerror(err)); return (FAILURE); } if (rename(tmpfile_name, conf_file) == -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, conf_file, strerror(err)); rc = FAILURE; } else if (chmod(conf_file, 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", conf_file, 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)); } } return (rc); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include "cryptoadm.h" #define REQ_ARG_CNT 2 /* subcommand index */ enum subcommand_index { CRYPTO_LIST, CRYPTO_DISABLE, CRYPTO_ENABLE, CRYPTO_INSTALL, CRYPTO_UNINSTALL, CRYPTO_UNLOAD, CRYPTO_REFRESH, CRYPTO_START, CRYPTO_STOP, CRYPTO_HELP }; /* * TRANSLATION_NOTE * Command keywords are not to be translated. */ static char *cmd_table[] = { "list", "disable", "enable", "install", "uninstall", "unload", "refresh", "start", "stop", "--help" }; /* provider type */ enum provider_type_index { PROV_UEF_LIB, PROV_KEF_SOFT, PROV_KEF_HARD, METASLOT, PROV_BADNAME }; typedef struct { char cp_name[MAXPATHLEN]; enum provider_type_index cp_type; } cryptoadm_provider_t; /* * TRANSLATION_NOTE * Operand keywords are not to be translated. */ static const char *KN_PROVIDER = "provider="; static const char *KN_MECH = "mechanism="; static const char *KN_ALL = "all"; static const char *KN_TOKEN = "token="; static const char *KN_SLOT = "slot="; static const char *KN_DEFAULT_KS = "default-keystore"; static const char *KN_AUTO_KEY_MIGRATE = "auto-key-migrate"; /* static variables */ static boolean_t allflag = B_FALSE; static boolean_t rndflag = B_FALSE; static mechlist_t *mecharglist = NULL; /* static functions */ static void usage(void); static int get_provider_type(char *); static int process_mech_operands(int, char **, boolean_t); static int do_list(int, char **); static int do_disable(int, char **); static int do_enable(int, char **); static int do_install(int, char **); static int do_uninstall(int, char **); static int do_unload(int, char **); static int do_refresh(int); static int do_start(int); static int do_stop(int); static int list_simple_for_all(boolean_t); static int list_mechlist_for_all(boolean_t); static int list_policy_for_all(void); int main(int argc, char *argv[]) { char *subcmd; int cmdnum; int cmd_index = 0; int rc = SUCCESS; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); cryptodebug_init(basename(argv[0])); if (argc < REQ_ARG_CNT) { usage(); return (ERROR_USAGE); } /* get the subcommand index */ cmd_index = 0; subcmd = argv[1]; cmdnum = sizeof (cmd_table)/sizeof (cmd_table[0]); while ((cmd_index < cmdnum) && (strcmp(subcmd, cmd_table[cmd_index]) != 0)) { cmd_index++; } if (cmd_index >= cmdnum) { usage(); return (ERROR_USAGE); } /* do the subcommand */ switch (cmd_index) { case CRYPTO_LIST: rc = do_list(argc, argv); break; case CRYPTO_DISABLE: rc = do_disable(argc, argv); break; case CRYPTO_ENABLE: rc = do_enable(argc, argv); break; case CRYPTO_INSTALL: rc = do_install(argc, argv); break; case CRYPTO_UNINSTALL: rc = do_uninstall(argc, argv); break; case CRYPTO_UNLOAD: rc = do_unload(argc, argv); break; case CRYPTO_REFRESH: rc = do_refresh(argc); break; case CRYPTO_START: rc = do_start(argc); break; case CRYPTO_STOP: rc = do_stop(argc); break; case CRYPTO_HELP: usage(); rc = SUCCESS; break; default: /* should not come here */ usage(); rc = ERROR_USAGE; break; } return (rc); } static void usage(void) { /* * TRANSLATION_NOTE * Command usage is not to be translated. Only the word "Usage:" * along with localized expressions indicating what kind of value * is expected for arguments. */ (void) fprintf(stderr, gettext("Usage:\n")); (void) fprintf(stderr, " cryptoadm list [-mpv] [provider=<%s> | metaslot]" " [mechanism=<%s>]\n", gettext("provider-name"), gettext("mechanism-list")); (void) fprintf(stderr, " cryptoadm disable provider=<%s>" " mechanism=<%s> | random | all\n", gettext("provider-name"), gettext("mechanism-list")); (void) fprintf(stderr, " cryptoadm disable metaslot" " [auto-key-migrate] [mechanism=<%s>]\n", gettext("mechanism-list")); (void) fprintf(stderr, " cryptoadm enable provider=<%s>" " mechanism=<%s> | random | all\n", gettext("provider-name"), gettext("mechanism-list")); (void) fprintf(stderr, " cryptoadm enable metaslot [mechanism=<%s>]" " [[token=<%s>] [slot=<%s>]" " | [default-keystore]] | [auto-key-migrate]\n", gettext("mechanism-list"), gettext("token-label"), gettext("slot-description")); (void) fprintf(stderr, " cryptoadm install provider=<%s>\n", gettext("provider-name")); (void) fprintf(stderr, " cryptoadm install provider=<%s> [mechanism=<%s>]\n", gettext("provider-name"), gettext("mechanism-list")); (void) fprintf(stderr, " cryptoadm uninstall provider=<%s>\n", gettext("provider-name")); (void) fprintf(stderr, " cryptoadm unload provider=<%s>\n", gettext("provider-name")); (void) fprintf(stderr, " cryptoadm refresh\n" " cryptoadm start\n" " cryptoadm stop\n" " cryptoadm --help\n"); } /* * Get the provider type. This function returns * - PROV_UEF_LIB if provname contains an absolute path name * - PROV_KEF_SOFT if provname is a base name only (e.g., "aes"). * - PROV_KEF_HARD if provname contains one slash only and the slash is not * the 1st character (e.g., "mca/0"). * - PROV_BADNAME otherwise. */ static int get_provider_type(char *provname) { char *pslash1; char *pslash2; if (provname == NULL) { return (FAILURE); } if (provname[0] == '/') { return (PROV_UEF_LIB); } else if ((pslash1 = strchr(provname, SEP_SLASH)) == NULL) { /* no slash */ return (PROV_KEF_SOFT); } else { pslash2 = strrchr(provname, SEP_SLASH); if (pslash1 == pslash2) { return (PROV_KEF_HARD); } else { return (PROV_BADNAME); } } } /* * 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); } /* * Process the "feature" operands. * * "argc" and "argv" contain values specified on the command line. * All other arguments are used for returning parsing results. * If any of these arguments are NULL, that keyword is not expected, * and FAILURE will be returned. */ static int process_metaslot_operands(int argc, char **argv, char **meta_ks_token, char **meta_ks_slot, boolean_t *use_default, boolean_t *auto_key_migrate_flag) { int c = 2; int rc = SUCCESS; while (++c < argc) { if ((strncmp(argv[c], KN_MECH, strlen(KN_MECH)) == 0) && strlen(argv[c]) > strlen(KN_MECH)) { /* process mechanism operands */ if ((rc = process_mech_operands(argc, argv, B_TRUE)) != SUCCESS) { goto finish; } } else if ((strncmp(argv[c], KN_TOKEN, strlen(KN_TOKEN)) == 0) && strlen(argv[c]) > strlen(KN_TOKEN)) { if ((meta_ks_token) && (strtok(argv[c], "=") != NULL)) { char *tmp; if ((tmp = strtok(NULL, "=")) != NULL) { *meta_ks_token = strdup(tmp); } else { return (FAILURE); } } else { return (FAILURE); } } else if ((strncmp(argv[c], KN_SLOT, strlen(KN_SLOT)) == 0) && strlen(argv[c]) > strlen(KN_SLOT)) { if ((meta_ks_slot) && (strtok(argv[c], "=") != NULL)) { char *tmp; if ((tmp = strtok(NULL, "=")) != NULL) { *meta_ks_slot = strdup(tmp); } else { return (FAILURE); } } else { return (FAILURE); } } else if (strncmp(argv[c], KN_DEFAULT_KS, strlen(KN_DEFAULT_KS)) == 0) { if (use_default) { *use_default = B_TRUE; } else { return (FAILURE); } } else if (strncmp(argv[c], KN_AUTO_KEY_MIGRATE, strlen(KN_AUTO_KEY_MIGRATE)) == 0) { if (auto_key_migrate_flag) { *auto_key_migrate_flag = B_TRUE; } else { return (FAILURE); } } else { return (FAILURE); } } finish: return (rc); } /* * Process the "feature" operands. */ static int process_feature_operands(int argc, char **argv) { int c = 2; while (++c < argc) { if (strcmp(argv[c], KN_ALL) == 0) { allflag = B_TRUE; rndflag = B_TRUE; /* all includes random also. */ } else if (strcmp(argv[c], RANDOM) == 0) { rndflag = B_TRUE; } } return (SUCCESS); } /* * 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); } /* * 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; int ch; cryptoadm_provider_t *prov = NULL; int rc = SUCCESS; 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 disable" subcommand. */ static int do_disable(int argc, char **argv) { cryptoadm_provider_t *prov = NULL; int rc = SUCCESS; boolean_t auto_key_migrate_flag = B_FALSE; if ((argc < 3) || (argc > 5)) { usage(); return (ERROR_USAGE); } prov = get_provider(argc, argv); if (prov == NULL) { usage(); return (ERROR_USAGE); } if (prov->cp_type == PROV_BADNAME) { return (FAILURE); } 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 (prov->cp_type == METASLOT) { if ((argc > 3) && (rc = process_metaslot_operands(argc, argv, NULL, NULL, NULL, &auto_key_migrate_flag)) != SUCCESS) { usage(); return (rc); } } else if (!allflag && !rndflag && (rc = process_mech_operands(argc, argv, B_FALSE)) != SUCCESS) { return (rc); } switch (prov->cp_type) { case METASLOT: rc = disable_metaslot(mecharglist, allflag, auto_key_migrate_flag); break; case PROV_UEF_LIB: rc = disable_uef_lib(prov->cp_name, rndflag, allflag, mecharglist); break; case PROV_KEF_SOFT: if (rndflag && !allflag) { if ((mecharglist = create_mech(RANDOM)) == NULL) { rc = FAILURE; break; } } if (getzoneid() == GLOBAL_ZONEID) { rc = disable_kef_software(prov->cp_name, rndflag, allflag, mecharglist); } else { /* * TRANSLATION_NOTE * "disable" 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"), "disable", "global"); rc = FAILURE; } break; case PROV_KEF_HARD: if (rndflag && !allflag) { if ((mecharglist = create_mech(RANDOM)) == NULL) { rc = FAILURE; break; } } if (getzoneid() == GLOBAL_ZONEID) { rc = disable_kef_hardware(prov->cp_name, rndflag, allflag, mecharglist); } else { /* * TRANSLATION_NOTE * "disable" 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"), "disable", "global"); rc = FAILURE; } break; default: /* should not come here */ rc = FAILURE; break; } out: free(prov); if (mecharglist != NULL) { free_mechlist(mecharglist); } return (rc); } /* * 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) || (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); } /* * 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); } /* * The top level function for the "cryptoadm uninstall" subcommand. */ static int do_uninstall(int argc, char **argv) { cryptoadm_provider_t *prov = NULL; int rc = SUCCESS; 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 * "uninstall" 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."), "uninstall"); free(prov); return (FAILURE); } if (prov->cp_type == PROV_UEF_LIB) { rc = uninstall_uef_lib(prov->cp_name); } else if (prov->cp_type == PROV_KEF_SOFT) { if (getzoneid() == GLOBAL_ZONEID) { /* unload and remove from kcf.conf */ rc = uninstall_kef(prov->cp_name); } else { /* * TRANSLATION_NOTE * "uninstall" 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"), "uninstall", "global"); rc = FAILURE; } } free(prov); return (rc); } /* * 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); } /* * The top level function for the "cryptoadm refresh" subcommand. */ static int do_refresh(int argc) { if (argc != 2) { usage(); return (ERROR_USAGE); } if (getzoneid() == GLOBAL_ZONEID) { return (refresh()); } else { /* non-global zone */ /* * Note: in non-global zone, this must silently return SUCCESS * due to integration with SMF, for "svcadm refresh cryptosvc" */ return (SUCCESS); } } /* * The top level function for the "cryptoadm start" subcommand. * This used to start up kcfd, but now all it does is load up the * initial providers. */ static int do_start(int argc) { if (argc != 2) { usage(); return (ERROR_USAGE); } return (do_refresh(argc)); } /* * The top level function for the "cryptoadm stop" subcommand. * This no longer does anything useful, but we leave it here * for compatibility. */ static int do_stop(int argc) { if (argc != 2) { usage(); return (ERROR_USAGE); } 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); 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); } /* * 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); } /* * 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); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2010 Nexenta Systems, Inc. All rights reserved. */ #ifndef _CRYPTOADM_H #define _CRYPTOADM_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define TMPFILE_TEMPLATE "/etc/crypto/admXXXXXX" #define ERROR_USAGE 2 #define HW_PROVIDER_NCP 1 #define HW_PROVIDER_N2CP 2 #define HW_PROVIDER_N2RNG 3 /* * Common keywords and delimiters for pkcs11.conf and kcf.conf files are * defined in usr/lib/libcryptoutil/common/cryptoutil.h. The following is * the extra keywords and delimiters used in kcf.conf file. */ #define SEP_SLASH '/' #define EF_SUPPORTED "supportedlist=" #define EF_UNLOAD "unload" #define RANDOM "random" #define UEF_FRAME_LIB "/usr/lib/libpkcs11.so" #define ADD_MODE 1 #define DELETE_MODE 2 #define MODIFY_MODE 3 #define REFRESH 1 #define NOT_REFRESH 0 typedef char prov_name_t[MAXNAMELEN]; typedef char mech_name_t[CRYPTO_MAX_MECH_NAME]; typedef struct mechlist { mech_name_t name; struct mechlist *next; } mechlist_t; typedef struct entry { prov_name_t name; mechlist_t *suplist; /* supported list */ uint_t sup_count; mechlist_t *dislist; /* disabled list */ uint_t dis_count; boolean_t load; /* B_FALSE after cryptoadm unload */ } entry_t; typedef struct entrylist { entry_t *pent; struct entrylist *next; } entrylist_t; typedef enum { NO_RNG, HAS_RNG } flag_val_t; extern int errno; /* adm_util */ extern boolean_t is_in_list(char *, mechlist_t *); extern mechlist_t *create_mech(char *); extern void free_mechlist(mechlist_t *); /* adm_kef_util */ extern boolean_t is_device(char *); extern char *ent2str(entry_t *); extern entry_t *getent_kef(char *provname, entrylist_t *pdevlist, entrylist_t *psoftlist); extern int check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist, boolean_t *in_kernel); extern int check_kernel_for_hard(char *provname, crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel); extern int disable_mechs(entry_t **, mechlist_t *, boolean_t, mechlist_t *); extern int enable_mechs(entry_t **, boolean_t, mechlist_t *); extern int get_kcfconf_info(entrylist_t **, entrylist_t **); extern int get_admindev_info(entrylist_t **, entrylist_t **); extern int get_mech_count(mechlist_t *); extern entry_t *create_entry(char *provname); extern int insert_kcfconf(entry_t *); extern int split_hw_provname(char *, char *, int *); extern int update_kcfconf(entry_t *, int); extern void free_entry(entry_t *); extern void free_entrylist(entrylist_t *); extern void print_mechlist(char *, mechlist_t *); extern void print_kef_policy(char *provname, entry_t *pent, boolean_t has_random, boolean_t has_mechs); extern boolean_t filter_mechlist(mechlist_t **, const char *); extern uentry_t *getent_uef(char *); /* adm_uef */ extern int list_mechlist_for_lib(char *, mechlist_t *, flag_val_t *, boolean_t, boolean_t, boolean_t); extern int list_policy_for_lib(char *); extern int disable_uef_lib(char *, boolean_t, boolean_t, mechlist_t *); extern int enable_uef_lib(char *, boolean_t, boolean_t, mechlist_t *); extern int install_uef_lib(char *); extern int uninstall_uef_lib(char *); extern int print_uef_policy(uentry_t *); extern void display_token_flags(CK_FLAGS flags); extern int convert_mechlist(CK_MECHANISM_TYPE **, CK_ULONG *, mechlist_t *); extern void display_verbose_mech_header(); extern void display_mech_info(CK_MECHANISM_INFO *); extern int display_policy(uentry_t *); extern int update_pkcs11conf(uentry_t *); extern int update_policylist(uentry_t *, mechlist_t *, int); /* adm_kef */ extern int list_mechlist_for_soft(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist); extern int list_mechlist_for_hard(char *); extern int list_policy_for_soft(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist); extern int list_policy_for_hard(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist, crypto_get_dev_list_t *pdevlist); extern int disable_kef_software(char *, boolean_t, boolean_t, mechlist_t *); extern int disable_kef_hardware(char *, boolean_t, boolean_t, mechlist_t *); extern int enable_kef(char *, boolean_t, boolean_t, mechlist_t *); extern int install_kef(char *, mechlist_t *); extern int uninstall_kef(char *); extern int unload_kef_soft(char *provname); extern int refresh(void); /* adm_ioctl */ extern crypto_load_soft_config_t *setup_soft_conf(entry_t *); extern crypto_load_soft_disabled_t *setup_soft_dis(entry_t *); extern crypto_load_dev_disabled_t *setup_dev_dis(entry_t *); extern crypto_unload_soft_module_t *setup_unload_soft(entry_t *); extern int get_dev_info(char *, int, int, mechlist_t **); extern int get_dev_list(crypto_get_dev_list_t **); extern int get_soft_info(char *provname, mechlist_t **ppmechlist, entrylist_t *phardlist, entrylist_t *psoftlist); extern int get_soft_list(crypto_get_soft_list_t **); /* adm_metaslot */ extern int list_metaslot_info(boolean_t, boolean_t, mechlist_t *); extern int list_metaslot_policy(); extern int disable_metaslot(mechlist_t *, boolean_t, boolean_t); extern int enable_metaslot(char *, char *, boolean_t, mechlist_t *, boolean_t, boolean_t); #ifdef __cplusplus } #endif #endif /* _CRYPTOADM_H */ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # PROG = decrypt # Hammerhead: ROOTBIN64=ROOTBIN (path flattening), so ROOTLINK64=ROOTLINK # and ROOTDECLINK=ROOTPROG. Removed duplicate 64-bit variables and # ../../bin symlink rules (circular when /bin -> usr/bin). ROOTLINK= $(ROOTBIN)/encrypt DCFILE=$(PROG).dc include ../../Makefile.cmd include ../../Makefile.cmd.64 CFLAGS += $(CCVERBOSE) CERRWARN += -Wno-parentheses CERRWARN += $(CNOWARN_UNINIT) LDLIBS += -lkmf -lpkcs11 -lcryptoutil .KEEP_STATE: all: $(PROG) install: all $(ROOTPROG) $(ROOTLINK) $(ROOTLINK): $(ROOTPROG) $(RM) $@; $(LN) $(ROOTPROG) $@ clean: $(RM) $(PROG) $(DCFILE): $(RM) messages.po $(XGETTEXT) $(XGETFLAGS) -t $(PROG).c $(SED) -e '/^domain/d' messages.po > $@ $(RM) messages.po include ../../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Portions Copyright 2005 Richard Lowe */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * decrypt.c * * Implements encrypt(1) and decrypt(1) commands * * One binary performs both encrypt/decrypt operation. * * Usage: * -a algorithm mechanism name without CKM_ prefix. Case * does not matter * -k keyfile file containing key data. If not specified user is * prompted to enter key. key length > 0 is required * -i infile input file to encrypt/decrypt. If omitted, stdin used. * -o outfile output file to encrypt/decrypt. If omitted, stdout used. * if infile & outfile are same, a temp file is used for * output and infile is replaced with this file after * operation is complete * -l Display the list of algorithms * -v Display verbose information * -T tokenspec Specify a PKCS#11 token (optionally used with -K) * -K keylabel Specify the symmetric PKCS#11 token key label * * Implementation notes: * IV data - It is generated by random bytes equal to one block size. * * Encrypted output format - * - Output format version number (1) - 4 bytes in network byte order. * - Iterations used in key gen function, 4 bytes in network byte order. * - IV ('ivlen' bytes). Length is algorithm-dependent (see mech_aliases) * - Salt data used in key gen (16 bytes) * - Cipher text data (remainder of the file) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Buffer size for reading file. This is given a rather high value * to get better performance when a hardware provider is present. */ #define BUFFERSIZE (1024 * 64) #define BLOCKSIZE (128) /* Largest guess for block size */ #define PROGRESSSIZE (1024 * 40) /* stdin progress indicator size */ #define SUNW_ENCRYPT_FILE_VERSION 1 /* * Exit Status codes */ #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 /* No errors */ #define EXIT_FAILURE 1 /* All errors except usage */ #endif /* EXIT_SUCCESS */ #define EXIT_USAGE 2 /* usage/syntax error */ #define ENCRYPT_NAME "encrypt" /* name of encrypt command */ #define ENCRYPT_OPTIONS "a:T:K:k:i:o:lv" /* options for encrypt */ #define DECRYPT_NAME "decrypt" /* name of decrypt command */ #define DECRYPT_OPTIONS "a:T:K:k:i:o:lv" /* options for decrypt */ /* * Structure containing info for encrypt/decrypt * command */ struct CommandInfo { char *name; /* name of the command */ char *options; /* command line options */ CK_FLAGS flags; CK_ATTRIBUTE_TYPE type; /* type of command */ /* function pointers for various operations */ CK_RV (*Init)(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE); CK_RV (*Update)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR); CK_RV (*Crypt)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR); CK_RV (*Final)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR); }; static struct CommandInfo encrypt_cmd = { ENCRYPT_NAME, ENCRYPT_OPTIONS, CKF_ENCRYPT, CKA_ENCRYPT, C_EncryptInit, C_EncryptUpdate, C_Encrypt, C_EncryptFinal }; static struct CommandInfo decrypt_cmd = { DECRYPT_NAME, DECRYPT_OPTIONS, CKF_DECRYPT, CKA_DECRYPT, C_DecryptInit, C_DecryptUpdate, C_Decrypt, C_DecryptFinal }; struct mech_alias { CK_MECHANISM_TYPE type; char *alias; CK_ULONG keysize_min; CK_ULONG keysize_max; int keysize_unit; int ivlen; boolean_t available; }; #define MECH_ALIASES_COUNT 4 static struct mech_alias mech_aliases[] = { { CKM_AES_CBC_PAD, "aes", ULONG_MAX, 0L, 8, 16, B_FALSE }, { CKM_RC4, "arcfour", ULONG_MAX, 0L, 1, 0, B_FALSE }, { CKM_DES_CBC_PAD, "des", 8, 8, 8, 8, B_FALSE }, { CKM_DES3_CBC_PAD, "3des", 24, 24, 8, 8, B_FALSE }, }; static CK_BBOOL truevalue = TRUE; static CK_BBOOL falsevalue = FALSE; static boolean_t aflag = B_FALSE; /* -a flag, required */ static boolean_t kflag = B_FALSE; /* -k flag */ static boolean_t iflag = B_FALSE; /* -i flag, use stdin if absent */ static boolean_t oflag = B_FALSE; /* -o flag, use stdout if absent */ static boolean_t lflag = B_FALSE; /* -l flag (list) */ static boolean_t vflag = B_FALSE; /* -v flag (verbose) */ static boolean_t Tflag = B_FALSE; /* -T flag (tokenspec) */ static boolean_t Kflag = B_FALSE; /* -K flag (keylabel) */ static char *keyfile = NULL; /* name of keyfile */ static char *inputfile = NULL; /* name of input file */ static char *outputfile = NULL; /* name of output file */ static char *token_label = NULL; /* name of PKCS#11 token */ static char *key_label = NULL; /* name of PKCS#11 token key label */ static int status_pos = 0; /* current position of progress bar element */ /* * function prototypes */ static void usage(struct CommandInfo *cmd); static int execute_cmd(struct CommandInfo *cmd, char *algo_str); static int crypt_multipart(struct CommandInfo *cmd, CK_SESSION_HANDLE hSession, int infd, int outfd, off_t insize); int main(int argc, char **argv) { extern char *optarg; extern int optind; char *optstr; int c; /* current getopts flag */ char *algo_str = NULL; /* algorithm string */ struct CommandInfo *cmd; char *cmdname; /* name of command */ boolean_t errflag = B_FALSE; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); /* * Based on command name, determine * type of command. */ cmdname = basename(argv[0]); cryptodebug_init(cmdname); if (strcmp(cmdname, encrypt_cmd.name) == 0) { cmd = &encrypt_cmd; } else if (strcmp(cmdname, decrypt_cmd.name) == 0) { cmd = &decrypt_cmd; } else { cryptoerror(LOG_STDERR, gettext( "command name must be either encrypt or decrypt")); exit(EXIT_USAGE); } optstr = cmd->options; /* Parse command line arguments */ while (!errflag && (c = getopt(argc, argv, optstr)) != -1) { switch (c) { case 'a': aflag = B_TRUE; algo_str = optarg; break; case 'k': kflag = B_TRUE; keyfile = optarg; break; case 'T': Tflag = B_TRUE; token_label = optarg; break; case 'K': Kflag = B_TRUE; key_label = optarg; break; case 'i': iflag = B_TRUE; inputfile = optarg; break; case 'o': oflag = B_TRUE; outputfile = optarg; break; case 'l': lflag = B_TRUE; break; case 'v': vflag = B_TRUE; break; default: errflag = B_TRUE; } } if (errflag || (!aflag && !lflag) || (lflag && argc > 2) || (kflag && Kflag) || (Tflag && !Kflag) || (optind < argc)) { usage(cmd); exit(EXIT_USAGE); } return (execute_cmd(cmd, algo_str)); } /* * usage message */ static void usage(struct CommandInfo *cmd) { (void) fprintf(stderr, gettext("Usage:\n")); if (cmd->type == CKA_ENCRYPT) { (void) fprintf(stderr, gettext(" encrypt -l\n")); (void) fprintf(stderr, gettext(" encrypt -a " "[-v] [-k | -K [-T ]] " "[-i ] [-o ]\n")); } else { (void) fprintf(stderr, gettext(" decrypt -l\n")); (void) fprintf(stderr, gettext(" decrypt -a " "[-v] [-k | -K [-T ]] " "[-i ] [-o ]\n")); } } /* * Print out list of algorithms in default and verbose mode */ static void algorithm_list() { int mech; (void) printf(gettext("Algorithm Keysize: Min Max (bits)\n" "------------------------------------------\n")); for (mech = 0; mech < MECH_ALIASES_COUNT; mech++) { if (mech_aliases[mech].available == B_FALSE) continue; (void) printf("%-15s", mech_aliases[mech].alias); if (mech_aliases[mech].keysize_min != UINT_MAX && mech_aliases[mech].keysize_max != 0) (void) printf(" %5lu %5lu\n", (mech_aliases[mech].keysize_min * mech_aliases[mech].keysize_unit), (mech_aliases[mech].keysize_max * mech_aliases[mech].keysize_unit)); else (void) printf("\n"); } } /* * This function will login into the token with the provided password and * find the token key object with the specified keytype and keylabel. */ static int get_token_key(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keytype, char *keylabel, CK_BYTE *password, int password_len, CK_OBJECT_HANDLE *keyobj) { CK_RV rv; CK_ATTRIBUTE pTmpl[10]; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_BBOOL true = 1; CK_BBOOL is_token = 1; CK_ULONG key_obj_count = 1; int i; CK_KEY_TYPE ckKeyType = keytype; rv = C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)password, (CK_ULONG)password_len); if (rv != CKR_OK) { (void) fprintf(stderr, "Cannot login to the token." " error = %s\n", pkcs11_strerror(rv)); return (-1); } i = 0; pTmpl[i].type = CKA_TOKEN; pTmpl[i].pValue = &is_token; pTmpl[i].ulValueLen = sizeof (CK_BBOOL); i++; pTmpl[i].type = CKA_CLASS; pTmpl[i].pValue = &class; pTmpl[i].ulValueLen = sizeof (class); i++; pTmpl[i].type = CKA_LABEL; pTmpl[i].pValue = keylabel; pTmpl[i].ulValueLen = strlen(keylabel); i++; pTmpl[i].type = CKA_KEY_TYPE; pTmpl[i].pValue = &ckKeyType; pTmpl[i].ulValueLen = sizeof (ckKeyType); i++; pTmpl[i].type = CKA_PRIVATE; pTmpl[i].pValue = &true; pTmpl[i].ulValueLen = sizeof (true); i++; rv = C_FindObjectsInit(hSession, pTmpl, i); if (rv != CKR_OK) { goto out; } rv = C_FindObjects(hSession, keyobj, 1, &key_obj_count); (void) C_FindObjectsFinal(hSession); out: if (rv != CKR_OK) { (void) fprintf(stderr, "Cannot retrieve key object. error = %s\n", pkcs11_strerror(rv)); return (-1); } if (key_obj_count == 0) { (void) fprintf(stderr, "Cannot find the key object.\n"); return (-1); } return (0); } /* * Execute the command. * cmd - command pointing to type of operation. * algo_str - alias of the algorithm passed. */ static int execute_cmd(struct CommandInfo *cmd, char *algo_str) { CK_RV rv; CK_ULONG slotcount; CK_SLOT_ID slotID; CK_SLOT_ID_PTR pSlotList = NULL; CK_MECHANISM_TYPE mech_type = 0; CK_MECHANISM_INFO info, kg_info; CK_MECHANISM mech; CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; CK_BYTE_PTR pkeydata = NULL; CK_BYTE salt[CK_PKCS5_PBKD2_SALT_SIZE]; CK_ULONG keysize = 0; int i, slot, mek; /* index variables */ int status; struct stat insbuf; /* stat buf for infile */ struct stat outsbuf; /* stat buf for outfile */ char tmpnam[PATH_MAX]; /* tmp file name */ CK_OBJECT_HANDLE key = (CK_OBJECT_HANDLE) 0; int infd = 0; /* input file, stdin default */ int outfd = 1; /* output file, stdout default */ char *outfilename = NULL; boolean_t errflag = B_TRUE; boolean_t inoutsame = B_FALSE; /* if both input & output are same */ boolean_t leavefilealone = B_FALSE; CK_BYTE_PTR pivbuf = NULL_PTR; CK_ULONG ivlen = 0L; int mech_match = 0; uint32_t iterations = CK_PKCS5_PBKD2_ITERATIONS; CK_ULONG keylen; uint32_t version = SUNW_ENCRYPT_FILE_VERSION; CK_KEY_TYPE keytype; KMF_RETURN kmfrv; CK_SLOT_ID token_slot_id; if (aflag) { /* Determine if algorithm is valid */ for (mech_match = 0; mech_match < MECH_ALIASES_COUNT; mech_match++) { if (strcmp(algo_str, mech_aliases[mech_match].alias) == 0) { mech_type = mech_aliases[mech_match].type; break; } } if (mech_match == MECH_ALIASES_COUNT) { cryptoerror(LOG_STDERR, gettext("unknown algorithm -- %s"), algo_str); return (EXIT_FAILURE); } /* * Process keyfile or get the token pin if -K is specified. * * If a keyfile is provided, get the key data from * the file. Otherwise, prompt for a passphrase. The * passphrase is used as the key data. */ if (Kflag) { /* get the pin of the token */ if (token_label == NULL || !strlen(token_label)) { token_label = pkcs11_default_token(); } status = pkcs11_get_pass(token_label, (char **)&pkeydata, (size_t *)&keysize, 0, B_FALSE); } else if (kflag) { /* get the key file */ status = pkcs11_read_data(keyfile, (void **)&pkeydata, (size_t *)&keysize); } else { /* get the key from input */ status = pkcs11_get_pass(NULL, (char **)&pkeydata, (size_t *)&keysize, 0, (cmd->type == CKA_ENCRYPT) ? B_TRUE : B_FALSE); } if (status != 0 || keysize == 0L) { cryptoerror(LOG_STDERR, kflag ? gettext("invalid key.") : gettext("invalid passphrase.")); return (EXIT_FAILURE); } } bzero(salt, sizeof (salt)); /* Initialize pkcs */ rv = C_Initialize(NULL); if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { cryptoerror(LOG_STDERR, gettext("failed to initialize " "PKCS #11 framework: %s"), pkcs11_strerror(rv)); goto cleanup; } /* Get slot count */ rv = C_GetSlotList(0, NULL_PTR, &slotcount); if (rv != CKR_OK || slotcount == 0) { cryptoerror(LOG_STDERR, gettext( "failed to find any cryptographic provider," "please check with your system administrator: %s"), pkcs11_strerror(rv)); goto cleanup; } /* Found at least one slot, allocate memory for slot list */ pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID)); if (pSlotList == NULL_PTR) { int err = errno; cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(err)); goto cleanup; } /* Get the list of slots */ if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext( "failed to find any cryptographic provider," "please check with your system administrator: %s"), pkcs11_strerror(rv)); goto cleanup; } if (lflag) { /* Iterate through slots */ for (slot = 0; slot < slotcount; slot++) { /* Iterate through each mechanism */ for (mek = 0; mek < MECH_ALIASES_COUNT; mek++) { rv = C_GetMechanismInfo(pSlotList[slot], mech_aliases[mek].type, &info); if (rv != CKR_OK) continue; /* * Set to minimum/maximum key sizes assuming * the values available are not 0. */ if (info.ulMinKeySize && (info.ulMinKeySize < mech_aliases[mek].keysize_min)) mech_aliases[mek].keysize_min = info.ulMinKeySize; if (info.ulMaxKeySize && (info.ulMaxKeySize > mech_aliases[mek].keysize_max)) mech_aliases[mek].keysize_max = info.ulMaxKeySize; mech_aliases[mek].available = B_TRUE; } } algorithm_list(); errflag = B_FALSE; goto cleanup; } /* * Find a slot with matching mechanism * * If -K is specified, we find the slot id for the token first, then * check if the slot supports the algorithm. */ i = 0; if (Kflag) { kmfrv = kmf_pk11_token_lookup(NULL, token_label, &token_slot_id); if (kmfrv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("no matching PKCS#11 token")); errflag = B_TRUE; goto cleanup; } rv = C_GetMechanismInfo(token_slot_id, mech_type, &info); if (rv == CKR_OK && (info.flags & cmd->flags)) slotID = token_slot_id; else i = slotcount; } else { for (i = 0; i < slotcount; i++) { slotID = pSlotList[i]; rv = C_GetMechanismInfo(slotID, mech_type, &info); if (rv != CKR_OK) { continue; /* to the next slot */ } else { /* * If the slot support the crypto, also * make sure it supports the correct * key generation mech if needed. * * We need PKCS5 when RC4 is used or * when the key is entered on cmd line. */ if ((info.flags & cmd->flags) && (mech_type == CKM_RC4) || (keyfile == NULL)) { rv = C_GetMechanismInfo(slotID, CKM_PKCS5_PBKD2, &kg_info); if (rv == CKR_OK) break; } else if (info.flags & cmd->flags) { break; } } } } /* Show error if no matching mechanism found */ if (i == slotcount) { cryptoerror(LOG_STDERR, gettext("no cryptographic provider was " "found for this algorithm -- %s"), algo_str); goto cleanup; } /* Open a session */ rv = C_OpenSession(slotID, CKF_SERIAL_SESSION, NULL_PTR, NULL, &hSession); if (rv != CKR_OK) { cryptoerror(LOG_STDERR, gettext("can not open PKCS #11 session: %s"), pkcs11_strerror(rv)); goto cleanup; } /* * Generate IV data for encrypt. */ ivlen = mech_aliases[mech_match].ivlen; if ((pivbuf = malloc((size_t)ivlen)) == NULL) { int err = errno; cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(err)); goto cleanup; } if (cmd->type == CKA_ENCRYPT) { if ((pkcs11_get_urandom((void *)pivbuf, mech_aliases[mech_match].ivlen)) != 0) { cryptoerror(LOG_STDERR, gettext( "Unable to generate random " "data for initialization vector.")); goto cleanup; } } /* * Create the key object */ rv = pkcs11_mech2keytype(mech_type, &keytype); if (rv != CKR_OK) { cryptoerror(LOG_STDERR, gettext("unable to find key type for algorithm.")); goto cleanup; } /* Open input file */ if (iflag) { if ((infd = open(inputfile, O_RDONLY | O_NONBLOCK)) == -1) { cryptoerror(LOG_STDERR, gettext( "can not open input file %s"), inputfile); goto cleanup; } /* Get info on input file */ if (fstat(infd, &insbuf) == -1) { cryptoerror(LOG_STDERR, gettext( "can not stat input file %s"), inputfile); goto cleanup; } } /* * Prepare output file * If the input & output file are same, * the output is written to a temp * file first, then renamed to the original file * after the crypt operation */ inoutsame = B_FALSE; if (oflag) { outfilename = outputfile; if ((stat(outputfile, &outsbuf) != -1) && (insbuf.st_ino == outsbuf.st_ino)) { char *dir; /* create temp file on same dir */ dir = dirname(outputfile); (void) snprintf(tmpnam, sizeof (tmpnam), "%s/encrXXXXXX", dir); outfilename = tmpnam; if ((outfd = mkstemp(tmpnam)) == -1) { cryptoerror(LOG_STDERR, gettext( "cannot create temp file")); goto cleanup; } inoutsame = B_TRUE; } else { /* Create file for output */ if ((outfd = open(outfilename, O_CREAT|O_WRONLY|O_TRUNC, 0644)) == -1) { cryptoerror(LOG_STDERR, gettext( "cannot open output file %s"), outfilename); /* Cannot open file, should leave it alone */ leavefilealone = B_TRUE; goto cleanup; } } } /* * Read the version number from the head of the file * to know how to interpret the data that follows. */ if (cmd->type == CKA_DECRYPT) { if (read(infd, &version, sizeof (version)) != sizeof (version)) { cryptoerror(LOG_STDERR, gettext( "failed to get format version from " "input file.")); goto cleanup; } /* convert to host byte order */ version = ntohl(version); switch (version) { case 1: /* * Version 1 output format: * - Output format version 1 (4 bytes) * - Iterations used in key gen function (4 bytes) * - IV ('ivlen' bytes). The length algorithm-dependent * - Salt data used in key gen (16 bytes) * - Cipher text data (remainder of the file) * * An encrypted file has IV as first block (0 or * more bytes depending on mechanism) followed * by cipher text. Get the IV from the encrypted * file. */ /* * Read iteration count and salt data. */ if (read(infd, &iterations, sizeof (iterations)) != sizeof (iterations)) { cryptoerror(LOG_STDERR, gettext( "failed to get iterations from " "input file.")); goto cleanup; } /* convert to host byte order */ iterations = ntohl(iterations); if (ivlen > 0 && read(infd, pivbuf, ivlen) != ivlen) { cryptoerror(LOG_STDERR, gettext( "failed to get initialization " "vector from input file.")); goto cleanup; } if (read(infd, salt, sizeof (salt)) != sizeof (salt)) { cryptoerror(LOG_STDERR, gettext( "failed to get salt data from " "input file.")); goto cleanup; } break; default: cryptoerror(LOG_STDERR, gettext( "Unrecognized format version read from " "input file - expected %d, got %d."), SUNW_ENCRYPT_FILE_VERSION, version); goto cleanup; } } /* * If Kflag is set, let's find the token key now. * * If Kflag is not set and if encrypting, we need some random * salt data to create the key. If decrypting, * the salt should come from head of the file * to be decrypted. */ if (Kflag) { rv = get_token_key(hSession, keytype, key_label, pkeydata, keysize, &key); if (rv != CKR_OK) { cryptoerror(LOG_STDERR, gettext( "Can not find the token key")); goto cleanup; } else { goto do_crypto; } } else if (cmd->type == CKA_ENCRYPT) { rv = pkcs11_get_urandom((void *)salt, sizeof (salt)); if (rv != 0) { cryptoerror(LOG_STDERR, gettext("unable to generate random " "data for key salt.")); goto cleanup; } } /* * If key input is read from a file, treat it as * raw key data, unless it is to be used with RC4, * in which case it must be used to generate a pkcs5 * key to address security concerns with RC4 keys. */ if (kflag && keyfile != NULL && keytype != CKK_RC4) { /* XXX : why wasn't SUNW_C_KeyToObject used here? */ CK_OBJECT_CLASS objclass = CKO_SECRET_KEY; CK_ATTRIBUTE template[5]; int nattr = 0; template[nattr].type = CKA_CLASS; template[nattr].pValue = &objclass; template[nattr].ulValueLen = sizeof (objclass); nattr++; template[nattr].type = CKA_KEY_TYPE; template[nattr].pValue = &keytype; template[nattr].ulValueLen = sizeof (keytype); nattr++; template[nattr].type = cmd->type; template[nattr].pValue = &truevalue; template[nattr].ulValueLen = sizeof (truevalue); nattr++; template[nattr].type = CKA_TOKEN; template[nattr].pValue = &falsevalue; template[nattr].ulValueLen = sizeof (falsevalue); nattr++; template[nattr].type = CKA_VALUE; template[nattr].pValue = pkeydata; template[nattr].ulValueLen = keysize; nattr++; rv = C_CreateObject(hSession, template, nattr, &key); } else { /* * If the encryption type has a fixed key length, * then its not necessary to set the key length * parameter when generating the key. */ if (keytype == CKK_DES || keytype == CKK_DES3) keylen = 0; else keylen = 16; /* * Generate a cryptographically secure key using * the key read from the file given (-k keyfile) or * the passphrase entered by the user. */ rv = pkcs11_PasswdToPBKD2Object(hSession, (char *)pkeydata, (size_t)keysize, (void *)salt, sizeof (salt), iterations, keytype, keylen, cmd->flags, &key); } if (rv != CKR_OK) { cryptoerror(LOG_STDERR, gettext( "failed to generate a key: %s"), pkcs11_strerror(rv)); goto cleanup; } do_crypto: /* Setup up mechanism */ mech.mechanism = mech_type; mech.pParameter = (CK_VOID_PTR)pivbuf; mech.ulParameterLen = ivlen; if ((rv = cmd->Init(hSession, &mech, key)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext( "failed to initialize crypto operation: %s"), pkcs11_strerror(rv)); goto cleanup; } /* Write the version header encrypt command */ if (cmd->type == CKA_ENCRYPT) { /* convert to network order for storage */ uint32_t netversion = htonl(version); uint32_t netiter; if (write(outfd, &netversion, sizeof (netversion)) != sizeof (netversion)) { cryptoerror(LOG_STDERR, gettext( "failed to write version number " "to output file.")); goto cleanup; } /* * Write the iteration and salt data, even if they * were not used to generate a key. */ netiter = htonl(iterations); if (write(outfd, &netiter, sizeof (netiter)) != sizeof (netiter)) { cryptoerror(LOG_STDERR, gettext( "failed to write iterations to output")); goto cleanup; } if (ivlen > 0 && write(outfd, pivbuf, ivlen) != ivlen) { cryptoerror(LOG_STDERR, gettext( "failed to write initialization vector " "to output")); goto cleanup; } if (write(outfd, salt, sizeof (salt)) != sizeof (salt)) { cryptoerror(LOG_STDERR, gettext( "failed to write salt data to output")); goto cleanup; } } if (crypt_multipart(cmd, hSession, infd, outfd, insbuf.st_size) == -1) { goto cleanup; } errflag = B_FALSE; /* * Clean up */ cleanup: /* Clear the key data, so others cannot snoop */ if (pkeydata != NULL) { bzero(pkeydata, keysize); free(pkeydata); pkeydata = NULL; } /* Destroy key object */ if (Kflag != B_FALSE && key != (CK_OBJECT_HANDLE) 0) { (void) C_DestroyObject(hSession, key); } /* free allocated memory */ if (pSlotList != NULL) free(pSlotList); if (pivbuf != NULL) free(pivbuf); /* close all the files */ if (iflag && (infd != -1)) (void) close(infd); if (oflag && (outfd != -1)) (void) close(outfd); /* rename tmp output to input file */ if (inoutsame) { if (rename(outfilename, inputfile) == -1) { (void) unlink(outfilename); cryptoerror(LOG_STDERR, gettext("rename failed.")); } } /* If error occurred and the file was new, remove the output file */ if (errflag && (outfilename != NULL) && !leavefilealone) { (void) unlink(outfilename); } /* close pkcs11 session */ if (hSession != CK_INVALID_HANDLE) (void) C_CloseSession(hSession); (void) C_Finalize(NULL); return (errflag); } /* * Function for printing progress bar when the verbose flag * is set. * * The vertical bar is printed at 25, 50, and 75% complete. * * The function is passed the number of positions on the screen it needs to * advance and loops. */ static void print_status(int pos_to_advance) { while (pos_to_advance > 0) { switch (status_pos) { case 0: (void) fprintf(stderr, gettext("[")); break; case 19: case 39: case 59: (void) fprintf(stderr, gettext("|")); break; default: (void) fprintf(stderr, gettext(".")); } pos_to_advance--; status_pos++; } } /* * Encrypt/Decrypt in multi part. * * This function reads the input file (infd) and writes the * encrypted/decrypted output to file (outfd). * * cmd - pointing to commandinfo * hSession - pkcs session * infd - input file descriptor * outfd - output file descriptor * */ static int crypt_multipart(struct CommandInfo *cmd, CK_SESSION_HANDLE hSession, int infd, int outfd, off_t insize) { CK_RV rv; CK_ULONG resultlen; CK_ULONG resultbuflen; CK_BYTE_PTR resultbuf; CK_ULONG datalen; CK_BYTE databuf[BUFFERSIZE]; CK_BYTE outbuf[BUFFERSIZE+BLOCKSIZE]; CK_ULONG status_index = 0; /* current total file size read */ float status_last = 0.0; /* file size of last element used */ float status_incr = 0.0; /* file size element increments */ int pos; /* # of progress bar elements to be print */ ssize_t nread; boolean_t errflag = B_FALSE; datalen = sizeof (databuf); resultbuflen = sizeof (outbuf); resultbuf = outbuf; /* Divide into 79 increments for progress bar element spacing */ if (vflag && iflag) status_incr = (insize / 79.0); while ((nread = read(infd, databuf, datalen)) > 0) { /* Start with the initial buffer */ resultlen = resultbuflen; rv = cmd->Update(hSession, databuf, (CK_ULONG)nread, resultbuf, &resultlen); /* Need a bigger buffer? */ if (rv == CKR_BUFFER_TOO_SMALL) { /* free the old buffer */ if (resultbuf != NULL && resultbuf != outbuf) { bzero(resultbuf, resultbuflen); free(resultbuf); } /* allocate a new big buffer */ if ((resultbuf = malloc((size_t)resultlen)) == NULL) { int err = errno; cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(err)); return (-1); } resultbuflen = resultlen; /* Try again with bigger buffer */ rv = cmd->Update(hSession, databuf, (CK_ULONG)nread, resultbuf, &resultlen); } if (rv != CKR_OK) { errflag = B_TRUE; cryptoerror(LOG_STDERR, gettext( "crypto operation failed: %s"), pkcs11_strerror(rv)); break; } /* write the output */ if (write(outfd, resultbuf, resultlen) != resultlen) { cryptoerror(LOG_STDERR, gettext( "failed to write result to output file.")); errflag = B_TRUE; break; } if (vflag) { status_index += resultlen; /* * If input is from stdin, do a our own progress bar * by printing periods at a pre-defined increment * until the file is done. */ if (!iflag) { /* * Print at least 1 element in case the file * is small, it looks better than nothing. */ if (status_pos == 0) { (void) fprintf(stderr, gettext(".")); status_pos = 1; } while ((status_index - status_last) > (PROGRESSSIZE)) { (void) fprintf(stderr, gettext(".")); status_last += PROGRESSSIZE; } continue; } /* Calculate the number of elements need to be print */ if (insize <= BUFFERSIZE) pos = 78; else pos = (int)((status_index - status_last) / status_incr); /* Add progress bar elements, if needed */ if (pos > 0) { print_status(pos); status_last += (status_incr * pos); } } } /* Print verbose completion */ if (vflag) { if (iflag) (void) fprintf(stderr, "]"); (void) fprintf(stderr, "\n%s\n", gettext("Done.")); } /* Error in reading */ if (nread == -1) { cryptoerror(LOG_STDERR, gettext( "error reading from input file")); errflag = B_TRUE; } if (!errflag) { /* Do the final part */ rv = cmd->Final(hSession, resultbuf, &resultlen); if (rv == CKR_OK) { /* write the output */ if (write(outfd, resultbuf, resultlen) != resultlen) { cryptoerror(LOG_STDERR, gettext( "failed to write result to output file.")); errflag = B_TRUE; } } else { cryptoerror(LOG_STDERR, gettext( "crypto operation failed: %s"), pkcs11_strerror(rv)); errflag = B_TRUE; } } if (resultbuf != NULL && resultbuf != outbuf) { bzero(resultbuf, resultbuflen); free(resultbuf); } if (errflag) { return (-1); } else { return (0); } } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # PROG = digest # Hammerhead: ROOTBIN64=ROOTBIN (path flattening), so ROOTLINK64=ROOTLINK # and ROOTDIGLINK=ROOTPROG. Removed duplicate 64-bit variables and # ../../bin symlink rules (circular when /bin -> usr/bin). ROOTLINK= $(ROOTBIN)/mac DCFILE= $(PROG).dc include ../../Makefile.cmd include ../../Makefile.cmd.64 CFLAGS += $(CCVERBOSE) CERRWARN += $(CNOWARN_UNINIT) LDLIBS += -lkmf -lpkcs11 -lcryptoutil .KEEP_STATE: all: $(PROG) install: all $(ROOTBIN) $(ROOTLINK) $(ROOTLINK): $(ROOTPROG) $(RM) $@; $(LN) $(ROOTPROG) $@ clean: $(RM) $(PROG) $(DCFILE): $(RM) messages.po $(XGETTEXT) $(XGETFLAGS) -t $(PROG).c $(SED) -e '/^domain/d' messages.po > $@ $(RM) messages.po include ../../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * digest.c * * Implements digest(1) and mac(1) commands * If command name is mac, performs mac operation * else perform digest operation * * See the man pages for digest and mac for details on * how these commands work. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Buffer size for reading file. This is given a rather high value * to get better performance when a hardware provider is present. */ #define BUFFERSIZE (1024 * 64) /* * RESULTLEN - large enough size in bytes to hold result for * digest and mac results for all mechanisms */ #define RESULTLEN (512) /* * Exit Status codes */ #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 /* No errors */ #define EXIT_FAILURE 1 /* All errors except usage */ #endif /* EXIT_SUCCESS */ #define EXIT_USAGE 2 /* usage/syntax error */ #define MAC_NAME "mac" /* name of mac command */ #define MAC_OPTIONS "lva:k:T:K:" /* for getopt */ #define DIGEST_NAME "digest" /* name of digest command */ #define DIGEST_OPTIONS "lva:" /* for getopt */ /* Saved command line options */ static boolean_t vflag = B_FALSE; /* -v (verbose) flag, optional */ static boolean_t aflag = B_FALSE; /* -a flag, required */ static boolean_t lflag = B_FALSE; /* -l flag, for mac and digest */ static boolean_t kflag = B_FALSE; /* -k keyfile */ static boolean_t Tflag = B_FALSE; /* -T token_spec */ static boolean_t Kflag = B_FALSE; /* -K key_label */ static char *keyfile = NULL; /* name of file containing key value */ static char *token_label = NULL; /* tokensSpec: tokenName[:manufId[:serial]] */ static char *key_label = NULL; /* PKCS#11 symmetric token key label */ static CK_BYTE buf[BUFFERSIZE]; struct mech_alias { CK_MECHANISM_TYPE type; char *alias; CK_ULONG keysize_min; CK_ULONG keysize_max; int keysize_unit; boolean_t available; }; #define MECH_ALIASES_COUNT 11 static struct mech_alias mech_aliases[] = { { CKM_SHA_1, "sha1", ULONG_MAX, 0L, 8, B_FALSE }, { CKM_MD5, "md5", ULONG_MAX, 0L, 8, B_FALSE }, { CKM_DES_MAC, "des_mac", ULONG_MAX, 0L, 8, B_FALSE }, { CKM_SHA_1_HMAC, "sha1_hmac", ULONG_MAX, 0L, 8, B_FALSE }, { CKM_MD5_HMAC, "md5_hmac", ULONG_MAX, 0L, 8, B_FALSE }, { CKM_SHA256, "sha256", ULONG_MAX, 0L, 8, B_FALSE }, { CKM_SHA384, "sha384", ULONG_MAX, 0L, 8, B_FALSE }, { CKM_SHA512, "sha512", ULONG_MAX, 0L, 8, B_FALSE }, { CKM_SHA256_HMAC, "sha256_hmac", ULONG_MAX, 0L, 8, B_FALSE }, { CKM_SHA384_HMAC, "sha384_hmac", ULONG_MAX, 0L, 8, B_FALSE }, { CKM_SHA512_HMAC, "sha512_hmac", ULONG_MAX, 0L, 8, B_FALSE } }; static CK_BBOOL true = TRUE; static void usage(boolean_t mac_cmd); static int execute_cmd(char *algo_str, int filecount, char **filelist, boolean_t mac_cmd); static CK_RV do_mac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech, int fd, CK_OBJECT_HANDLE key, CK_BYTE_PTR *psignature, CK_ULONG_PTR psignaturelen); static CK_RV do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech, int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen); int main(int argc, char **argv) { extern char *optarg; extern int optind; int errflag = 0; /* We had an optstr parse error */ int c; /* current getopts flag */ char *algo_str; /* mechanism/algorithm string */ int filecount; boolean_t mac_cmd; /* if TRUE, do mac, else do digest */ char *optstr; char **filelist; /* list of files */ char *cmdname = NULL; /* name of command */ (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defiend by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); /* * Based on command name, determine * type of command. mac is mac * everything else is digest. */ cmdname = basename(argv[0]); cryptodebug_init(cmdname); if (strcmp(cmdname, MAC_NAME) == 0) mac_cmd = B_TRUE; else if (strcmp(cmdname, DIGEST_NAME) == 0) mac_cmd = B_FALSE; else { cryptoerror(LOG_STDERR, gettext( "command name must be either digest or mac\n")); exit(EXIT_USAGE); } if (mac_cmd) { optstr = MAC_OPTIONS; } else { optstr = DIGEST_OPTIONS; } /* Parse command line arguments */ while (!errflag && (c = getopt(argc, argv, optstr)) != -1) { switch (c) { case 'v': vflag = B_TRUE; break; case 'a': aflag = B_TRUE; algo_str = optarg; break; case 'k': kflag = B_TRUE; keyfile = optarg; break; case 'l': lflag = B_TRUE; break; case 'T': Tflag = B_TRUE; token_label = optarg; break; case 'K': Kflag = B_TRUE; key_label = optarg; break; default: errflag++; } } filecount = argc - optind; if (errflag || (!aflag && !lflag) || (lflag && argc > 2) || (kflag && Kflag) || (Tflag && !Kflag) || filecount < 0) { usage(mac_cmd); exit(EXIT_USAGE); } if (filecount == 0) { filelist = NULL; } else { filelist = &argv[optind]; } return (execute_cmd(algo_str, filecount, filelist, mac_cmd)); } /* * usage message for digest/mac */ static void usage(boolean_t mac_cmd) { (void) fprintf(stderr, gettext("Usage:\n")); if (mac_cmd) { (void) fprintf(stderr, gettext(" mac -l\n")); (void) fprintf(stderr, gettext(" mac [-v] -a " "[-k | -K [-T ]] " "[file...]\n")); } else { (void) fprintf(stderr, gettext(" digest -l | [-v] " "-a [file...]\n")); } } /* * Print out list of available algorithms. */ static void algorithm_list(boolean_t mac_cmd) { int mech; if (mac_cmd) (void) printf(gettext("Algorithm Keysize: Min " "Max (bits)\n" "------------------------------------------\n")); for (mech = 0; mech < MECH_ALIASES_COUNT; mech++) { if (mech_aliases[mech].available == B_FALSE) continue; if (mac_cmd) { (void) printf("%-15s", mech_aliases[mech].alias); if (mech_aliases[mech].keysize_min != ULONG_MAX && mech_aliases[mech].keysize_max != 0) (void) printf(" %5lu %5lu\n", (mech_aliases[mech].keysize_min * mech_aliases[mech].keysize_unit), (mech_aliases[mech].keysize_max * mech_aliases[mech].keysize_unit)); else (void) printf("\n"); } else (void) printf("%s\n", mech_aliases[mech].alias); } } static int get_token_key(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keytype, char *keylabel, CK_BYTE *password, int password_len, CK_OBJECT_HANDLE *keyobj) { CK_RV rv; CK_ATTRIBUTE pTmpl[10]; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_BBOOL true = 1; CK_BBOOL is_token = 1; CK_ULONG key_obj_count = 1; int i; CK_KEY_TYPE ckKeyType = keytype; rv = C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)password, password_len); if (rv != CKR_OK) { (void) fprintf(stderr, "Cannot login to the token." " error = %s\n", pkcs11_strerror(rv)); return (-1); } i = 0; pTmpl[i].type = CKA_TOKEN; pTmpl[i].pValue = &is_token; pTmpl[i].ulValueLen = sizeof (CK_BBOOL); i++; pTmpl[i].type = CKA_CLASS; pTmpl[i].pValue = &class; pTmpl[i].ulValueLen = sizeof (class); i++; pTmpl[i].type = CKA_LABEL; pTmpl[i].pValue = keylabel; pTmpl[i].ulValueLen = strlen(keylabel); i++; pTmpl[i].type = CKA_KEY_TYPE; pTmpl[i].pValue = &ckKeyType; pTmpl[i].ulValueLen = sizeof (ckKeyType); i++; pTmpl[i].type = CKA_PRIVATE; pTmpl[i].pValue = &true; pTmpl[i].ulValueLen = sizeof (true); i++; rv = C_FindObjectsInit(hSession, pTmpl, i); if (rv != CKR_OK) { goto out; } rv = C_FindObjects(hSession, keyobj, 1, &key_obj_count); (void) C_FindObjectsFinal(hSession); out: if (rv != CKR_OK) { (void) fprintf(stderr, "Cannot retrieve key object. error = %s\n", pkcs11_strerror(rv)); return (-1); } if (key_obj_count == 0) { (void) fprintf(stderr, "Cannot find the key object.\n"); return (-1); } return (0); } /* * Execute the command. * algo_str - name of algorithm * filecount - no. of files to process, if 0, use stdin * filelist - list of files * mac_cmd - if true do mac else do digest */ static int execute_cmd(char *algo_str, int filecount, char **filelist, boolean_t mac_cmd) { int fd; char *filename = NULL; CK_RV rv; CK_ULONG slotcount; CK_SLOT_ID slotID; CK_SLOT_ID_PTR pSlotList = NULL; CK_MECHANISM_TYPE mech_type; CK_MECHANISM_INFO info; CK_MECHANISM mech; CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; CK_BYTE_PTR resultbuf = NULL; CK_ULONG resultlen; CK_BYTE_PTR pkeydata = NULL; CK_OBJECT_HANDLE key = (CK_OBJECT_HANDLE) 0; size_t keylen = 0; /* key length */ char *resultstr = NULL; /* result in hex string */ int resultstrlen; /* result string length */ int i; int exitcode = EXIT_SUCCESS; /* return code */ int slot, mek; /* index variables */ int mech_match = 0; CK_BYTE salt[CK_PKCS5_PBKD2_SALT_SIZE]; CK_ULONG keysize; CK_ULONG iterations = CK_PKCS5_PBKD2_ITERATIONS; CK_KEY_TYPE keytype; KMF_RETURN kmfrv; CK_SLOT_ID token_slot_id; if (aflag) { /* * Determine if algorithm/mechanism is valid */ for (mech_match = 0; mech_match < MECH_ALIASES_COUNT; mech_match++) { if (strcmp(algo_str, mech_aliases[mech_match].alias) == 0) { mech_type = mech_aliases[mech_match].type; break; } } if (mech_match == MECH_ALIASES_COUNT) { cryptoerror(LOG_STDERR, gettext("unknown algorithm -- %s"), algo_str); return (EXIT_FAILURE); } /* Get key to do a MAC operation */ if (mac_cmd) { int status; if (Kflag) { /* get the pin of the token */ if (token_label == NULL || !strlen(token_label)) { token_label = pkcs11_default_token(); } status = pkcs11_get_pass(token_label, (char **)&pkeydata, &keylen, 0, B_FALSE); } else if (keyfile != NULL) { /* get the key file */ status = pkcs11_read_data(keyfile, (void **)&pkeydata, &keylen); } else { /* get the key from input */ status = pkcs11_get_pass(NULL, (char **)&pkeydata, &keylen, 0, B_FALSE); } if (status != 0 || keylen == 0 || pkeydata == NULL) { cryptoerror(LOG_STDERR, (Kflag || (keyfile == NULL)) ? gettext("invalid passphrase.") : gettext("invalid key.")); return (EXIT_FAILURE); } } } /* Initialize, and get list of slots */ rv = C_Initialize(NULL); if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { cryptoerror(LOG_STDERR, gettext("failed to initialize PKCS #11 framework: %s"), pkcs11_strerror(rv)); return (EXIT_FAILURE); } /* Get slot count */ rv = C_GetSlotList(0, NULL_PTR, &slotcount); if (rv != CKR_OK || slotcount == 0) { cryptoerror(LOG_STDERR, gettext( "failed to find any cryptographic provider; " "please check with your system administrator: %s"), pkcs11_strerror(rv)); exitcode = EXIT_FAILURE; goto cleanup; } /* Found at least one slot, allocate memory for slot list */ pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID)); if (pSlotList == NULL_PTR) { int err = errno; cryptoerror(LOG_STDERR, gettext("malloc: %s\n"), strerror(err)); exitcode = EXIT_FAILURE; goto cleanup; } /* Get the list of slots */ if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext( "failed to find any cryptographic provider; " "please check with your system administrator: %s"), pkcs11_strerror(rv)); exitcode = EXIT_FAILURE; goto cleanup; } /* * Obtain list of algorithms if -l option was given */ if (lflag) { for (slot = 0; slot < slotcount; slot++) { /* Iterate through each mechanism */ for (mek = 0; mek < MECH_ALIASES_COUNT; mek++) { rv = C_GetMechanismInfo(pSlotList[slot], mech_aliases[mek].type, &info); /* Only check algorithms that can be used */ if ((rv != CKR_OK) || (!mac_cmd && (info.flags & CKF_SIGN)) || (mac_cmd && (info.flags & CKF_DIGEST))) continue; /* * Set to minimum/maximum key sizes assuming * the values available are not 0. */ if (info.ulMinKeySize && (info.ulMinKeySize < mech_aliases[mek].keysize_min)) mech_aliases[mek].keysize_min = info.ulMinKeySize; if (info.ulMaxKeySize && (info.ulMaxKeySize > mech_aliases[mek].keysize_max)) mech_aliases[mek].keysize_max = info.ulMaxKeySize; mech_aliases[mek].available = B_TRUE; } } algorithm_list(mac_cmd); goto cleanup; } /* * Find a slot with matching mechanism * * If -K is specified, we find the slot id for the token first, then * check if the slot supports the algorithm. */ i = 0; if (Kflag) { kmfrv = kmf_pk11_token_lookup(NULL, token_label, &token_slot_id); if (kmfrv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("no matching PKCS#11 token")); exitcode = EXIT_FAILURE; goto cleanup; } rv = C_GetMechanismInfo(token_slot_id, mech_type, &info); if (rv == CKR_OK && (info.flags & CKF_SIGN)) slotID = token_slot_id; else i = slotcount; } else { for (i = 0; i < slotcount; i++) { slotID = pSlotList[i]; rv = C_GetMechanismInfo(slotID, mech_type, &info); if (rv != CKR_OK) { continue; /* to the next slot */ } else { if (mac_cmd) { /* * Make sure the slot supports * PKCS5 key generation if we * will be using it later. * We use it whenever the key * is entered at command line. */ if ((info.flags & CKF_SIGN) && (keyfile == NULL)) { CK_MECHANISM_INFO kg_info; rv = C_GetMechanismInfo(slotID, CKM_PKCS5_PBKD2, &kg_info); if (rv == CKR_OK) break; } else if (info.flags & CKF_SIGN) { break; } } else { if (info.flags & CKF_DIGEST) break; } } } } /* Show error if no matching mechanism found */ if (i == slotcount) { cryptoerror(LOG_STDERR, gettext("no cryptographic provider was " "found for this algorithm -- %s"), algo_str); exitcode = EXIT_FAILURE; goto cleanup; } /* Mechanism is supported. Go ahead & open a session */ rv = C_OpenSession(slotID, CKF_SERIAL_SESSION, NULL_PTR, NULL, &hSession); if (rv != CKR_OK) { cryptoerror(LOG_STDERR, gettext("can not open PKCS#11 session: %s"), pkcs11_strerror(rv)); exitcode = EXIT_FAILURE; goto cleanup; } /* Create a key object for mac operation */ if (mac_cmd) { /* * If we read keybytes from a file, * do NOT process them with C_GenerateKey, * treat them as raw keydata bytes and * create a key object for them. */ if (keyfile) { /* XXX : why wasn't SUNW_C_KeyToObject used here? */ CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE tmpl_keytype = CKK_GENERIC_SECRET; CK_BBOOL false = FALSE; int nattr = 0; CK_ATTRIBUTE template[5]; if (mech_type == CKM_DES_MAC) { tmpl_keytype = CKK_DES; } template[nattr].type = CKA_CLASS; template[nattr].pValue = &class; template[nattr].ulValueLen = sizeof (class); nattr++; template[nattr].type = CKA_KEY_TYPE; template[nattr].pValue = &tmpl_keytype; template[nattr].ulValueLen = sizeof (tmpl_keytype); nattr++; template[nattr].type = CKA_SIGN; template[nattr].pValue = &true; template[nattr].ulValueLen = sizeof (true); nattr++; template[nattr].type = CKA_TOKEN; template[nattr].pValue = &false; template[nattr].ulValueLen = sizeof (false); nattr++; template[nattr].type = CKA_VALUE; template[nattr].pValue = pkeydata; template[nattr].ulValueLen = keylen; nattr++; rv = C_CreateObject(hSession, template, nattr, &key); } else if (Kflag) { if (mech_type == CKM_DES_MAC) { keytype = CKK_DES; } else { keytype = CKK_GENERIC_SECRET; } rv = get_token_key(hSession, keytype, key_label, pkeydata, keylen, &key); if (rv != CKR_OK) { exitcode = EXIT_FAILURE; goto cleanup; } } else { CK_KEY_TYPE keytype; if (mech_type == CKM_DES_MAC) { keytype = CKK_DES; keysize = 0; } else { keytype = CKK_GENERIC_SECRET; keysize = 16; /* 128 bits */ } /* * We use a fixed salt (0x0a, 0x0a, 0x0a ...) * for creating the key so that the end user * will be able to generate the same 'mac' * using the same passphrase. */ (void) memset(salt, 0x0a, sizeof (salt)); rv = pkcs11_PasswdToPBKD2Object(hSession, (char *)pkeydata, (size_t)keylen, (void *)salt, sizeof (salt), iterations, keytype, keysize, CKF_SIGN, &key); } if (rv != CKR_OK) { cryptoerror(LOG_STDERR, gettext("unable to create key for crypto " "operation: %s"), pkcs11_strerror(rv)); exitcode = EXIT_FAILURE; goto cleanup; } } /* Allocate a buffer to store result. */ resultlen = RESULTLEN; if ((resultbuf = malloc(resultlen)) == NULL) { int err = errno; cryptoerror(LOG_STDERR, gettext("malloc: %s\n"), strerror(err)); exitcode = EXIT_FAILURE; goto cleanup; } /* Allocate a buffer to store result string */ resultstrlen = RESULTLEN; if ((resultstr = malloc(resultstrlen)) == NULL) { int err = errno; cryptoerror(LOG_STDERR, gettext("malloc: %s\n"), strerror(err)); exitcode = EXIT_FAILURE; goto cleanup; } mech.mechanism = mech_type; mech.pParameter = NULL_PTR; mech.ulParameterLen = 0; exitcode = EXIT_SUCCESS; i = 0; do { if (filecount > 0 && filelist != NULL) { filename = filelist[i]; if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) { cryptoerror(LOG_STDERR, gettext( "can not open input file %s\n"), filename); exitcode = EXIT_USAGE; continue; } } else { fd = 0; /* use stdin */ } /* * Perform the operation */ if (mac_cmd) { rv = do_mac(hSession, &mech, fd, key, &resultbuf, &resultlen); } else { rv = do_digest(hSession, &mech, fd, &resultbuf, &resultlen); } if (rv != CKR_OK) { cryptoerror(LOG_STDERR, gettext("crypto operation failed for " "file %s: %s\n"), filename ? filename : "STDIN", pkcs11_strerror(rv)); exitcode = EXIT_FAILURE; continue; } /* if result size has changed, allocate a bigger resulstr buf */ if (resultlen != RESULTLEN) { resultstrlen = 2 * resultlen + 1; resultstr = realloc(resultstr, resultstrlen); if (resultstr == NULL) { int err = errno; cryptoerror(LOG_STDERR, gettext("realloc: %s\n"), strerror(err)); exitcode = EXIT_FAILURE; goto cleanup; } } /* Output the result */ tohexstr(resultbuf, resultlen, resultstr, resultstrlen); /* Include mechanism name for verbose */ if (vflag) (void) fprintf(stdout, "%s ", algo_str); /* Include file name for multiple files, or if verbose */ if (filecount > 1 || (vflag && filecount > 0)) { (void) fprintf(stdout, "(%s) = ", filename); } (void) fprintf(stdout, "%s\n", resultstr); (void) close(fd); } while (++i < filecount); /* clear and free the key */ if (mac_cmd) { (void) memset(pkeydata, 0, keylen); free(pkeydata); pkeydata = NULL; } cleanup: if (resultbuf != NULL) { free(resultbuf); } if (resultstr != NULL) { free(resultstr); } if (pSlotList != NULL) { free(pSlotList); } if (!Kflag && key != (CK_OBJECT_HANDLE) 0) { (void) C_DestroyObject(hSession, key); } if (hSession != CK_INVALID_HANDLE) (void) C_CloseSession(hSession); (void) C_Finalize(NULL_PTR); return (exitcode); } /* * do_digest - Compute digest of a file * * hSession - session * pmech - ptr to mechanism to be used for digest * fd - file descriptor * pdigest - buffer where digest result is returned * pdigestlen - length of digest buffer on input, * length of result on output */ static CK_RV do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech, int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen) { CK_RV rv; ssize_t nread; int saved_errno; if ((rv = C_DigestInit(hSession, pmech)) != CKR_OK) { return (rv); } while ((nread = read(fd, buf, sizeof (buf))) > 0) { /* Get the digest */ rv = C_DigestUpdate(hSession, buf, (CK_ULONG)nread); if (rv != CKR_OK) return (rv); } saved_errno = errno; /* for later use */ /* * Perform the C_DigestFinal, even if there is a read error. * Otherwise C_DigestInit will return CKR_OPERATION_ACTIVE * next time it is called (for another file) */ rv = C_DigestFinal(hSession, *pdigest, pdigestlen); /* result too big to fit? Allocate a bigger buffer */ if (rv == CKR_BUFFER_TOO_SMALL) { *pdigest = realloc(*pdigest, *pdigestlen); if (*pdigest == NULL_PTR) { int err = errno; cryptoerror(LOG_STDERR, gettext("realloc: %s\n"), strerror(err)); return (CKR_HOST_MEMORY); } rv = C_DigestFinal(hSession, *pdigest, pdigestlen); } /* There was a read error */ if (nread == -1) { cryptoerror(LOG_STDERR, gettext( "error reading file: %s"), strerror(saved_errno)); return (CKR_GENERAL_ERROR); } else { return (rv); } } /* * do_mac - Compute mac of a file * * hSession - session * pmech - ptr to mechanism to be used * fd - file descriptor * key - key to be used * psignature - ptr buffer where mac result is returned * returns new buf if current buf is small * psignaturelen - length of mac buffer on input, * length of result on output */ static CK_RV do_mac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech, int fd, CK_OBJECT_HANDLE key, CK_BYTE_PTR *psignature, CK_ULONG_PTR psignaturelen) { CK_RV rv; ssize_t nread; int saved_errno; if ((rv = C_SignInit(hSession, pmech, key)) != CKR_OK) { return (rv); } while ((nread = read(fd, buf, sizeof (buf))) > 0) { /* Get the MAC */ rv = C_SignUpdate(hSession, buf, (CK_ULONG)nread); if (rv != CKR_OK) return (rv); } saved_errno = errno; /* for later use */ /* * Perform the C_SignFinal, even if there is a read error. * Otherwise C_SignInit will return CKR_OPERATION_ACTIVE * next time it is called (for another file) */ rv = C_SignFinal(hSession, *psignature, psignaturelen); /* result too big to fit? Allocate a bigger buffer */ if (rv == CKR_BUFFER_TOO_SMALL) { *psignature = realloc(*psignature, *psignaturelen); if (*psignature == NULL_PTR) { int err = errno; cryptoerror(LOG_STDERR, gettext("realloc: %s\n"), strerror(err)); return (CKR_HOST_MEMORY); } rv = C_SignFinal(hSession, *psignature, psignaturelen); } /* There was a read error */ if (nread == -1) { cryptoerror(LOG_STDERR, gettext("error reading file: %s"), strerror(saved_errno)); return (CKR_GENERAL_ERROR); } else { return (rv); } } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # PROG = elfsign OBJS = elfsign.o SRCS = $(OBJS:.o=.c) include $(SRC)/cmd/Makefile.cmd CFLAGS += $(CCVERBOSE) LDLIBS += -lkmf -lelfsign -lcryptoutil .KEEP_STATE: all: $(PROG) $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(DYNFLAGS) $(POST_PROCESS) install: all $(ROOTPROG) clean: $(RM) -f $(OBJS) $(PROG) lint: lint_SRCS include $(SRC)/cmd/Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Developer command for adding the signature section to an ELF object * PSARC 2001/488 * * DEBUG Information: * This command uses the cryptodebug() function from libcryptoutil. * Set SUNW_CRYPTO_DEBUG to stderr or syslog for all debug to go to auth.debug */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SIGN "sign" #define SIGN_OPTS "c:e:F:k:P:T:v" #define VERIFY "verify" #define VERIFY_OPTS "c:e:v" #define REQUEST "request" #define REQUEST_OPTS "i:k:r:T:" #define LIST "list" #define LIST_OPTS "c:e:f:" enum cmd_e { ES_SIGN, ES_VERIFY, ES_REQUEST, ES_LIST }; enum field_e { FLD_UNKNOWN, FLD_SUBJECT, FLD_ISSUER, FLD_FORMAT, FLD_SIGNER, FLD_TIME }; #define MIN_ARGS 3 /* The minimum # args to do anything */ #define ES_DEFAULT_KEYSIZE 1024 static struct { enum cmd_e cmd; /* sub command: sign | verify | request */ char *cert; /* -c | */ /* -r */ char **elfobj; /* -e */ int elfcnt; enum ES_ACTION es_action; ELFsign_t ess; /* libelfsign opaque "state" */ int extracnt; enum field_e field; /* -f */ char internal_req; /* Sun internal certificate request */ char *pinpath; /* -P */ char *privpath; /* -k */ char *token_label; /* -T */ boolean_t verbose; /* chatty output */ } cmd_info; enum ret_e { EXIT_OKAY, EXIT_INVALID_ARG, EXIT_VERIFY_FAILED, EXIT_CANT_OPEN_ELF_OBJECT, EXIT_BAD_CERT, EXIT_BAD_PRIVATEKEY, EXIT_SIGN_FAILED, EXIT_VERIFY_FAILED_UNSIGNED, EXIT_CSR_FAILED, EXIT_MEMORY_ERROR }; struct field_s { char *name; enum field_e field; } fields[] = { { "subject", FLD_SUBJECT }, { "issuer", FLD_ISSUER }, { "format", FLD_FORMAT }, { "signer", FLD_SIGNER }, { "time", FLD_TIME }, NULL, 0 }; typedef enum ret_e ret_t; static void usage(void); static ret_t getelfobj(char *); static char *getpin(void); static ret_t do_sign(char *); static ret_t do_verify(char *); static ret_t do_cert_request(char *); static ret_t do_list(char *); static void es_error(const char *fmt, ...); static char *time_str(time_t t); static void sig_info_print(struct ELFsign_sig_info *esip); int main(int argc, char **argv) { extern char *optarg; char *scmd = NULL; char *opts; /* The set of flags for cmd */ int errflag = 0; /* We had an options parse error */ int c; /* current getopts flag */ ret_t (*action)(char *); /* Function pointer for the action */ ret_t ret; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defiend by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); cryptodebug_init("elfsign"); if (argc < MIN_ARGS) { es_error(gettext("invalid number of arguments")); usage(); return (EXIT_INVALID_ARG); } scmd = argv[1]; cmd_info.cert = NULL; cmd_info.elfobj = NULL; cmd_info.elfcnt = 0; cmd_info.es_action = ES_GET; cmd_info.ess = NULL; cmd_info.extracnt = 0; cmd_info.field = FLD_UNKNOWN; cmd_info.internal_req = '\0'; cmd_info.pinpath = NULL; cmd_info.privpath = NULL; cmd_info.token_label = NULL; cmd_info.verbose = B_FALSE; if (strcmp(scmd, SIGN) == 0) { cmd_info.cmd = ES_SIGN; opts = SIGN_OPTS; cryptodebug("cmd=sign opts=%s", opts); action = do_sign; cmd_info.es_action = ES_UPDATE_RSA_SHA1; } else if (strcmp(scmd, VERIFY) == 0) { cmd_info.cmd = ES_VERIFY; opts = VERIFY_OPTS; cryptodebug("cmd=verify opts=%s", opts); action = do_verify; } else if (strcmp(scmd, REQUEST) == 0) { cmd_info.cmd = ES_REQUEST; opts = REQUEST_OPTS; cryptodebug("cmd=request opts=%s", opts); action = do_cert_request; } else if (strcmp(scmd, LIST) == 0) { cmd_info.cmd = ES_LIST; opts = LIST_OPTS; cryptodebug("cmd=list opts=%s", opts); action = do_list; } else { es_error(gettext("Unknown sub-command: %s"), scmd); usage(); return (EXIT_INVALID_ARG); } /* * Note: There is no need to check that optarg isn't NULL * because getopt does that for us. */ while (!errflag && (c = getopt(argc - 1, argv + 1, opts)) != EOF) { if (strchr("ceFihkPTr", c) != NULL) cryptodebug("c=%c, '%s'", c, optarg); else cryptodebug("c=%c", c); switch (c) { case 'c': cmd_info.cert = optarg; break; case 'e': cmd_info.elfcnt++; cmd_info.elfobj = (char **)realloc(cmd_info.elfobj, sizeof (char *) * cmd_info.elfcnt); if (cmd_info.elfobj == NULL) { es_error(gettext( "Too many elf objects specified.")); return (EXIT_INVALID_ARG); } cmd_info.elfobj[cmd_info.elfcnt - 1] = optarg; break; case 'f': { struct field_s *fp; cmd_info.field = FLD_UNKNOWN; for (fp = fields; fp->name != NULL; fp++) { if (strcasecmp(optarg, fp->name) == 0) { cmd_info.field = fp->field; break; } } if (cmd_info.field == FLD_UNKNOWN) { cryptodebug("Invalid field option"); errflag++; } } break; case 'F': if (strcasecmp(optarg, ES_FMT_RSA_MD5_SHA1) == 0) cmd_info.es_action = ES_UPDATE_RSA_MD5_SHA1; else if (strcasecmp(optarg, ES_FMT_RSA_SHA1) == 0) cmd_info.es_action = ES_UPDATE_RSA_SHA1; else { cryptodebug("Invalid format option"); errflag++; } break; case 'i': /* Undocumented internal Sun use only */ cmd_info.internal_req = *optarg; break; case 'k': cmd_info.privpath = optarg; if (cmd_info.token_label != NULL || cmd_info.pinpath != NULL) errflag++; break; case 'P': cmd_info.pinpath = optarg; if (cmd_info.privpath != NULL) errflag++; break; case 'r': cmd_info.cert = optarg; break; case 'T': cmd_info.token_label = optarg; if (cmd_info.privpath != NULL) errflag++; break; case 'v': cmd_info.verbose = B_TRUE; break; default: errflag++; } } optind++; /* we skipped over subcommand */ cmd_info.extracnt = argc - optind; if (cmd_info.extracnt != 0 && cmd_info.cmd != ES_SIGN && cmd_info.cmd != ES_VERIFY) { cryptodebug("Extra arguments, optind=%d, argc=%d", optind, argc); errflag++; } switch (cmd_info.cmd) { case ES_VERIFY: if (cmd_info.elfcnt + argc - optind == 0) { cryptodebug("Missing elfobj"); errflag++; } break; case ES_SIGN: if (((cmd_info.privpath == NULL) && (cmd_info.token_label == NULL)) || (cmd_info.cert == NULL) || (cmd_info.elfcnt + argc - optind == 0)) { cryptodebug("Missing privpath|token_label/cert/elfobj"); errflag++; } break; case ES_REQUEST: if (((cmd_info.privpath == NULL) && (cmd_info.token_label == NULL)) || (cmd_info.cert == NULL)) { cryptodebug("Missing privpath|token_label/certreq"); errflag++; } break; case ES_LIST: if ((cmd_info.cert != NULL) == (cmd_info.elfcnt > 0)) { cryptodebug("Neither or both of cert/elfobj"); errflag++; } break; } if (errflag) { usage(); return (EXIT_INVALID_ARG); } switch (cmd_info.cmd) { case ES_REQUEST: case ES_LIST: ret = action(NULL); break; default: { int i; ret_t iret; ret = EXIT_OKAY; iret = EXIT_OKAY; for (i = 0; i < cmd_info.elfcnt && (ret == EXIT_OKAY || cmd_info.cmd != ES_SIGN); i++) { iret = action(cmd_info.elfobj[i]); if (iret > ret) ret = iret; } for (i = optind; i < argc && (ret == EXIT_OKAY || cmd_info.cmd != ES_SIGN); i++) { iret = action(argv[i]); if (iret > ret) ret = iret; } break; } } if (cmd_info.elfobj != NULL) free(cmd_info.elfobj); return (ret); } static void usage(void) { /* BEGIN CSTYLED */ (void) fprintf(stderr, gettext( "usage:\n" "\telfsign sign [-v] [-e ] -c \n" "\t\t[-F ] -k [elf_object]..." "\n" "\telfsign sign [-v] [-e ] -c \n" "\t\t[-F ] -T [-P ] [elf_object]..." "\n\n" "\telfsign verify [-v] [-c ] [-e ]\n" "\t\t[elf_object]..." "\n\n" "\telfsign request -r -k " "\n" "\telfsign request -r -T " "\n\n" "\telfsign list -f field -c " "\n" "\telfsign list -f field -e " "\n")); /* END CSTYLED */ } static ret_t getelfobj(char *elfpath) { ELFsign_status_t estatus; ret_t ret = EXIT_SIGN_FAILED; estatus = elfsign_begin(elfpath, cmd_info.es_action, &(cmd_info.ess)); switch (estatus) { case ELFSIGN_SUCCESS: ret = EXIT_OKAY; break; case ELFSIGN_INVALID_ELFOBJ: es_error(gettext( "Unable to open %s as an ELF object."), elfpath); ret = EXIT_CANT_OPEN_ELF_OBJECT; break; default: es_error(gettext("unexpected failure: %d"), estatus); if (cmd_info.cmd == ES_SIGN) { ret = EXIT_SIGN_FAILED; } else if (cmd_info.cmd == ES_VERIFY) { ret = EXIT_VERIFY_FAILED; } } return (ret); } static ret_t setcertpath(void) { ELFsign_status_t estatus; ret_t ret = EXIT_SIGN_FAILED; if (cmd_info.cert == NULL) return (EXIT_OKAY); estatus = elfsign_setcertpath(cmd_info.ess, cmd_info.cert); switch (estatus) { case ELFSIGN_SUCCESS: ret = EXIT_OKAY; break; case ELFSIGN_INVALID_CERTPATH: if (cmd_info.cert != NULL) { es_error(gettext("Unable to open %s as a certificate."), cmd_info.cert); } ret = EXIT_BAD_CERT; break; default: es_error(gettext("unusable certificate: %s"), cmd_info.cert); if (cmd_info.cmd == ES_SIGN) { ret = EXIT_SIGN_FAILED; } else if (cmd_info.cmd == ES_VERIFY) { ret = EXIT_VERIFY_FAILED; } } return (ret); } /* * getpin - return pointer to token PIN in static storage */ static char * getpin(void) { static char pinbuf[PASS_MAX + 1]; char *pp; FILE *pinfile; if (cmd_info.pinpath == NULL) return (getpassphrase( gettext("Enter PIN for PKCS#11 token: "))); if ((pinfile = fopen(cmd_info.pinpath, "r")) == NULL) { es_error(gettext("failed to open %s."), cmd_info.pinpath); return (NULL); } pp = fgets(pinbuf, sizeof (pinbuf), pinfile); (void) fclose(pinfile); if (pp == NULL) { es_error(gettext("failed to read PIN from %s."), cmd_info.pinpath); return (NULL); } pp = &pinbuf[strlen(pinbuf) - 1]; if (*pp == '\n') *pp = '\0'; return (pinbuf); } /* * Add the .SUNW_signature sections for the ELF signature */ static ret_t do_sign(char *object) { ret_t ret; ELFsign_status_t elfstat; struct filesignatures *fssp = NULL; size_t fs_len; uchar_t sig[SIG_MAX_LENGTH]; size_t sig_len = SIG_MAX_LENGTH; uchar_t hash[SIG_MAX_LENGTH]; size_t hash_len = SIG_MAX_LENGTH; ELFCert_t cert = NULL; char *dn; size_t dn_len; cryptodebug("do_sign"); if ((ret = getelfobj(object)) != EXIT_OKAY) return (ret); if (cmd_info.token_label && !elfcertlib_settoken(cmd_info.ess, cmd_info.token_label)) { es_error(gettext("Unable to access token: %s"), cmd_info.token_label); ret = EXIT_SIGN_FAILED; goto cleanup; } if ((ret = setcertpath()) != EXIT_OKAY) goto cleanup; if (!elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, &cert, cmd_info.es_action)) { es_error(gettext("Unable to load certificate: %s"), cmd_info.cert); ret = EXIT_BAD_CERT; goto cleanup; } if (cmd_info.privpath != NULL) { if (!elfcertlib_loadprivatekey(cmd_info.ess, cert, cmd_info.privpath)) { es_error(gettext("Unable to load private key: %s"), cmd_info.privpath); ret = EXIT_BAD_PRIVATEKEY; goto cleanup; } } else { char *pin = getpin(); if (pin == NULL) { es_error(gettext("Unable to get PIN")); ret = EXIT_BAD_PRIVATEKEY; goto cleanup; } if (!elfcertlib_loadtokenkey(cmd_info.ess, cert, cmd_info.token_label, pin)) { es_error(gettext("Unable to access private key " "in token %s"), cmd_info.token_label); ret = EXIT_BAD_PRIVATEKEY; goto cleanup; } } /* * Get the DN from the certificate. */ if ((dn = elfcertlib_getdn(cert)) == NULL) { es_error(gettext("Unable to find DN in certificate %s"), cmd_info.cert); ret = EXIT_SIGN_FAILED; goto cleanup; } dn_len = strlen(dn); cryptodebug("DN = %s", dn); elfstat = elfsign_signatures(cmd_info.ess, &fssp, &fs_len, ES_GET); if (elfstat != ELFSIGN_SUCCESS) { if (elfstat != ELFSIGN_NOTSIGNED) { es_error(gettext("Unable to retrieve existing " "signature block in %s"), object); ret = EXIT_SIGN_FAILED; goto cleanup; } fssp = NULL; /* * force creation and naming of signature section * so the hash doesn't change */ if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len, cmd_info.es_action) != ELFSIGN_SUCCESS) { es_error(gettext("Unable to insert " "signature block into %s"), object); ret = EXIT_SIGN_FAILED; goto cleanup; } } bzero(hash, sizeof (hash)); if (elfsign_hash(cmd_info.ess, hash, &hash_len) != ELFSIGN_SUCCESS) { es_error(gettext("Unable to calculate hash of ELF object %s"), object); ret = EXIT_SIGN_FAILED; goto cleanup; } bzero(sig, sizeof (sig)); if (!elfcertlib_sign(cmd_info.ess, cert, hash, hash_len, sig, &sig_len)) { es_error(gettext("Unable to sign %s using key from %s"), object, cmd_info.privpath ? cmd_info.privpath : cmd_info.token_label); ret = EXIT_SIGN_FAILED; goto cleanup; } { /* DEBUG START */ const int sigstr_len = sizeof (char) * sig_len * 2 + 1; char *sigstr = malloc(sigstr_len); tohexstr(sig, sig_len, sigstr, sigstr_len); cryptodebug("sig value is: %s", sigstr); free(sigstr); } /* DEBUG END */ fssp = elfsign_insert_dso(cmd_info.ess, fssp, dn, dn_len, sig, sig_len, NULL, 0); if (fssp == NULL) { es_error(gettext("Unable to prepare signature for %s"), object); ret = EXIT_SIGN_FAILED; goto cleanup; } if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len, cmd_info.es_action) != ELFSIGN_SUCCESS) { es_error(gettext("Unable to update %s: with signature"), object); ret = EXIT_SIGN_FAILED; goto cleanup; } if (cmd_info.verbose || (cmd_info.elfcnt + cmd_info.extracnt) > 1) { (void) fprintf(stdout, gettext("elfsign: %s signed successfully.\n"), object); } if (cmd_info.verbose) { struct ELFsign_sig_info *esip; if (elfsign_sig_info(fssp, &esip)) { sig_info_print(esip); elfsign_sig_info_free(esip); } } ret = EXIT_OKAY; cleanup: free(fssp); bzero(sig, sig_len); bzero(hash, hash_len); if (cert != NULL) elfcertlib_releasecert(cmd_info.ess, cert); if (cmd_info.ess != NULL) elfsign_end(cmd_info.ess); return (ret); } /* * Verify the signature of the object * This subcommand is intended to be used by developers during their build * processes. Therefore we can not assume that the certificate is in * /etc/crypto/certs so we must use the path we got from the commandline. */ static ret_t do_verify(char *object) { ELFsign_status_t res; struct ELFsign_sig_info *esip; ret_t retval; cryptodebug("do_verify"); if ((retval = getelfobj(object)) != EXIT_OKAY) return (retval); if ((retval = setcertpath()) != EXIT_OKAY) { elfsign_end(cmd_info.ess); return (retval); } res = elfsign_verify_signature(cmd_info.ess, &esip); switch (res) { case ELFSIGN_SUCCESS: (void) fprintf(stdout, gettext("elfsign: verification of %s passed.\n"), object); if (cmd_info.verbose) sig_info_print(esip); retval = EXIT_OKAY; break; case ELFSIGN_FAILED: case ELFSIGN_INVALID_CERTPATH: es_error(gettext("verification of %s failed."), object); if (cmd_info.verbose) sig_info_print(esip); retval = EXIT_VERIFY_FAILED; break; case ELFSIGN_NOTSIGNED: es_error(gettext("no signature found in %s."), object); retval = EXIT_VERIFY_FAILED_UNSIGNED; break; default: es_error(gettext("unexpected failure attempting verification " "of %s."), object); retval = EXIT_VERIFY_FAILED_UNSIGNED; break; } if (esip != NULL) elfsign_sig_info_free(esip); if (cmd_info.ess != NULL) elfsign_end(cmd_info.ess); return (retval); } #define SET_VALUE(f, s) \ kmfrv = f; \ if (kmfrv != KMF_OK) { \ char *e = NULL; \ (void) kmf_get_kmf_error_str(kmfrv, &e); \ cryptoerror(LOG_STDERR, \ gettext("Failed to %s: %s\n"), \ s, (e ? e : "unknown error")); \ if (e) free(e); \ goto cleanup; \ } static KMF_RETURN create_csr(char *dn) { KMF_RETURN kmfrv = KMF_OK; KMF_HANDLE_T kmfhandle = NULL; KMF_KEY_HANDLE pubk, prik; KMF_X509_NAME csrSubject; KMF_CSR_DATA csr; KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_MD5WithRSA; KMF_DATA signedCsr = { 0, NULL }; char *err; KMF_ATTRIBUTE attrlist[16]; KMF_ENCODE_FORMAT format; KMF_KEYSTORE_TYPE kstype; KMF_KEY_ALG keytype; uint32_t keylength; KMF_CREDENTIAL cred; char *pin = NULL; int numattr; if ((kmfrv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { (void) kmf_get_kmf_error_str(kmfrv, &err); cryptoerror(LOG_STDERR, gettext("Error initializing KMF: %s\n"), (err ? err : "unknown error")); if (err) free(err); return (kmfrv); } (void) memset(&csr, 0, sizeof (csr)); (void) memset(&csrSubject, 0, sizeof (csrSubject)); if (cmd_info.privpath != NULL) { kstype = KMF_KEYSTORE_OPENSSL; format = KMF_FORMAT_ASN1; } else { boolean_t readonly; /* args checking verified (cmd_info.token_label != NULL) */ /* Get a PIN to store the private key in the token */ pin = getpin(); if (pin == NULL) { (void) kmf_finalize(kmfhandle); return (KMF_ERR_AUTH_FAILED); } kstype = KMF_KEYSTORE_PK11TOKEN; readonly = B_FALSE; numattr = 0; kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); kmf_set_attr_at_index(attrlist, numattr++, KMF_TOKEN_LABEL_ATTR, cmd_info.token_label, strlen(cmd_info.token_label)); kmf_set_attr_at_index(attrlist, numattr++, KMF_READONLY_ATTR, &readonly, sizeof (readonly)); kmfrv = kmf_configure_keystore(kmfhandle, numattr, attrlist); if (kmfrv != KMF_OK) { goto cleanup; } } /* Create the RSA keypair */ keytype = KMF_RSA; keylength = ES_DEFAULT_KEYSIZE; (void) memset(&prik, 0, sizeof (prik)); (void) memset(&pubk, 0, sizeof (pubk)); numattr = 0; kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength)); if (pin != NULL) { cred.cred = pin; cred.credlen = strlen(pin); kmf_set_attr_at_index(attrlist, numattr++, KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL)); } kmf_set_attr_at_index(attrlist, numattr++, KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); kmf_set_attr_at_index(attrlist, numattr++, KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); if (kstype == KMF_KEYSTORE_OPENSSL) { kmf_set_attr_at_index(attrlist, numattr++, KMF_KEY_FILENAME_ATTR, cmd_info.privpath, strlen(cmd_info.privpath)); kmf_set_attr_at_index(attrlist, numattr++, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); } kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist); if (kmfrv != KMF_OK) { (void) kmf_get_kmf_error_str(kmfrv, &err); cryptoerror(LOG_STDERR, gettext("Create RSA keypair failed: %s"), (err ? err : "unknown error")); free(err); goto cleanup; } kmfrv = kmf_dn_parser(dn, &csrSubject); if (kmfrv != KMF_OK) { (void) kmf_get_kmf_error_str(kmfrv, &err); cryptoerror(LOG_STDERR, gettext("Error parsing subject name: %s\n"), (err ? err : "unknown error")); free(err); goto cleanup; } SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "keypair"); SET_VALUE(kmf_set_csr_version(&csr, 2), "version number"); SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), "subject name"); SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "SignatureAlgorithm"); if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) == KMF_OK) { kmfrv = kmf_create_csr_file(&signedCsr, KMF_FORMAT_PEM, cmd_info.cert); } cleanup: (void) kmf_free_kmf_key(kmfhandle, &prik); (void) kmf_free_data(&signedCsr); (void) kmf_free_signed_csr(&csr); (void) kmf_finalize(kmfhandle); return (kmfrv); } #define CN_MAX_LENGTH 64 /* Verisign implementation limit */ /* * Generate a certificate request into the file named cmd_info.cert */ /*ARGSUSED*/ static ret_t do_cert_request(char *object) { const char PartnerDNFMT[] = "CN=%s, " "OU=Class B, " "OU=Solaris Cryptographic Framework, " "OU=Partner Object Signing, " "O=Sun Microsystems Inc"; const char SunCDNFMT[] = "CN=%s, " "OU=Class B, " "OU=Solaris Cryptographic Framework, " "OU=Corporate Object Signing, " "O=Sun Microsystems Inc"; const char SunSDNFMT[] = "CN=%s, " "OU=Class B, " "OU=Solaris Signed Execution, " "OU=Corporate Object Signing, " "O=Sun Microsystems Inc"; const char *dnfmt = NULL; char cn[CN_MAX_LENGTH + 1]; char *dn = NULL; size_t dn_len; KMF_RETURN kmfret; cryptodebug("do_cert_request"); /* * Get the DN prefix from the user */ switch (cmd_info.internal_req) { case 'c': dnfmt = SunCDNFMT; (void) fprintf(stdout, gettext( "Enter Sun Microsystems, Inc. Release name.\n" "This will be the prefix of the Certificate DN: ")); break; case 's': dnfmt = SunSDNFMT; (void) fprintf(stdout, gettext( "Enter Sun Microsystems, Inc. Release name.\n" "This will be the prefix of the Certificate DN: ")); break; default: dnfmt = PartnerDNFMT; (void) fprintf(stdout, gettext( "Enter Company Name / Stock Symbol" " or some other globally unique identifier.\n" "This will be the prefix of the Certificate DN: ")); break; } if ((fgets(cn, sizeof (cn), stdin) == NULL) || (cn[0] == '\n')) { es_error(gettext("you must specify a Certificate DN prefix")); return (EXIT_INVALID_ARG); } if (cn[strlen(cn) - 1] == '\n') { cn[strlen(cn) - 1] = '\0'; /* chop trailing \n */ } else { es_error(gettext("You must specify a Certificate DN prefix " "of no more than %d characters"), CN_MAX_LENGTH); return (EXIT_INVALID_ARG); } /* Update DN string */ dn_len = strlen(cn) + strlen(dnfmt); dn = malloc(dn_len + 1); (void) snprintf(dn, dn_len, dnfmt, cn); cryptodebug("Generating Certificate request for DN: %s", dn); kmfret = create_csr(dn); free(dn); if (kmfret == KMF_OK) return (EXIT_OKAY); else return (EXIT_CSR_FAILED); } static void str_print(char *s) { if (s == NULL) return; (void) fprintf(stdout, "%s\n", s); } /*ARGSUSED*/ static ret_t do_list(char *object) { ret_t retval; if (cmd_info.elfcnt > 0) { ELFsign_status_t elfstat; struct filesignatures *fssp = NULL; size_t fs_len; struct ELFsign_sig_info *esip; if ((retval = getelfobj(cmd_info.elfobj[0])) != EXIT_OKAY) return (retval); elfstat = elfsign_signatures(cmd_info.ess, &fssp, &fs_len, ES_GET); if (elfstat == ELFSIGN_SUCCESS) { retval = EXIT_OKAY; if (elfsign_sig_info(fssp, &esip)) { switch (cmd_info.field) { case FLD_FORMAT: str_print(esip->esi_format); break; case FLD_SIGNER: str_print(esip->esi_signer); break; case FLD_TIME: if (esip->esi_time == 0) retval = EXIT_INVALID_ARG; else str_print(time_str( esip->esi_time)); break; default: retval = EXIT_INVALID_ARG; } elfsign_sig_info_free(esip); } free(fssp); } else retval = EXIT_VERIFY_FAILED_UNSIGNED; elfsign_end(cmd_info.ess); } else { ELFCert_t cert; /* * Initialize the ESS record here even though we are not * actually opening any ELF files. */ if (elfsign_begin(NULL, ES_GET, &(cmd_info.ess)) != ELFSIGN_SUCCESS) return (EXIT_MEMORY_ERROR); if (elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, &cert, cmd_info.es_action)) { retval = EXIT_OKAY; switch (cmd_info.field) { case FLD_SUBJECT: str_print(elfcertlib_getdn(cert)); break; case FLD_ISSUER: str_print(elfcertlib_getissuer(cert)); break; default: retval = EXIT_INVALID_ARG; } elfcertlib_releasecert(cmd_info.ess, cert); } else retval = EXIT_BAD_CERT; elfsign_end(cmd_info.ess); } return (retval); } static void es_error(const char *fmt, ...) { char msgbuf[BUFSIZ]; va_list args; va_start(args, fmt); (void) vsnprintf(msgbuf, sizeof (msgbuf), fmt, args); va_end(args); (void) fflush(stdout); cryptoerror(LOG_STDERR, "%s", msgbuf); (void) fflush(stderr); } static char * time_str(time_t t) { static char buf[80]; char *bufp; bufp = buf; if (strftime(buf, sizeof (buf), NULL, localtime(&t)) == 0) bufp = ctime(&t); return (bufp); } static void sig_info_print(struct ELFsign_sig_info *esip) { if (esip == NULL) return; (void) fprintf(stdout, gettext("format: %s.\n"), esip->esi_format); (void) fprintf(stdout, gettext("signer: %s.\n"), esip->esi_signer); if (esip->esi_time == 0) return; (void) fprintf(stdout, gettext("signed on: %s.\n"), time_str(esip->esi_time)); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. # ETCCRYPTOFILES = \ kcf.conf \ pkcs11.conf \ kmf.conf include ../../Makefile.cmd .KEEP_STATE: ROOTETC= $(ROOT)/etc ROOTCRYPTODIR= $(ROOTETC)/crypto IETCCRYPTOFILES= $(ETCCRYPTOFILES:%=$(ROOTCRYPTODIR)/%) $(ROOTCRYPTODIR)/%: % $(INS.file) $(IETCCRYPTOFILES): FILEMODE= 644 install: $(IETCCRYPTOFILES) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # /etc/crypto/kcf.conf # # Do NOT edit this file by hand. An administrator should use cryptoadm(8) # to administer the cryptographic framework. # # This document does not constitute an API. The /etc/crypto/kcf.conf file may # not exist or may have a different content or interpretation in a future # release. The existence of this notice does not imply that any other # documentation that lacks this notice constitutes an API. # # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # /etc/crypto/kmf.conf # # This file contains non-default plugin entries to the Solaris Key Management # Framework (KMF). Do NOT edit this file by hand. An administrator should use # kmfcfg(8) to install or uninstall a non-default plugin. A developer for a # KMF plugin package should provide an input file and use the {i,r}.kmfconf # class action scripts to update this file during the installation and removal # of the package. # # This document does not constitute an API. The /etc/crypto/kmf.conf file # may not exist or may have a different content or interpretation in a future # release. The existence of this notice does not imply that any other # documentation that lacks this notice constitutes an API. # # The format for each entry is: # keystore:modulepath=path[;option=option_str] # # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # /etc/crypto/pkcs11.conf # # Do NOT edit this file by hand. An administrator should use cryptoadm(8) # to administer the cryptographic framework. A developer for a user-level # cryptographic provider package should provide an input file and use the # {i,r}.pkcs11conf class action scripts to update this file during the # installation and removal of the package. # # This document does not constitute an API. The /etc/crypto/pkcs11.conf file # may not exist or may have a different content or interpretation in a future # release. The existence of this notice does not imply that any other # documentation that lacks this notice constitutes an API. # # # Start SUNWcsr metaslot:metaslot_status=enabled;metaslot_auto_key_migrate=enabled;metaslot_token=Sun Software PKCS#11 softtoken;metaslot_slot=Sun Crypto Softtoken /usr/lib/security/$ISA/pkcs11_kernel.so /usr/lib/security/$ISA/pkcs11_softtoken.so /usr/lib/security/$ISA/pkcs11_tpm.so # End SUNWcsr # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Makefile for policy testing code # PROG = kmfcfg OBJS = kmfcfg.o \ list.o \ delete.o \ util.o \ create.o \ modify.o \ export.o \ import.o \ install.o \ uninstall.o include ../../Makefile.cmd KMFDIR = $(SRC)/lib/libkmf SRCS = $(OBJS:%.o=%.c) POFILES = $(OBJS:%.o=%.po) POFILE = $(PROG)_msg.po MSGFILES = $(SRCS:%.c=%.i) CPPFLAGS += -I$(ROOT)/usr/include/libxml2 \ -I$(KMFDIR)/include -I. LDLIBS += -L$(ROOT)/usr/lib -lkmf -lcryptoutil XMLLIB = -lxml2 # Hammerhead: GNU Make fix - prevent .c: suffix rule from building # 'install' executable from install.c (clashes with install: target) .PHONY: install all clean clobber .KEEP_STATE: XMLDIR= $(ROOT)/etc/security DTDDIR= $(ROOT)/usr/share/lib/xml/dtd ROOTDTDS= $(DTDDIR)/kmfpolicy.dtd ROOTXML= $(XMLDIR)/kmfpolicy.xml $(ROOTDTDS) : FILEMODE = 444 $(ROOTXML) : FILEMODE = 644 all: $(PROG) $(ROOTDTDS) $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(XMLLIB) $(POST_PROCESS) $(POFILE): $(POFILES) $(RM) $@; $(CAT) $(POFILES) > $@ install: all $(ROOTDTDS) $(ROOTXML) $(ROOTPROG) $(XMLDIR)/%: % $(INS.file) $(DTDDIR)/%: % $(INS.file) clean: $(RM) $(OBJS) include ../../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include "util.h" int kc_create(int argc, char *argv[]) { KMF_RETURN ret; int rv = KC_OK; int opt; extern int optind_av; extern char *optarg_av; char *filename = NULL; int ocsp_set_attr = 0; boolean_t crl_set_attr = 0; KMF_POLICY_RECORD plc; (void) memset(&plc, 0, sizeof (KMF_POLICY_RECORD)); while ((opt = getopt_av(argc, argv, "i:(dbfile)" "p:(policy)" "d:(ignore-date)" "e:(ignore-unknown-eku)" "a:(ignore-trust-anchor)" "v:(validity-adjusttime)" "t:(ta-name)" "s:(ta-serial)" "o:(ocsp-responder)" "P:(ocsp-proxy)" "r:(ocsp-use-cert-responder)" "T:(ocsp-response-lifetime)" "R:(ocsp-ignore-response-sign)" "n:(ocsp-responder-cert-name)" "A:(ocsp-responder-cert-serial)" "c:(crl-basefilename)" "I:(crl-directory)" "g:(crl-get-crl-uri)" "X:(crl-proxy)" "S:(crl-ignore-crl-sign)" "D:(crl-ignore-crl-date)" "m:(mapper-name)" "M:(mapper-directory)" "Q:(mapper-pathname)" "q:(mapper-options)" "u:(keyusage)" "E:(ekunames)" "O:(ekuoids)")) != EOF) { switch (opt) { case 'i': filename = get_string(optarg_av, &rv); if (filename == NULL) { (void) fprintf(stderr, gettext("Error dbfile input.\n")); } break; case 'p': plc.name = get_string(optarg_av, &rv); if (plc.name == NULL) { (void) fprintf(stderr, gettext("Error policy name.\n")); } break; case 'd': plc.ignore_date = get_boolean(optarg_av); if (plc.ignore_date == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } break; case 'e': plc.ignore_unknown_ekus = get_boolean(optarg_av); if (plc.ignore_unknown_ekus == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } break; case 'a': plc.ignore_trust_anchor = get_boolean(optarg_av); if (plc.ignore_trust_anchor == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } break; case 'v': plc.validity_adjusttime = get_string(optarg_av, &rv); if (plc.validity_adjusttime == NULL) { (void) fprintf(stderr, gettext("Error time input.\n")); } else { uint32_t adj; /* for syntax checking */ if (str2lifetime( plc.validity_adjusttime, &adj) < 0) { (void) fprintf(stderr, gettext("Error time " "input.\n")); rv = KC_ERR_USAGE; } } break; case 't': plc.ta_name = get_string(optarg_av, &rv); if (plc.ta_name == NULL) { (void) fprintf(stderr, gettext("Error name input.\n")); } else if (strcasecmp(plc.ta_name, "search") != 0) { KMF_X509_NAME taDN; /* for syntax checking */ if (kmf_dn_parser(plc.ta_name, &taDN) != KMF_OK) { (void) fprintf(stderr, gettext("Error name " "input.\n")); rv = KC_ERR_USAGE; } else { kmf_free_dn(&taDN); } } break; case 's': plc.ta_serial = get_string(optarg_av, &rv); if (plc.ta_serial == NULL) { (void) fprintf(stderr, gettext("Error serial input.\n")); } else { uchar_t *bytes = NULL; size_t bytelen; ret = kmf_hexstr_to_bytes( (uchar_t *)plc.ta_serial, &bytes, &bytelen); if (ret != KMF_OK || bytes == NULL) { (void) fprintf(stderr, gettext("serial number " "must be specified as a " "hex number " "(ex: 0x0102030405" "ffeeddee)\n")); rv = KC_ERR_USAGE; } if (bytes != NULL) free(bytes); } break; case 'o': plc.VAL_OCSP_RESPONDER_URI = get_string(optarg_av, &rv); if (plc.VAL_OCSP_RESPONDER_URI == NULL) { (void) fprintf(stderr, gettext( "Error responder input.\n")); } else { ocsp_set_attr++; } break; case 'P': plc.VAL_OCSP_PROXY = get_string(optarg_av, &rv); if (plc.VAL_OCSP_PROXY == NULL) { (void) fprintf(stderr, gettext("Error proxy input.\n")); } else { ocsp_set_attr++; } break; case 'r': plc.VAL_OCSP_URI_FROM_CERT = get_boolean(optarg_av); if (plc.VAL_OCSP_URI_FROM_CERT == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { ocsp_set_attr++; } break; case 'T': plc.VAL_OCSP_RESP_LIFETIME = get_string(optarg_av, &rv); if (plc.VAL_OCSP_RESP_LIFETIME == NULL) { (void) fprintf(stderr, gettext("Error time input.\n")); } else { uint32_t adj; /* for syntax checking */ if (str2lifetime( plc.VAL_OCSP_RESP_LIFETIME, &adj) < 0) { (void) fprintf(stderr, gettext("Error time " "input.\n")); rv = KC_ERR_USAGE; } else { ocsp_set_attr++; } } break; case 'R': plc.VAL_OCSP_IGNORE_RESP_SIGN = get_boolean(optarg_av); if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { ocsp_set_attr++; } break; case 'n': plc.VAL_OCSP_RESP_CERT_NAME = get_string(optarg_av, &rv); if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) { (void) fprintf(stderr, gettext("Error name input.\n")); } else { KMF_X509_NAME respDN; /* for syntax checking */ if (kmf_dn_parser( plc.VAL_OCSP_RESP_CERT_NAME, &respDN) != KMF_OK) { (void) fprintf(stderr, gettext("Error name " "input.\n")); rv = KC_ERR_USAGE; } else { kmf_free_dn(&respDN); ocsp_set_attr++; } } break; case 'A': plc.VAL_OCSP_RESP_CERT_SERIAL = get_string(optarg_av, &rv); if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) { (void) fprintf(stderr, gettext("Error serial input.\n")); } else { uchar_t *bytes = NULL; size_t bytelen; ret = kmf_hexstr_to_bytes((uchar_t *) plc.VAL_OCSP_RESP_CERT_SERIAL, &bytes, &bytelen); if (ret != KMF_OK || bytes == NULL) { (void) fprintf(stderr, gettext("serial number " "must be specified as a " "hex number " "(ex: 0x0102030405" "ffeeddee)\n")); rv = KC_ERR_USAGE; break; } if (bytes != NULL) free(bytes); ocsp_set_attr++; } break; case 'c': plc.VAL_CRL_BASEFILENAME = get_string(optarg_av, &rv); if (plc.VAL_CRL_BASEFILENAME == NULL) { (void) fprintf(stderr, gettext("Error boolean input.\n")); } else { crl_set_attr++; } break; case 'I': plc.VAL_CRL_DIRECTORY = get_string(optarg_av, &rv); if (plc.VAL_CRL_DIRECTORY == NULL) { (void) fprintf(stderr, gettext("Error boolean input.\n")); } else { crl_set_attr++; } break; case 'g': plc.VAL_CRL_GET_URI = get_boolean(optarg_av); if (plc.VAL_CRL_GET_URI == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { crl_set_attr++; } break; case 'X': plc.VAL_CRL_PROXY = get_string(optarg_av, &rv); if (plc.VAL_CRL_PROXY == NULL) { (void) fprintf(stderr, gettext("Error proxy input.\n")); } else { crl_set_attr++; } break; case 'S': plc.VAL_CRL_IGNORE_SIGN = get_boolean(optarg_av); if (plc.VAL_CRL_IGNORE_SIGN == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { crl_set_attr++; } break; case 'D': plc.VAL_CRL_IGNORE_DATE = get_boolean(optarg_av); if (plc.VAL_CRL_IGNORE_DATE == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { crl_set_attr++; } break; case 'u': plc.ku_bits = parseKUlist(optarg_av); if (plc.ku_bits == 0) { (void) fprintf(stderr, gettext( "Error keyusage input.\n")); rv = KC_ERR_USAGE; } break; case 'E': if (parseEKUNames(optarg_av, &plc) != 0) { (void) fprintf(stderr, gettext("Error EKU input.\n")); rv = KC_ERR_USAGE; } break; case 'O': if (parseEKUOIDs(optarg_av, &plc) != 0) { (void) fprintf(stderr, gettext("Error EKU OID input.\n")); rv = KC_ERR_USAGE; } break; case 'm': plc.mapper.mapname = get_string(optarg_av, &rv); if (plc.mapper.mapname == NULL) { (void) fprintf(stderr, gettext("Error mapper-name " "input.\n")); } break; case 'M': plc.mapper.dir = get_string(optarg_av, &rv); if (plc.mapper.dir == NULL) { (void) fprintf(stderr, gettext("Error mapper-dir " "input.\n")); } break; case 'Q': plc.mapper.pathname = get_string(optarg_av, &rv); if (plc.mapper.pathname == NULL) { (void) fprintf(stderr, gettext("Error mapper-pathname " "input.\n")); } break; case 'q': plc.mapper.options = get_string(optarg_av, &rv); if (plc.mapper.options == NULL) { (void) fprintf(stderr, gettext("Error mapper-options " "input.\n")); } break; default: (void) fprintf(stderr, gettext("Error input option.\n")); rv = KC_ERR_USAGE; break; } if (rv != KC_OK) goto out; } /* No additional args allowed. */ argc -= optind_av; if (argc) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (filename == NULL) { filename = strdup(KMF_DEFAULT_POLICY_FILE); if (filename == NULL) { rv = KC_ERR_MEMORY; goto out; } } /* * Must have a policy name. The policy name can not be default * if using the default policy file. */ if (plc.name == NULL) { (void) fprintf(stderr, gettext("You must specify a policy name\n")); rv = KC_ERR_USAGE; goto out; } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 && strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) { (void) fprintf(stderr, gettext("Can not create a default policy in the default " "policy file\n")); rv = KC_ERR_USAGE; goto out; } /* * If the policy file exists and the policy is in the policy file * already, we will not create it again. */ if (access(filename, R_OK) == 0) { POLICY_LIST *plclist = NULL, *pnode; int found = 0; rv = load_policies(filename, &plclist); if (rv != KMF_OK) goto out; pnode = plclist; while (pnode != NULL && !found) { if (strcmp(plc.name, pnode->plc.name) == 0) found++; pnode = pnode->next; } free_policy_list(plclist); if (found) { (void) fprintf(stderr, gettext("Could not create policy \"%s\" - exists " "already\n"), plc.name); rv = KC_ERR_USAGE; goto out; } } /* * If any OCSP attribute is set, turn on the OCSP checking flag. * Also set "has_resp_cert" to be true, if the responder cert * is provided. */ if (ocsp_set_attr > 0) plc.revocation |= KMF_REVOCATION_METHOD_OCSP; if (plc.VAL_OCSP_RESP_CERT.name != NULL && plc.VAL_OCSP_RESP_CERT.serial != NULL) { plc.VAL_OCSP.has_resp_cert = B_TRUE; } /* * Setting mapper-name (with optional mapper-dir) and mapper-pathname is * mutually exclusive. Also, you cannot set options only, you need the * name or pathname, and you can set the directory only with the name, * not the pathname. */ if ((plc.mapper.mapname != NULL && plc.mapper.pathname != NULL) || (plc.mapper.dir != NULL && plc.mapper.pathname != NULL) || (plc.mapper.dir != NULL && plc.mapper.mapname == NULL) || (plc.mapper.options != NULL && plc.mapper.mapname == NULL && plc.mapper.pathname == NULL)) { (void) fprintf(stderr, gettext("Error in mapper input options\n")); rv = KC_ERR_USAGE; goto out; } /* * If any CRL attribute is set, turn on the CRL checking flag. */ if (crl_set_attr > 0) plc.revocation |= KMF_REVOCATION_METHOD_CRL; /* * Does a sanity check on the new policy. */ ret = kmf_verify_policy(&plc); if (ret != KMF_OK) { print_sanity_error(ret); rv = KC_ERR_ADD_POLICY; goto out; } /* * Add to the DB. */ ret = kmf_add_policy_to_db(&plc, filename, B_FALSE); if (ret != KMF_OK) { (void) fprintf(stderr, gettext("Error adding policy to database: 0x%04x\n"), ret); rv = KC_ERR_ADD_POLICY; } out: if (filename != NULL) free(filename); kmf_free_policy_record(&plc); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include "util.h" int kc_delete(int argc, char *argv[]) { int rv = KC_OK; KMF_RETURN kmfrv = KMF_OK; int opt; extern int optind_av; extern char *optarg_av; char *filename = NULL; char *policyname = NULL; while ((opt = getopt_av(argc, argv, "i:(dbfile)p:(policy)")) != EOF) { switch (opt) { case 'i': filename = get_string(optarg_av, &rv); if (filename == NULL) { (void) fprintf(stderr, gettext("Error dbfile input.\n")); } break; case 'p': policyname = get_string(optarg_av, &rv); if (policyname == NULL) { (void) fprintf(stderr, gettext("Error policy name.\n")); } break; default: (void) fprintf(stderr, gettext("Error input option.\n")); rv = KC_ERR_USAGE; break; } if (rv != KC_OK) goto out; } /* No additional args allowed. */ argc -= optind_av; if (argc) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (filename == NULL) { filename = strdup(KMF_DEFAULT_POLICY_FILE); if (filename == NULL) { rv = KC_ERR_MEMORY; goto out; } } /* * Must have a policy name. The policy name can not be default * if using the default policy file. */ if (policyname == NULL) { (void) fprintf(stderr, gettext("You must specify a policy name\n")); rv = KC_ERR_USAGE; goto out; } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 && strcmp(policyname, KMF_DEFAULT_POLICY_NAME) == 0) { (void) fprintf(stderr, gettext("Can not delete the default policy in the default " "policy file\n")); rv = KC_ERR_USAGE; goto out; } /* Check the access permission of the policy DB */ if (access(filename, W_OK) < 0) { int err = errno; (void) fprintf(stderr, gettext("Cannot access \"%s\" for delete - %s\n"), filename, strerror(err)); rv = KC_ERR_ACCESS; goto out; } kmfrv = kmf_delete_policy_from_db(policyname, filename); if (kmfrv != KMF_OK) rv = KC_ERR_DELETE_POLICY; out: if (filename != NULL) free(filename); if (policyname != NULL) free(policyname); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include "util.h" int kc_export(int argc, char *argv[]) { int rv = KC_OK; char *filename = NULL; char *outfile = NULL; char *policyname = NULL; POLICY_LIST *plclist = NULL, *pnode; int opt, found = 0; extern int optind_av; extern char *optarg_av; while ((opt = getopt_av(argc, argv, "d:(dbfile)p:(policy)o:(outfile)")) != EOF) { switch (opt) { case 'd': filename = get_string(optarg_av, &rv); if (filename == NULL) { (void) fprintf(stderr, gettext("Error dbfile input.\n")); } break; case 'p': policyname = get_string(optarg_av, &rv); if (policyname == NULL) { (void) fprintf(stderr, gettext("Error policy name.\n")); } break; case 'o': outfile = get_string(optarg_av, &rv); if (outfile == NULL) { (void) fprintf(stderr, gettext("Error outfile input.\n")); } break; default: (void) fprintf(stderr, gettext("Error input option.\n")); rv = KC_ERR_USAGE; break; } if (rv != KC_OK) goto out; } /* No additional args allowed. */ argc -= optind_av; if (argc) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (filename == NULL) { filename = strdup(KMF_DEFAULT_POLICY_FILE); if (filename == NULL) { rv = KC_ERR_MEMORY; goto out; } } if (policyname == NULL) { (void) fprintf(stderr, gettext("You must specify a policy name\n")); rv = KC_ERR_USAGE; goto out; } if (outfile == NULL) { (void) fprintf(stderr, gettext("You must specify a output DB file\n")); rv = KC_ERR_USAGE; goto out; } if (strcmp(outfile, KMF_DEFAULT_POLICY_FILE) == 0 && strcmp(policyname, KMF_DEFAULT_POLICY_NAME) == 0) { (void) fprintf(stderr, gettext("Can not export the default policy record to " "the system default policy database\n")); rv = KC_ERR_USAGE; goto out; } rv = load_policies(filename, &plclist); if (rv != KMF_OK) goto out; pnode = plclist; while (pnode != NULL && !found) { if (strcmp(policyname, pnode->plc.name) == 0) { KMF_RETURN ret; found++; ret = kmf_verify_policy(&pnode->plc); if (ret != KMF_OK) { print_sanity_error(ret); rv = KC_ERR_VERIFY_POLICY; break; } rv = kmf_add_policy_to_db(&pnode->plc, outfile, B_FALSE); } pnode = pnode->next; } if (!found) { (void) fprintf(stderr, gettext("Could not find policy \"%s\" in %s\n"), policyname, filename); rv = KC_ERR_FIND_POLICY; } out: if (filename != NULL) free(filename); if (policyname != NULL) free(policyname); if (outfile != NULL) free(outfile); free_policy_list(plclist); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include "util.h" int kc_import(int argc, char *argv[]) { int rv = KC_OK; char *filename = NULL; char *infile = NULL; char *policyname = NULL; POLICY_LIST *plclist = NULL, *pnode; int opt, found = 0; extern int optind_av; extern char *optarg_av; while ((opt = getopt_av(argc, argv, "d:(dbfile)p:(policy)i:(infile)")) != EOF) { switch (opt) { case 'd': filename = get_string(optarg_av, &rv); if (filename == NULL) { (void) fprintf(stderr, gettext("Error dbfile input.\n")); } break; case 'p': policyname = get_string(optarg_av, &rv); if (policyname == NULL) { (void) fprintf(stderr, gettext("Error policy name.\n")); } break; case 'i': infile = get_string(optarg_av, &rv); if (infile == NULL) { (void) fprintf(stderr, gettext("Error infile input.\n")); } break; default: (void) fprintf(stderr, gettext("Error input option.\n")); rv = KC_ERR_USAGE; break; } if (rv != KC_OK) goto out; } /* No additional args allowed. */ argc -= optind_av; if (argc) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (filename == NULL) { filename = strdup(KMF_DEFAULT_POLICY_FILE); if (filename == NULL) { rv = KC_ERR_MEMORY; goto out; } } if (policyname == NULL) { (void) fprintf(stderr, gettext("You must specify a policy name\n")); rv = KC_ERR_USAGE; goto out; } if (infile == NULL) { (void) fprintf(stderr, gettext("You must specify a input DB file\n")); rv = KC_ERR_USAGE; goto out; } if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 && strcmp(policyname, KMF_DEFAULT_POLICY_NAME) == 0) { (void) fprintf(stderr, gettext("Can not import the default policy record to " "the system default policy database\n")); rv = KC_ERR_USAGE; goto out; } rv = load_policies(infile, &plclist); if (rv != KMF_OK) goto out; pnode = plclist; while (pnode != NULL && !found) { if (strcmp(policyname, pnode->plc.name) == 0) { KMF_RETURN ret; found++; ret = kmf_verify_policy(&pnode->plc); if (ret != KMF_OK) { print_sanity_error(ret); rv = KC_ERR_VERIFY_POLICY; break; } rv = kmf_add_policy_to_db(&pnode->plc, filename, B_FALSE); } pnode = pnode->next; } if (!found) { (void) fprintf(stderr, gettext("Could not find policy \"%s\" in %s\n"), policyname, infile); rv = KC_ERR_FIND_POLICY; } out: if (filename != NULL) free(filename); if (policyname != NULL) free(policyname); if (infile != NULL) free(infile); free_policy_list(plclist); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include "util.h" static int err; /* To store errno which may be overwritten by gettext() */ int kc_install(int argc, char *argv[]) { int rv = KC_OK; int opt; extern int optind_av; extern char *optarg_av; char *keystore_name = NULL; char *modulepath = NULL; char *option_str = NULL; conf_entry_t *entry = NULL; char realpath[MAXPATHLEN]; struct stat statbuf; FILE *pfile = NULL; FILE *pfile_tmp = NULL; char tmpfile_name[MAXPATHLEN]; int found_count = 0; char buffer[BUFSIZ]; char *ptr; boolean_t found; while ((opt = getopt_av(argc, argv, "k:(keystore)m:(modulepath)" "o:(option)")) != EOF) { switch (opt) { case 'k': if (keystore_name != NULL) rv = KC_ERR_USAGE; else { keystore_name = get_string(optarg_av, &rv); if (keystore_name == NULL) { (void) fprintf(stderr, gettext( "Error keystore input.\n")); } } break; case 'm': if (modulepath != NULL) rv = KC_ERR_USAGE; else { modulepath = get_string(optarg_av, &rv); if (modulepath == NULL) { (void) fprintf(stderr, gettext("Error modulepath.\n")); } } break; case 'o': if (option_str != NULL) { rv = KC_ERR_USAGE; } else { option_str = get_string(optarg_av, &rv); if (option_str == NULL) { (void) fprintf(stderr, gettext("Error option input.\n")); } } break; default: (void) fprintf(stderr, gettext("Error input option.\n")); rv = KC_ERR_USAGE; break; } if (rv != KC_OK) goto out; } /* No additional args allowed. */ argc -= optind_av; if (argc) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (keystore_name == NULL || modulepath == NULL) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (strcasecmp(keystore_name, "nss") == 0 || strcasecmp(keystore_name, "pkcs11") == 0 || strcasecmp(keystore_name, "file") == 0) { (void) fprintf(stderr, gettext("Can not use the built-in keystore name %s\n"), keystore_name); rv = KC_ERR_USAGE; goto out; } entry = get_keystore_entry(keystore_name); if (entry != NULL) { (void) fprintf(stderr, gettext("%s exists already.\n"), keystore_name); rv = KC_ERR_USAGE; goto out; } /* * Find the absolute path of the module and check if it exists in * the system. If $ISA is in the path, will check the 32bit version * only. */ if (strncmp(modulepath, "/", 1) != 0) { /* * Only contain the base name; prepand it with * KMF_PLUGIN_PATH */ (void) snprintf(realpath, MAXPATHLEN, "%s%s", KMF_PLUGIN_PATH, modulepath); } else { char *buf = modulepath; char *isa; if ((isa = strstr(buf, PKCS11_ISA)) != NULL) { (void) strncpy(realpath, buf, isa - buf); isa += strlen(PKCS11_ISA) - 1; (void) strlcat(realpath, isa, MAXPATHLEN); } else { (void) strlcpy(realpath, modulepath, MAXPATHLEN); } } if (stat(realpath, &statbuf) != 0) { (void) fprintf(stderr, gettext("%s not found.\n"), realpath); rv = KC_ERR_ACCESS; goto out; } if ((pfile = fopen(_PATH_KMF_CONF, "r+")) == NULL) { err = errno; (void) fprintf(stderr, gettext("failed to update the configuration - %s\n"), strerror(err)); rv = KC_ERR_ACCESS; goto out; } if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; (void) fprintf(stderr, gettext("failed to lock the configuration - %s\n"), strerror(err)); rv = KC_ERR_INSTALL; goto out; } /* * Create a temporary file in the /etc/crypto directory. */ (void) strlcpy(tmpfile_name, CONF_TEMPFILE, sizeof (tmpfile_name)); if (mkstemp(tmpfile_name) == -1) { err = errno; (void) fprintf(stderr, gettext("failed to create a temporary file - %s\n"), strerror(err)); rv = KC_ERR_INSTALL; goto out; } if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { err = errno; (void) fprintf(stderr, gettext("failed to open %s - %s\n"), tmpfile_name, strerror(err)); rv = KC_ERR_INSTALL; goto out; } /* * Loop thru the config file. If the file was reserved within a * package bracket, just uncomment it. Other wise, append it at * the end. The resulting file will be saved in the temp file first. */ while (fgets(buffer, BUFSIZ, pfile) != NULL) { found = B_FALSE; if (buffer[0] == '#') { ptr = buffer; ptr++; while (*ptr == '#' || *ptr == ' ') ptr++; if (strncmp(keystore_name, ptr, strlen(keystore_name)) == 0) { found = B_TRUE; found_count++; } } if (found == B_FALSE) { if (fputs(buffer, pfile_tmp) == EOF) { rv = KC_ERR_INSTALL; goto out; } } else { if (found_count == 1) { if (fputs(ptr, pfile_tmp) == EOF) { rv = KC_ERR_INSTALL; goto out; } } else { /* * Found a second entry with #keystore_name. * This should not happen. The kmf.conf file * is corrupted. Give a warning and skip * this entry. */ (void) fprintf(stderr, gettext( "(Warning) Found an additional reserved " "entry for %s.\n"), keystore_name); } } } if (found_count == 0) { char buf[MAXPATHLEN]; /* * This entry was not in package before, append it to the * end of the temp file. */ if (option_str == NULL) (void) snprintf(buf, MAXPATHLEN, "%s:%s%s\n", keystore_name, CONF_MODULEPATH, modulepath); else (void) snprintf(buf, MAXPATHLEN, "%s:%s%s;%s%s\n", keystore_name, CONF_MODULEPATH, modulepath, CONF_OPTION, option_str); if (fputs(buf, pfile_tmp) == EOF) { err = errno; (void) fprintf(stderr, gettext( "failed to write to %s: %s\n"), tmpfile_name, strerror(err)); rv = KC_ERR_INSTALL; goto out; } } out: if (pfile != NULL) (void) fclose(pfile); if (rv != KC_OK && pfile_tmp != NULL) (void) unlink(tmpfile_name); if (pfile_tmp != NULL) (void) fclose(pfile_tmp); if (rv == KC_OK) { if (rename(tmpfile_name, _PATH_KMF_CONF) == -1) { err = errno; (void) fprintf(stderr, gettext( "failed to update the configuration - %s"), strerror(err)); return (KC_ERR_INSTALL); } if (chmod(_PATH_KMF_CONF, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { err = errno; (void) fprintf(stderr, gettext( "failed to update the configuration - %s\n"), strerror(err)); return (KC_ERR_INSTALL); } } return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include #include #include #include "util.h" /* * The verbcmd construct allows genericizing information about a verb so * that it is easier to manipulate. Makes parsing code easier to read, * fix, and extend with new verbs. */ typedef struct verbcmd_s { char *verb; int (*action)(int, char *[]); char *synopsis; } verbcmd; int kc_list(int argc, char *argv[]); int kc_delete(int argc, char *argv[]); int kc_create(int argc, char *argv[]); int kc_modify(int argc, char *argv[]); int kc_export(int argc, char *argv[]); int kc_import(int argc, char *argv[]); int kc_install(int argc, char *argv[]); int kc_uninstall(int argc, char *argv[]); static int kc_help(); static verbcmd cmds[] = { { "list", kc_list, "list [dbfile=dbfile] [policy=policyname]\n" "\tlist plugin" }, { "delete", kc_delete, "delete [dbfile=dbfile] " "policy=policyname" }, { "create", kc_create, "create [dbfile=dbfile] policy=policyname\n" "\t\t[ignore-date=true|false]\n" "\t\t[ignore-unknown-eku=true|false]\n" "\t\t[ignore-trust-anchor=true|false]\n" "\t\t[validity-adjusttime=adjusttime]\n" "\t\t[ta-name=trust anchor subject DN]\n" "\t\t[ta-serial=trust anchor serial number]\n" "\t\t[ocsp-responder=URL]\n" "\t\t[ocsp-proxy=URL]\n" "\t\t[ocsp-use-cert-responder=true|false]\n" "\t\t[ocsp-response-lifetime=timelimit]\n" "\t\t[ocsp-ignore-response-sign=true|false]\n" "\t\t[ocsp-responder-cert-name=Issuer DN]\n" "\t\t[ocsp-responder-cert-serial=serial number]\n" "\t\t[crl-basefilename=basefilename]\n" "\t\t[crl-directory=directory]\n" "\t\t[crl-get-crl-uri=true|false]\n" "\t\t[crl-proxy=URL]\n" "\t\t[crl-ignore-crl-sign=true|false]\n" "\t\t[crl-ignore-crl-date=true|false]\n" "\t\t[keyusage=digitalSignature|nonRepudiation\n\t" "\t\t|keyEncipherment | dataEncipherment |\n\t" "\t\tkeyAgreement |keyCertSign |\n\t" "\t\tcRLSign | encipherOnly | decipherOnly],[...]\n" "\t\t[ekunames=serverAuth | clientAuth |\n\t" "\t\tcodeSigning | emailProtection |\n\t" "\t\tipsecEndSystem | ipsecTunnel |\n\t" "\t\tipsecUser | timeStamping |\n\t" "\t\tOCSPSigning],[...]\n" "\t\t[ekuoids=OID,OID,OID...]\n" "\t\t[mapper-name=name of mapper library]\n" "\t\t[mapper-directory=dir where mapper library resides]\n" "\t\t[mapper-path=full pathname of mapper library]\n" "\t\t[mapper-options=mapper options]\n"}, { "modify", kc_modify, "modify [dbfile=dbfile] policy=policyname\n" "\t\t[ignore-date=true|false]\n" "\t\t[ignore-unknown-eku=true|false]\n" "\t\t[ignore-trust-anchor=true|false]\n" "\t\t[validity-adjusttime=adjusttime]\n" "\t\t[ta-name=trust anchor subject DN | search]\n" "\t\t[ta-serial=trust anchor serial number]\n" "\t\t[ocsp-responder=URL]\n" "\t\t[ocsp-proxy=URL]\n" "\t\t[ocsp-use-cert-responder=true|false]\n" "\t\t[ocsp-response-lifetime=timelimit]\n" "\t\t[ocsp-ignore-response-sign=true|false]\n" "\t\t[ocsp-responder-cert-name=Issuer DN]\n" "\t\t[ocsp-responder-cert-serial=serial number]\n" "\t\t[ocsp-none=true|false]\n" "\t\t[crl-basefilename=basefilename]\n" "\t\t[crl-directory=directory]\n" "\t\t[crl-get-crl-uri=true|false]\n" "\t\t[crl-proxy=URL]\n" "\t\t[crl-ignore-crl-sign=true|false]\n" "\t\t[crl-ignore-crl-date=true|false]\n" "\t\t[crl-none=true|false]\n" "\t\t[keyusage=digitalSignature|nonRepudiation\n\t" "\t\t|keyEncipherment | dataEncipherment |\n\t" "\t\tkeyAgreement |keyCertSign |\n\t" "\t\tcRLSign | encipherOnly | decipherOnly],[...]\n" "\t\t[keyusage-none=true|false]\n" "\t\t[ekunames=serverAuth | clientAuth |\n\t" "\t\tcodeSigning | emailProtection |\n\t" "\t\tipsecEndSystem | ipsecTunnel |\n\t" "\t\tipsecUser | timeStamping |\n\t" "\t\tOCSPSigning],[...]\n" "\t\t[ekuoids=OID,OID,OID...]\n" "\t\t[eku-none=true|false]\n\n" "\t\t[mapper-name=name of mapper library]\n" "\t\t[mapper-directory=dir where mapper library resides]\n" "\t\t[mapper-path=full pathname of mapper library]\n" "\t\t[mapper-options=mapper options]\n" "\tmodify plugin keystore=keystorename option=optionstring\n"}, { "import", kc_import, "import [dbfile=dbfile] policy=policyname " "infile=inputdbfile\n" }, { "export", kc_export, "export [dbfile=dbfile] policy=policyname " "outfile=newdbfile\n" }, { "install", kc_install, "install keystore=keystorename " "modulepath=path [option=optionstring]\n"}, { "uninstall", kc_uninstall, "uninstall keystore=keystorename\n"}, { "-?", kc_help, "help"}, { "help", kc_help, ""} }; static int num_cmds = sizeof (cmds) / sizeof (verbcmd); static char *prog; static void usage(void) { int i; /* Display this block only in command-line mode. */ (void) fprintf(stdout, gettext("Usage:\n")); (void) fprintf(stdout, gettext("\t%s -?\t(help and usage)\n"), prog); (void) fprintf(stdout, gettext("\t%s subcommand [options...]\n"), prog); (void) fprintf(stdout, gettext("where subcommands may be:\n")); /* Display only those verbs that match the current tool mode. */ for (i = 0; i < num_cmds; i++) { /* Do NOT i18n/l10n. */ (void) fprintf(stdout, "\t%s\n", cmds[i].synopsis); } } static int kc_help() { usage(); return (0); } int main(int argc, char *argv[]) { int ret; int found; int i; (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); prog = basename(argv[0]); argv++; argc--; if (argc == 0) { usage(); exit(1); } if (argc == 1 && argv[0][0] == '-') { switch (argv[0][1]) { case '?': return (kc_help()); default: usage(); exit(1); } } found = -1; for (i = 0; i < num_cmds; i++) { if (strcmp(cmds[i].verb, argv[0]) == 0) { found = i; break; } } if (found < 0) { (void) fprintf(stderr, gettext("Invalid command: %s\n"), argv[0]); exit(1); } /* * Note the action functions can return values from * the key management framework, and those values can conflict * with the utility error codes. */ ret = (*cmds[found].action)(argc, argv); switch (ret) { case KC_OK: break; case KC_ERR_USAGE: break; case KC_ERR_LOADDB: (void) fprintf(stderr, gettext("Error loading database\n")); break; case KC_ERR_FIND_POLICY: break; case KC_ERR_DELETE_POLICY: (void) fprintf(stderr, gettext("Error deleting policy " "from database.\n")); break; case KC_ERR_ADD_POLICY: break; case KC_ERR_VERIFY_POLICY: break; case KC_ERR_INCOMPLETE_POLICY: break; case KC_ERR_MEMORY: (void) fprintf(stderr, gettext("Out of memory.\n")); break; case KC_ERR_ACCESS: break; case KC_ERR_INSTALL: break; case KC_ERR_UNINSTALL: break; default: (void) fprintf(stderr, gettext("%s operation failed. " "error 0x%02x\n"), cmds[found].verb, ret); break; } return (ret); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include "util.h" #define LIB_NSS_PATH "/usr/lib/mps/libnss3.so" #define LIB_NSPR_PATH "/usr/lib/mps/libnspr4.so" static void show_policy(KMF_POLICY_RECORD *plc) { int i; if (plc == NULL) return; (void) printf("Name: %s\n", plc->name); (void) printf(gettext("Ignore Date: %s\n"), plc->ignore_date ? gettext("true") : gettext("false")); (void) printf(gettext("Ignore Unknown EKUs: %s\n"), plc->ignore_unknown_ekus ? gettext("true") : gettext("false")); (void) printf(gettext("Ignore TA: %s\n"), plc->ignore_trust_anchor ? gettext("true") : gettext("false")); (void) printf(gettext("Validity Adjusted Time: %s\n"), plc->validity_adjusttime ? plc->validity_adjusttime : ""); if (plc->ta_name == NULL && plc->ta_serial == NULL) { (void) printf(gettext("Trust Anchor Certificate: \n")); } else if (strcasecmp(plc->ta_name, "search") == 0) { (void) printf(gettext("Trust Anchor Certificate: " "Search by Issuer\n")); } else { (void) printf(gettext("Trust Anchor Certificate:\n")); (void) printf(gettext("\tName: %s\n"), plc->ta_name ? plc->ta_name : ""); (void) printf(gettext("\tSerial Number: %s\n"), plc->ta_serial ? plc->ta_serial : ""); } if (plc->ku_bits != 0) { (void) printf(gettext("Key Usage Bits: ")); for (i = KULOWBIT; i <= KUHIGHBIT; i++) { char *s = kmf_ku_to_string( (plc->ku_bits & (1<eku_set.eku_count > 0) { (void) printf(gettext("Extended Key Usage Values:\n")); for (i = 0; i < plc->eku_set.eku_count; i++) { char *s = kmf_oid_to_ekuname( &plc->eku_set.ekulist[i]); (void) printf("\t%s\t(%s)\n", kmf_oid_to_string(&plc->eku_set.ekulist[i]), s ? s : "unknown"); } } else { (void) printf(gettext("Extended Key Usage Values: \n")); } (void) printf(gettext("Validation Policy Information:\n")); if (plc->revocation & KMF_REVOCATION_METHOD_OCSP) { (void) printf(gettext(" OCSP:\n")); (void) printf(gettext("\tResponder URI: %s\n"), plc->VAL_OCSP_BASIC.responderURI ? plc->VAL_OCSP_BASIC.responderURI : ""); (void) printf(gettext("\tProxy: %s\n"), plc->VAL_OCSP_BASIC.proxy ? plc->VAL_OCSP_BASIC.proxy : ""); (void) printf(gettext("\tUse ResponderURI from Certificate: " "%s\n"), plc->VAL_OCSP_BASIC.uri_from_cert ? gettext("true") : gettext("false")); (void) printf(gettext("\tResponse lifetime: %s\n"), plc->VAL_OCSP_BASIC.response_lifetime ? plc->VAL_OCSP_BASIC.response_lifetime : ""); (void) printf(gettext("\tIgnore Response signature: %s\n"), plc->VAL_OCSP_BASIC.ignore_response_sign ? gettext("true") : gettext("false")); if (!plc->VAL_OCSP.has_resp_cert) { (void) printf(gettext("\tResponder Certificate:" " \n")); } else { (void) printf(gettext("\tResponder Certificate:\n")); (void) printf(gettext("\t\tName: %s\n"), plc->VAL_OCSP_RESP_CERT.name ? plc->VAL_OCSP_RESP_CERT.name : ""); (void) printf(gettext("\t\tSerial: %s\n"), plc->VAL_OCSP_RESP_CERT.serial ? plc->VAL_OCSP_RESP_CERT.serial : ""); } } if (plc->revocation & KMF_REVOCATION_METHOD_CRL) { (void) printf(gettext(" CRL:\n")); (void) printf(gettext("\tBase filename: %s\n"), plc->validation_info.crl_info.basefilename ? plc->validation_info.crl_info.basefilename : ""); (void) printf(gettext("\tDirectory: %s\n"), plc->validation_info.crl_info.directory ? plc->validation_info.crl_info.directory : ""); (void) printf(gettext("\tDownload and cache CRL: %s\n"), plc->validation_info.crl_info.get_crl_uri ? gettext("true") : gettext("false")); (void) printf(gettext("\tProxy: %s\n"), plc->validation_info.crl_info.proxy ? plc->validation_info.crl_info.proxy : ""); (void) printf(gettext("\tIgnore CRL signature: %s\n"), plc->validation_info.crl_info.ignore_crl_sign ? gettext("true") : gettext("false")); (void) printf(gettext("\tIgnore CRL validity date: %s\n"), plc->validation_info.crl_info.ignore_crl_date ? gettext("true") : gettext("false")); } (void) printf(gettext("Mapper name: %s\n"), plc->mapper.mapname ? plc->mapper.mapname : ""); (void) printf(gettext("Mapper pathname: %s\n"), plc->mapper.pathname ? plc->mapper.pathname : ""); (void) printf(gettext("Mapper directory: %s\n"), plc->mapper.dir ? plc->mapper.dir : ""); (void) printf(gettext("Mapper options: %s\n"), plc->mapper.options ? plc->mapper.options : ""); (void) printf("\n"); } void show_plugin(void) { conf_entrylist_t *phead = NULL; struct stat statbuf; (void) printf(gettext("KMF plugin information:\n")); (void) printf(gettext("-----------------------\n")); /* List the built-in plugins */ (void) printf("pkcs11:kmf_pkcs11.so.1 (built-in)\n"); (void) printf("file:kmf_openssl.so.1 (built-in)\n"); /* * If the NSS libraries are not installed in the system, * then we will not show the nss plugin either. */ if (stat(LIB_NSS_PATH, &statbuf) == 0 && stat(LIB_NSPR_PATH, &statbuf) == 0) { (void) printf("nss:kmf_nss.so.1 (built-in)\n"); } /* List non-default plugins, if there is any. */ if (get_entrylist(&phead) == KMF_OK) { while (phead != NULL) { (void) printf("%s:%s", phead->entry->keystore, phead->entry->modulepath); if (phead->entry->option == NULL) (void) printf("\n"); else (void) printf(";option=%s\n", phead->entry->option); phead = phead->next; } free_entrylist(phead); } } int kc_list(int argc, char *argv[]) { int rv = KC_OK; int opt, found = 0; extern int optind_av; extern char *optarg_av; char *filename = NULL; char *policyname = NULL; POLICY_LIST *plclist = NULL, *pnode; int sanity_err = 0; boolean_t list_plugin = B_FALSE; while ((opt = getopt_av(argc, argv, "i:(dbfile)p:(policy)m(plugin)")) != EOF) { switch (opt) { case 'i': if (list_plugin) rv = KC_ERR_USAGE; else { filename = get_string(optarg_av, &rv); if (filename == NULL) { (void) fprintf(stderr, gettext("Error dbfile input.\n")); } } break; case 'p': if (list_plugin) rv = KC_ERR_USAGE; else { policyname = get_string(optarg_av, &rv); if (policyname == NULL) { (void) fprintf(stderr, gettext("Error policy name.\n")); } } break; case 'm': list_plugin = B_TRUE; break; default: (void) fprintf(stderr, gettext("Error input option.\n")); rv = KC_ERR_USAGE; break; } if (rv != KC_OK) goto out; } /* No additional args allowed. */ argc -= optind_av; if (argc) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (list_plugin) { show_plugin(); goto out; } if (filename == NULL) { filename = strdup(KMF_DEFAULT_POLICY_FILE); if (filename == NULL) { rv = KC_ERR_MEMORY; goto out; } } /* Check the access permission of the policy DB */ if (access(filename, R_OK) < 0) { int err = errno; (void) fprintf(stderr, gettext("Cannot access \"%s\" for list - %s\n"), filename, strerror(err)); rv = KC_ERR_ACCESS; goto out; } rv = load_policies(filename, &plclist); if (rv != KMF_OK) { goto out; } pnode = plclist; while (pnode != NULL) { if (policyname == NULL || strcmp(policyname, pnode->plc.name) == 0) { KMF_POLICY_RECORD *plc = &pnode->plc; found++; rv = kmf_verify_policy(plc); if (rv != KMF_OK) { (void) fprintf(stderr, gettext( "Policy Name: '%s' is invalid\n"), plc->name); sanity_err++; } else { show_policy(&pnode->plc); } } pnode = pnode->next; } free_policy_list(plclist); if (!found) { if (policyname) (void) fprintf(stderr, gettext( "Cannot find policy '%s'\n"), policyname); else (void) fprintf(stderr, gettext("Cannot find " "any policies to display\n")); rv = KC_ERR_FIND_POLICY; } else if (sanity_err) { rv = KC_ERR_VERIFY_POLICY; } out: if (filename != NULL) free(filename); if (policyname != NULL) free(policyname); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include "util.h" #define KC_IGNORE_DATE 0x0000001 #define KC_IGNORE_UNKNOWN_EKUS 0x0000002 #define KC_IGNORE_TRUST_ANCHOR 0x0000004 #define KC_VALIDITY_ADJUSTTIME 0x0000008 #define KC_TA_NAME 0x0000010 #define KC_TA_SERIAL 0x0000020 #define KC_OCSP_RESPONDER_URI 0x0000040 #define KC_OCSP_PROXY 0x0000080 #define KC_OCSP_URI_FROM_CERT 0x0000100 #define KC_OCSP_RESP_LIFETIME 0x0000200 #define KC_OCSP_IGNORE_RESP_SIGN 0x0000400 #define KC_OCSP_RESP_CERT_NAME 0x0000800 #define KC_OCSP_RESP_CERT_SERIAL 0x0001000 #define KC_OCSP_NONE 0x0002000 #define KC_CRL_BASEFILENAME 0x0004000 #define KC_CRL_DIRECTORY 0x0008000 #define KC_CRL_GET_URI 0x0010000 #define KC_CRL_PROXY 0x0020000 #define KC_CRL_IGNORE_SIGN 0x0040000 #define KC_CRL_IGNORE_DATE 0x0080000 #define KC_CRL_NONE 0x0100000 #define KC_KEYUSAGE 0x0200000 #define KC_KEYUSAGE_NONE 0x0400000 #define KC_EKUS 0x0800000 #define KC_EKUS_NONE 0x1000000 #define KC_MAPPER_OPTIONS 0x2000000 static int err; /* To store errno which may be overwritten by gettext() */ #define UPDATE_IF_DIFFERENT(old, new) \ if ((old != NULL && new != NULL && strcmp(old, new) != 0) || \ (old == NULL && new != NULL)) { \ if (old != NULL) \ free(old); \ old = new; \ } int kc_modify_policy(int argc, char *argv[]) { KMF_RETURN ret; int rv = KC_OK; int opt; extern int optind_av; extern char *optarg_av; char *filename = NULL; char *mapper_name = NULL; char *mapper_dir = NULL; char *mapper_pathname = NULL; uint32_t flags = 0; boolean_t ocsp_none_opt = B_FALSE; boolean_t crl_none_opt = B_FALSE; boolean_t ku_none_opt = B_FALSE; boolean_t eku_none_opt = B_FALSE; int ocsp_set_attr = 0; int crl_set_attr = 0; KMF_POLICY_RECORD oplc, plc; (void) memset(&plc, 0, sizeof (KMF_POLICY_RECORD)); (void) memset(&oplc, 0, sizeof (KMF_POLICY_RECORD)); while ((opt = getopt_av(argc, argv, "i:(dbfile)" "p:(policy)" "d:(ignore-date)" "e:(ignore-unknown-eku)" "a:(ignore-trust-anchor)" "v:(validity-adjusttime)" "t:(ta-name)" "s:(ta-serial)" "o:(ocsp-responder)" "P:(ocsp-proxy)" "r:(ocsp-use-cert-responder)" "T:(ocsp-response-lifetime)" "R:(ocsp-ignore-response-sign)" "n:(ocsp-responder-cert-name)" "A:(ocsp-responder-cert-serial)" "y:(ocsp-none)" "c:(crl-basefilename)" "I:(crl-directory)" "g:(crl-get-crl-uri)" "X:(crl-proxy)" "S:(crl-ignore-crl-sign)" "D:(crl-ignore-crl-date)" "z:(crl-none)" "u:(keyusage)" "Y:(keyusage-none)" "E:(ekunames)" "O:(ekuoids)" "m:(mapper-name)" "M:(mapper-directory)" "Q:(mapper-pathname)" "q:(mapper-options)" "Z:(eku-none)")) != EOF) { switch (opt) { case 'i': filename = get_string(optarg_av, &rv); if (filename == NULL) { (void) fprintf(stderr, gettext("Error dbfile input.\n")); } break; case 'p': plc.name = get_string(optarg_av, &rv); if (plc.name == NULL) { (void) fprintf(stderr, gettext("Error policy name.\n")); } break; case 'd': plc.ignore_date = get_boolean(optarg_av); if (plc.ignore_date == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_IGNORE_DATE; } break; case 'e': plc.ignore_unknown_ekus = get_boolean(optarg_av); if (plc.ignore_unknown_ekus == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_IGNORE_UNKNOWN_EKUS; } break; case 'a': plc.ignore_trust_anchor = get_boolean(optarg_av); if (plc.ignore_trust_anchor == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_IGNORE_TRUST_ANCHOR; } break; case 'v': plc.validity_adjusttime = get_string(optarg_av, &rv); if (plc.validity_adjusttime == NULL) { (void) fprintf(stderr, gettext("Error time input.\n")); } else { uint32_t adj; /* for syntax checking */ if (str2lifetime( plc.validity_adjusttime, &adj) < 0) { (void) fprintf(stderr, gettext("Error time " "input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_VALIDITY_ADJUSTTIME; } } break; case 't': plc.ta_name = get_string(optarg_av, &rv); if (plc.ta_name == NULL) { (void) fprintf(stderr, gettext("Error name input.\n")); } else if (strcasecmp(plc.ta_name, "search")) { KMF_X509_NAME taDN; /* for syntax checking */ if (kmf_dn_parser(plc.ta_name, &taDN) != KMF_OK) { (void) fprintf(stderr, gettext("Error name " "input.\n")); rv = KC_ERR_USAGE; } else { kmf_free_dn(&taDN); flags |= KC_TA_NAME; } } else { flags |= KC_TA_NAME; } break; case 's': plc.ta_serial = get_string(optarg_av, &rv); if (plc.ta_serial == NULL) { (void) fprintf(stderr, gettext("Error serial input.\n")); } else { uchar_t *bytes = NULL; size_t bytelen; ret = kmf_hexstr_to_bytes( (uchar_t *)plc.ta_serial, &bytes, &bytelen); if (ret != KMF_OK || bytes == NULL) { (void) fprintf(stderr, gettext("serial number " "must be specified as a " "hex number " "(ex: 0x0102030405" "ffeeddee)\n")); rv = KC_ERR_USAGE; break; } if (bytes != NULL) free(bytes); flags |= KC_TA_SERIAL; } break; case 'o': plc.VAL_OCSP_RESPONDER_URI = get_string(optarg_av, &rv); if (plc.VAL_OCSP_RESPONDER_URI == NULL) { (void) fprintf(stderr, gettext("Error responder " "input.\n")); } else { flags |= KC_OCSP_RESPONDER_URI; ocsp_set_attr++; } break; case 'P': plc.VAL_OCSP_PROXY = get_string(optarg_av, &rv); if (plc.VAL_OCSP_PROXY == NULL) { (void) fprintf(stderr, gettext("Error proxy input.\n")); } else { flags |= KC_OCSP_PROXY; ocsp_set_attr++; } break; case 'r': plc.VAL_OCSP_URI_FROM_CERT = get_boolean(optarg_av); if (plc.VAL_OCSP_URI_FROM_CERT == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_OCSP_URI_FROM_CERT; ocsp_set_attr++; } break; case 'T': plc.VAL_OCSP_RESP_LIFETIME = get_string(optarg_av, &rv); if (plc.VAL_OCSP_RESP_LIFETIME == NULL) { (void) fprintf(stderr, gettext("Error time input.\n")); } else { uint32_t adj; /* for syntax checking */ if (str2lifetime( plc.VAL_OCSP_RESP_LIFETIME, &adj) < 0) { (void) fprintf(stderr, gettext("Error time " "input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_OCSP_RESP_LIFETIME; ocsp_set_attr++; } } break; case 'R': plc.VAL_OCSP_IGNORE_RESP_SIGN = get_boolean(optarg_av); if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_OCSP_IGNORE_RESP_SIGN; ocsp_set_attr++; } break; case 'n': plc.VAL_OCSP_RESP_CERT_NAME = get_string(optarg_av, &rv); if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) { (void) fprintf(stderr, gettext("Error name input.\n")); } else { KMF_X509_NAME respDN; /* for syntax checking */ if (kmf_dn_parser( plc.VAL_OCSP_RESP_CERT_NAME, &respDN) != KMF_OK) { (void) fprintf(stderr, gettext("Error name " "input.\n")); rv = KC_ERR_USAGE; } else { kmf_free_dn(&respDN); flags |= KC_OCSP_RESP_CERT_NAME; ocsp_set_attr++; } } break; case 'A': plc.VAL_OCSP_RESP_CERT_SERIAL = get_string(optarg_av, &rv); if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) { (void) fprintf(stderr, gettext("Error serial input.\n")); } else { uchar_t *bytes = NULL; size_t bytelen; ret = kmf_hexstr_to_bytes((uchar_t *) plc.VAL_OCSP_RESP_CERT_SERIAL, &bytes, &bytelen); if (ret != KMF_OK || bytes == NULL) { (void) fprintf(stderr, gettext("serial number " "must be specified as a " "hex number " "(ex: 0x0102030405" "ffeeddee)\n")); rv = KC_ERR_USAGE; break; } if (bytes != NULL) free(bytes); flags |= KC_OCSP_RESP_CERT_SERIAL; ocsp_set_attr++; } break; case 'y': ocsp_none_opt = get_boolean(optarg_av); if (ocsp_none_opt == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_OCSP_NONE; } break; case 'c': plc.VAL_CRL_BASEFILENAME = get_string(optarg_av, &rv); if (plc.VAL_CRL_BASEFILENAME == NULL) { (void) fprintf(stderr, gettext( "Error basefilename input.\n")); } else { flags |= KC_CRL_BASEFILENAME; crl_set_attr++; } break; case 'I': plc.VAL_CRL_DIRECTORY = get_string(optarg_av, &rv); if (plc.VAL_CRL_DIRECTORY == NULL) { (void) fprintf(stderr, gettext("Error boolean input.\n")); } else { flags |= KC_CRL_DIRECTORY; crl_set_attr++; } break; case 'g': plc.VAL_CRL_GET_URI = get_boolean(optarg_av); if (plc.VAL_CRL_GET_URI == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_CRL_GET_URI; crl_set_attr++; } break; case 'X': plc.VAL_CRL_PROXY = get_string(optarg_av, &rv); if (plc.VAL_CRL_PROXY == NULL) { (void) fprintf(stderr, gettext("Error proxy input.\n")); } else { flags |= KC_CRL_PROXY; crl_set_attr++; } break; case 'S': plc.VAL_CRL_IGNORE_SIGN = get_boolean(optarg_av); if (plc.VAL_CRL_IGNORE_SIGN == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_CRL_IGNORE_SIGN; crl_set_attr++; } break; case 'D': plc.VAL_CRL_IGNORE_DATE = get_boolean(optarg_av); if (plc.VAL_CRL_IGNORE_DATE == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_CRL_IGNORE_DATE; crl_set_attr++; } break; case 'z': crl_none_opt = get_boolean(optarg_av); if (crl_none_opt == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_CRL_NONE; } break; case 'u': plc.ku_bits = parseKUlist(optarg_av); if (plc.ku_bits == 0) { (void) fprintf(stderr, gettext( "Error keyusage input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_KEYUSAGE; } break; case 'Y': ku_none_opt = get_boolean(optarg_av); if (ku_none_opt == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_KEYUSAGE_NONE; } break; case 'E': if (parseEKUNames(optarg_av, &plc) != 0) { (void) fprintf(stderr, gettext("Error EKU input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_EKUS; } break; case 'O': if (parseEKUOIDs(optarg_av, &plc) != 0) { (void) fprintf(stderr, gettext("Error EKU OID input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_EKUS; } break; case 'Z': eku_none_opt = get_boolean(optarg_av); if (eku_none_opt == -1) { (void) fprintf(stderr, gettext("Error boolean input.\n")); rv = KC_ERR_USAGE; } else { flags |= KC_EKUS_NONE; } break; case 'm': mapper_name = get_string(optarg_av, &rv); if (mapper_name == NULL) { (void) fprintf(stderr, gettext("Error mapper-name " "input.\n")); } break; case 'M': mapper_dir = get_string(optarg_av, &rv); if (mapper_dir == NULL) { (void) fprintf(stderr, gettext("Error mapper-directory " "input.\n")); } break; case 'Q': mapper_pathname = get_string(optarg_av, &rv); if (mapper_pathname == NULL) { (void) fprintf(stderr, gettext("Error mapper-pathname " "input.\n")); } break; case 'q': plc.mapper.options = get_string(optarg_av, &rv); rv = 0; /* its ok for this to be NULL */ flags |= KC_MAPPER_OPTIONS; break; default: (void) fprintf(stderr, gettext("Error input option.\n")); rv = KC_ERR_USAGE; break; } if (rv != KC_OK) goto out; } /* No additional args allowed. */ argc -= optind_av; if (argc) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (filename == NULL) { filename = strdup(KMF_DEFAULT_POLICY_FILE); if (filename == NULL) { rv = KC_ERR_MEMORY; goto out; } } /* * Must have a policy name. The policy name can not be default * if using the default policy file. */ if (plc.name == NULL) { (void) fprintf(stderr, gettext("You must specify a policy name.\n")); rv = KC_ERR_USAGE; goto out; } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 && strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) { (void) fprintf(stderr, gettext("Can not modify the default policy in the default " "policy file.\n")); rv = KC_ERR_USAGE; goto out; } /* Check the access permission of the policy DB */ if (access(filename, W_OK) < 0) { int err = errno; (void) fprintf(stderr, gettext("Cannot access \"%s\" for modify - %s\n"), filename, strerror(err)); rv = KC_ERR_ACCESS; goto out; } /* Try to load the named policy from the DB */ ret = kmf_get_policy(filename, plc.name, &oplc); if (ret != KMF_OK) { (void) fprintf(stderr, gettext("Error loading policy \"%s\" from %s\n"), filename, plc.name); return (KC_ERR_FIND_POLICY); } /* Update the general policy attributes. */ if (flags & KC_IGNORE_DATE) oplc.ignore_date = plc.ignore_date; if (flags & KC_IGNORE_UNKNOWN_EKUS) oplc.ignore_unknown_ekus = plc.ignore_unknown_ekus; if (flags & KC_IGNORE_TRUST_ANCHOR) oplc.ignore_trust_anchor = plc.ignore_trust_anchor; if (flags & KC_VALIDITY_ADJUSTTIME) { if (oplc.validity_adjusttime) free(oplc.validity_adjusttime); oplc.validity_adjusttime = plc.validity_adjusttime; } if (flags & KC_TA_NAME) { if (oplc.ta_name) free(oplc.ta_name); oplc.ta_name = plc.ta_name; } if (flags & KC_TA_SERIAL) { if (oplc.ta_serial) free(oplc.ta_serial); oplc.ta_serial = plc.ta_serial; } /* * There are some combinations of attributes that are not valid. * * First, setting mapper-name (with optional mapper-directory) and * mapper-pathname is mutually exclusive. */ if ((mapper_name != NULL && mapper_pathname != NULL) || (mapper_name != NULL && oplc.mapper.pathname != NULL) || (mapper_pathname != NULL && oplc.mapper.mapname != NULL) || /* Mapper directory can be set only if mapper name is set. */ (mapper_dir != NULL && mapper_pathname != NULL) || (mapper_dir != NULL && mapper_name == NULL && oplc.mapper.mapname == NULL) || (mapper_dir != NULL && oplc.mapper.pathname != NULL) || /* Options can be set only if mapper name or pathname is set. */ ((plc.mapper.options != NULL || oplc.mapper.options != NULL) && (mapper_name == NULL && oplc.mapper.mapname == NULL && mapper_pathname == NULL && oplc.mapper.pathname == NULL))) { (void) fprintf(stderr, gettext("Error in mapper input options\n")); if (mapper_name != NULL) free(mapper_name); if (mapper_pathname != NULL) free(mapper_pathname); if (mapper_dir != NULL) free(mapper_dir); if (flags & KC_MAPPER_OPTIONS && plc.mapper.options != NULL) free(plc.mapper.options); rv = KC_ERR_USAGE; goto out; } else { if (mapper_name != NULL) plc.mapper.mapname = mapper_name; if (mapper_pathname != NULL) plc.mapper.pathname = mapper_pathname; if (mapper_dir != NULL) plc.mapper.dir = mapper_dir; } UPDATE_IF_DIFFERENT(oplc.mapper.mapname, plc.mapper.mapname); UPDATE_IF_DIFFERENT(oplc.mapper.pathname, plc.mapper.pathname); UPDATE_IF_DIFFERENT(oplc.mapper.dir, plc.mapper.dir); if (flags & KC_MAPPER_OPTIONS) { if (oplc.mapper.options != NULL) free(oplc.mapper.options); oplc.mapper.options = plc.mapper.options; } /* Update the OCSP policy */ if (ocsp_none_opt == B_TRUE) { if (ocsp_set_attr > 0) { (void) fprintf(stderr, gettext("Can not set ocsp-none=true and other " "OCSP attributes at the same time.\n")); rv = KC_ERR_USAGE; goto out; } /* * If the original policy does not have OCSP checking, * then we do not need to do anything. If the original * policy has the OCSP checking, then we need to release the * space of OCSP attributes and turn the OCSP checking off. */ if (oplc.revocation & KMF_REVOCATION_METHOD_OCSP) { if (oplc.VAL_OCSP_BASIC.responderURI) { free(oplc.VAL_OCSP_BASIC.responderURI); oplc.VAL_OCSP_BASIC.responderURI = NULL; } if (oplc.VAL_OCSP_BASIC.proxy) { free(oplc.VAL_OCSP_BASIC.proxy); oplc.VAL_OCSP_BASIC.proxy = NULL; } if (oplc.VAL_OCSP_BASIC.response_lifetime) { free(oplc.VAL_OCSP_BASIC.response_lifetime); oplc.VAL_OCSP_BASIC.response_lifetime = NULL; } if (flags & KC_OCSP_RESP_CERT_NAME) { free(oplc.VAL_OCSP_RESP_CERT.name); oplc.VAL_OCSP_RESP_CERT.name = NULL; } if (flags & KC_OCSP_RESP_CERT_SERIAL) { free(oplc.VAL_OCSP_RESP_CERT.serial); oplc.VAL_OCSP_RESP_CERT.serial = NULL; } /* Turn off the OCSP checking */ oplc.revocation &= ~KMF_REVOCATION_METHOD_OCSP; } } else { /* * If the "ocsp-none" option is not set or is set to false, * then we only need to do the modification if there is at * least one OCSP attribute is specified. */ if (ocsp_set_attr > 0) { if (flags & KC_OCSP_RESPONDER_URI) { if (oplc.VAL_OCSP_RESPONDER_URI) free(oplc.VAL_OCSP_RESPONDER_URI); oplc.VAL_OCSP_RESPONDER_URI = plc.VAL_OCSP_RESPONDER_URI; } if (flags & KC_OCSP_PROXY) { if (oplc.VAL_OCSP_PROXY) free(oplc.VAL_OCSP_PROXY); oplc.VAL_OCSP_PROXY = plc.VAL_OCSP_PROXY; } if (flags & KC_OCSP_URI_FROM_CERT) oplc.VAL_OCSP_URI_FROM_CERT = plc.VAL_OCSP_URI_FROM_CERT; if (flags & KC_OCSP_RESP_LIFETIME) { if (oplc.VAL_OCSP_RESP_LIFETIME) free(oplc.VAL_OCSP_RESP_LIFETIME); oplc.VAL_OCSP_RESP_LIFETIME = plc.VAL_OCSP_RESP_LIFETIME; } if (flags & KC_OCSP_IGNORE_RESP_SIGN) oplc.VAL_OCSP_IGNORE_RESP_SIGN = plc.VAL_OCSP_IGNORE_RESP_SIGN; if (flags & KC_OCSP_RESP_CERT_NAME) { if (oplc.VAL_OCSP_RESP_CERT_NAME) free(oplc.VAL_OCSP_RESP_CERT_NAME); oplc.VAL_OCSP_RESP_CERT_NAME = plc.VAL_OCSP_RESP_CERT_NAME; } if (flags & KC_OCSP_RESP_CERT_SERIAL) { if (oplc.VAL_OCSP_RESP_CERT_SERIAL) free(oplc.VAL_OCSP_RESP_CERT_SERIAL); oplc.VAL_OCSP_RESP_CERT_SERIAL = plc.VAL_OCSP_RESP_CERT_SERIAL; } if (oplc.VAL_OCSP_RESP_CERT_NAME != NULL && oplc.VAL_OCSP_RESP_CERT_SERIAL != NULL) oplc.VAL_OCSP.has_resp_cert = B_TRUE; else oplc.VAL_OCSP.has_resp_cert = B_FALSE; /* Turn on the OCSP checking */ oplc.revocation |= KMF_REVOCATION_METHOD_OCSP; } } /* Update the CRL policy */ if (crl_none_opt == B_TRUE) { if (crl_set_attr > 0) { (void) fprintf(stderr, gettext("Can not set crl-none=true and other CRL " "attributes at the same time.\n")); rv = KC_ERR_USAGE; goto out; } /* * If the original policy does not have CRL checking, * then we do not need to do anything. If the original * policy has the CRL checking, then we need to release the * space of CRL attributes and turn the CRL checking off. */ if (oplc.revocation & KMF_REVOCATION_METHOD_CRL) { if (oplc.VAL_CRL_BASEFILENAME) { free(oplc.VAL_CRL_BASEFILENAME); oplc.VAL_CRL_BASEFILENAME = NULL; } if (oplc.VAL_CRL_DIRECTORY) { free(oplc.VAL_CRL_DIRECTORY); oplc.VAL_CRL_DIRECTORY = NULL; } if (oplc.VAL_CRL_PROXY) { free(oplc.VAL_CRL_PROXY); oplc.VAL_CRL_PROXY = NULL; } /* Turn off the CRL checking */ oplc.revocation &= ~KMF_REVOCATION_METHOD_CRL; } } else { /* * If the "ocsp-none" option is not set or is set to false, * then we only need to do the modification if there is at * least one CRL attribute is specified. */ if (crl_set_attr > 0) { if (flags & KC_CRL_BASEFILENAME) { if (oplc.VAL_CRL_BASEFILENAME) free(oplc.VAL_CRL_BASEFILENAME); oplc.VAL_CRL_BASEFILENAME = plc.VAL_CRL_BASEFILENAME; } if (flags & KC_CRL_DIRECTORY) { if (oplc.VAL_CRL_DIRECTORY) free(oplc.VAL_CRL_DIRECTORY); oplc.VAL_CRL_DIRECTORY = plc.VAL_CRL_DIRECTORY; } if (flags & KC_CRL_GET_URI) { oplc.VAL_CRL_GET_URI = plc.VAL_CRL_GET_URI; } if (flags & KC_CRL_PROXY) { if (oplc.VAL_CRL_PROXY) free(oplc.VAL_CRL_PROXY); oplc.VAL_CRL_PROXY = plc.VAL_CRL_PROXY; } if (flags & KC_CRL_IGNORE_SIGN) { oplc.VAL_CRL_IGNORE_SIGN = plc.VAL_CRL_IGNORE_SIGN; } if (flags & KC_CRL_IGNORE_DATE) { oplc.VAL_CRL_IGNORE_DATE = plc.VAL_CRL_IGNORE_DATE; } /* Turn on the CRL checking */ oplc.revocation |= KMF_REVOCATION_METHOD_CRL; } } /* Update the Key Usage */ if (ku_none_opt == B_TRUE) { if (flags & KC_KEYUSAGE) { (void) fprintf(stderr, gettext("Can not set keyusage-none=true and " "modify the keyusage value at the same time.\n")); rv = KC_ERR_USAGE; goto out; } oplc.ku_bits = 0; } else { /* * If the "keyusage-none" option is not set or is set to * false, then we only need to do the modification if * the keyusage value is specified. */ if (flags & KC_KEYUSAGE) oplc.ku_bits = plc.ku_bits; } /* Update the Extended Key Usage */ if (eku_none_opt == B_TRUE) { if (flags & KC_EKUS) { (void) fprintf(stderr, gettext("Can not set eku-none=true and modify " "EKU values at the same time.\n")); rv = KC_ERR_USAGE; goto out; } /* Release current EKU list (if any) */ if (oplc.eku_set.eku_count > 0) { kmf_free_eku_policy(&oplc.eku_set); oplc.eku_set.eku_count = 0; oplc.eku_set.ekulist = NULL; } } else { /* * If the "eku-none" option is not set or is set to false, * then we only need to do the modification if either * "ekuname" or "ekuoids" is specified. */ if (flags & KC_EKUS) { /* Release current EKU list (if any) */ kmf_free_eku_policy(&oplc.eku_set); oplc.eku_set = plc.eku_set; } } /* Do a sanity check on the modified policy */ ret = kmf_verify_policy(&oplc); if (ret != KMF_OK) { print_sanity_error(ret); rv = KC_ERR_VERIFY_POLICY; goto out; } /* The modify operation is a delete followed by an add */ ret = kmf_delete_policy_from_db(oplc.name, filename); if (ret != KMF_OK) { rv = KC_ERR_DELETE_POLICY; goto out; } /* * Now add the modified policy back to the DB. */ ret = kmf_add_policy_to_db(&oplc, filename, B_FALSE); if (ret != KMF_OK) { (void) fprintf(stderr, gettext("Error adding policy to database: 0x%04x\n"), ret); rv = KC_ERR_ADD_POLICY; goto out; } out: if (filename != NULL) free(filename); kmf_free_policy_record(&oplc); return (rv); } static int kc_modify_plugin(int argc, char *argv[]) { int rv = KC_OK; int opt; extern int optind_av; extern char *optarg_av; char *keystore_name = NULL; char *option = NULL; boolean_t modify_plugin = B_FALSE; boolean_t has_option_arg = B_FALSE; conf_entry_t *entry = NULL; FILE *pfile = NULL; FILE *pfile_tmp = NULL; char tmpfile_name[MAXPATHLEN]; char buffer[MAXPATHLEN]; char buffer2[MAXPATHLEN]; while ((opt = getopt_av(argc, argv, "p(plugin)k:(keystore)o:(option)")) != EOF) { switch (opt) { case 'p': if (modify_plugin) { (void) fprintf(stderr, gettext("duplicate plugin input.\n")); rv = KC_ERR_USAGE; } else { modify_plugin = B_TRUE; } break; case 'k': if (keystore_name != NULL) rv = KC_ERR_USAGE; else { keystore_name = get_string(optarg_av, &rv); if (keystore_name == NULL) { (void) fprintf(stderr, gettext( "Error keystore input.\n")); rv = KC_ERR_USAGE; } } break; case 'o': if (has_option_arg) { (void) fprintf(stderr, gettext("duplicate option input.\n")); rv = KC_ERR_USAGE; } else { has_option_arg = B_TRUE; option = get_string(optarg_av, NULL); } break; default: (void) fprintf(stderr, gettext("Error input option.\n")); rv = KC_ERR_USAGE; break; } if (rv != KC_OK) goto out; } /* No additional args allowed. */ argc -= optind_av; if (argc) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (keystore_name == NULL || has_option_arg == B_FALSE) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (strcasecmp(keystore_name, "nss") == 0 || strcasecmp(keystore_name, "pkcs11") == 0 || strcasecmp(keystore_name, "file") == 0) { (void) fprintf(stderr, gettext("Can not modify the built-in keystore %s\n"), keystore_name); rv = KC_ERR_USAGE; goto out; } entry = get_keystore_entry(keystore_name); if (entry == NULL) { (void) fprintf(stderr, gettext("%s does not exist.\n"), keystore_name); rv = KC_ERR_USAGE; goto out; } if ((entry->option == NULL && option == NULL) || (entry->option != NULL && option != NULL && strcmp(entry->option, option) == 0)) { (void) fprintf(stderr, gettext("No change - " "the new option is same as the old option.\n")); rv = KC_OK; goto out; } if ((pfile = fopen(_PATH_KMF_CONF, "r+")) == NULL) { err = errno; (void) fprintf(stderr, gettext("failed to update the configuration - %s\n"), strerror(err)); rv = KC_ERR_ACCESS; goto out; } if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; (void) fprintf(stderr, gettext("failed to lock the configuration - %s\n"), strerror(err)); rv = KC_ERR_MODIFY_PLUGIN; goto out; } /* * Create a temporary file in the /etc/crypto directory. */ (void) strlcpy(tmpfile_name, CONF_TEMPFILE, sizeof (tmpfile_name)); if (mkstemp(tmpfile_name) == -1) { err = errno; (void) fprintf(stderr, gettext("failed to create a temporary file - %s\n"), strerror(err)); rv = KC_ERR_MODIFY_PLUGIN; goto out; } if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { err = errno; (void) fprintf(stderr, gettext("failed to open %s - %s\n"), tmpfile_name, strerror(err)); rv = KC_ERR_MODIFY_PLUGIN; goto out; } /* * Loop thru the config file and update the entry. */ while (fgets(buffer, MAXPATHLEN, pfile) != NULL) { char *name; int len; if (buffer[0] == '#') { if (fputs(buffer, pfile_tmp) == EOF) { rv = KC_ERR_MODIFY_PLUGIN; goto out; } else { continue; } } /* * make a copy of the original buffer to buffer2. Also get * rid of the trailing '\n' from buffer2. */ (void) strlcpy(buffer2, buffer, MAXPATHLEN); len = strlen(buffer2); if (buffer2[len-1] == '\n') { len--; } buffer2[len] = '\0'; if ((name = strtok(buffer2, SEP_COLON)) == NULL) { rv = KC_ERR_UNINSTALL; goto out; } if (strcmp(name, keystore_name) == 0) { /* found the entry */ if (option == NULL) (void) snprintf(buffer, MAXPATHLEN, "%s:%s%s\n", keystore_name, CONF_MODULEPATH, entry->modulepath); else (void) snprintf(buffer, MAXPATHLEN, "%s:%s%s;%s%s\n", keystore_name, CONF_MODULEPATH, entry->modulepath, CONF_OPTION, option); if (fputs(buffer, pfile_tmp) == EOF) { err = errno; (void) fprintf(stderr, gettext( "failed to write to %s: %s\n"), tmpfile_name, strerror(err)); rv = KC_ERR_MODIFY_PLUGIN; goto out; } } else { if (fputs(buffer, pfile_tmp) == EOF) { rv = KC_ERR_UNINSTALL; goto out; } } } if (rename(tmpfile_name, _PATH_KMF_CONF) == -1) { err = errno; (void) fprintf(stderr, gettext( "failed to update the configuration - %s"), strerror(err)); rv = KC_ERR_MODIFY_PLUGIN; goto out; } if (chmod(_PATH_KMF_CONF, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { err = errno; (void) fprintf(stderr, gettext( "failed to update the configuration - %s\n"), strerror(err)); rv = KC_ERR_MODIFY_PLUGIN; goto out; } out: if (entry != NULL) free_entry(entry); if (pfile != NULL) (void) fclose(pfile); if (rv != KC_OK && pfile_tmp != NULL) (void) unlink(tmpfile_name); if (pfile_tmp != NULL) (void) fclose(pfile_tmp); return (rv); } int kc_modify(int argc, char *argv[]) { if (argc > 2 && strcmp(argv[0], "modify") == 0 && strcmp(argv[1], "plugin") == 0) { return (kc_modify_plugin(argc, argv)); } else { return (kc_modify_policy(argc, argv)); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include "util.h" static int err; /* To store errno which may be overwritten by gettext() */ int kc_uninstall(int argc, char *argv[]) { int rv = KC_OK; int opt; extern int optind_av; extern char *optarg_av; char *keystore_name = NULL; conf_entry_t *entry = NULL; FILE *pfile = NULL; FILE *pfile_tmp = NULL; char tmpfile_name[MAXPATHLEN]; char buffer[MAXPATHLEN]; char buffer2[MAXPATHLEN]; boolean_t found; boolean_t in_package; while ((opt = getopt_av(argc, argv, "k:(keystore)")) != EOF) { switch (opt) { case 'k': if (keystore_name != NULL) rv = KC_ERR_USAGE; else { keystore_name = get_string(optarg_av, &rv); if (keystore_name == NULL) { (void) fprintf(stderr, gettext( "Error keystore input.\n")); } } break; default: (void) fprintf(stderr, gettext("Error input option.\n")); rv = KC_ERR_USAGE; break; } if (rv != KC_OK) goto out; } /* No additional args allowed. */ argc -= optind_av; if (argc) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (keystore_name == NULL) { (void) fprintf(stderr, gettext("Error input option\n")); rv = KC_ERR_USAGE; goto out; } if (strcasecmp(keystore_name, "nss") == 0 || strcasecmp(keystore_name, "pkcs11") == 0 || strcasecmp(keystore_name, "file") == 0) { (void) fprintf(stderr, gettext("Can not uninstall the built-in keystore %s\n"), keystore_name); rv = KC_ERR_UNINSTALL; goto out; } entry = get_keystore_entry(keystore_name); if (entry == NULL) { (void) fprintf(stderr, gettext("%s does not exist.\n"), keystore_name); rv = KC_ERR_USAGE; goto out; } if ((pfile = fopen(_PATH_KMF_CONF, "r+")) == NULL) { err = errno; (void) fprintf(stderr, gettext("failed to update the configuration - %s\n"), strerror(err)); rv = KC_ERR_ACCESS; goto out; } if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; (void) fprintf(stderr, gettext("failed to lock the configuration - %s\n"), strerror(err)); rv = KC_ERR_UNINSTALL; goto out; } /* * Create a temporary file in the /etc/crypto directory. */ (void) strlcpy(tmpfile_name, CONF_TEMPFILE, sizeof (tmpfile_name)); if (mkstemp(tmpfile_name) == -1) { err = errno; (void) fprintf(stderr, gettext("failed to create a temporary file - %s\n"), strerror(err)); rv = KC_ERR_UNINSTALL; goto out; } if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { err = errno; (void) fprintf(stderr, gettext("failed to open a temporary file - %s\n"), strerror(err)); rv = KC_ERR_UNINSTALL; goto out; } /* * Loop thru the config file. If the plugin to be uninstalled is in * a package, then just comment it off. */ in_package = B_FALSE; while (fgets(buffer, MAXPATHLEN, pfile) != NULL) { found = B_FALSE; if (buffer[0] != ' ' && buffer[0] != '\n' && buffer[0] != '\t') { if (strstr(buffer, " Start ") != NULL) { in_package = B_TRUE; } else if (strstr(buffer, " End ") != NULL) { in_package = B_FALSE; } else if (buffer[0] != '#') { char *name; int len; /* * make a copy of the original buffer to * buffer2. Also get rid of the trailing * '\n' from buffer2. */ (void) strlcpy(buffer2, buffer, MAXPATHLEN); /* get rid of trailing '\n' */ len = strlen(buffer2); if (buffer2[len-1] == '\n') { len--; } buffer2[len] = '\0'; if ((name = strtok(buffer2, SEP_COLON)) == NULL) { rv = KC_ERR_UNINSTALL; goto out; } if (strcmp(keystore_name, name) == 0) found = B_TRUE; } } if (found) { /* * If found and not in_package, then don't write * this line to the result file. */ if (in_package) { (void) snprintf(buffer2, sizeof (buffer2), "%s%s", "#", buffer); if (fputs(buffer2, pfile_tmp) == EOF) { rv = KC_ERR_UNINSTALL; goto out; } } } else { if (fputs(buffer, pfile_tmp) == EOF) { rv = KC_ERR_UNINSTALL; goto out; } } } out: if (pfile != NULL) (void) fclose(pfile); if (rv != KC_OK && pfile_tmp != NULL) (void) unlink(tmpfile_name); if (pfile_tmp != NULL) (void) fclose(pfile_tmp); if (rv == KC_OK) { if (rename(tmpfile_name, _PATH_KMF_CONF) == -1) { err = errno; (void) fprintf(stderr, gettext( "failed to update the configuration - %s"), strerror(err)); return (KC_ERR_UNINSTALL); } if (chmod(_PATH_KMF_CONF, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { err = errno; (void) fprintf(stderr, gettext( "failed to update the configuration - %s\n"), strerror(err)); return (KC_ERR_UNINSTALL); } } return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include "util.h" /* Supporting structures and global variables for getopt_av(). */ typedef struct av_opts_s { int shortnm; /* short name character */ char *longnm; /* long name string, NOT terminated */ int longnm_len; /* length of long name string */ boolean_t has_arg; /* takes optional argument */ } av_opts; static av_opts *opts_av = NULL; static const char *_save_optstr = NULL; static int _save_numopts = 0; int optind_av = 1; char *optarg_av = NULL; void free_policy_list(POLICY_LIST *plist) { POLICY_LIST *n = plist, *old; if (plist == NULL) return; while (n != NULL) { old = n; kmf_free_policy_record(&n->plc); n = n->next; free(old); } plist = NULL; } int load_policies(char *file, POLICY_LIST **policy_list) { int rv = KC_OK; KMF_RETURN kmfrv = KMF_OK; POLICY_LIST *newitem, *plist = NULL; xmlParserCtxtPtr ctxt; xmlDocPtr doc = NULL; xmlNodePtr cur, node; /* Create a parser context */ ctxt = xmlNewParserCtxt(); if (ctxt == NULL) return (KMF_ERR_POLICY_DB_FORMAT); /* Read the policy DB and verify it against the schema. */ doc = xmlCtxtReadFile(ctxt, file, NULL, XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); if (doc == NULL || ctxt->valid == 0) { kmfrv = KMF_ERR_POLICY_DB_FORMAT; goto end; } cur = xmlDocGetRootElement(doc); if (cur == NULL) { kmfrv = KMF_ERR_POLICY_DB_FORMAT; goto end; } node = cur->xmlChildrenNode; while (node != NULL) { char *c; /* * Search for the policy that matches the given name. */ if (!xmlStrcmp((const xmlChar *)node->name, (const xmlChar *)KMF_POLICY_ELEMENT)) { /* Check the name attribute */ c = (char *)xmlGetProp(node, (const xmlChar *)KMF_POLICY_NAME_ATTR); /* If a match, parse the rest of the data */ if (c != NULL) { xmlFree(c); newitem = malloc(sizeof (POLICY_LIST)); if (newitem != NULL) { (void) memset(newitem, 0, sizeof (POLICY_LIST)); kmfrv = parsePolicyElement(node, &newitem->plc); } else { kmfrv = KMF_ERR_MEMORY; goto end; } /* add to linked list */ if (plist == NULL) { plist = newitem; } else { POLICY_LIST *n = plist; while (n->next != NULL) n = n->next; n->next = newitem; newitem->next = NULL; } } } node = node->next; } end: if (ctxt != NULL) xmlFreeParserCtxt(ctxt); if (doc != NULL) xmlFreeDoc(doc); if (kmfrv != KMF_OK) { free_policy_list(plist); rv = KC_ERR_LOADDB; } else { *policy_list = plist; } return (rv); } /* * Return 0 if there is any error in the input string. */ uint16_t parseKUlist(char *kustring) { uint16_t cur_bit; uint16_t kubits = 0; char *p; p = strtok(kustring, ","); while (p != NULL) { cur_bit = kmf_string_to_ku(p); if (cur_bit == 0) { kubits = 0; break; } kubits |= cur_bit; p = strtok(NULL, ","); } return (kubits); } static void addToEKUList(KMF_EKU_POLICY *ekus, KMF_OID *newoid) { if (newoid != NULL && ekus != NULL) { ekus->eku_count++; ekus->ekulist = realloc( ekus->ekulist, ekus->eku_count * sizeof (KMF_OID)); if (ekus->ekulist != NULL) { ekus->ekulist[ekus->eku_count-1] = *newoid; } } } int parseEKUNames(char *ekulist, KMF_POLICY_RECORD *plc) { int rv = KC_OK; char *p; KMF_OID *newoid; KMF_EKU_POLICY *ekus = &plc->eku_set; if (ekulist == NULL || !strlen(ekulist)) return (0); /* * The list should be comma separated list of EKU Names. */ p = strtok(ekulist, ","); /* If no tokens found, then maybe its just a single EKU value */ if (p == NULL) { newoid = kmf_ekuname_to_oid(ekulist); if (newoid != NULL) { addToEKUList(ekus, newoid); free(newoid); } else { rv = KC_ERR_USAGE; } } while (p != NULL) { newoid = kmf_ekuname_to_oid(p); if (newoid != NULL) { addToEKUList(ekus, newoid); free(newoid); } else { rv = KC_ERR_USAGE; break; } p = strtok(NULL, ","); } if (rv != KC_OK) kmf_free_eku_policy(ekus); return (rv); } int parseEKUOIDs(char *ekulist, KMF_POLICY_RECORD *plc) { int rv = KC_OK; char *p; KMF_OID newoid = { 0, NULL }; KMF_EKU_POLICY *ekus = &plc->eku_set; if (ekulist == NULL || !strlen(ekulist)) return (0); /* * The list should be comma separated list of EKU Names. */ p = strtok(ekulist, ","); if (p == NULL) { if (kmf_string_to_oid(ekulist, &newoid) == KMF_OK) { addToEKUList(ekus, &newoid); } else { rv = KC_ERR_USAGE; } } while (p != NULL && rv == 0) { if (kmf_string_to_oid(p, &newoid) == KMF_OK) { addToEKUList(ekus, &newoid); } else { rv = KC_ERR_USAGE; break; } p = strtok(NULL, ","); } if (rv != KC_OK) kmf_free_eku_policy(ekus); return (rv); } int get_boolean(char *arg) { if (arg == NULL) return (-1); if (strcasecmp(arg, "true") == 0) return (1); if (strcasecmp(arg, "false") == 0) return (0); return (-1); } /* * This function processes the input string. It removes the beginning * and ending blank's first, makes a copy of the resulting string and * return it. * * This function returns NULL, if there is an error in the * input string or when the system is out of memory. The output * "err_flag" argument will record the error code, if it is not NULL. */ char * get_string(char *str, int *err_flag) { char *p; int len, i; char *retstr = NULL; if (str == NULL) { if (err_flag != NULL) *err_flag = KC_ERR_USAGE; return (NULL); } /* Remove beginning whitespace */ p = str; while (p != NULL && isspace(*p)) p++; if (p == NULL) { if (err_flag != NULL) *err_flag = KC_ERR_USAGE; return (NULL); } /* Remove the trailing blanks */ len = strlen(p); while (len > 0 && isspace(p[len-1])) len--; if (len == 0) { if (err_flag != NULL) *err_flag = KC_ERR_USAGE; return (NULL); } /* Check if there is any non-printable character */ i = 0; while (i < len) { if (isprint(p[i])) i++; else { if (err_flag != NULL) *err_flag = KC_ERR_USAGE; return (NULL); } } /* Make a copy of the string and return it */ retstr = malloc(len + 1); if (retstr == NULL) { if (err_flag != NULL) *err_flag = KC_ERR_MEMORY; return (NULL); } if (err_flag != NULL) *err_flag = KC_OK; (void) strncpy(retstr, p, len); retstr[len] = '\0'; return (retstr); } /* * Breaks out the getopt-style option string into a structure that can be * traversed later for calls to getopt_av(). Option string is NOT altered, * but the struct fields point to locations within option string. */ static int populate_opts(char *optstring) { int i; av_opts *temp; char *marker; if (optstring == NULL || *optstring == '\0') return (0); /* * This tries to imitate getopt(3c) Each option must conform to: * [ ':' ] [ '(' ')' ] * If long name is missing, the short name is used for long name. */ for (i = 0; *optstring != '\0'; i++) { if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { free(opts_av); opts_av = NULL; return (0); } else opts_av = (av_opts *)temp; marker = optstring; /* may need optstring later */ opts_av[i].shortnm = *marker++; /* set short name */ if (*marker == ':') { /* check for opt arg */ marker++; opts_av[i].has_arg = B_TRUE; } if (*marker == '(') { /* check and set long name */ marker++; opts_av[i].longnm = marker; opts_av[i].longnm_len = strcspn(marker, ")"); optstring = marker + opts_av[i].longnm_len + 1; } else { /* use short name option character */ opts_av[i].longnm = optstring; opts_av[i].longnm_len = 1; optstring = marker; } } return (i); } /* * getopt_av() is very similar to getopt(3c) in that the takes an option * string, compares command line arguments for matches, and returns a single * letter option when a match is found. However, getopt_av() differs from * getopt(3c) by allowing both longname options and values be found * on the command line. */ int getopt_av(int argc, char * const *argv, const char *optstring) { int i; int len; if (optind_av >= argc) return (EOF); /* First time or when optstring changes from previous one */ if (_save_optstr != optstring) { if (opts_av != NULL) free(opts_av); opts_av = NULL; _save_optstr = optstring; _save_numopts = populate_opts((char *)optstring); } for (i = 0; i < _save_numopts; i++) { if (strcmp(argv[optind_av], "--") == 0) { optind_av++; break; } len = strcspn(argv[optind_av], "="); if (len == opts_av[i].longnm_len && strncmp(argv[optind_av], opts_av[i].longnm, opts_av[i].longnm_len) == 0) { /* matched */ if (!opts_av[i].has_arg) { optind_av++; return (opts_av[i].shortnm); } /* needs optarg */ if (argv[optind_av][len] == '=') { optarg_av = &(argv[optind_av][len+1]); optind_av++; return (opts_av[i].shortnm); } optarg_av = NULL; optind_av++; return ((int)'?'); } } return (EOF); } void print_sanity_error(KMF_RETURN ret) { switch (ret) { case KMF_ERR_POLICY_NAME: (void) fprintf(stderr, gettext("Error in the policy name\n")); break; case KMF_ERR_TA_POLICY: (void) fprintf(stderr, gettext("Error in trust anchor attributes\n")); break; case KMF_ERR_OCSP_POLICY: (void) fprintf(stderr, gettext("Error in OCSP policy attributes\n")); break; default: break; } } conf_entry_t * get_keystore_entry(char *kstore_name) { conf_entrylist_t *phead = NULL; conf_entrylist_t *ptr; conf_entry_t *rtn_entry = NULL; if (kstore_name == NULL) return (NULL); if (get_entrylist(&phead) != KMF_OK) return (NULL); ptr = phead; while (ptr != NULL) { if (strcmp(ptr->entry->keystore, kstore_name) == 0) break; ptr = ptr->next; } if (ptr != NULL) /* found the entry */ rtn_entry = dup_entry(ptr->entry); free_entrylist(phead); return (rtn_entry); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _UTIL_H #define _UTIL_H #ifdef __cplusplus extern "C" { #endif #include typedef struct _policy_list { KMF_POLICY_RECORD plc; struct _policy_list *next; } POLICY_LIST; void free_policy_list(POLICY_LIST *); int getopt_av(int, char * const *, const char *); int load_policies(char *, POLICY_LIST **); int get_boolean(char *); char *get_string(char *, int *err_flag); int parseEKUOIDs(char *, KMF_POLICY_RECORD *); int parseEKUNames(char *, KMF_POLICY_RECORD *); uint16_t parseKUlist(char *); void print_sanity_error(KMF_RETURN); conf_entry_t *get_keystore_entry(char *); #define KC_OK 0 #define KC_ERR_USAGE 1 #define KC_ERR_LOADDB 2 #define KC_ERR_FIND_POLICY 3 #define KC_ERR_DELETE_POLICY 4 #define KC_ERR_ADD_POLICY 5 #define KC_ERR_VERIFY_POLICY 6 #define KC_ERR_INCOMPLETE_POLICY 7 #define KC_ERR_MEMORY 8 #define KC_ERR_ACCESS 9 #define KC_ERR_INSTALL 10 #define KC_ERR_UNINSTALL 11 #define KC_ERR_MODIFY_PLUGIN 12 #define CONF_TEMPFILE "/etc/crypto/kmfXXXXXX" #ifdef __cplusplus } #endif #endif /* _UTIL_H */ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG = pktool OBJS = pktool.o \ common.o \ setpin.o \ list.o \ delete.o \ import.o \ inittoken.o \ export.o \ tokens.o \ gencert.o \ gencsr.o \ download.o \ genkey.o \ signcsr.o \ genkeypair.o include ../../Makefile.cmd KMFDIR = $(SRC)/lib/libkmf SRCS = $(OBJS:%.o=%.c) POFILES = $(OBJS:%.o=%.po) POFILE = $(PROG)_msg.po MSGFILES=$(SRCS:%.c=%.i) CPPFLAGS += -I. -I$(KMFDIR)/include -I$(ROOT)/usr/include/libxml2 \ -I$(KMFDIR)/ber_der/inc CFLAGS += $(CCVERBOSE) -DDEBUG CERRWARN += $(CNOWARN_UNINIT) # not linted, too much mess, but it should be SMATCH=off LDLIBS += -lkmf -lpkcs11 -lcryptoutil .KEEP_STATE: all : $(PROG) $(PROG) : $(OBJS) $(LINK.c) -o $@ $(OBJS) $(DYNFLAGS) $(LDLIBS) $(POST_PROCESS) $(POFILE) : $(POFILES) $(RM) $@; $(CAT) $(POFILES) > $@ install : all $(ROOTPROG) clean : $(RM) $(OBJS) include ../../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * This file contains the functions that are shared among * the various services this tool will ultimately provide. * The functions in this file return PKCS#11 CK_RV errors. * Only one session and one login per token is supported * at this time. */ #include #include #include #include #include #include #include #include #include #include #include #include "common.h" /* Local status variables. */ static boolean_t initialized = B_FALSE; static boolean_t session_opened = B_FALSE; static boolean_t logged_in = B_FALSE; /* Supporting structures and global variables for getopt_av(). */ typedef struct av_opts_s { int shortnm; /* short name character */ char *longnm; /* long name string, NOT terminated */ int longnm_len; /* length of long name string */ boolean_t has_arg; /* takes optional argument */ } av_opts; static av_opts *opts_av = NULL; static const char *_save_optstr = NULL; static int _save_numopts = 0; int optind_av = 1; char *optarg_av = NULL; static void close_sess(CK_SESSION_HANDLE); static void logout_token(CK_SESSION_HANDLE); struct oid_table_entry { const KMF_OID *oid; char *name; }; struct oid_table_entry oid_table[] = { { &KMFOID_ECC_secp112r1, "secp112r1"}, { &KMFOID_ECC_secp112r2, "secp112r2"}, { &KMFOID_ECC_secp128r1, "secp128r1"}, { &KMFOID_ECC_secp128r2, "secp128r2"}, { &KMFOID_ECC_secp160k1, "secp160k1"}, { &KMFOID_ECC_secp160r1, "secp160r1"}, { &KMFOID_ECC_secp160r2, "secp160r2"}, { &KMFOID_ECC_secp192k1, "secp192k1"}, { &KMFOID_ECC_secp192r1, "secp192r1"}, { &KMFOID_ECC_secp224k1, "secp224k1"}, { &KMFOID_ECC_secp224r1, "secp224r1"}, { &KMFOID_ECC_secp256k1, "secp256k1"}, { &KMFOID_ECC_secp256r1, "secp256r1"}, { &KMFOID_ECC_secp384r1, "secp384r1"}, { &KMFOID_ECC_secp521r1, "secp521r1"}, { &KMFOID_ECC_sect113r1, "sect113r1"}, { &KMFOID_ECC_sect113r2, "sect113r2"}, { &KMFOID_ECC_sect131r1, "sect131r1"}, { &KMFOID_ECC_sect131r2, "sect131r2"}, { &KMFOID_ECC_sect163k1, "sect163k1"}, { &KMFOID_ECC_sect163r1, "sect163r1"}, { &KMFOID_ECC_sect163r2, "sect163r2"}, { &KMFOID_ECC_sect193r1, "sect193r1"}, { &KMFOID_ECC_sect193r2, "sect193r2"}, { &KMFOID_ECC_sect233k1, "sect233k1"}, { &KMFOID_ECC_sect233r1, "sect233r1"}, { &KMFOID_ECC_sect239k1, "sect239k1"}, { &KMFOID_ECC_sect283k1, "sect283k1"}, { &KMFOID_ECC_sect283r1, "sect283r1"}, { &KMFOID_ECC_sect409k1, "sect409k1"}, { &KMFOID_ECC_sect409r1, "sect409r1"}, { &KMFOID_ECC_sect571k1, "sect571k1"}, { &KMFOID_ECC_sect571r1, "sect571r1"}, { &KMFOID_ECC_c2pnb163v1, "c2pnb163v1"}, { &KMFOID_ECC_c2pnb163v2, "c2pnb163v2"}, { &KMFOID_ECC_c2pnb163v3, "c2pnb163v3"}, { &KMFOID_ECC_c2pnb176v1, "c2pnb176v1"}, { &KMFOID_ECC_c2tnb191v1, "c2tnb191v1"}, { &KMFOID_ECC_c2tnb191v2, "c2tnb191v2"}, { &KMFOID_ECC_c2tnb191v3, "c2tnb191v3"}, { &KMFOID_ECC_c2pnb208w1, "c2pnb208w1"}, { &KMFOID_ECC_c2tnb239v1, "c2tnb239v1"}, { &KMFOID_ECC_c2tnb239v2, "c2tnb239v2"}, { &KMFOID_ECC_c2tnb239v3, "c2tnb239v3"}, { &KMFOID_ECC_c2pnb272w1, "c2pnb272w1"}, { &KMFOID_ECC_c2pnb304w1, "c2pnb304w1"}, { &KMFOID_ECC_c2tnb359v1, "c2tnb359v1"}, { &KMFOID_ECC_c2pnb368w1, "c2pnb368w1"}, { &KMFOID_ECC_c2tnb431r1, "c2tnb431r1"}, { &KMFOID_ECC_prime192v2, "prime192v2"}, { &KMFOID_ECC_prime192v3, "prime192v3"}, { &KMFOID_MD5, "md5"}, { &KMFOID_SHA1, "sha1"}, { &KMFOID_SHA256, "sha256"}, { &KMFOID_SHA384, "sha384"}, { &KMFOID_SHA512, "sha512"} }; int number_of_oids = sizeof (oid_table) / sizeof (struct oid_table_entry); #define number_of_curves (number_of_oids - 5) /* * Perform PKCS#11 setup here. Currently only C_Initialize is required, * along with setting/resetting state variables. */ static CK_RV init_pkcs11(void) { CK_RV rv = CKR_OK; /* If C_Initialize() already called, nothing to do here. */ if (initialized == B_TRUE) return (CKR_OK); /* Reset state variables because C_Initialize() not yet done. */ session_opened = B_FALSE; logged_in = B_FALSE; /* Initialize PKCS#11 library. */ if ((rv = C_Initialize(NULL_PTR)) != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { return (rv); } initialized = B_TRUE; return (CKR_OK); } /* * Finalize PKCS#11 library and reset state variables. Open sessions, * if any, are closed, and thereby any logins are logged out also. */ void final_pk11(CK_SESSION_HANDLE sess) { /* If the library wasn't initialized, nothing to do here. */ if (!initialized) return; /* Make sure the sesion is closed first. */ close_sess(sess); (void) C_Finalize(NULL); initialized = B_FALSE; } /* * Close PKCS#11 session and reset state variables. Any logins are * logged out. */ static void close_sess(CK_SESSION_HANDLE sess) { if (sess == 0) { return; } /* If session is already closed, nothing to do here. */ if (!session_opened) return; /* Make sure user is logged out of token. */ logout_token(sess); (void) C_CloseSession(sess); session_opened = B_FALSE; } /* * Log user out of token and reset status variable. */ static void logout_token(CK_SESSION_HANDLE sess) { if (sess == 0) { return; } /* If already logged out, nothing to do here. */ if (!logged_in) return; (void) C_Logout(sess); logged_in = B_FALSE; } /* * Gets PIN from user. Caller needs to free the returned PIN when done. * If two prompts are given, the PIN is confirmed with second prompt. * Note that getphassphrase() may return data in static memory area. */ CK_RV get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen) { char *save_phrase, *phrase1, *phrase2; /* Prompt user for a PIN. */ if (prompt1 == NULL) { return (CKR_ARGUMENTS_BAD); } if ((phrase1 = getpassphrase(prompt1)) == NULL) { return (CKR_FUNCTION_FAILED); } /* Duplicate 1st PIN in separate chunk of memory. */ if ((save_phrase = strdup(phrase1)) == NULL) return (CKR_HOST_MEMORY); /* If second prompt given, PIN confirmation is requested. */ if (prompt2 != NULL) { if ((phrase2 = getpassphrase(prompt2)) == NULL) { free(save_phrase); return (CKR_FUNCTION_FAILED); } if (strcmp(save_phrase, phrase2) != 0) { free(save_phrase); return (CKR_PIN_INCORRECT); } } *pin = (CK_UTF8CHAR_PTR)save_phrase; *pinlen = strlen(save_phrase); return (CKR_OK); } int yn_to_int(char *ynstr) { char *y = gettext("yes"); char *n = gettext("no"); if (ynstr == NULL) return (-1); if (strncasecmp(ynstr, y, 1) == 0) return (1); else if (strncasecmp(ynstr, n, 1) == 0) return (0); else return (-1); } /* * Gets yes/no response from user. If either no prompt is supplied, a * default prompt is used. If not message for invalid input is supplied, * a default will not be provided. If the user provides no response, * the input default B_TRUE == yes, B_FALSE == no is returned. * Otherwise, B_TRUE is returned for yes, and B_FALSE for no. */ boolean_t yesno(char *prompt, char *invalid, boolean_t dflt) { char *response, buf[1024]; int ans; if (prompt == NULL) prompt = gettext("Enter (y)es or (n)o? "); for (;;) { /* Prompt user. */ (void) printf("%s", prompt); (void) fflush(stdout); /* Get the response. */ if ((response = fgets(buf, sizeof (buf), stdin)) == NULL) break; /* go to default response */ /* Skip any leading white space. */ while (isspace(*response)) response++; if (*response == '\0') break; /* go to default response */ ans = yn_to_int(response); if (ans == 1) return (B_TRUE); else if (ans == 0) return (B_FALSE); /* Indicate invalid input, and try again. */ if (invalid != NULL) (void) printf("%s", invalid); } return (dflt); } /* * Gets the list of slots which have tokens in them. Keeps adjusting * the size of the slot list buffer until the call is successful or an * irrecoverable error occurs. */ CK_RV get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) { CK_ULONG tmp_count = 0; CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR; int rv = CKR_OK; if (!initialized) if ((rv = init_pkcs11()) != CKR_OK) return (rv); /* * Get the slot count first because we don't know how many * slots there are and how many of those slots even have tokens. * Don't specify an arbitrary buffer size for the slot list; * it may be too small (see section 11.5 of PKCS#11 spec). * Also select only those slots that have tokens in them, * because this tool has no need to know about empty slots. */ if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK) return (rv); if (tmp_count == 0) { *slot_list = NULL_PTR; *slot_count = 0; return (CKR_OK); } /* Allocate initial space for the slot list. */ if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count * sizeof (CK_SLOT_ID))) == NULL) return (CKR_HOST_MEMORY); /* Then get the slot list itself. */ for (;;) { if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) { *slot_list = tmp_list; *slot_count = tmp_count; break; } if (rv != CKR_BUFFER_TOO_SMALL) { free(tmp_list); break; } /* If the number of slots grew, try again. */ if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list, tmp_count * sizeof (CK_SLOT_ID))) == NULL) { free(tmp_list); rv = CKR_HOST_MEMORY; break; } tmp_list = tmp2_list; } return (rv); } /* * Breaks out the getopt-style option string into a structure that can be * traversed later for calls to getopt_av(). Option string is NOT altered, * but the struct fields point to locations within option string. */ static int populate_opts(char *optstring) { int i; av_opts *temp; char *marker; if (optstring == NULL || *optstring == '\0') return (0); /* * This tries to imitate getopt(3c) Each option must conform to: * [ ':' ] [ '(' ')' ] * If long name is missing, the short name is used for long name. */ for (i = 0; *optstring != '\0'; i++) { if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { if (opts_av != NULL) free(opts_av); opts_av = NULL; return (0); } else { opts_av = (av_opts *)temp; } (void) memset(&opts_av[i], 0, sizeof (av_opts)); marker = optstring; /* may need optstring later */ opts_av[i].shortnm = *marker++; /* set short name */ if (*marker == ':') { /* check for opt arg */ marker++; opts_av[i].has_arg = B_TRUE; } if (*marker == '(') { /* check and set long name */ marker++; opts_av[i].longnm = marker; opts_av[i].longnm_len = strcspn(marker, ")"); optstring = marker + opts_av[i].longnm_len + 1; } else { /* use short name option character */ opts_av[i].longnm = optstring; opts_av[i].longnm_len = 1; optstring = marker; } } return (i); } /* * getopt_av() is very similar to getopt(3c) in that the takes an option * string, compares command line arguments for matches, and returns a single * letter option when a match is found. However, getopt_av() differs from * getopt(3c) by requiring that only longname options and values be found * on the command line and all leading dashes are omitted. In other words, * it tries to enforce only longname "option=value" arguments on the command * line. Boolean options are not allowed either. */ int getopt_av(int argc, char * const *argv, const char *optstring) { int i; int len; char *cur_option; if (optind_av >= argc) return (EOF); /* First time or when optstring changes from previous one */ if (_save_optstr != optstring) { if (opts_av != NULL) free(opts_av); opts_av = NULL; _save_optstr = optstring; _save_numopts = populate_opts((char *)optstring); } for (i = 0; i < _save_numopts; i++) { cur_option = argv[optind_av]; if (strcmp(cur_option, "--") == 0) { optind_av++; break; } if (cur_option[0] == '-' && strlen(cur_option) == 2) { len = 1; cur_option++; /* remove "-" */ } else { len = strcspn(cur_option, "="); } if (len == opts_av[i].longnm_len && strncmp(cur_option, opts_av[i].longnm, opts_av[i].longnm_len) == 0) { /* matched */ if (!opts_av[i].has_arg) { optind_av++; return (opts_av[i].shortnm); } /* needs optarg */ if (cur_option[len] == '=') { optarg_av = &(cur_option[len+1]); optind_av++; return (opts_av[i].shortnm); } optarg_av = NULL; optind_av++; return ((int)'?'); } } return (EOF); } KMF_KEYSTORE_TYPE KS2Int(char *keystore_str) { if (keystore_str == NULL) return (0); if (strcasecmp(keystore_str, "pkcs11") == 0) return (KMF_KEYSTORE_PK11TOKEN); else if (strcasecmp(keystore_str, "nss") == 0) return (KMF_KEYSTORE_NSS); else if (strcasecmp(keystore_str, "file") == 0) return (KMF_KEYSTORE_OPENSSL); else return (0); } /* * compare_oids * return 1 if equal */ boolean_t compare_oids(KMF_OID *oid1, const KMF_OID *oid2) { return ((oid1->Length == oid2->Length) && !memcmp(oid1->Data, oid2->Data, oid1->Length)); } int Str2KeyType(char *algm, KMF_OID *hashoid, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg) { if (algm == NULL) { /* Default to SHA1+RSA */ *sigAlg = KMF_ALGID_SHA1WithRSA; *ktype = KMF_RSA; } else if (strcasecmp(algm, "DSA") == 0) { if (hashoid == NULL || compare_oids(hashoid, &KMFOID_SHA1)) *sigAlg = KMF_ALGID_SHA1WithDSA; else if (compare_oids(hashoid, &KMFOID_SHA256)) *sigAlg = KMF_ALGID_SHA256WithDSA; else return (-1); /* unsupported hash/key combo */ *ktype = KMF_DSA; } else if (strcasecmp(algm, "RSA") == 0) { if (hashoid == NULL || compare_oids(hashoid, &KMFOID_SHA1)) *sigAlg = KMF_ALGID_SHA1WithRSA; else if (compare_oids(hashoid, &KMFOID_SHA256)) *sigAlg = KMF_ALGID_SHA256WithRSA; else if (compare_oids(hashoid, &KMFOID_SHA384)) *sigAlg = KMF_ALGID_SHA384WithRSA; else if (compare_oids(hashoid, &KMFOID_SHA512)) *sigAlg = KMF_ALGID_SHA512WithRSA; else if (compare_oids(hashoid, &KMFOID_MD5)) *sigAlg = KMF_ALGID_MD5WithRSA; else return (-1); /* unsupported hash/key combo */ *ktype = KMF_RSA; } else if (strcasecmp(algm, "EC") == 0) { /* EC keys may be used with some SHA2 hashes */ if (hashoid == NULL || compare_oids(hashoid, &KMFOID_SHA1)) *sigAlg = KMF_ALGID_SHA1WithECDSA; else if (compare_oids(hashoid, &KMFOID_SHA256)) *sigAlg = KMF_ALGID_SHA256WithECDSA; else if (compare_oids(hashoid, &KMFOID_SHA384)) *sigAlg = KMF_ALGID_SHA384WithECDSA; else if (compare_oids(hashoid, &KMFOID_SHA512)) *sigAlg = KMF_ALGID_SHA512WithECDSA; else return (-1); /* unsupported hash/key combo */ *ktype = KMF_ECDSA; } else { return (-1); } return (0); } int Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype) { if (algm == NULL) *ktype = KMF_AES; else if (strcasecmp(algm, "aes") == 0) *ktype = KMF_AES; else if (strcasecmp(algm, "arcfour") == 0) *ktype = KMF_RC4; else if (strcasecmp(algm, "des") == 0) *ktype = KMF_DES; else if (strcasecmp(algm, "3des") == 0) *ktype = KMF_DES3; else if (strcasecmp(algm, "generic") == 0) *ktype = KMF_GENERIC_SECRET; else return (-1); return (0); } int Str2Lifetime(char *ltimestr, uint32_t *ltime) { int num; char timetok[6]; if (ltimestr == NULL || strlen(ltimestr) == 0) { /* default to 1 year lifetime */ *ltime = SECSPERDAY * DAYSPERNYEAR; return (0); } (void) memset(timetok, 0, sizeof (timetok)); if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2) return (-1); if (strcasecmp(timetok, "day") == 0|| strcasecmp(timetok, "days") == 0) { *ltime = num * SECSPERDAY; } else if (strcasecmp(timetok, "hour") == 0|| strcasecmp(timetok, "hours") == 0) { *ltime = num * SECSPERHOUR; } else if (strcasecmp(timetok, "year") == 0 || strcasecmp(timetok, "years") == 0) { *ltime = num * SECSPERDAY * DAYSPERNYEAR; } else { *ltime = 0; return (-1); } return (0); } int OT2Int(char *objclass) { char *c = NULL; int retval = 0; if (objclass == NULL) return (-1); c = strchr(objclass, ':'); if (c != NULL) { if (strcasecmp(c, ":private") == 0) retval = PK_PRIVATE_OBJ; else if (strcasecmp(c, ":public") == 0) retval = PK_PUBLIC_OBJ; else if (strcasecmp(c, ":both") == 0) retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ; else /* unrecognized option */ return (-1); *c = '\0'; } if (strcasecmp(objclass, "public") == 0) { if (retval) return (-1); return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | PK_PUBKEY_OBJ); } else if (strcasecmp(objclass, "private") == 0) { if (retval) return (-1); return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ); } else if (strcasecmp(objclass, "both") == 0) { if (retval) return (-1); return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ); } else if (strcasecmp(objclass, "cert") == 0) { return (retval | PK_CERT_OBJ); } else if (strcasecmp(objclass, "key") == 0) { if (retval == 0) /* return all keys */ return (retval | PK_KEY_OBJ); else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ)) /* return all keys */ return (retval | PK_KEY_OBJ); else if (retval & PK_PUBLIC_OBJ) /* Only return public keys */ return (retval | PK_PUBKEY_OBJ); else if (retval & PK_PRIVATE_OBJ) /* Only return private keys */ return (retval | PK_PRIKEY_OBJ); } else if (strcasecmp(objclass, "crl") == 0) { if (retval) return (-1); return (retval | PK_CRL_OBJ); } if (retval == 0) /* No matches found */ retval = -1; return (retval); } KMF_ENCODE_FORMAT Str2Format(char *formstr) { if (formstr == NULL || strcasecmp(formstr, "der") == 0) return (KMF_FORMAT_ASN1); if (strcasecmp(formstr, "pem") == 0) return (KMF_FORMAT_PEM); if (strcasecmp(formstr, "pkcs12") == 0) return (KMF_FORMAT_PKCS12); if (strcasecmp(formstr, "raw") == 0) return (KMF_FORMAT_RAWKEY); return (KMF_FORMAT_UNDEF); } KMF_RETURN select_token(void *kmfhandle, char *token, int readonly) { KMF_ATTRIBUTE attlist[10]; int i = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_RETURN rv = KMF_OK; if (token == NULL) return (KMF_ERR_BAD_PARAMETER); kmf_set_attr_at_index(attlist, i, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); i++; if (token) { kmf_set_attr_at_index(attlist, i, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); i++; } kmf_set_attr_at_index(attlist, i, KMF_READONLY_ATTR, &readonly, sizeof (readonly)); i++; rv = kmf_configure_keystore(kmfhandle, i, attlist); if (rv == KMF_ERR_TOKEN_SELECTED) rv = KMF_OK; return (rv); } KMF_RETURN configure_nss(void *kmfhandle, char *dir, char *prefix) { KMF_ATTRIBUTE attlist[10]; int i = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; KMF_RETURN rv = KMF_OK; kmf_set_attr_at_index(attlist, i, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); i++; if (dir) { kmf_set_attr_at_index(attlist, i, KMF_DIRPATH_ATTR, dir, strlen(dir)); i++; } if (prefix) { kmf_set_attr_at_index(attlist, i, KMF_CERTPREFIX_ATTR, prefix, strlen(prefix)); i++; kmf_set_attr_at_index(attlist, i, KMF_KEYPREFIX_ATTR, prefix, strlen(prefix)); i++; } rv = kmf_configure_keystore(kmfhandle, i, attlist); if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED) rv = KMF_OK; return (rv); } KMF_RETURN get_pk12_password(KMF_CREDENTIAL *cred) { KMF_RETURN rv = KMF_OK; char prompt[1024]; /* * Get the password to use for the PK12 encryption. */ (void) strlcpy(prompt, gettext("Enter password to use for " "accessing the PKCS12 file: "), sizeof (prompt)); if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, (ulong_t *)&cred->credlen) != CKR_OK) { cred->cred = NULL; cred->credlen = 0; } return (rv); } #define FILENAME_PROMPT gettext("Filename:") #define FILENAME_MINLEN 1 #define FILENAME_MAXLEN MAXPATHLEN #define COUNTRY_PROMPT gettext("Country Name (2 letter code) [US]:") #define STATE_PROMPT gettext("State or Province Name (full name) " \ "[Some-State]:") #define LOCALITY_PROMPT gettext("Locality Name (eg, city) []:") #define ORG_PROMPT gettext("Organization Name (eg, company) []:") #define UNIT_PROMPT gettext("Organizational Unit Name (eg, section) []:") #define NAME_PROMPT gettext("Common Name (eg, YOUR name) []:") #define EMAIL_PROMPT gettext("Email Address []:") #define SERNO_PROMPT gettext("Serial Number (hex value, example: " \ "0x01020304):") #define SERNO_MINLEN 3 #define SERNO_MAXLEN 42 #define LABEL_PROMPT gettext("Enter a label for the certificate:") #define LABEL_MINLEN 1 #define LABEL_MAXLEN 1024 #define COUNTRY_DEFAULT "US" #define STATE_DEFAULT NULL #define INVALID_INPUT gettext("Invalid input; please re-enter ...") #define SUBNAMESIZ 1024 #define RDN_MIN 1 #define RDN_MAX 64 #define COUNTRYNAME_MIN 2 #define COUNTRYNAME_MAX 2 static char * get_input_string(char *prompt, char *default_str, int min_len, int max_len) { char buf[1024]; char *response = NULL; char *ret = NULL; int len; for (;;) { (void) printf("\t%s", prompt); (void) fflush(stdout); response = fgets(buf, sizeof (buf), stdin); if (response == NULL) { if (default_str != NULL) { ret = strdup(default_str); } break; } /* Skip any leading white space. */ while (isspace(*response)) response++; if (*response == '\0') { if (default_str != NULL) { ret = strdup(default_str); } break; } len = strlen(response); response[len-1] = '\0'; /* get rid of "LF" */ len--; if (len >= min_len && len <= max_len) { ret = strdup(response); break; } (void) printf("%s\n", INVALID_INPUT); } return (ret); } int get_filename(char *txt, char **result) { char prompt[1024]; char *fname = NULL; (void) snprintf(prompt, sizeof (prompt), gettext("Enter filename for the %s: "), txt); fname = get_input_string(prompt, NULL, FILENAME_MINLEN, FILENAME_MAXLEN); *result = fname; return (0); } int get_certlabel(char **result) { char *label = NULL; label = get_input_string(LABEL_PROMPT, NULL, LABEL_MINLEN, LABEL_MAXLEN); *result = label; return (0); } int get_serial(char **result) { char *serial = NULL; serial = get_input_string(SERNO_PROMPT, NULL, SERNO_MINLEN, SERNO_MAXLEN); *result = serial; return (0); } int get_subname(char **result) { char *country = NULL; char *state = NULL; char *locality = NULL; char *org = NULL; char *unit = NULL; char *name = NULL; char *email = NULL; char *subname = NULL; (void) printf("Entering following fields for subject (a DN) ...\n"); country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT, COUNTRYNAME_MIN, COUNTRYNAME_MAX); if (country == NULL) return (-1); state = get_input_string(STATE_PROMPT, STATE_DEFAULT, RDN_MIN, RDN_MAX); locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX); org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX); unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX); name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX); email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX); /* Now create a subject name from the input strings */ if ((subname = malloc(SUBNAMESIZ)) == NULL) goto out; (void) memset(subname, 0, SUBNAMESIZ); (void) strlcpy(subname, "C=", SUBNAMESIZ); (void) strlcat(subname, country, SUBNAMESIZ); if (state != NULL) { (void) strlcat(subname, ", ST=", SUBNAMESIZ); (void) strlcat(subname, state, SUBNAMESIZ); } if (locality != NULL) { (void) strlcat(subname, ", L=", SUBNAMESIZ); (void) strlcat(subname, locality, SUBNAMESIZ); } if (org != NULL) { (void) strlcat(subname, ", O=", SUBNAMESIZ); (void) strlcat(subname, org, SUBNAMESIZ); } if (unit != NULL) { (void) strlcat(subname, ", OU=", SUBNAMESIZ); (void) strlcat(subname, unit, SUBNAMESIZ); } if (name != NULL) { (void) strlcat(subname, ", CN=", SUBNAMESIZ); (void) strlcat(subname, name, SUBNAMESIZ); } if (email != NULL) { (void) strlcat(subname, ", E=", SUBNAMESIZ); (void) strlcat(subname, email, SUBNAMESIZ); } out: if (country) free(country); if (state) free(state); if (locality) free(locality); if (org) free(org); if (unit) free(unit); if (name) free(name); if (email) free(email); if (subname == NULL) return (-1); else { *result = subname; return (0); } } /* * Parse a string of KeyUsage values and convert * them to the correct KU Bits. * The field may be marked "critical" by prepending * "critical:" to the list. * EX: critical:digitialSignature,keyEncipherment */ KMF_RETURN verify_keyusage(char *kustr, uint16_t *kubits, int *critical) { KMF_RETURN ret = KMF_OK; uint16_t kuval; char *k; *kubits = 0; if (kustr == NULL || strlen(kustr) == 0) return (KMF_ERR_BAD_PARAMETER); /* Check to see if this is critical */ if (strncasecmp(kustr, "critical:", strlen("critical:")) == 0) { *critical = TRUE; kustr += strlen("critical:"); } else { *critical = FALSE; } k = strtok(kustr, ","); while (k != NULL) { kuval = kmf_string_to_ku(k); if (kuval == 0) { *kubits = 0; return (KMF_ERR_BAD_PARAMETER); } *kubits |= kuval; k = strtok(NULL, ","); } return (ret); } /* * Verify the alternate subject label is real or invalid. * * The field may be marked "critical" by prepending * "critical:" to the list. * EX: "critical:IP=1.2.3.4" */ KMF_RETURN verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical) { char *p; KMF_RETURN rv = KMF_OK; /* Check to see if this is critical */ if (strncasecmp(arg, "critical:", strlen("critical:")) == 0) { *critical = TRUE; arg += strlen("critical:"); } else { *critical = FALSE; } /* Make sure there is an "=" sign */ p = strchr(arg, '='); if (p == NULL) return (KMF_ERR_BAD_PARAMETER); p[0] = '\0'; if (strcmp(arg, "IP") == 0) *type = GENNAME_IPADDRESS; else if (strcmp(arg, "DNS") == 0) *type = GENNAME_DNSNAME; else if (strcmp(arg, "EMAIL") == 0) *type = GENNAME_RFC822NAME; else if (strcmp(arg, "URI") == 0) *type = GENNAME_URI; else if (strcmp(arg, "DN") == 0) *type = GENNAME_DIRECTORYNAME; else if (strcmp(arg, "RID") == 0) *type = GENNAME_REGISTEREDID; else if (strcmp(arg, "KRB") == 0) *type = GENNAME_KRB5PRINC; else if (strcmp(arg, "UPN") == 0) *type = GENNAME_SCLOGON_UPN; else rv = KMF_ERR_BAD_PARAMETER; p[0] = '='; return (rv); } int get_token_password(KMF_KEYSTORE_TYPE kstype, char *token_spec, KMF_CREDENTIAL *cred) { char prompt[1024]; char temptoken[32]; char *p = NULL; char *t = NULL; int len; (void) memset(temptoken, 0, sizeof (temptoken)); if (kstype == KMF_KEYSTORE_PK11TOKEN) { p = strchr(token_spec, ':'); if (p != NULL) *p = 0; } len = strlen(token_spec); if (len > sizeof (temptoken)) len = sizeof (temptoken); (void) strncpy(temptoken, token_spec, len); /* * Strip trailing whitespace */ t = temptoken + (len - 1); while (isspace(*t) && t >= temptoken) { *t = 0x00; t--; } /* * Login to the token first. */ (void) snprintf(prompt, sizeof (prompt), gettext(DEFAULT_TOKEN_PROMPT), temptoken); if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, (ulong_t *)&cred->credlen) != CKR_OK) { cred->cred = NULL; cred->credlen = 0; } if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL) *p = ':'; return (KMF_OK); } KMF_RETURN verify_file(char *filename) { KMF_RETURN ret = KMF_OK; int fd; /* * Attempt to open with the EXCL flag so that if * it already exists, the open will fail. It will * also fail if the file cannot be created due to * permissions on the parent directory, or if the * parent directory itself does not exist. */ fd = open(filename, O_CREAT | O_EXCL, 0600); if (fd == -1) { if (errno == EEXIST) return (KMF_ERR_OPEN_FILE); else return (KMF_ERR_WRITE_FILE); } /* If we were able to create it, delete it. */ (void) close(fd); (void) unlink(filename); return (ret); } void display_error(void *handle, KMF_RETURN errcode, char *prefix) { KMF_RETURN rv1, rv2; char *plugin_errmsg = NULL; char *kmf_errmsg = NULL; rv1 = kmf_get_plugin_error_str(handle, &plugin_errmsg); rv2 = kmf_get_kmf_error_str(errcode, &kmf_errmsg); cryptoerror(LOG_STDERR, "%s:", prefix); if (rv1 == KMF_OK && plugin_errmsg) { cryptoerror(LOG_STDERR, gettext("keystore error: %s"), plugin_errmsg); kmf_free_str(plugin_errmsg); } if (rv2 == KMF_OK && kmf_errmsg) { cryptoerror(LOG_STDERR, gettext("libkmf error: %s"), kmf_errmsg); kmf_free_str(kmf_errmsg); } if (rv1 != KMF_OK && rv2 != KMF_OK) cryptoerror(LOG_STDERR, gettext("\n")); } static KMF_RETURN addToEKUList(EKU_LIST *ekus, int critical, KMF_OID *newoid) { if (newoid != NULL && ekus != NULL) { ekus->eku_count++; ekus->critlist = realloc(ekus->critlist, ekus->eku_count * sizeof (int)); if (ekus->critlist != NULL) ekus->critlist[ekus->eku_count-1] = critical; else return (KMF_ERR_MEMORY); ekus->ekulist = realloc( ekus->ekulist, ekus->eku_count * sizeof (KMF_OID)); if (ekus->ekulist != NULL) ekus->ekulist[ekus->eku_count-1] = *newoid; else return (KMF_ERR_MEMORY); } return (KMF_OK); } void free_eku_list(EKU_LIST *ekus) { if (ekus != NULL && ekus->eku_count > 0) { int i; for (i = 0; i < ekus->eku_count; i++) { kmf_free_data(&ekus->ekulist[i]); } free(ekus->ekulist); free(ekus->critlist); free(ekus); } } static KMF_RETURN parse_ekus(char *ekustr, EKU_LIST *ekus) { KMF_RETURN rv = KMF_OK; KMF_OID *newoid; int critical; if (strncasecmp(ekustr, "critical:", strlen("critical:")) == 0) { critical = TRUE; ekustr += strlen("critical:"); } else { critical = FALSE; } newoid = kmf_ekuname_to_oid(ekustr); if (newoid != NULL) { rv = addToEKUList(ekus, critical, newoid); free(newoid); } else { rv = PK_ERR_USAGE; } return (rv); } KMF_RETURN verify_ekunames(char *ekuliststr, EKU_LIST **ekulist) { KMF_RETURN rv = KMF_OK; char *p; EKU_LIST *ekus = NULL; if (ekuliststr == NULL || strlen(ekuliststr) == 0) return (0); ekus = calloc(sizeof (EKU_LIST), 1); if (ekus == NULL) return (KMF_ERR_MEMORY); /* * The list should be comma separated list of EKU Names. */ p = strtok(ekuliststr, ","); /* If no tokens found, then maybe it's just a single EKU value */ if (p == NULL) { rv = parse_ekus(ekuliststr, ekus); } while (p != NULL) { rv = parse_ekus(p, ekus); if (rv != KMF_OK) break; p = strtok(NULL, ","); } if (rv != KMF_OK) free_eku_list(ekus); else *ekulist = ekus; return (rv); } KMF_RETURN token_auth_needed(KMF_HANDLE_T handle, char *tokenlabel, int *auth) { CK_TOKEN_INFO info; CK_SLOT_ID slot; CK_RV ckrv; KMF_RETURN rv; *auth = 0; rv = kmf_pk11_token_lookup(handle, tokenlabel, &slot); if (rv != KMF_OK) return (rv); ckrv = C_GetTokenInfo(slot, &info); if (ckrv != KMF_OK) return (KMF_ERR_INTERNAL); *auth = (info.flags & CKF_LOGIN_REQUIRED); return (KMF_OK); } void show_ecc_curves() { int i; (void) printf(gettext("Supported ECC curve names:\n")); for (i = 0; i < number_of_curves; i++) { (void) printf("%s", oid_table[i].name); if (i > 0 && ((i+1) % 5) == 0) (void) printf("\n"); else if (i+1 < number_of_curves) (void) printf(", "); } (void) printf("\n"); } KMF_OID * ecc_name_to_oid(char *name) { int i; for (i = 0; i < number_of_oids; i++) { if (strcasecmp(name, oid_table[i].name) == 0) return ((KMF_OID *)oid_table[i].oid); } return (NULL); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _PKTOOL_COMMON_H #define _PKTOOL_COMMON_H /* * This file contains data and functions shared between all the * modules that comprise this tool. */ #ifdef __cplusplus extern "C" { #endif #include /* I18N helpers. */ #include #include #include #include /* Defines used throughout */ /* Error codes */ #define PK_ERR_NONE 0 #define PK_ERR_USAGE 1 #define PK_ERR_QUIT 2 #define PK_ERR_PK11 3 #define PK_ERR_SYSTEM 4 #define PK_ERR_OPENSSL 5 #define PK_ERR_NSS 6 /* Types of objects for searches. */ #define PK_PRIVATE_OBJ 0x0001 #define PK_PUBLIC_OBJ 0x0002 #define PK_CERT_OBJ 0x0010 #define PK_PRIKEY_OBJ 0x0020 #define PK_PUBKEY_OBJ 0x0040 #define PK_SYMKEY_OBJ 0x0080 #define PK_CRL_OBJ 0x0100 #define PK_KEY_OBJ (PK_PRIKEY_OBJ | PK_PUBKEY_OBJ | PK_SYMKEY_OBJ) #define PK_ALL_OBJ (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ |\ PK_CERT_OBJ| PK_CRL_OBJ | PK_KEY_OBJ) #define PK_DEFAULT_KEYTYPE "rsa" #define PK_DEFAULT_KEYLENGTH 2048 #define PK_DEFAULT_DIRECTORY "." #define PK_DEFAULT_SERIALNUM 1 #define PK_DEFAULT_PK11TOKEN SOFT_TOKEN_LABEL /* Constants for attribute templates. */ extern CK_BBOOL pk_false; extern CK_BBOOL pk_true; typedef struct { int eku_count; int *critlist; KMF_OID *ekulist; } EKU_LIST; /* Common functions. */ extern void final_pk11(CK_SESSION_HANDLE sess); extern CK_RV login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess); extern CK_RV quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess); extern CK_RV get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen); extern boolean_t yesno(char *prompt, char *invalid, boolean_t dflt); extern CK_RV get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count); extern int get_subname(char **); extern int get_serial(char **); extern int get_certlabel(char **); extern int get_filename(char *, char **); extern int getopt_av(int argc, char * const argv[], const char *optstring); extern char *optarg_av; extern int optind_av; int OT2Int(char *); int PK2Int(char *); KMF_KEYSTORE_TYPE KS2Int(char *); int Str2KeyType(char *, KMF_OID *, KMF_KEY_ALG *, KMF_ALGORITHM_INDEX *); int Str2SymKeyType(char *, KMF_KEY_ALG *); int Str2Lifetime(char *, uint32_t *); KMF_RETURN select_token(void *, char *, int); KMF_RETURN configure_nss(void *, char *, char *); KMF_ENCODE_FORMAT Str2Format(char *); KMF_RETURN get_pk12_password(KMF_CREDENTIAL *); KMF_RETURN hexstring2bytes(uchar_t *, uchar_t **, size_t *); KMF_RETURN verify_altname(char *arg, KMF_GENERALNAMECHOICES *, int *); KMF_RETURN verify_keyusage(char *arg, uint16_t *, int *); KMF_RETURN verify_file(char *); KMF_RETURN verify_ekunames(char *, EKU_LIST **); KMF_RETURN token_auth_needed(KMF_HANDLE_T, char *, int *); KMF_OID *ecc_name_to_oid(char *); void show_ecc_curves(); KMF_RETURN genkeypair_pkcs11(KMF_HANDLE_T, char *, char *, KMF_KEY_ALG, int, KMF_CREDENTIAL *, KMF_OID *, KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); KMF_RETURN genkeypair_file(KMF_HANDLE_T, KMF_KEY_ALG, int, KMF_ENCODE_FORMAT, char *, KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); KMF_RETURN genkeypair_nss(KMF_HANDLE_T, char *, char *, char *, char *, KMF_KEY_ALG, int, KMF_CREDENTIAL *, KMF_OID *, KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); void free_eku_list(EKU_LIST *); int yn_to_int(char *); int get_token_password(KMF_KEYSTORE_TYPE, char *, KMF_CREDENTIAL *); void display_error(void *, KMF_RETURN, char *); #define DEFAULT_NSS_TOKEN "internal" #define DEFAULT_TOKEN_PROMPT "Enter PIN for %s: " #define EMPTYSTRING(s) (s == NULL || !strlen((char *)s)) /* * The "dir" option is only valid with the NSS keystore. This check * forces PK_ERR_USAGE when it is used with non-NSS keystore. */ #define DIR_OPTION_CHECK(k, d) \ if (k != KMF_KEYSTORE_NSS && d != NULL) { \ cryptoerror(LOG_STDERR, gettext("The 'dir' option is " \ "not supported with the indicated keystore\n")); \ return (PK_ERR_USAGE); \ } #ifdef __cplusplus } #endif #endif /* _PKTOOL_COMMON_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 Milan Jurik. All rights reserved. * Copyright 2017 Toomas Soome */ /* * This file implements the token object delete operation for this tool. * It loads the PKCS#11 modules, finds the object to delete, deletes it, * and cleans up. User must be R/W logged into the token. */ #include #include #include #include #include "common.h" #include static KMF_RETURN pk_destroy_keys(void *handle, KMF_ATTRIBUTE *attrlist, int numattr) { int i; KMF_RETURN rv = KMF_OK; uint32_t *numkeys; KMF_KEY_HANDLE *keys = NULL; int del_num = 0; KMF_ATTRIBUTE delete_attlist[16]; KMF_KEYSTORE_TYPE kstype; uint32_t len; boolean_t destroy = B_TRUE; KMF_CREDENTIAL cred; char *slotlabel = NULL; len = sizeof (kstype); rv = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr, &kstype, &len); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(delete_attlist, del_num, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); del_num++; /* "destroy" is optional. Default is TRUE */ (void) kmf_get_attr(KMF_DESTROY_BOOL_ATTR, attrlist, numattr, (void *)&destroy, NULL); kmf_set_attr_at_index(delete_attlist, del_num, KMF_DESTROY_BOOL_ATTR, &destroy, sizeof (boolean_t)); del_num++; switch (kstype) { case KMF_KEYSTORE_NSS: rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr, (void *)&cred, NULL); if (rv == KMF_OK) { if (cred.credlen > 0) { kmf_set_attr_at_index(delete_attlist, del_num, KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL)); del_num++; } } slotlabel = kmf_get_attr_ptr(KMF_TOKEN_LABEL_ATTR, attrlist, numattr); if (slotlabel != NULL) { kmf_set_attr_at_index(delete_attlist, del_num, KMF_TOKEN_LABEL_ATTR, slotlabel, strlen(slotlabel)); del_num++; } break; case KMF_KEYSTORE_OPENSSL: break; case KMF_KEYSTORE_PK11TOKEN: rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr, (void *)&cred, NULL); if (rv == KMF_OK) { if (cred.credlen > 0) { kmf_set_attr_at_index(delete_attlist, del_num, KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL)); del_num++; } } break; default: return (PK_ERR_USAGE); } numkeys = kmf_get_attr_ptr(KMF_COUNT_ATTR, attrlist, numattr); if (numkeys == NULL) return (PK_ERR_USAGE); keys = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr); if (keys == NULL) return (PK_ERR_USAGE); for (i = 0; rv == KMF_OK && i < *numkeys; i++) { int num = del_num; kmf_set_attr_at_index(delete_attlist, num, KMF_KEY_HANDLE_ATTR, &keys[i], sizeof (KMF_KEY_HANDLE)); num++; rv = kmf_delete_key_from_keystore(handle, num, delete_attlist); } return (rv); } static KMF_RETURN pk_delete_keys(KMF_HANDLE_T kmfhandle, KMF_ATTRIBUTE *attlist, int numattr, char *desc, int *keysdeleted) { KMF_RETURN rv = KMF_OK; uint32_t numkeys = 0; int num = numattr; *keysdeleted = 0; numkeys = 0; kmf_set_attr_at_index(attlist, num, KMF_COUNT_ATTR, &numkeys, sizeof (uint32_t)); num++; rv = kmf_find_key(kmfhandle, num, attlist); if (rv == KMF_OK && numkeys > 0) { KMF_KEY_HANDLE *keys = NULL; char prompt[1024]; (void) snprintf(prompt, sizeof (prompt), gettext("%d %s key(s) found, do you want " "to delete them (y/N) ?"), numkeys, (desc != NULL ? desc : "")); if (!yesno(prompt, gettext("Respond with yes or no.\n"), B_FALSE)) { *keysdeleted = numkeys; return (KMF_OK); } keys = (KMF_KEY_HANDLE *)malloc(numkeys * sizeof (KMF_KEY_HANDLE)); if (keys == NULL) return (KMF_ERR_MEMORY); (void) memset(keys, 0, numkeys * sizeof (KMF_KEY_HANDLE)); kmf_set_attr_at_index(attlist, num, KMF_KEY_HANDLE_ATTR, keys, sizeof (KMF_KEY_HANDLE)); num++; rv = kmf_find_key(kmfhandle, num, attlist); if (rv == KMF_OK) { rv = pk_destroy_keys(kmfhandle, attlist, num); } free(keys); } *keysdeleted = numkeys; return (rv); } static KMF_RETURN pk_delete_certs(KMF_HANDLE_T kmfhandle, KMF_ATTRIBUTE *attlist, int numattr) { KMF_RETURN rv = KMF_OK; uint32_t numcerts = 0; int num = numattr; kmf_set_attr_at_index(attlist, num, KMF_COUNT_ATTR, &numcerts, sizeof (uint32_t)); num++; rv = kmf_find_cert(kmfhandle, num, attlist); if (rv == KMF_OK && numcerts > 0) { char prompt[1024]; (void) snprintf(prompt, sizeof (prompt), gettext("%d certificate(s) found, do you want " "to delete them (y/N) ?"), numcerts); if (!yesno(prompt, gettext("Respond with yes or no.\n"), B_FALSE)) { return (KMF_OK); } /* * Use numattr because delete cert does not require * KMF_COUNT_ATTR attribute. */ rv = kmf_delete_cert_from_keystore(kmfhandle, numattr, attlist); } return (rv); } static KMF_RETURN delete_nss_keys(KMF_HANDLE_T kmfhandle, char *dir, char *prefix, char *token, int oclass, char *objlabel, KMF_CREDENTIAL *tokencred) { KMF_RETURN rv = KMF_OK; char *keytype = NULL; int nk, numkeys = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_CLASS keyclass; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } if (tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } if (token && strlen(token)) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } if (oclass & PK_PRIKEY_OBJ) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; keytype = "private"; rv = pk_delete_keys(kmfhandle, attrlist, num, keytype, &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_PRIKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; keytype = "symmetric"; rv = pk_delete_keys(kmfhandle, attrlist, num, keytype, &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_SYMKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { int num = numattr; keyclass = KMF_ASYM_PUB; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; keytype = "public"; rv = pk_delete_keys(kmfhandle, attrlist, num, keytype, &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_PUBKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && numkeys == 0) rv = KMF_ERR_KEY_NOT_FOUND; return (rv); } static KMF_RETURN delete_nss_certs(KMF_HANDLE_T kmfhandle, char *dir, char *prefix, char *token, char *objlabel, KMF_BIGINT *serno, char *issuer, char *subject, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serno != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serno, sizeof (KMF_BIGINT)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; if (token != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } rv = pk_delete_certs(kmfhandle, attrlist, numattr); return (rv); } static KMF_RETURN delete_nss_crl(void *kmfhandle, char *dir, char *prefix, char *token, char *issuer, char *subject) { KMF_RETURN rv = KMF_OK; int numattr = 0; KMF_ATTRIBUTE attrlist[8]; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (token != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } rv = kmf_delete_crl(kmfhandle, numattr, attrlist); return (rv); } static KMF_RETURN delete_pk11_keys(KMF_HANDLE_T kmfhandle, char *token, int oclass, char *objlabel, KMF_CREDENTIAL *tokencred) { KMF_RETURN rv = KMF_OK; int nk, numkeys = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_CLASS keyclass; boolean_t token_bool = B_TRUE; boolean_t private; /* * Symmetric keys and RSA/DSA private keys are always * created with the "CKA_PRIVATE" field == TRUE, so * make sure we search for them with it also set. */ if (oclass & (PK_SYMKEY_OBJ | PK_PRIKEY_OBJ)) oclass |= PK_PRIVATE_OBJ; rv = select_token(kmfhandle, token, FALSE); if (rv != KMF_OK) { return (rv); } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } private = ((oclass & PK_PRIVATE_OBJ) > 0); kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVATE_BOOL_ATTR, &private, sizeof (private)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR, &token_bool, sizeof (token_bool)); numattr++; if (oclass & PK_PRIKEY_OBJ) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; rv = pk_delete_keys(kmfhandle, attrlist, num, "private", &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_PRIKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; rv = pk_delete_keys(kmfhandle, attrlist, num, "symmetric", &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_SYMKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { int num = numattr; private = B_FALSE; keyclass = KMF_ASYM_PUB; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; rv = pk_delete_keys(kmfhandle, attrlist, num, "public", &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_PUBKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && numkeys == 0) rv = KMF_ERR_KEY_NOT_FOUND; return (rv); } static KMF_RETURN delete_pk11_certs(KMF_HANDLE_T kmfhandle, char *token, char *objlabel, KMF_BIGINT *serno, char *issuer, char *subject, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN kmfrv; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; kmfrv = select_token(kmfhandle, token, FALSE); if (kmfrv != KMF_OK) { return (kmfrv); } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serno != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serno, sizeof (KMF_BIGINT)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; kmfrv = pk_delete_certs(kmfhandle, attrlist, numattr); return (kmfrv); } static KMF_RETURN delete_file_certs(KMF_HANDLE_T kmfhandle, char *dir, char *filename, KMF_BIGINT *serial, char *issuer, char *subject, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN rv; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } if (filename != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; rv = pk_delete_certs(kmfhandle, attrlist, numattr); return (rv); } static KMF_RETURN delete_file_keys(KMF_HANDLE_T kmfhandle, int oclass, char *dir, char *infile) { KMF_RETURN rv = KMF_OK; char *keytype = ""; int nk, numkeys = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_CLASS keyclass; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } if (infile != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, infile, strlen(infile)); numattr++; } if (oclass & (PK_PUBKEY_OBJ | PK_PRIKEY_OBJ)) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; keytype = "Asymmetric"; rv = pk_delete_keys(kmfhandle, attrlist, num, keytype, &nk); numkeys += nk; } if (oclass & PK_SYMKEY_OBJ) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; keytype = "symmetric"; rv = pk_delete_keys(kmfhandle, attrlist, num, keytype, &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && numkeys > 0) rv = KMF_OK; } if (rv == KMF_OK && numkeys == 0) rv = KMF_ERR_KEY_NOT_FOUND; return (rv); } static KMF_RETURN delete_file_crl(void *kmfhandle, char *filename) { KMF_RETURN rv; int numattr = 0; KMF_ATTRIBUTE attrlist[4]; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; if (filename == NULL || strlen(filename) == 0) return (KMF_ERR_BAD_PARAMETER); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (filename) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_FILENAME_ATTR, filename, strlen(filename)); numattr++; } rv = kmf_delete_crl(kmfhandle, numattr, attrlist); return (rv); } /* * Delete token objects. */ int pk_delete(int argc, char *argv[]) { int opt; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *subject = NULL; char *issuer = NULL; char *dir = NULL; char *prefix = NULL; char *infile = NULL; char *object_label = NULL; char *serstr = NULL; int oclass = 0; KMF_BIGINT serial = { NULL, 0 }; KMF_HANDLE_T kmfhandle = NULL; KMF_KEYSTORE_TYPE kstype = 0; KMF_RETURN kmfrv, keyrv, certrv, crlrv; int rv = 0; char *find_criteria = NULL; KMF_CERT_VALIDITY find_criteria_flag = KMF_ALL_CERTS; KMF_CREDENTIAL tokencred = { NULL, 0 }; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "T:(token)y:(objtype)l:(label)" "k:(keystore)s:(subject)n:(nickname)" "d:(dir)p:(prefix)S:(serial)i:(issuer)" "c:(criteria)" "f:(infile)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = optarg_av; break; case 'y': /* object type: public, private, both */ if (oclass) return (PK_ERR_USAGE); oclass = OT2Int(optarg_av); if (oclass == -1) return (PK_ERR_USAGE); break; case 'l': /* objects with specific label */ case 'n': if (object_label) return (PK_ERR_USAGE); object_label = (char *)optarg_av; break; case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 's': subject = optarg_av; break; case 'i': issuer = optarg_av; break; case 'd': dir = optarg_av; break; case 'p': prefix = optarg_av; break; case 'S': serstr = optarg_av; break; case 'f': infile = optarg_av; break; case 'c': find_criteria = optarg_av; if (!strcasecmp(find_criteria, "valid")) find_criteria_flag = KMF_NONEXPIRED_CERTS; else if (!strcasecmp(find_criteria, "expired")) find_criteria_flag = KMF_EXPIRED_CERTS; else if (!strcasecmp(find_criteria, "both")) find_criteria_flag = KMF_ALL_CERTS; else return (PK_ERR_USAGE); break; default: return (PK_ERR_USAGE); } } /* Assume keystore = PKCS#11 if not specified */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && kstype != KMF_KEYSTORE_PK11TOKEN) { (void) fprintf(stderr, gettext("The objtype parameter " "is only relevant if keystore=pkcs11\n")); return (PK_ERR_USAGE); } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) return (PK_ERR_USAGE); /* Done parsing command line options. */ DIR_OPTION_CHECK(kstype, dir); if (kstype == KMF_KEYSTORE_PK11TOKEN && token_spec == NULL) { token_spec = PK_DEFAULT_PK11TOKEN; } else if (kstype == KMF_KEYSTORE_NSS && token_spec == NULL) { token_spec = DEFAULT_NSS_TOKEN; } if (serstr != NULL) { 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")); return (PK_ERR_USAGE); } serial.val = bytes; serial.len = bytelen; /* If serial number was given, it must be a cert search */ if (oclass == 0) oclass = PK_CERT_OBJ; } /* * If no object type was given but subject or issuer was, * it must be a certificate we are looking to delete. */ if ((issuer != NULL || subject != NULL) && oclass == 0) oclass = PK_CERT_OBJ; /* If no object class specified, delete everything but CRLs */ if (oclass == 0) oclass = PK_CERT_OBJ | PK_KEY_OBJ; if ((kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS) && (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ))) { (void) get_token_password(kstype, token_spec, &tokencred); } if ((kmfrv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) return (kmfrv); keyrv = certrv = crlrv = KMF_OK; switch (kstype) { case KMF_KEYSTORE_PK11TOKEN: if (oclass & PK_KEY_OBJ) { keyrv = delete_pk11_keys(kmfhandle, token_spec, oclass, object_label, &tokencred); /* * If deleting groups of objects, it is OK * to ignore the "key not found" case so that * we can continue to find other objects. */ if (keyrv != KMF_OK && keyrv != KMF_ERR_KEY_NOT_FOUND) break; } if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { certrv = delete_pk11_certs(kmfhandle, token_spec, object_label, &serial, issuer, subject, find_criteria_flag); /* * If cert delete failed, but we are looking at * other objects, then it is OK. */ if (certrv != KMF_OK && certrv != KMF_ERR_CERT_NOT_FOUND) break; } if (oclass & PK_CRL_OBJ) crlrv = delete_file_crl(kmfhandle, infile); break; case KMF_KEYSTORE_NSS: keyrv = certrv = crlrv = KMF_OK; if (oclass & PK_KEY_OBJ) { keyrv = delete_nss_keys(kmfhandle, dir, prefix, token_spec, oclass, (char *)object_label, &tokencred); if (keyrv != KMF_OK && keyrv != KMF_ERR_KEY_NOT_FOUND) break; } if (oclass & PK_CERT_OBJ) { certrv = delete_nss_certs(kmfhandle, dir, prefix, token_spec, (char *)object_label, &serial, issuer, subject, find_criteria_flag); if (certrv != KMF_OK && certrv != KMF_ERR_CERT_NOT_FOUND) break; } if (oclass & PK_CRL_OBJ) crlrv = delete_nss_crl(kmfhandle, dir, prefix, token_spec, (char *)object_label, subject); break; case KMF_KEYSTORE_OPENSSL: if (oclass & PK_KEY_OBJ) { keyrv = delete_file_keys(kmfhandle, oclass, dir, infile); if (keyrv != KMF_OK) break; } if (oclass & (PK_CERT_OBJ)) { certrv = delete_file_certs(kmfhandle, dir, infile, &serial, issuer, subject, find_criteria_flag); if (certrv != KMF_OK) break; } if (oclass & PK_CRL_OBJ) crlrv = delete_file_crl(kmfhandle, infile); break; default: rv = PK_ERR_USAGE; break; } /* * Logic here: * If searching for more than just one class of object (key or cert) * and only 1 of the classes was not found, it is not an error. * If searching for just one class of object, that failure should * be reported. * * Any error other than "KMF_ERR_[key/cert]_NOT_FOUND" should * be reported either way. */ if (keyrv != KMF_ERR_KEY_NOT_FOUND && keyrv != KMF_OK) kmfrv = keyrv; else if (certrv != KMF_OK && certrv != KMF_ERR_CERT_NOT_FOUND) kmfrv = certrv; else if (crlrv != KMF_OK && crlrv != KMF_ERR_CRL_NOT_FOUND) kmfrv = crlrv; /* * If nothing was found, return error. */ if ((keyrv == KMF_ERR_KEY_NOT_FOUND && (oclass & PK_KEY_OBJ)) && (certrv == KMF_ERR_CERT_NOT_FOUND && (oclass & PK_CERT_OBJ))) kmfrv = KMF_ERR_KEY_NOT_FOUND; if (kmfrv != KMF_OK) goto out; if (keyrv != KMF_OK && (oclass == PK_KEY_OBJ)) kmfrv = keyrv; else if (certrv != KMF_OK && (oclass == PK_CERT_OBJ)) kmfrv = certrv; else if (crlrv != KMF_OK && (oclass == PK_CRL_OBJ)) kmfrv = crlrv; out: if (kmfrv != KMF_OK) { display_error(kmfhandle, kmfrv, gettext("Error deleting objects")); } if (serial.val != NULL) free(serial.val); (void) kmf_finalize(kmfhandle); return (kmfrv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include "common.h" #include int pk_download(int argc, char *argv[]) { int rv; int opt; extern int optind_av; extern char *optarg_av; int oclass = 0; char *url = NULL; char *http_proxy = NULL; char *dir = NULL; char *outfile = NULL; char *proxy = NULL; int proxy_port = 0; KMF_HANDLE_T kmfhandle = NULL; KMF_ENCODE_FORMAT format; KMF_RETURN ch_rv = KMF_OK; char *fullpath = NULL; KMF_DATA cert = { 0, NULL }; KMF_DATA cert_der = { 0, NULL }; while ((opt = getopt_av(argc, argv, "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 't': if (oclass) return (PK_ERR_USAGE); oclass = OT2Int(optarg_av); if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ))) return (PK_ERR_USAGE); break; case 'u': if (url) return (PK_ERR_USAGE); url = optarg_av; break; case 'h': if (http_proxy) return (PK_ERR_USAGE); http_proxy = optarg_av; break; case 'o': if (outfile) return (PK_ERR_USAGE); outfile = optarg_av; break; case 'd': if (dir) return (PK_ERR_USAGE); dir = optarg_av; break; default: cryptoerror(LOG_STDERR, gettext( "unrecognized download 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); } /* Check the dir and outfile options */ if (outfile == NULL) { /* If outfile is not specified, use the basename of URI */ outfile = basename(url); } fullpath = get_fullpath(dir, outfile); if (fullpath == NULL) { cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile " "option value \n")); return (PK_ERR_USAGE); } /* Check if the file exists and might be overwritten. */ if (verify_file(fullpath) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Warning: file \"%s\" exists, " "will be overwritten."), fullpath); if (yesno(gettext("Continue with download? "), gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { return (0); } } /* URI MUST be specified */ if (url == NULL) { cryptoerror(LOG_STDERR, gettext("A URL must be specified\n")); rv = PK_ERR_USAGE; goto end; } /* * Get the http proxy from the command "http_proxy" option or the * environment variable. The command option has a higher priority. */ if (http_proxy == NULL) http_proxy = getenv("http_proxy"); if (http_proxy != NULL) { char *ptmp = http_proxy; char *proxy_port_s; if (strncasecmp(ptmp, "http://", 7) == 0) ptmp += 7; /* skip the scheme prefix */ proxy = strtok(ptmp, ":"); proxy_port_s = strtok(NULL, "\0"); if (proxy_port_s != NULL) proxy_port = strtol(proxy_port_s, NULL, 0); else proxy_port = 8080; } /* If objtype is not specified, default to CRL */ if (oclass == 0) { oclass = PK_CRL_OBJ; } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); rv = PK_ERR_USAGE; goto end; } /* Now we are ready to download */ if (oclass & PK_CRL_OBJ) { rv = kmf_download_crl(kmfhandle, url, proxy, proxy_port, 30, fullpath, &format); } else if (oclass & PK_CERT_OBJ) { rv = kmf_download_cert(kmfhandle, url, proxy, proxy_port, 30, fullpath, &format); } if (rv != KMF_OK) { switch (rv) { case KMF_ERR_BAD_URI: cryptoerror(LOG_STDERR, gettext("Error in parsing URI\n")); rv = PK_ERR_USAGE; break; case KMF_ERR_OPEN_FILE: cryptoerror(LOG_STDERR, gettext("Error in opening file\n")); rv = PK_ERR_USAGE; break; case KMF_ERR_WRITE_FILE: cryptoerror(LOG_STDERR, gettext("Error in writing file\n")); rv = PK_ERR_USAGE; break; case KMF_ERR_BAD_CRLFILE: cryptoerror(LOG_STDERR, gettext("Not a CRL file\n")); rv = PK_ERR_USAGE; break; case KMF_ERR_BAD_CERTFILE: cryptoerror(LOG_STDERR, gettext("Not a certificate file\n")); rv = PK_ERR_USAGE; break; case KMF_ERR_MEMORY: cryptoerror(LOG_STDERR, gettext("Not enough memory\n")); rv = PK_ERR_SYSTEM; break; default: cryptoerror(LOG_STDERR, gettext("Error in downloading the file.\n")); rv = PK_ERR_SYSTEM; break; } goto end; } /* * If the file is successfully downloaded, we also check the date. * If the downloaded file is outdated, give a warning. */ if (oclass & PK_CRL_OBJ) { ch_rv = kmf_check_crl_date(kmfhandle, fullpath); } else { /* certificate */ ch_rv = kmf_read_input_file(kmfhandle, fullpath, &cert); if (ch_rv != KMF_OK) goto end; if (format == KMF_FORMAT_PEM) { int len; ch_rv = kmf_pem_to_der(cert.Data, cert.Length, &cert_der.Data, &len); if (ch_rv != KMF_OK) goto end; cert_der.Length = (size_t)len; } ch_rv = kmf_check_cert_date(kmfhandle, format == KMF_FORMAT_ASN1 ? &cert : &cert_der); } end: if (ch_rv == KMF_ERR_VALIDITY_PERIOD) { cryptoerror(LOG_STDERR, gettext("Warning: the downloaded file is expired.\n")); } else if (ch_rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Warning: failed to check the validity.\n")); } if (fullpath) free(fullpath); kmf_free_data(&cert); kmf_free_data(&cert_der); (void) kmf_finalize(kmfhandle); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * This file implements the export operation for this tool. * The basic flow of the process is to find the soft token, * log into it, find the PKCS#11 objects in the soft token * to be exported matching keys with their certificates, export * them to the PKCS#12 file encrypting them with a file password * if desired, and log out. */ #include #include #include #include #include #include "common.h" #include static KMF_RETURN pk_find_export_cert(KMF_HANDLE_T kmfhandle, KMF_ATTRIBUTE *attrlist, int numattr, KMF_X509_DER_CERT *cert) { KMF_RETURN rv = KMF_OK; uint32_t numcerts = 0; numcerts = 0; (void) memset(cert, 0, sizeof (KMF_X509_DER_CERT)); kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &numcerts, sizeof (uint32_t)); numattr++; rv = kmf_find_cert(kmfhandle, numattr, attrlist); if (rv != KMF_OK) { return (rv); } if (numcerts == 0) { cryptoerror(LOG_STDERR, gettext("No matching certificates found.")); return (KMF_ERR_CERT_NOT_FOUND); } else if (numcerts == 1) { kmf_set_attr_at_index(attrlist, numattr, KMF_X509_DER_CERT_ATTR, cert, sizeof (KMF_X509_DER_CERT)); numattr++; rv = kmf_find_cert(kmfhandle, numattr, attrlist); } else if (numcerts > 1) { cryptoerror(LOG_STDERR, gettext("%d certificates found, refine the " "search parameters to eliminate ambiguity\n"), numcerts); return (KMF_ERR_BAD_PARAMETER); } return (rv); } static KMF_RETURN pk_export_file_objects(KMF_HANDLE_T kmfhandle, int oclass, char *issuer, char *subject, KMF_BIGINT *serial, char *infile, char *filename) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT kmfcert; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; /* If searching for public objects or certificates, find certs now */ if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (infile != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, infile, strlen(infile)); numattr++; } rv = pk_find_export_cert(kmfhandle, attrlist, numattr, &kmfcert); if (rv == KMF_OK) { kstype = KMF_KEYSTORE_OPENSSL; 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, &kmfcert.certificate, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); numattr++; rv = kmf_store_cert(kmfhandle, numattr, attrlist); kmf_free_kmf_cert(kmfhandle, &kmfcert); } } return (rv); } static KMF_RETURN pk_export_pk12_nss(KMF_HANDLE_T kmfhandle, char *token_spec, char *dir, char *prefix, char *certlabel, char *issuer, char *subject, KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred, char *filename) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype; KMF_CREDENTIAL p12cred = { NULL, 0 }; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); if (token_spec == NULL) token_spec = DEFAULT_NSS_TOKEN; kstype = KMF_KEYSTORE_NSS; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (certlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (tokencred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; (void) get_pk12_password(&p12cred); kmf_set_attr_at_index(attrlist, numattr, KMF_PK12CRED_ATTR, &p12cred, sizeof (KMF_CREDENTIAL)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_OUTPUT_FILENAME_ATTR, filename, strlen(filename)); numattr++; rv = kmf_export_pk12(kmfhandle, numattr, attrlist); if (p12cred.cred) free(p12cred.cred); return (rv); } static KMF_RETURN pk_export_pk12_files(KMF_HANDLE_T kmfhandle, char *certfile, char *keyfile, char *outfile) { KMF_RETURN rv; KMF_KEYSTORE_TYPE kstype; KMF_CREDENTIAL p12cred = { NULL, 0 }; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; kstype = KMF_KEYSTORE_OPENSSL; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (certfile != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, certfile, strlen(certfile)); numattr++; } if (keyfile != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, keyfile, strlen(keyfile)); numattr++; } (void) get_pk12_password(&p12cred); kmf_set_attr_at_index(attrlist, numattr, KMF_PK12CRED_ATTR, &p12cred, sizeof (KMF_CREDENTIAL)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_OUTPUT_FILENAME_ATTR, outfile, strlen(outfile)); numattr++; rv = kmf_export_pk12(kmfhandle, numattr, attrlist); if (p12cred.cred) free(p12cred.cred); return (rv); } static KMF_RETURN pk_export_nss_objects(KMF_HANDLE_T kmfhandle, char *token_spec, int oclass, char *certlabel, char *issuer, char *subject, KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt, char *dir, char *prefix, char *filename) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT kmfcert; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); /* If searching for public objects or certificates, find certs now */ if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (certlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } rv = pk_find_export_cert(kmfhandle, attrlist, numattr, &kmfcert); if (rv == KMF_OK) { kstype = KMF_KEYSTORE_OPENSSL; 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, &kmfcert.certificate, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &kfmt, sizeof (kfmt)); numattr++; rv = kmf_store_cert(kmfhandle, numattr, attrlist); kmf_free_kmf_cert(kmfhandle, &kmfcert); } } return (rv); } static KMF_RETURN pk_export_pk12_pk11(KMF_HANDLE_T kmfhandle, char *token_spec, char *certlabel, char *issuer, char *subject, KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred, char *filename) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype; KMF_CREDENTIAL p12cred = { NULL, 0 }; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; rv = select_token(kmfhandle, token_spec, TRUE); if (rv != KMF_OK) { return (rv); } kstype = KMF_KEYSTORE_PK11TOKEN; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (certlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (tokencred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } (void) get_pk12_password(&p12cred); kmf_set_attr_at_index(attrlist, numattr, KMF_PK12CRED_ATTR, &p12cred, sizeof (KMF_CREDENTIAL)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_OUTPUT_FILENAME_ATTR, filename, strlen(filename)); numattr++; rv = kmf_export_pk12(kmfhandle, numattr, attrlist); if (p12cred.cred) free(p12cred.cred); return (rv); } static KMF_RETURN pk_export_pk11_keys(KMF_HANDLE_T kmfhandle, char *token, KMF_CREDENTIAL *cred, KMF_ENCODE_FORMAT format, char *label, char *filename, int oclass) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_KEY_CLASS kclass = KMF_KEYCLASS_NONE; int numattr = 0; uint32_t numkeys = 1; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_HANDLE key; boolean_t is_token = B_TRUE; if (EMPTYSTRING(label)) { cryptoerror(LOG_STDERR, gettext("A label " "must be specified to export a key.")); return (KMF_ERR_BAD_PARAMETER); } rv = select_token(kmfhandle, token, TRUE); if (rv != KMF_OK) { return (rv); } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, label, strlen(label)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &numkeys, sizeof (numkeys)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &key, sizeof (key)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR, &is_token, sizeof (is_token)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); numattr++; /* Check to see if we are exporting private or public only */ if ((oclass & PK_KEY_OBJ) == PK_PRIKEY_OBJ) kclass = KMF_ASYM_PRI; else if ((oclass & PK_KEY_OBJ) == PK_PUBKEY_OBJ) kclass = KMF_ASYM_PUB; else if ((oclass & PK_KEY_OBJ) == PK_SYMKEY_OBJ) kclass = KMF_SYMMETRIC; else /* only 1 key at a time can be exported here, so default to pri */ kclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, &kclass, sizeof (kclass)); numattr++; rv = kmf_find_key(kmfhandle, numattr, attrlist); /* * If nothing found but caller wanted ALL keys, try symmetric * this time. */ if (rv == KMF_ERR_KEY_NOT_FOUND && (oclass == PK_KEY_OBJ)) { kclass = KMF_SYMMETRIC; rv = kmf_find_key(kmfhandle, numattr, attrlist); } /* * If nothing found but caller wanted ALL keys, try asymmetric * public this time. */ if (rv == KMF_ERR_KEY_NOT_FOUND && (oclass == PK_KEY_OBJ)) { kclass = KMF_ASYM_PUB; rv = kmf_find_key(kmfhandle, numattr, attrlist); } if (rv == KMF_OK && key.keyclass == KMF_SYMMETRIC) { KMF_RAW_SYM_KEY rkey; (void) memset(&rkey, 0, sizeof (KMF_RAW_SYM_KEY)); rv = kmf_get_sym_key_value(kmfhandle, &key, &rkey); if (rv == KMF_OK) { int fd, n, total = 0; fd = open(filename, O_CREAT | O_RDWR |O_TRUNC, 0600); if (fd == -1) { rv = KMF_ERR_OPEN_FILE; goto done; } do { n = write(fd, rkey.keydata.val + total, rkey.keydata.len - total); if (n < 0) { if (errno == EINTR) continue; (void) close(fd); rv = KMF_ERR_WRITE_FILE; goto done; } total += n; } while (total < rkey.keydata.len); (void) close(fd); } done: kmf_free_bigint(&rkey.keydata); kmf_free_kmf_key(kmfhandle, &key); } else if (rv == KMF_OK) { KMF_KEYSTORE_TYPE sslks = KMF_KEYSTORE_OPENSSL; (void) printf(gettext("Found %d asymmetric keys\n"), numkeys); numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &sslks, sizeof (sslks)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_RAW_KEY_ATTR, key.keyp, sizeof (KMF_RAW_KEY_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, filename, strlen(filename)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, &key.keyclass, sizeof (KMF_KEY_CLASS)); numattr++; rv = kmf_store_key(kmfhandle, numattr, attrlist); kmf_free_kmf_key(kmfhandle, &key); } return (rv); } static KMF_RETURN pk_export_pk11_objects(KMF_HANDLE_T kmfhandle, char *token_spec, KMF_CREDENTIAL *cred, char *certlabel, char *issuer, char *subject, KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt, char *filename) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT kmfcert; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; rv = select_token(kmfhandle, token_spec, TRUE); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL)); numattr++; } if (certlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } rv = pk_find_export_cert(kmfhandle, attrlist, numattr, &kmfcert); if (rv == KMF_OK) { kstype = KMF_KEYSTORE_OPENSSL; 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, &kmfcert.certificate, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &kfmt, sizeof (kfmt)); numattr++; rv = kmf_store_cert(kmfhandle, numattr, attrlist); kmf_free_kmf_cert(kmfhandle, &kmfcert); } return (rv); } /* * Export objects from one keystore to a file. */ int pk_export(int argc, char *argv[]) { int opt; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *filename = NULL; char *dir = NULL; char *prefix = NULL; char *certlabel = NULL; char *subject = NULL; char *issuer = NULL; char *infile = NULL; char *keyfile = NULL; char *certfile = NULL; char *serstr = NULL; KMF_KEYSTORE_TYPE kstype = 0; KMF_ENCODE_FORMAT kfmt = KMF_FORMAT_PKCS12; KMF_RETURN rv = KMF_OK; int oclass = PK_CERT_OBJ; KMF_BIGINT serial = { NULL, 0 }; KMF_HANDLE_T kmfhandle = NULL; KMF_CREDENTIAL tokencred = { NULL, 0 }; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "k:(keystore)y:(objtype)T:(token)" "d:(dir)p:(prefix)" "l:(label)n:(nickname)s:(subject)" "i:(issuer)S:(serial)" "K:(keyfile)c:(certfile)" "F:(outformat)" "I:(infile)o:(outfile)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 'y': oclass = OT2Int(optarg_av); if (oclass == -1) return (PK_ERR_USAGE); break; case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = 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 'n': case 'l': if (certlabel) return (PK_ERR_USAGE); certlabel = optarg_av; break; case 's': if (subject) return (PK_ERR_USAGE); subject = optarg_av; break; case 'i': if (issuer) return (PK_ERR_USAGE); issuer = optarg_av; break; case 'S': serstr = optarg_av; break; case 'F': kfmt = Str2Format(optarg_av); if (kfmt == KMF_FORMAT_UNDEF) return (PK_ERR_USAGE); break; case 'I': /* output file name */ if (infile) return (PK_ERR_USAGE); infile = optarg_av; break; case 'o': /* output file name */ if (filename) return (PK_ERR_USAGE); filename = optarg_av; break; case 'c': /* input cert file name */ if (certfile) return (PK_ERR_USAGE); certfile = optarg_av; break; case 'K': /* input key file name */ if (keyfile) return (PK_ERR_USAGE); keyfile = optarg_av; break; default: return (PK_ERR_USAGE); } } /* Assume keystore = PKCS#11 if not specified */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; /* Filename arg is required. */ if (EMPTYSTRING(filename)) { cryptoerror(LOG_STDERR, gettext("You must specify " "an 'outfile' parameter when exporting.\n")); return (PK_ERR_USAGE); } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) return (PK_ERR_USAGE); DIR_OPTION_CHECK(kstype, dir); /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && kstype != KMF_KEYSTORE_PK11TOKEN) { (void) fprintf(stderr, gettext("The objtype parameter " "is only relevant if keystore=pkcs11\n")); return (PK_ERR_USAGE); } if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) token_spec = PK_DEFAULT_PK11TOKEN; else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) token_spec = DEFAULT_NSS_TOKEN; if (kstype == KMF_KEYSTORE_OPENSSL) { if (kfmt != KMF_FORMAT_PKCS12) { cryptoerror(LOG_STDERR, gettext("PKCS12 " "is the only export format " "supported for the 'file' " "keystore.\n")); return (PK_ERR_USAGE); } if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) { cryptoerror(LOG_STDERR, gettext("A cert file" "and a key file must be specified " "when exporting to PKCS12 from the " "'file' keystore.\n")); return (PK_ERR_USAGE); } } /* Check if the file exists */ if (verify_file(filename) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Warning: file \"%s\" exists, " "will be overwritten."), filename); if (yesno(gettext("Continue with export? "), gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { return (0); } else { /* remove the file */ (void) unlink(filename); } } if (serstr != NULL) { 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")); return (PK_ERR_USAGE); } serial.val = bytes; serial.len = bytelen; } /* * We need a password in the following situations: * 1. When accessing PKCS11 token * 2. If NSS keystore, when making a PKCS12 file or when * accessing any private object or key. */ if (kstype == KMF_KEYSTORE_PK11TOKEN || ((kstype == KMF_KEYSTORE_NSS) && ((oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ)) || (kfmt == KMF_FORMAT_PKCS12)))) { (void) get_token_password(kstype, token_spec, &tokencred); } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing " "KMF: 0x%02x\n"), rv); return (rv); } switch (kstype) { case KMF_KEYSTORE_PK11TOKEN: if (kfmt == KMF_FORMAT_PKCS12) rv = pk_export_pk12_pk11(kmfhandle, token_spec, certlabel, issuer, subject, &serial, &tokencred, filename); else if ((oclass & PK_KEY_OBJ) || kfmt == KMF_FORMAT_RAWKEY) rv = pk_export_pk11_keys(kmfhandle, token_spec, &tokencred, kfmt, certlabel, filename, oclass); else rv = pk_export_pk11_objects(kmfhandle, token_spec, &tokencred, certlabel, issuer, subject, &serial, kfmt, filename); break; case KMF_KEYSTORE_NSS: if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; if (kfmt == KMF_FORMAT_PKCS12) rv = pk_export_pk12_nss(kmfhandle, token_spec, dir, prefix, certlabel, issuer, subject, &serial, &tokencred, filename); else rv = pk_export_nss_objects(kmfhandle, token_spec, oclass, certlabel, issuer, subject, &serial, kfmt, dir, prefix, filename); break; case KMF_KEYSTORE_OPENSSL: if (kfmt == KMF_FORMAT_PKCS12) rv = pk_export_pk12_files(kmfhandle, certfile, keyfile, filename); else rv = pk_export_file_objects(kmfhandle, oclass, issuer, subject, &serial, infile, filename); break; default: rv = PK_ERR_USAGE; break; } if (rv != KMF_OK) { display_error(kmfhandle, rv, gettext("Error exporting objects")); } if (serial.val != NULL) free(serial.val); (void) kmf_finalize(kmfhandle); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include "common.h" #include #define SET_VALUE(f, s) { \ kmfrv = f; \ if (kmfrv != KMF_OK) { \ cryptoerror(LOG_STDERR, \ gettext("Failed to set %s: 0x%02x\n"), \ s, kmfrv); \ goto cleanup; \ } \ } 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, 0, 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); } static int gencert_file(KMF_HANDLE_T kmfhandle, KMF_KEY_ALG keyAlg, KMF_ALGORITHM_INDEX sigAlg, int keylen, KMF_ENCODE_FORMAT fmt, uint32_t ltime, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, KMF_BIGINT *serial, uint16_t kubits, int kucrit, char *outcert, char *outkey, EKU_LIST *ekulist) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; KMF_X509_CERTIFICATE signedCert; KMF_X509_NAME certSubject; KMF_X509_NAME certIssuer; KMF_DATA x509DER; char *fullcertpath = NULL; char *fullkeypath = NULL; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; KMF_ATTRIBUTE attrlist[10]; int numattr = 0; (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 (EMPTYSTRING(outcert) || EMPTYSTRING(outkey)) { cryptoerror(LOG_STDERR, gettext("No output file was specified for " "the cert or key\n")); return (PK_ERR_USAGE); } fullcertpath = strdup(outcert); if (verify_file(fullcertpath)) { cryptoerror(LOG_STDERR, gettext("Cannot write the indicated output " "certificate file (%s).\n"), fullcertpath); free(fullcertpath); return (PK_ERR_USAGE); } /* 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 (%s)\n"), subject); 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 (%s)\n"), subject); kmf_free_dn(&certSubject); return (PK_ERR_USAGE); } /* * 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_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, 0, 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++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, fullcertpath, strlen(fullcertpath)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &fmt, sizeof (fmt)); numattr++; kmfrv = kmf_store_cert(kmfhandle, numattr, attrlist); cleanup: if (fullkeypath != NULL) free(fullkeypath); if (fullcertpath != NULL) free(fullcertpath); kmf_free_data(&x509DER); kmf_free_dn(&certSubject); kmf_free_dn(&certIssuer); return (kmfrv); } 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, 0, 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); } 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); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include "common.h" #include #define SET_VALUE(f, s) \ kmfrv = f; \ if (kmfrv != KMF_OK) { \ cryptoerror(LOG_STDERR, \ gettext("Failed to %s: 0x%02\n"), \ s, kmfrv); \ goto cleanup; \ } static KMF_RETURN gencsr_pkcs11(KMF_HANDLE_T kmfhandle, char *token, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, char *certlabel, KMF_KEY_ALG keyAlg, int keylen, uint16_t kubits, int kucrit, KMF_ENCODE_FORMAT fmt, char *csrfile, KMF_CREDENTIAL *tokencred, EKU_LIST *ekulist, KMF_ALGORITHM_INDEX sigAlg, KMF_OID *curveoid) { KMF_RETURN kmfrv = KMF_OK; KMF_KEY_HANDLE pubk, prik; KMF_X509_NAME csrSubject; KMF_CSR_DATA csr; KMF_DATA signedCsr = { 0, NULL }; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; (void) memset(&csr, 0, sizeof (csr)); (void) memset(&csrSubject, 0, sizeof (csrSubject)); /* If the subject name cannot be parsed, flag it now and exit */ if ((kmfrv = kmf_dn_parser(subject, &csrSubject)) != KMF_OK) return (kmfrv); /* 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, keyAlg, keylen, tokencred, curveoid, &prik, &pubk); if (kmfrv != KMF_OK) return (kmfrv); SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "keypair"); SET_VALUE(kmf_set_csr_version(&csr, 2), "version number"); SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), "subject name"); SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "SignatureAlgorithm"); if (altname != NULL) { SET_VALUE(kmf_set_csr_subject_altname(&csr, altname, altcrit, alttype), "SetCSRSubjectAltName"); } if (kubits != 0) { SET_VALUE(kmf_set_csr_ku(&csr, kucrit, kubits), "SetCSRKeyUsage"); } 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, csrfile); } cleanup: (void) kmf_free_data(&signedCsr); (void) kmf_free_signed_csr(&csr); /* 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_PUBKEY_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); /* * If there is an error, then we need to remove the private key * from the token. */ if (kmfrv != KMF_OK) { 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); } (void) kmf_free_kmf_key(kmfhandle, &prik); return (kmfrv); } 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 = { 0, NULL }; 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 != 0) { 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); } static KMF_RETURN gencsr_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, int keylen, uint16_t kubits, int kucrit, KMF_ENCODE_FORMAT fmt, char *csrfile, KMF_CREDENTIAL *tokencred, EKU_LIST *ekulist, KMF_ALGORITHM_INDEX sigAlg, KMF_OID *curveoid) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; KMF_X509_NAME csrSubject; KMF_CSR_DATA csr; KMF_DATA signedCsr = { 0, NULL }; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; if (token == NULL) token = DEFAULT_NSS_TOKEN; kmfrv = configure_nss(kmfhandle, dir, prefix); if (kmfrv != KMF_OK) return (kmfrv); (void) memset(&csr, 0, sizeof (csr)); (void) memset(&csrSubject, 0, sizeof (csrSubject)); (void) memset(&pubk, 0, sizeof (pubk)); (void) memset(&prik, 0, sizeof (prik)); /* If the subject name cannot be parsed, flag it now and exit */ if ((kmfrv = kmf_dn_parser(subject, &csrSubject)) != KMF_OK) { return (kmfrv); } kmfrv = genkeypair_nss(kmfhandle, token, nickname, dir, prefix, keyAlg, keylen, tokencred, curveoid, &prik, &pubk); if (kmfrv != KMF_OK) return (kmfrv); SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "kmf_set_csr_pubkey"); SET_VALUE(kmf_set_csr_version(&csr, 2), "kmf_set_csr_version"); 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 != 0) { 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, csrfile); } cleanup: (void) kmf_free_data(&signedCsr); (void) kmf_free_kmf_key(kmfhandle, &prik); /* delete the 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_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); numattr++; if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } if (token && strlen(token)) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } (void) kmf_delete_key_from_keystore(kmfhandle, numattr, attrlist); (void) kmf_free_signed_csr(&csr); return (kmfrv); } 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); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include "common.h" #include static KMF_RETURN genkey_nss(KMF_HANDLE_T kmfhandle, char *token, char *dir, char *prefix, char *keylabel, KMF_KEY_ALG keyAlg, int keylen, KMF_CREDENTIAL *tokencred) { KMF_RETURN kmfrv = KMF_OK; KMF_KEY_HANDLE key; KMF_ATTRIBUTE attlist[20]; int i = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; KMF_KEY_ALG keytype; uint32_t keylength; if (keylabel == NULL) { cryptoerror(LOG_STDERR, gettext("A key label must be specified \n")); return (KMF_ERR_BAD_PARAMETER); } kmfrv = configure_nss(kmfhandle, dir, prefix); if (kmfrv != KMF_OK) return (kmfrv); (void) memset(&key, 0, sizeof (KMF_KEY_HANDLE)); keytype = keyAlg; keylength = keylen; kmf_set_attr_at_index(attlist, i, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); i++; kmf_set_attr_at_index(attlist, i, KMF_KEY_HANDLE_ATTR, &key, sizeof (KMF_KEY_HANDLE)); i++; kmf_set_attr_at_index(attlist, i, KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); i++; kmf_set_attr_at_index(attlist, i, KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength)); i++; if (keylabel != NULL) { kmf_set_attr_at_index(attlist, i, KMF_KEYLABEL_ATTR, keylabel, strlen(keylabel)); i++; } if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attlist, i, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); i++; } if (token != NULL) { kmf_set_attr_at_index(attlist, i, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); i++; } kmfrv = kmf_create_sym_key(kmfhandle, i, attlist); return (kmfrv); } static KMF_RETURN genkey_pkcs11(KMF_HANDLE_T kmfhandle, char *token, char *keylabel, KMF_KEY_ALG keyAlg, int keylen, char *senstr, char *extstr, boolean_t print_hex, KMF_CREDENTIAL *tokencred) { KMF_RETURN kmfrv = KMF_OK; KMF_KEY_HANDLE key; KMF_RAW_SYM_KEY *rkey = NULL; boolean_t sensitive = B_FALSE; boolean_t not_extractable = B_FALSE; char *hexstr = NULL; int hexstrlen; KMF_ATTRIBUTE attlist[20]; int i = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_KEY_ALG keytype; uint32_t keylength; if (keylabel == NULL) { cryptoerror(LOG_STDERR, gettext("A key label must be specified \n")); return (KMF_ERR_BAD_PARAMETER); } /* Check the sensitive option value if specified. */ if (senstr != NULL) { if (tolower(senstr[0]) == 'y') sensitive = B_TRUE; else if (tolower(senstr[0]) == 'n') sensitive = B_FALSE; else { cryptoerror(LOG_STDERR, gettext("Incorrect sensitive option value.\n")); return (KMF_ERR_BAD_PARAMETER); } } /* Check the extractable option value if specified. */ if (extstr != NULL) { if (tolower(extstr[0]) == 'y') not_extractable = B_FALSE; else if (tolower(extstr[0]) == 'n') not_extractable = B_TRUE; else { cryptoerror(LOG_STDERR, gettext("Incorrect extractable option value.\n")); return (KMF_ERR_BAD_PARAMETER); } } /* Select a PKCS11 token first */ kmfrv = select_token(kmfhandle, token, FALSE); if (kmfrv != KMF_OK) { return (kmfrv); } (void) memset(&key, 0, sizeof (KMF_KEY_HANDLE)); keytype = keyAlg; keylength = keylen; /* bits */ kmf_set_attr_at_index(attlist, i, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); i++; kmf_set_attr_at_index(attlist, i, KMF_KEY_HANDLE_ATTR, &key, sizeof (KMF_KEY_HANDLE)); i++; kmf_set_attr_at_index(attlist, i, KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); i++; kmf_set_attr_at_index(attlist, i, KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength)); i++; if (keylabel != NULL) { kmf_set_attr_at_index(attlist, i, KMF_KEYLABEL_ATTR, keylabel, strlen(keylabel)); i++; } if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attlist, i, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); i++; } kmf_set_attr_at_index(attlist, i, KMF_SENSITIVE_BOOL_ATTR, &sensitive, sizeof (sensitive)); i++; kmf_set_attr_at_index(attlist, i, KMF_NON_EXTRACTABLE_BOOL_ATTR, ¬_extractable, sizeof (not_extractable)); i++; kmfrv = kmf_create_sym_key(kmfhandle, i, attlist); if (kmfrv != KMF_OK) { goto out; } if (print_hex) { if (sensitive == B_TRUE || not_extractable == B_TRUE) { cryptoerror(LOG_STDERR, gettext("Warning: can not reveal the key value " "for a sensitive or non-extractable key.\n")); goto out; } else { rkey = malloc(sizeof (KMF_RAW_SYM_KEY)); if (rkey == NULL) { kmfrv = KMF_ERR_MEMORY; goto out; } (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY)); kmfrv = kmf_get_sym_key_value(kmfhandle, &key, rkey); if (kmfrv != KMF_OK) { goto out; } hexstrlen = 2 * rkey->keydata.len + 1; hexstr = malloc(hexstrlen); if (hexstr == NULL) { kmfrv = KMF_ERR_MEMORY; goto out; } tohexstr(rkey->keydata.val, rkey->keydata.len, hexstr, hexstrlen); (void) printf(gettext("\tKey Value =\"%s\"\n"), hexstr); } } out: kmf_free_raw_sym_key(rkey); if (hexstr != NULL) free(hexstr); return (kmfrv); } static KMF_RETURN genkey_file(KMF_HANDLE_T kmfhandle, KMF_KEY_ALG keyAlg, int keylen, char *dir, char *outkey, boolean_t print_hex) { KMF_RETURN kmfrv = KMF_OK; KMF_KEY_HANDLE key; KMF_RAW_SYM_KEY *rkey = NULL; char *hexstr = NULL; int hexstrlen; KMF_ATTRIBUTE attlist[20]; int i = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; KMF_KEY_ALG keytype; uint32_t keylength; char *dirpath; if (EMPTYSTRING(outkey)) { cryptoerror(LOG_STDERR, gettext("No output key file was specified for the key\n")); return (KMF_ERR_BAD_PARAMETER); } if (verify_file(outkey)) { cryptoerror(LOG_STDERR, gettext("Cannot write the indicated output " "key file (%s).\n"), outkey); return (KMF_ERR_BAD_PARAMETER); } (void) memset(&key, 0, sizeof (KMF_KEY_HANDLE)); keytype = keyAlg; keylength = keylen; dirpath = dir; kmf_set_attr_at_index(attlist, i, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); i++; kmf_set_attr_at_index(attlist, i, KMF_KEY_HANDLE_ATTR, &key, sizeof (KMF_KEY_HANDLE)); i++; kmf_set_attr_at_index(attlist, i, KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); i++; kmf_set_attr_at_index(attlist, i, KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength)); i++; if (dirpath != NULL) { kmf_set_attr_at_index(attlist, i, KMF_DIRPATH_ATTR, dirpath, strlen(dirpath)); i++; } if (outkey != NULL) { kmf_set_attr_at_index(attlist, i, KMF_KEY_FILENAME_ATTR, outkey, strlen(outkey)); i++; } kmfrv = kmf_create_sym_key(kmfhandle, i, attlist); if (kmfrv != KMF_OK) { goto out; } if (print_hex) { rkey = malloc(sizeof (KMF_RAW_SYM_KEY)); if (rkey == NULL) { kmfrv = KMF_ERR_MEMORY; goto out; } (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY)); kmfrv = kmf_get_sym_key_value(kmfhandle, &key, rkey); if (kmfrv != KMF_OK) { goto out; } hexstrlen = 2 * rkey->keydata.len + 1; hexstr = malloc(hexstrlen); if (hexstr == NULL) { kmfrv = KMF_ERR_MEMORY; goto out; } tohexstr(rkey->keydata.val, rkey->keydata.len, hexstr, hexstrlen); (void) printf(gettext("\tKey Value =\"%s\"\n"), hexstr); } out: kmf_free_raw_sym_key(rkey); if (hexstr != NULL) free(hexstr); return (kmfrv); } int pk_genkey(int argc, char *argv[]) { int rv; int opt; extern int optind_av; extern char *optarg_av; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; char *tokenname = NULL; char *dir = NULL; char *prefix = NULL; char *keytype = "generic"; char *keylenstr = NULL; int keylen = 0; char *keylabel = NULL; char *outkey = NULL; char *senstr = NULL; char *extstr = NULL; char *printstr = NULL; KMF_HANDLE_T kmfhandle = NULL; KMF_KEY_ALG keyAlg = KMF_GENERIC_SECRET; boolean_t print_hex = B_FALSE; KMF_CREDENTIAL tokencred = { NULL, 0 }; while ((opt = getopt_av(argc, argv, "k:(keystore)l:(label)T:(token)d:(dir)p:(prefix)" "t:(keytype)y:(keylen)K:(outkey)P:(print)" "s:(sensitive)e:(extractable)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 'l': if (keylabel) return (PK_ERR_USAGE); keylabel = 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 'y': if (keylenstr) return (PK_ERR_USAGE); keylenstr = optarg_av; break; case 'K': if (outkey) return (PK_ERR_USAGE); outkey = optarg_av; break; case 'P': if (printstr) return (PK_ERR_USAGE); printstr = optarg_av; break; case 's': if (senstr) return (PK_ERR_USAGE); senstr = optarg_av; break; case 'e': if (extstr) return (PK_ERR_USAGE); extstr = optarg_av; break; default: return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) { return (PK_ERR_USAGE); } /* Check keytype. If not specified, default to AES */ if (keytype != NULL && Str2SymKeyType(keytype, &keyAlg) != 0) { cryptoerror(LOG_STDERR, gettext("Unrecognized keytype(%s).\n"), keytype); return (PK_ERR_USAGE); } /* * Check and set the key length. * - For DES and 3DES, the key size are fixed. Ingore the keylen * option, even if it is specified. * - For AES and ARCFOUR, if keylen is not specified, default to * 128 bits. */ if (keyAlg == KMF_DES) keylen = 64; /* fixed size; ignore input */ else if (keyAlg == KMF_DES3) keylen = 192; /* fixed size; ignore input */ else /* AES, ARCFOUR, or GENERIC SECRET */ { if (keylenstr == NULL) { cryptoerror(LOG_STDERR, gettext("Key length must be specified for " "AES, ARCFOUR or GENERIC symmetric keys.\n")); return (PK_ERR_USAGE); } if (sscanf(keylenstr, "%d", &keylen) != 1) { cryptoerror(LOG_STDERR, gettext("Unrecognized key length (%s).\n"), keytype); return (PK_ERR_USAGE); } if (keylen == 0 || (keylen % 8) != 0) { cryptoerror(LOG_STDERR, gettext("Key length bitlength must be a " "multiple of 8.\n")); return (PK_ERR_USAGE); } } /* check the print option */ if (printstr != NULL) { if (kstype == KMF_KEYSTORE_NSS) { cryptoerror(LOG_STDERR, gettext("The print option does not apply " "to the NSS keystore.\n")); return (PK_ERR_USAGE); } if (tolower(printstr[0]) == 'y') print_hex = B_TRUE; else if (tolower(printstr[0]) == 'n') print_hex = B_FALSE; else { cryptoerror(LOG_STDERR, gettext("Incorrect print option value.\n")); return (PK_ERR_USAGE); } } /* check the sensitive and extractable options */ if ((senstr != NULL || extstr != NULL) && (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_OPENSSL)) { cryptoerror(LOG_STDERR, gettext("The sensitive or extractable option applies " "to the PKCS11 keystore only.\n")); return (PK_ERR_USAGE); } if (kstype == KMF_KEYSTORE_PK11TOKEN && tokenname == NULL) { tokenname = PK_DEFAULT_PK11TOKEN; } else if (kstype == KMF_KEYSTORE_NSS && tokenname == NULL) { tokenname = DEFAULT_NSS_TOKEN; } DIR_OPTION_CHECK(kstype, dir); if (kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS) (void) get_token_password(kstype, tokenname, &tokencred); if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); goto end; } if (kstype == KMF_KEYSTORE_NSS) { rv = genkey_nss(kmfhandle, tokenname, dir, prefix, keylabel, keyAlg, keylen, &tokencred); } else if (kstype == KMF_KEYSTORE_OPENSSL) { rv = genkey_file(kmfhandle, keyAlg, keylen, dir, outkey, print_hex); } else { rv = genkey_pkcs11(kmfhandle, tokenname, keylabel, keyAlg, keylen, senstr, extstr, print_hex, &tokencred); } end: if (rv != KMF_OK) display_error(kmfhandle, rv, gettext("Error generating key")); if (tokencred.cred != NULL) free(tokencred.cred); (void) kmf_finalize(kmfhandle); if (rv != KMF_OK) return (PK_ERR_USAGE); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include "common.h" #include #define SET_VALUE(f, s) \ kmfrv = f; \ if (kmfrv != KMF_OK) { \ cryptoerror(LOG_STDERR, \ gettext("Failed to set %s: 0x%02x\n"), \ s, kmfrv); \ goto cleanup; \ } KMF_RETURN genkeypair_pkcs11(KMF_HANDLE_T kmfhandle, char *token, char *keylabel, KMF_KEY_ALG keyAlg, int keylen, KMF_CREDENTIAL *tokencred, KMF_OID *curveoid, KMF_KEY_HANDLE *outPriKey, KMF_KEY_HANDLE *outPubKey) { KMF_RETURN kmfrv = KMF_OK; KMF_KEY_HANDLE pubk, prik; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; KMF_KEY_ALG keytype; uint32_t keylength; keylength = keylen; /* bits */ keytype = keyAlg; /* Select a PKCS11 token */ kmfrv = select_token(kmfhandle, token, FALSE); if (kmfrv != KMF_OK) return (kmfrv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength)); numattr++; if (keylabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, keylabel, strlen(keylabel)); numattr++; } if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); numattr++; if (keytype == KMF_ECDSA && curveoid != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ECC_CURVE_OID_ATTR, curveoid, sizeof (KMF_OID)); numattr++; } kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist); if (kmfrv != KMF_OK) { return (kmfrv); } if (kmfrv == KMF_OK) { if (outPriKey != NULL) *outPriKey = prik; if (outPubKey != NULL) *outPubKey = pubk; } return (kmfrv); } KMF_RETURN genkeypair_file(KMF_HANDLE_T kmfhandle, KMF_KEY_ALG keyAlg, int keylen, KMF_ENCODE_FORMAT fmt, char *outkey, KMF_KEY_HANDLE *outPriKey, KMF_KEY_HANDLE *outPubKey) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; char *fullkeypath = NULL; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; KMF_ATTRIBUTE attrlist[10]; int numattr = 0; KMF_KEY_ALG keytype; uint32_t keylength; KMF_ENCODE_FORMAT format; if (EMPTYSTRING(outkey)) { cryptoerror(LOG_STDERR, gettext("No output file was specified for " "the key\n")); return (PK_ERR_USAGE); } fullkeypath = strdup(outkey); if (verify_file(fullkeypath)) { cryptoerror(LOG_STDERR, gettext("Cannot write the indicated output " "key file (%s).\n"), fullkeypath); free(fullkeypath); return (PK_ERR_USAGE); } keylength = keylen; /* bits */ keytype = keyAlg; format = fmt; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength)); numattr++; if (fullkeypath != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, fullkeypath, strlen(fullkeypath)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); numattr++; kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist); if (kmfrv != KMF_OK) { goto cleanup; } cleanup: if (fullkeypath != NULL) free(fullkeypath); if (kmfrv == KMF_OK) { if (outPriKey != NULL) *outPriKey = prik; if (outPubKey != NULL) *outPubKey = pubk; } return (kmfrv); } KMF_RETURN genkeypair_nss(KMF_HANDLE_T kmfhandle, char *token, char *nickname, char *dir, char *prefix, KMF_KEY_ALG keyAlg, int keylen, KMF_CREDENTIAL *tokencred, KMF_OID *curveoid, KMF_KEY_HANDLE *outPriKey, KMF_KEY_HANDLE *outPubKey) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; KMF_KEY_ALG keytype; uint32_t keylength; if (token == NULL) token = DEFAULT_NSS_TOKEN; kmfrv = configure_nss(kmfhandle, dir, prefix); if (kmfrv != KMF_OK) return (kmfrv); keylength = keylen; /* bits */ keytype = keyAlg; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength)); numattr++; if (nickname != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, nickname, strlen(nickname)); numattr++; } if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } if (token != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); numattr++; if (keytype == KMF_ECDSA && curveoid != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ECC_CURVE_OID_ATTR, curveoid, sizeof (KMF_OID)); numattr++; } kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist); if (kmfrv != KMF_OK) { return (kmfrv); } if (kmfrv == KMF_OK) { if (outPriKey != NULL) *outPriKey = prik; if (outPubKey != NULL) *outPubKey = pubk; } return (kmfrv); } int pk_genkeypair(int argc, char *argv[]) { int rv; int opt; extern int optind_av; extern char *optarg_av; KMF_KEYSTORE_TYPE kstype = 0; char *tokenname = NULL; char *dir = NULL; char *prefix = NULL; char *keytype = PK_DEFAULT_KEYTYPE; int keylen = PK_DEFAULT_KEYLENGTH; char *label = NULL; char *outkey = NULL; char *format = NULL; KMF_HANDLE_T kmfhandle = NULL; KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1; KMF_KEY_ALG keyAlg = KMF_RSA; KMF_ALGORITHM_INDEX sigAlg; KMF_CREDENTIAL tokencred = { NULL, 0 }; KMF_OID *curveoid = NULL; /* ECC */ int y_flag = 0; while ((opt = getopt_av(argc, argv, "k:(keystore)s:(subject)n:(nickname)" "T:(token)d:(dir)p:(prefix)t:(keytype)y:(keylen)" "l:(label)K:(outkey)F:(format)C:(curve)" "E(listcurves)")) != EOF) { if (opt != 'i' && opt != 'E' && EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 'l': case 'n': if (label) return (PK_ERR_USAGE); label = 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 '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 'K': if (outkey) return (PK_ERR_USAGE); outkey = optarg_av; break; case 'F': if (format) return (PK_ERR_USAGE); format = 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': show_ecc_curves(); return (0); 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; 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 (Str2KeyType(keytype, NULL, &keyAlg, &sigAlg) != 0) { cryptoerror(LOG_STDERR, gettext("Unrecognized keytype (%s).\n"), keytype); 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); } 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 && kstype == KMF_KEYSTORE_NSS) { /* NSS only allows for 512-1024 bit DSA keys */ if (!y_flag) /* If nothing was given, default to 1024 */ keylen = 1024; else if (keylen > 1024 || keylen < 512) { (void) fprintf(stderr, gettext("NSS keystore only " "supports DSA keylengths of 512 - 1024 bits\n")); rv = PK_ERR_USAGE; goto end; } } if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) { if (label == NULL) { (void) fprintf(stderr, gettext("No key label specified\n")); rv = PK_ERR_USAGE; goto end; } 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 = genkeypair_nss(kmfhandle, tokenname, label, dir, prefix, keyAlg, keylen, &tokencred, curveoid, NULL, NULL); } else if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = genkeypair_pkcs11(kmfhandle, tokenname, label, keyAlg, keylen, &tokencred, curveoid, NULL, NULL); } else if (kstype == KMF_KEYSTORE_OPENSSL) { rv = genkeypair_file(kmfhandle, keyAlg, keylen, fmt, outkey, NULL, NULL); } if (rv != KMF_OK) display_error(kmfhandle, rv, gettext("Error creating and keypair")); end: if (tokencred.cred != NULL) free(tokencred.cred); (void) kmf_finalize(kmfhandle); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * This file implements the import operation for this tool. * The basic flow of the process is to decrypt the PKCS#12 * input file if it has a password, parse the elements in * the file, find the soft token, log into it, import the * PKCS#11 objects into the soft token, and log out. */ #include #include #include #include #include #include #include #include #include "common.h" #include #define NEW_ATTRLIST(a, n) \ { \ a = (KMF_ATTRIBUTE *)malloc(n * sizeof (KMF_ATTRIBUTE)); \ if (a == NULL) { \ rv = KMF_ERR_MEMORY; \ goto end; \ } \ (void) memset(a, 0, n * sizeof (KMF_ATTRIBUTE)); \ } static KMF_RETURN pk_import_pk12_files(KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *cred, char *outfile, char *certfile, char *keyfile, KMF_ENCODE_FORMAT outformat) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT *certs = NULL; KMF_RAW_KEY_DATA *keys = NULL; int ncerts = 0; int nkeys = 0; int i; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; KMF_ATTRIBUTE *attrlist = NULL; int numattr = 0; rv = kmf_import_objects(kmfhandle, outfile, cred, &certs, &ncerts, &keys, &nkeys); if (rv == KMF_OK) { (void) printf(gettext("Found %d certificate(s) and %d " "key(s) in %s\n"), ncerts, nkeys, outfile); } if (rv == KMF_OK && ncerts > 0) { char newcertfile[MAXPATHLEN]; NEW_ATTRLIST(attrlist, (3 + (3 * ncerts))); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &outformat, sizeof (outformat)); numattr++; for (i = 0; rv == KMF_OK && i < ncerts; i++) { int num = numattr; /* * If storing more than 1 cert, gotta change * the name so we don't overwrite the previous one. * Just append a _# to the name. */ if (i > 0) { (void) snprintf(newcertfile, sizeof (newcertfile), "%s_%d", certfile, i); kmf_set_attr_at_index(attrlist, num, KMF_CERT_FILENAME_ATTR, newcertfile, strlen(newcertfile)); num++; } else { kmf_set_attr_at_index(attrlist, num, KMF_CERT_FILENAME_ATTR, certfile, strlen(certfile)); num++; } if (certs[i].kmf_private.label != NULL) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_LABEL_ATTR, certs[i].kmf_private.label, strlen(certs[i].kmf_private.label)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i].certificate, sizeof (KMF_DATA)); num++; rv = kmf_store_cert(kmfhandle, num, attrlist); } free(attrlist); } if (rv == KMF_OK && nkeys > 0) { char newkeyfile[MAXPATHLEN]; numattr = 0; NEW_ATTRLIST(attrlist, (4 + (4 * nkeys))); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &outformat, sizeof (outformat)); numattr++; if (cred != NULL && cred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL)); numattr++; } /* The order of certificates and keys should match */ for (i = 0; rv == KMF_OK && i < nkeys; i++) { int num = numattr; if (i > 0) { (void) snprintf(newkeyfile, sizeof (newkeyfile), "%s_%d", keyfile, i); kmf_set_attr_at_index(attrlist, num, KMF_KEY_FILENAME_ATTR, newkeyfile, strlen(newkeyfile)); num++; } else { kmf_set_attr_at_index(attrlist, num, KMF_KEY_FILENAME_ATTR, keyfile, strlen(keyfile)); num++; } if (i < ncerts) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i], sizeof (KMF_CERT_DATA_ATTR)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_RAW_KEY_ATTR, &keys[i], sizeof (KMF_RAW_KEY_DATA)); num++; rv = kmf_store_key(kmfhandle, num, attrlist); } free(attrlist); } end: /* * Cleanup memory. */ if (certs) { for (i = 0; i < ncerts; i++) kmf_free_kmf_cert(kmfhandle, &certs[i]); free(certs); } if (keys) { for (i = 0; i < nkeys; i++) kmf_free_raw_key(&keys[i]); free(keys); } return (rv); } static KMF_RETURN pk_import_pk12_nss( KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *kmfcred, KMF_CREDENTIAL *tokencred, char *token_spec, char *dir, char *prefix, char *nickname, char *trustflags, char *filename) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT *certs = NULL; KMF_RAW_KEY_DATA *keys = NULL; int ncerts = 0; int nkeys = 0; int i; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; KMF_ATTRIBUTE *attrlist = NULL; int numattr = 0; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); rv = kmf_import_objects(kmfhandle, filename, kmfcred, &certs, &ncerts, &keys, &nkeys); if (rv == KMF_OK) (void) printf(gettext("Found %d certificate(s) and %d " "key(s) in %s\n"), ncerts, nkeys, filename); if (rv == KMF_OK) { numattr = 0; NEW_ATTRLIST(attrlist, (4 + (2 * nkeys))); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } if (nickname != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, nickname, strlen(nickname)); numattr++; } if (tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } /* The order of certificates and keys should match */ for (i = 0; i < nkeys; i++) { int num = numattr; if (i < ncerts) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i], sizeof (KMF_DATA)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_RAW_KEY_ATTR, &keys[i], sizeof (KMF_RAW_KEY_DATA)); num++; rv = kmf_store_key(kmfhandle, num, attrlist); } free(attrlist); attrlist = NULL; } if (rv == KMF_OK) { numattr = 0; NEW_ATTRLIST(attrlist, (3 + (2 * ncerts))); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } if (trustflags != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TRUSTFLAG_ATTR, trustflags, strlen(trustflags)); numattr++; } for (i = 0; rv == KMF_OK && i < ncerts; i++) { int num = numattr; if (certs[i].kmf_private.label != NULL) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_LABEL_ATTR, certs[i].kmf_private.label, strlen(certs[i].kmf_private.label)); num++; } else if (i == 0 && nickname != NULL) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_LABEL_ATTR, nickname, strlen(nickname)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i].certificate, sizeof (KMF_DATA)); num++; rv = kmf_store_cert(kmfhandle, num, attrlist); } free(attrlist); attrlist = NULL; if (rv != KMF_OK) { display_error(kmfhandle, rv, gettext("Error storing certificate in NSS token")); } } end: /* * Cleanup memory. */ if (certs) { for (i = 0; i < ncerts; i++) kmf_free_kmf_cert(kmfhandle, &certs[i]); free(certs); } if (keys) { for (i = 0; i < nkeys; i++) kmf_free_raw_key(&keys[i]); free(keys); } return (rv); } static KMF_RETURN pk_import_cert( KMF_HANDLE_T kmfhandle, KMF_KEYSTORE_TYPE kstype, char *label, char *token_spec, char *filename, char *dir, char *prefix, char *trustflags) { KMF_RETURN rv = KMF_OK; KMF_ATTRIBUTE attrlist[32]; KMF_CREDENTIAL tokencred; int i = 0; if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = select_token(kmfhandle, token_spec, FALSE); } else if (kstype == KMF_KEYSTORE_NSS) { rv = configure_nss(kmfhandle, dir, prefix); } if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, i, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (KMF_KEYSTORE_TYPE)); i++; kmf_set_attr_at_index(attrlist, i, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); i++; if (label != NULL) { kmf_set_attr_at_index(attrlist, i, KMF_CERT_LABEL_ATTR, label, strlen(label)); i++; } if (kstype == KMF_KEYSTORE_NSS) { if (trustflags != NULL) { kmf_set_attr_at_index(attrlist, i, KMF_TRUSTFLAG_ATTR, trustflags, strlen(trustflags)); i++; } if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, i, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); i++; } } rv = kmf_import_cert(kmfhandle, i, attrlist); if (rv == KMF_ERR_AUTH_FAILED) { /* * The token requires a credential, prompt and try again. */ (void) get_token_password(kstype, token_spec, &tokencred); kmf_set_attr_at_index(attrlist, i, KMF_CREDENTIAL_ATTR, &tokencred, sizeof (KMF_CREDENTIAL)); i++; rv = kmf_import_cert(kmfhandle, i, attrlist); } return (rv); } static KMF_RETURN pk_import_file_crl(void *kmfhandle, char *infile, char *outfile, KMF_ENCODE_FORMAT outfmt) { int numattr = 0; KMF_ATTRIBUTE attrlist[8]; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (infile) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_FILENAME_ATTR, infile, strlen(infile)); numattr++; } if (outfile) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_OUTFILE_ATTR, outfile, strlen(outfile)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &outfmt, sizeof (outfmt)); numattr++; return (kmf_import_crl(kmfhandle, numattr, attrlist)); } static KMF_RETURN pk_import_nss_crl(void *kmfhandle, boolean_t verify_crl_flag, char *infile, char *outdir, char *prefix) { KMF_RETURN rv; int numattr = 0; KMF_ATTRIBUTE attrlist[4]; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; rv = configure_nss(kmfhandle, outdir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (infile) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_FILENAME_ATTR, infile, strlen(infile)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_CHECK_ATTR, &verify_crl_flag, sizeof (verify_crl_flag)); numattr++; return (kmf_import_crl(kmfhandle, numattr, attrlist)); } static KMF_RETURN pk_import_pk12_pk11( KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *p12cred, KMF_CREDENTIAL *tokencred, char *label, char *token_spec, char *filename) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT *certs = NULL; KMF_RAW_KEY_DATA *keys = NULL; int ncerts = 0; int nkeys = 0; int i; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_ATTRIBUTE *attrlist = NULL; int numattr = 0; rv = select_token(kmfhandle, token_spec, FALSE); if (rv != KMF_OK) { return (rv); } rv = kmf_import_objects(kmfhandle, filename, p12cred, &certs, &ncerts, &keys, &nkeys); if (rv == KMF_OK) { NEW_ATTRLIST(attrlist, (3 + (2 * nkeys))); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (label != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, label, strlen(label)); numattr++; } if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } /* The order of certificates and keys should match */ for (i = 0; i < nkeys; i++) { int num = numattr; if (i < ncerts) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i].certificate, sizeof (KMF_DATA)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_RAW_KEY_ATTR, &keys[i], sizeof (KMF_RAW_KEY_DATA)); num++; rv = kmf_store_key(kmfhandle, num, attrlist); } free(attrlist); } if (rv == KMF_OK) { numattr = 0; NEW_ATTRLIST(attrlist, (1 + (2 * ncerts))); (void) printf(gettext("Found %d certificate(s) and %d " "key(s) in %s\n"), ncerts, nkeys, filename); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; for (i = 0; rv == KMF_OK && i < ncerts; i++) { int num = numattr; if (certs[i].kmf_private.label != NULL) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_LABEL_ATTR, certs[i].kmf_private.label, strlen(certs[i].kmf_private.label)); num++; } else if (i == 0 && label != NULL) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_LABEL_ATTR, label, strlen(label)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i].certificate, sizeof (KMF_DATA)); num++; rv = kmf_store_cert(kmfhandle, num, attrlist); } free(attrlist); } end: /* * Cleanup memory. */ if (certs) { for (i = 0; i < ncerts; i++) kmf_free_kmf_cert(kmfhandle, &certs[i]); free(certs); } if (keys) { for (i = 0; i < nkeys; i++) kmf_free_raw_key(&keys[i]); free(keys); } return (rv); } /*ARGSUSED*/ static KMF_RETURN pk_import_keys(KMF_HANDLE_T kmfhandle, KMF_KEYSTORE_TYPE kstype, char *token_spec, KMF_CREDENTIAL *cred, char *filename, char *label, char *senstr, char *extstr) { KMF_RETURN rv = KMF_OK; KMF_ATTRIBUTE attrlist[16]; KMF_KEYSTORE_TYPE fileks = KMF_KEYSTORE_OPENSSL; int numattr = 0; KMF_KEY_HANDLE key; KMF_RAW_KEY_DATA rawkey; KMF_KEY_CLASS class = KMF_ASYM_PRI; int numkeys = 1; if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = select_token(kmfhandle, token_spec, FALSE); } if (rv != KMF_OK) return (rv); /* * First, set up to read the keyfile using the FILE plugin * mechanisms. */ kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &fileks, sizeof (fileks)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &numkeys, sizeof (numkeys)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &key, sizeof (key)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_RAW_KEY_ATTR, &rawkey, sizeof (rawkey)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, &class, sizeof (class)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, filename, strlen(filename)); numattr++; rv = kmf_find_key(kmfhandle, numattr, attrlist); if (rv == KMF_OK) { numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (cred != NULL && cred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL)); numattr++; } if (label != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, label, strlen(label)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_RAW_KEY_ATTR, &rawkey, sizeof (rawkey)); numattr++; rv = kmf_store_key(kmfhandle, numattr, attrlist); if (rv == KMF_OK) { (void) printf(gettext("Importing %d keys\n"), numkeys); } kmf_free_kmf_key(kmfhandle, &key); kmf_free_raw_key(&rawkey); } else { cryptoerror(LOG_STDERR, gettext("Failed to load key from file (%s)\n"), filename); } return (rv); } static KMF_RETURN pk_import_rawkey(KMF_HANDLE_T kmfhandle, KMF_KEYSTORE_TYPE kstype, char *token, KMF_CREDENTIAL *cred, char *filename, char *label, KMF_KEY_ALG keyAlg, char *senstr, char *extstr) { KMF_RETURN rv = KMF_OK; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; uint32_t keylen; boolean_t sensitive = B_FALSE; boolean_t not_extractable = B_FALSE; KMF_DATA keydata = { 0, NULL }; KMF_KEY_HANDLE rawkey; rv = kmf_read_input_file(kmfhandle, filename, &keydata); if (rv != KMF_OK) return (rv); rv = select_token(kmfhandle, token, FALSE); if (rv != KMF_OK) { return (rv); } if (senstr != NULL) { if (tolower(senstr[0]) == 'y') sensitive = B_TRUE; else if (tolower(senstr[0]) == 'n') sensitive = B_FALSE; else { cryptoerror(LOG_STDERR, gettext("Incorrect sensitive option value.\n")); return (KMF_ERR_BAD_PARAMETER); } } if (extstr != NULL) { if (tolower(extstr[0]) == 'y') not_extractable = B_FALSE; else if (tolower(extstr[0]) == 'n') not_extractable = B_TRUE; else { cryptoerror(LOG_STDERR, gettext("Incorrect extractable option value.\n")); return (KMF_ERR_BAD_PARAMETER); } } 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, &rawkey, sizeof (rawkey)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYALG_ATTR, &keyAlg, sizeof (KMF_KEY_ALG)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_DATA_ATTR, keydata.Data, keydata.Length); numattr++; /* Key length is given in bits not bytes */ keylen = keydata.Length * 8; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLENGTH_ATTR, &keylen, sizeof (keydata.Length)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_SENSITIVE_BOOL_ATTR, &sensitive, sizeof (sensitive)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_NON_EXTRACTABLE_BOOL_ATTR, ¬_extractable, sizeof (not_extractable)); numattr++; if (label != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, label, strlen(label)); numattr++; } if (cred != NULL && cred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL)); numattr++; } rv = kmf_create_sym_key(kmfhandle, numattr, attrlist); return (rv); } /* * Import objects from into KMF repositories. */ int pk_import(int argc, char *argv[]) { int opt; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *filename = NULL; char *keyfile = NULL; char *certfile = NULL; char *crlfile = NULL; char *label = NULL; char *dir = NULL; char *prefix = NULL; char *trustflags = NULL; char *verify_crl = NULL; char *keytype = "generic"; char *senstr = NULL; char *extstr = NULL; boolean_t verify_crl_flag = B_FALSE; int oclass = 0; KMF_KEYSTORE_TYPE kstype = 0; KMF_ENCODE_FORMAT kfmt = 0; KMF_ENCODE_FORMAT okfmt = KMF_FORMAT_ASN1; KMF_RETURN rv = KMF_OK; KMF_CREDENTIAL pk12cred = { NULL, 0 }; KMF_CREDENTIAL tokencred = { NULL, 0 }; KMF_HANDLE_T kmfhandle = NULL; KMF_KEY_ALG keyAlg = KMF_GENERIC_SECRET; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "T:(token)i:(infile)" "k:(keystore)y:(objtype)" "d:(dir)p:(prefix)" "n:(certlabel)N:(label)" "K:(outkey)c:(outcert)" "v:(verifycrl)l:(outcrl)" "E:(keytype)s:(sensitive)x:(extractable)" "t:(trust)F:(outformat)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = optarg_av; break; case 'c': /* output cert file name */ if (certfile) return (PK_ERR_USAGE); certfile = optarg_av; break; case 'l': /* output CRL file name */ if (crlfile) return (PK_ERR_USAGE); crlfile = optarg_av; break; case 'K': /* output key file name */ if (keyfile) return (PK_ERR_USAGE); keyfile = optarg_av; break; case 'i': /* input file name */ if (filename) return (PK_ERR_USAGE); filename = optarg_av; break; case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 'y': oclass = OT2Int(optarg_av); if (oclass == -1) return (PK_ERR_USAGE); break; case 'd': dir = optarg_av; break; case 'p': if (prefix) return (PK_ERR_USAGE); prefix = optarg_av; break; case 'n': case 'N': if (label) return (PK_ERR_USAGE); label = optarg_av; break; case 'F': okfmt = Str2Format(optarg_av); if (okfmt == KMF_FORMAT_UNDEF) return (PK_ERR_USAGE); break; case 't': if (trustflags) return (PK_ERR_USAGE); trustflags = optarg_av; break; case 'v': verify_crl = optarg_av; if (tolower(verify_crl[0]) == 'y') verify_crl_flag = B_TRUE; else if (tolower(verify_crl[0]) == 'n') verify_crl_flag = B_FALSE; else return (PK_ERR_USAGE); break; case 'E': keytype = optarg_av; break; case 's': if (senstr) return (PK_ERR_USAGE); senstr = optarg_av; break; case 'x': if (extstr) return (PK_ERR_USAGE); extstr = optarg_av; break; default: return (PK_ERR_USAGE); } } /* Assume keystore = PKCS#11 if not specified */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; /* Filename arg is required. */ if (EMPTYSTRING(filename)) { cryptoerror(LOG_STDERR, gettext("The 'infile' parameter" "is required for the import operation.\n")); return (PK_ERR_USAGE); } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) return (PK_ERR_USAGE); DIR_OPTION_CHECK(kstype, dir); /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && kstype != KMF_KEYSTORE_PK11TOKEN) { (void) fprintf(stderr, gettext("The objtype parameter " "is only relevant if keystore=pkcs11\n")); return (PK_ERR_USAGE); } /* * You must specify a certlabel (cert label) when importing * into NSS or PKCS#11. */ if (kstype == KMF_KEYSTORE_NSS && (oclass != PK_CRL_OBJ) && EMPTYSTRING(label)) { cryptoerror(LOG_STDERR, gettext("The 'label' argument " "is required for this operation\n")); return (PK_ERR_USAGE); } if ((rv = kmf_get_file_format(filename, &kfmt)) != KMF_OK) { char *kmferrstr = NULL; KMF_RETURN rv2; /* * Allow for raw key data to be imported. */ if (rv == KMF_ERR_ENCODING) { rv = KMF_OK; kfmt = KMF_FORMAT_RAWKEY; /* * Set the object class only if it was not * given on the command line or if it was * specified as a symmetric key object. */ if (oclass == 0 || (oclass & PK_SYMKEY_OBJ)) { oclass = PK_SYMKEY_OBJ; } else { cryptoerror(LOG_STDERR, gettext( "The input file does not contain the " "object type indicated on command " "line.")); return (KMF_ERR_BAD_PARAMETER); } } else { if (rv == KMF_ERR_OPEN_FILE) { cryptoerror(LOG_STDERR, gettext("Cannot open file (%s)\n."), filename); } else { rv2 = kmf_get_kmf_error_str(rv, &kmferrstr); if (rv2 == KMF_OK && kmferrstr) { cryptoerror(LOG_STDERR, gettext("libkmf error: %s"), kmferrstr); kmf_free_str(kmferrstr); } } return (rv); } } /* Check parameters for raw key import operation */ if (kfmt == KMF_FORMAT_RAWKEY) { if (keytype != NULL && Str2SymKeyType(keytype, &keyAlg) != 0) { cryptoerror(LOG_STDERR, gettext("Unrecognized keytype(%s).\n"), keytype); return (PK_ERR_USAGE); } if (senstr != NULL && extstr != NULL && kstype != KMF_KEYSTORE_PK11TOKEN) { cryptoerror(LOG_STDERR, gettext("The sensitive or extractable option " "applies only when importing a key from a file " "into a PKCS#11 keystore.\n")); return (PK_ERR_USAGE); } } /* If no objtype was given, treat it as a certificate */ if (oclass == 0 && (kfmt == KMF_FORMAT_ASN1 || kfmt == KMF_FORMAT_PEM)) oclass = PK_CERT_OBJ; if (kstype == KMF_KEYSTORE_NSS) { if (oclass == PK_CRL_OBJ && (kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) { cryptoerror(LOG_STDERR, gettext( "CRL data can only be imported as DER or " "PEM format")); return (PK_ERR_USAGE); } if (oclass == PK_CERT_OBJ && (kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) { cryptoerror(LOG_STDERR, gettext( "Certificates can only be imported as DER or " "PEM format")); return (PK_ERR_USAGE); } /* we do not import private keys except in PKCS12 bundles */ if (oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)) { cryptoerror(LOG_STDERR, gettext( "Private key data can only be imported as part " "of a PKCS12 file.\n")); return (PK_ERR_USAGE); } } if (kstype == KMF_KEYSTORE_OPENSSL && oclass != PK_CRL_OBJ) { if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) { cryptoerror(LOG_STDERR, gettext( "The 'outkey' and 'outcert' parameters " "are required for the import operation " "when the 'file' keystore is used.\n")); return (PK_ERR_USAGE); } } if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) token_spec = PK_DEFAULT_PK11TOKEN; else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) token_spec = DEFAULT_NSS_TOKEN; if (kfmt == KMF_FORMAT_PKCS12) { (void) get_pk12_password(&pk12cred); } if ((kfmt == KMF_FORMAT_PKCS12 || kfmt == KMF_FORMAT_RAWKEY || (kfmt == KMF_FORMAT_PEM && (oclass & PK_KEY_OBJ))) && (kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS)) { (void) get_token_password(kstype, token_spec, &tokencred); } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing " "KMF: 0x%02x\n"), rv); goto end; } switch (kstype) { case KMF_KEYSTORE_PK11TOKEN: if (kfmt == KMF_FORMAT_PKCS12) rv = pk_import_pk12_pk11( kmfhandle, &pk12cred, &tokencred, label, token_spec, filename); else if (oclass == PK_CERT_OBJ) rv = pk_import_cert( kmfhandle, kstype, label, token_spec, filename, NULL, NULL, NULL); else if (oclass == PK_CRL_OBJ) rv = pk_import_file_crl( kmfhandle, filename, crlfile, okfmt); else if (kfmt == KMF_FORMAT_RAWKEY && oclass == PK_SYMKEY_OBJ) { rv = pk_import_rawkey(kmfhandle, kstype, token_spec, &tokencred, filename, label, keyAlg, senstr, extstr); } else if (kfmt == KMF_FORMAT_PEM || kfmt == KMF_FORMAT_PEM_KEYPAIR) { rv = pk_import_keys(kmfhandle, kstype, token_spec, &tokencred, filename, label, senstr, extstr); } else { rv = PK_ERR_USAGE; } break; case KMF_KEYSTORE_NSS: if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; if (kfmt == KMF_FORMAT_PKCS12) rv = pk_import_pk12_nss( kmfhandle, &pk12cred, &tokencred, token_spec, dir, prefix, label, trustflags, filename); else if (oclass == PK_CERT_OBJ) { rv = pk_import_cert( kmfhandle, kstype, label, token_spec, filename, dir, prefix, trustflags); } else if (oclass == PK_CRL_OBJ) { rv = pk_import_nss_crl( kmfhandle, verify_crl_flag, filename, dir, prefix); } break; case KMF_KEYSTORE_OPENSSL: if (kfmt == KMF_FORMAT_PKCS12) rv = pk_import_pk12_files( kmfhandle, &pk12cred, filename, certfile, keyfile, okfmt); else if (oclass == PK_CRL_OBJ) { rv = pk_import_file_crl( kmfhandle, filename, crlfile, okfmt); } else /* * It doesn't make sense to import anything * else for the files plugin. */ return (PK_ERR_USAGE); break; default: rv = PK_ERR_USAGE; break; } end: if (rv != KMF_OK) display_error(kmfhandle, rv, gettext("Error importing objects")); if (tokencred.cred != NULL) free(tokencred.cred); if (pk12cred.cred != NULL) free(pk12cred.cred); (void) kmf_finalize(kmfhandle); if (rv != KMF_OK) return (PK_ERR_USAGE); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * This file implements the inittoken operation for this tool. * The basic flow of the process is to load the PKCS#11 module, * find the token to be initialize , login using the SO pin, * and call C_InitToken. */ #include #include #include #include #include #include #include "common.h" 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); } } /* 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); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * This file implements the token object list operation for this tool. * It loads the PKCS#11 modules, finds the object to list, lists it, * and cleans up. User must be logged into the token to list private * objects. */ #include #include #include #include #include #include "common.h" #include static void pk_show_certs(KMF_HANDLE_T kmfhandle, KMF_X509_DER_CERT *certs, int num_certs) { int i; char *subject, *issuer, *serial, *id, *altname; char *start, *end, *keyusage, *extkeyusage; for (i = 0; i < num_certs; i++) { subject = NULL; issuer = NULL; serial = NULL; id = NULL; altname = NULL; start = end = NULL; keyusage = extkeyusage = NULL; (void) fprintf(stdout, gettext("%d. (X.509 certificate)\n"), i + 1); if (certs[i].kmf_private.label != NULL) (void) fprintf(stdout, gettext("\t%s: %s\n"), (certs[i].kmf_private.keystore_type == KMF_KEYSTORE_OPENSSL ? "Filename" : "Label"), certs[i].kmf_private.label); if (kmf_get_cert_id_str(&certs[i].certificate, &id) == KMF_OK) (void) fprintf(stdout, gettext("\tID: %s\n"), id); if (kmf_get_cert_subject_str(kmfhandle, &certs[i].certificate, &subject) == KMF_OK) (void) fprintf(stdout, gettext("\tSubject: %s\n"), subject); if (kmf_get_cert_issuer_str(kmfhandle, &certs[i].certificate, &issuer) == KMF_OK) (void) fprintf(stdout, gettext("\tIssuer: %s\n"), issuer); if (kmf_get_cert_start_date_str(kmfhandle, &certs[i].certificate, &start) == KMF_OK) (void) fprintf(stdout, gettext("\tNot Before: %s\n"), start); if (kmf_get_cert_end_date_str(kmfhandle, &certs[i].certificate, &end) == KMF_OK) (void) fprintf(stdout, gettext("\tNot After: %s\n"), end); if (kmf_get_cert_serial_str(kmfhandle, &certs[i].certificate, &serial) == KMF_OK) (void) fprintf(stdout, gettext("\tSerial: %s\n"), serial); if (kmf_get_cert_extn_str(kmfhandle, &certs[i].certificate, KMF_X509_EXT_SUBJ_ALTNAME, &altname) == KMF_OK) { (void) fprintf(stdout, gettext("\t%s\n"), altname); } if (kmf_get_cert_extn_str(kmfhandle, &certs[i].certificate, KMF_X509_EXT_KEY_USAGE, &keyusage) == KMF_OK) { (void) fprintf(stdout, gettext("\t%s\n"), keyusage); } if (kmf_get_cert_extn_str(kmfhandle, &certs[i].certificate, KMF_X509_EXT_EXT_KEY_USAGE, &extkeyusage) == KMF_OK) { (void) fprintf(stdout, gettext("\t%s\n"), extkeyusage); } kmf_free_str(subject); kmf_free_str(issuer); kmf_free_str(serial); kmf_free_str(id); kmf_free_str(altname); kmf_free_str(keyusage); kmf_free_str(extkeyusage); kmf_free_str(start); kmf_free_str(end); (void) fprintf(stdout, "\n"); } } static char * describeKey(KMF_KEY_HANDLE *key) { if (key->keyclass == KMF_ASYM_PUB) { if (key->keyalg == KMF_RSA) return (gettext("RSA public key")); if (key->keyalg == KMF_DSA) return (gettext("DSA public key")); if (key->keyalg == KMF_ECDSA) return (gettext("ECDSA public key")); } if (key->keyclass == KMF_ASYM_PRI) { if (key->keyalg == KMF_RSA) return (gettext("RSA private key")); if (key->keyalg == KMF_DSA) return (gettext("DSA private key")); if (key->keyalg == KMF_ECDSA) return (gettext("ECDSA private key")); } if (key->keyclass == KMF_SYMMETRIC) { switch (key->keyalg) { case KMF_AES: return (gettext("AES")); case KMF_RC4: return (gettext("ARCFOUR")); case KMF_DES: return (gettext("DES")); case KMF_DES3: return (gettext("Triple-DES")); default: return (gettext("symmetric")); } } return (gettext("unrecognized key object")); } static void pk_show_keys(void *handle, KMF_KEY_HANDLE *keys, int numkeys) { int i; for (i = 0; i < numkeys; i++) { (void) fprintf(stdout, gettext("Key #%d - %s: %s"), i+1, describeKey(&keys[i]), keys[i].keylabel ? keys[i].keylabel : gettext("No label")); if (keys[i].keyclass == KMF_SYMMETRIC) { KMF_RETURN rv; KMF_RAW_SYM_KEY rkey; (void) memset(&rkey, 0, sizeof (rkey)); rv = kmf_get_sym_key_value(handle, &keys[i], &rkey); if (rv == KMF_OK) { (void) fprintf(stdout, " (%d bits)", rkey.keydata.len * 8); kmf_free_bigint(&rkey.keydata); } else if (keys[i].kstype == KMF_KEYSTORE_PK11TOKEN) { if (rv == KMF_ERR_SENSITIVE_KEY) { (void) fprintf(stdout, " (sensitive)"); } else if (rv == KMF_ERR_UNEXTRACTABLE_KEY) { (void) fprintf(stdout, " (non-extractable)"); } else { char *err = NULL; if (kmf_get_kmf_error_str(rv, &err) == KMF_OK) (void) fprintf(stdout, " (error: %s)", err); if (err != NULL) free(err); } } } (void) fprintf(stdout, "\n"); } } /* * Generic routine used by all "list cert" operations to find * all matching certificates. */ static KMF_RETURN pk_find_certs(KMF_HANDLE_T kmfhandle, KMF_ATTRIBUTE *attrlist, int numattr) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT *certlist = NULL; uint32_t numcerts = 0; KMF_KEYSTORE_TYPE kstype; rv = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr, &kstype, NULL); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &numcerts, sizeof (uint32_t)); numattr++; rv = kmf_find_cert(kmfhandle, numattr, attrlist); if (rv == KMF_OK && numcerts > 0) { (void) printf(gettext("Found %d certificates.\n"), numcerts); certlist = (KMF_X509_DER_CERT *)malloc(numcerts * sizeof (KMF_X509_DER_CERT)); if (certlist == NULL) return (KMF_ERR_MEMORY); (void) memset(certlist, 0, numcerts * sizeof (KMF_X509_DER_CERT)); kmf_set_attr_at_index(attrlist, numattr, KMF_X509_DER_CERT_ATTR, certlist, sizeof (KMF_X509_DER_CERT)); numattr++; rv = kmf_find_cert(kmfhandle, numattr, attrlist); if (rv == KMF_OK) { int i; (void) pk_show_certs(kmfhandle, certlist, numcerts); for (i = 0; i < numcerts; i++) kmf_free_kmf_cert(kmfhandle, &certlist[i]); } free(certlist); } if (rv == KMF_ERR_CERT_NOT_FOUND && kstype != KMF_KEYSTORE_OPENSSL) rv = KMF_OK; return (rv); } static KMF_RETURN pk_list_keys(void *handle, KMF_ATTRIBUTE *attrlist, int numattr, char *label) { KMF_RETURN rv; KMF_KEY_HANDLE *keys; uint32_t numkeys = 0; KMF_KEYSTORE_TYPE kstype; rv = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr, &kstype, NULL); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &numkeys, sizeof (uint32_t)); numattr++; rv = kmf_find_key(handle, numattr, attrlist); if (rv == KMF_OK && numkeys > 0) { int i; (void) printf(gettext("Found %d %s keys.\n"), numkeys, label); keys = (KMF_KEY_HANDLE *)malloc(numkeys * sizeof (KMF_KEY_HANDLE)); if (keys == NULL) return (KMF_ERR_MEMORY); (void) memset(keys, 0, numkeys * sizeof (KMF_KEY_HANDLE)); kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, keys, sizeof (KMF_KEY_HANDLE)); numattr++; rv = kmf_find_key(handle, numattr, attrlist); if (rv == KMF_OK) pk_show_keys(handle, keys, numkeys); for (i = 0; i < numkeys; i++) kmf_free_kmf_key(handle, &keys[i]); free(keys); } if (rv == KMF_ERR_KEY_NOT_FOUND && kstype != KMF_KEYSTORE_OPENSSL) rv = KMF_OK; return (rv); } static KMF_RETURN list_pk11_objects(KMF_HANDLE_T kmfhandle, char *token, int oclass, char *objlabel, KMF_BIGINT *serial, char *issuer, char *subject, char *dir, char *filename, KMF_CREDENTIAL *tokencred, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN rv; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; int numattr = 0; KMF_ATTRIBUTE attrlist[18]; boolean_t token_bool = B_TRUE; boolean_t private = B_FALSE; KMF_KEY_CLASS keyclass; KMF_ENCODE_FORMAT format; int auth = 0; KMF_CREDENTIAL cred = { NULL, 0 }; /* * Symmetric keys and RSA/DSA/ECDSA private keys are always * created with the "CKA_PRIVATE" field == TRUE, so * make sure we search for them with it also set. */ if (oclass & (PK_SYMKEY_OBJ | PK_PRIKEY_OBJ)) oclass |= PK_PRIVATE_OBJ; rv = select_token(kmfhandle, token, !(oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ))); if (rv != KMF_OK) { return (rv); } rv = token_auth_needed(kmfhandle, token, &auth); if (rv != KMF_OK) return (rv); if (tokencred != NULL) cred = *tokencred; if (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ)) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } private = ((oclass & PK_PRIVATE_OBJ) > 0); kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVATE_BOOL_ATTR, &private, sizeof (private)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR, &token_bool, sizeof (token_bool)); numattr++; if (oclass & PK_PRIKEY_OBJ) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, num, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); num++; } /* list asymmetric private keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "asymmetric private"); } if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, num, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); num++; } format = KMF_FORMAT_RAWKEY; kmf_set_attr_at_index(attrlist, num, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); num++; /* list symmetric keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "symmetric"); } if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { int num = numattr; if (auth > 0 && (tokencred == NULL || tokencred->cred == NULL) && (cred.cred == NULL)) { (void) get_token_password(kstype, token, &cred); kmf_set_attr_at_index(attrlist, num, KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL)); num++; } private = B_FALSE; keyclass = KMF_ASYM_PUB; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; /* list asymmetric public keys (if any) */ rv = pk_list_keys(kmfhandle, attrlist, num, "asymmetric public"); } if (rv != KMF_OK) return (rv); } numattr = 0; if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (auth > 0 && (cred.cred == NULL)) { (void) get_token_password(kstype, token, &cred); } if (cred.cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL)); numattr++; } if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL && serial->val != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVATE_BOOL_ATTR, &private, sizeof (private)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; rv = pk_find_certs(kmfhandle, attrlist, numattr); if (rv != KMF_OK) return (rv); } numattr = 0; kstype = KMF_KEYSTORE_OPENSSL; /* CRL is file-based */ if (oclass & PK_CRL_OBJ) { char *crldata = NULL; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } if (filename != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_FILENAME_ATTR, filename, strlen(filename)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_DATA_ATTR, &crldata, sizeof (char *)); numattr++; rv = kmf_list_crl(kmfhandle, numattr, attrlist); if (rv == KMF_OK && crldata != NULL) { (void) printf("%s\n", crldata); free(crldata); } } return (rv); } static int list_file_objects(KMF_HANDLE_T kmfhandle, int oclass, char *dir, char *filename, KMF_BIGINT *serial, char *issuer, char *subject, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_CLASS keyclass; KMF_ENCODE_FORMAT format; char *defaultdir = "."; if (oclass & PK_KEY_OBJ) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (dir == NULL && filename == NULL) dir = defaultdir; if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } if (filename != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, filename, strlen(filename)); numattr++; } if (oclass & PK_PRIKEY_OBJ) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; /* list asymmetric private keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "asymmetric private"); } if (rv == KMF_ERR_KEY_NOT_FOUND) rv = KMF_OK; if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; format = KMF_FORMAT_RAWKEY; kmf_set_attr_at_index(attrlist, num, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); num++; /* list symmetric keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "symmetric"); } if (rv == KMF_ERR_KEY_NOT_FOUND) rv = KMF_OK; if (rv != KMF_OK) return (rv); } numattr = 0; if (oclass & PK_CERT_OBJ) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL && serial->val != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (filename != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); numattr++; } if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; rv = pk_find_certs(kmfhandle, attrlist, numattr); if (rv != KMF_OK) return (rv); } numattr = 0; if (oclass & PK_CRL_OBJ) { char *crldata = NULL; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } if (filename != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_FILENAME_ATTR, filename, strlen(filename)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_DATA_ATTR, &crldata, sizeof (char *)); numattr++; rv = kmf_list_crl(kmfhandle, numattr, attrlist); if (rv == KMF_OK && crldata != NULL) { (void) printf("%s\n", crldata); free(crldata); } } return (rv); } static int list_nss_objects(KMF_HANDLE_T kmfhandle, int oclass, char *token_spec, char *dir, char *prefix, char *nickname, KMF_BIGINT *serial, char *issuer, char *subject, KMF_CREDENTIAL *tokencred, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_CLASS keyclass; KMF_ENCODE_FORMAT format; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (oclass & PK_KEY_OBJ) { if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } if (token_spec && strlen(token_spec)) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } if (nickname != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, nickname, strlen(nickname)); numattr++; } } if (oclass & PK_PRIKEY_OBJ) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; /* list asymmetric private keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "asymmetric private"); } if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; format = KMF_FORMAT_RAWKEY; kmf_set_attr_at_index(attrlist, num, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); num++; /* list symmetric keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "symmetric"); } if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { int num = numattr; keyclass = KMF_ASYM_PUB; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; /* list asymmetric public keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "asymmetric public"); } /* If searching for public objects or certificates, find certs now */ numattr = 0; if (rv == KMF_OK && (oclass & PK_CERT_OBJ)) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (nickname != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, nickname, strlen(nickname)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; rv = pk_find_certs(kmfhandle, attrlist, numattr); } numattr = 0; if (rv == KMF_OK && (oclass & PK_CRL_OBJ)) { int numcrls; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_COUNT_ATTR, &numcrls, sizeof (int)); numattr++; rv = kmf_find_crl(kmfhandle, numattr, attrlist); if (rv == KMF_OK) { char **p; if (numcrls == 0) { (void) printf(gettext("No CRLs found in " "NSS keystore.\n")); return (KMF_OK); } p = malloc(numcrls * sizeof (char *)); if (p == NULL) { return (KMF_ERR_MEMORY); } (void) memset(p, 0, numcrls * sizeof (char *)); kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_NAMELIST_ATTR, p, sizeof (char *)); numattr++; rv = kmf_find_crl(kmfhandle, numattr, attrlist); if (rv == KMF_OK) { int i; for (i = 0; i < numcrls; i++) { (void) printf("%d. Name = %s\n", i + 1, p[i]); free(p[i]); } } free(p); } } return (rv); } /* * List token object. */ int pk_list(int argc, char *argv[]) { int opt; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *subject = NULL; char *issuer = NULL; char *dir = NULL; char *prefix = NULL; char *filename = NULL; char *serstr = NULL; KMF_BIGINT serial = { NULL, 0 }; char *list_label = NULL; int oclass = 0; KMF_KEYSTORE_TYPE kstype = 0; KMF_RETURN rv = KMF_OK; KMF_HANDLE_T kmfhandle = NULL; char *find_criteria = NULL; KMF_CERT_VALIDITY find_criteria_flag = KMF_ALL_CERTS; KMF_CREDENTIAL tokencred = { NULL, 0 }; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "k:(keystore)t:(objtype)T:(token)d:(dir)" "p:(prefix)n:(nickname)S:(serial)s:(subject)" "c:(criteria)" "i:(issuer)l:(label)f:(infile)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'k': if (kstype != 0) return (PK_ERR_USAGE); kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 't': if (oclass != 0) return (PK_ERR_USAGE); oclass = OT2Int(optarg_av); if (oclass == -1) return (PK_ERR_USAGE); break; case 's': if (subject) return (PK_ERR_USAGE); subject = optarg_av; break; case 'i': if (issuer) return (PK_ERR_USAGE); issuer = 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 'S': serstr = optarg_av; break; case 'f': if (filename) return (PK_ERR_USAGE); filename = optarg_av; break; case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = optarg_av; break; case 'n': case 'l': /* object with specific label */ if (list_label) return (PK_ERR_USAGE); list_label = optarg_av; break; case 'c': find_criteria = optarg_av; if (!strcasecmp(find_criteria, "valid")) find_criteria_flag = KMF_NONEXPIRED_CERTS; else if (!strcasecmp(find_criteria, "expired")) find_criteria_flag = KMF_EXPIRED_CERTS; else if (!strcasecmp(find_criteria, "both")) find_criteria_flag = KMF_ALL_CERTS; else 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) { /* Error message ? */ return (rv); } /* Assume keystore = PKCS#11 if not specified. */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && kstype != KMF_KEYSTORE_PK11TOKEN) { (void) fprintf(stderr, gettext("The objtype parameter " "is only relevant if keystore=pkcs11\n")); return (PK_ERR_USAGE); } if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) { token_spec = PK_DEFAULT_PK11TOKEN; } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) { token_spec = DEFAULT_NSS_TOKEN; } if (serstr != NULL) { 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")); return (PK_ERR_USAGE); } serial.val = bytes; serial.len = bytelen; /* if objtype was not given, it must be for certs */ if (oclass == 0) oclass = PK_CERT_OBJ; } if (oclass == 0 && (issuer != NULL || subject != NULL)) oclass = PK_CERT_OBJ; /* If no object class specified, list public objects. */ if (oclass == 0) oclass = PK_CERT_OBJ | PK_PUBKEY_OBJ; if ((kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS) && (oclass & (PK_PRIKEY_OBJ | PK_PRIVATE_OBJ))) { (void) get_token_password(kstype, token_spec, &tokencred); } if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = list_pk11_objects(kmfhandle, token_spec, oclass, list_label, &serial, issuer, subject, dir, filename, &tokencred, find_criteria_flag); } else if (kstype == KMF_KEYSTORE_NSS) { if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; rv = list_nss_objects(kmfhandle, oclass, token_spec, dir, prefix, list_label, &serial, issuer, subject, &tokencred, find_criteria_flag); } else if (kstype == KMF_KEYSTORE_OPENSSL) { rv = list_file_objects(kmfhandle, oclass, dir, filename, &serial, issuer, subject, find_criteria_flag); } if (rv != KMF_OK) { display_error(kmfhandle, rv, gettext("Error listing objects")); } if (serial.val != NULL) free(serial.val); if (tokencred.cred != NULL) free(tokencred.cred); (void) kmf_finalize(kmfhandle); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * This file comprises the main driver for this tool. * Upon parsing the command verbs from user input, it * branches to the appropriate modules to perform the * requested task. */ #include #include #include #include #include #include #include #include #include #include "common.h" /* * The verbcmd construct allows genericizing information about a verb so * that it is easier to manipulate. Makes parsing code easier to read, * fix, and extend with new verbs. */ typedef struct verbcmd_s { char *verb; int (*action)(int, char *[]); int mode; char *summary; char *synopsis; } verbcmd; /* External declarations for supported verb actions. */ extern int pk_setpin(int argc, char *argv[]); extern int pk_list(int argc, char *argv[]); extern int pk_delete(int argc, char *argv[]); extern int pk_import(int argc, char *argv[]); extern int pk_export(int argc, char *argv[]); extern int pk_tokens(int argc, char *argv[]); extern int pk_gencert(int argc, char *argv[]); extern int pk_gencsr(int argc, char *argv[]); extern int pk_download(int argc, char *argv[]); extern int pk_genkey(int argc, char *argv[]); extern int pk_signcsr(int argc, char *argv[]); extern int pk_inittoken(int argc, char *argv[]); extern int pk_genkeypair(int argc, char *argv[]); /* Forward declarations for "built-in" verb actions. */ static int pk_help(int argc, char *argv[]); #define TOKEN_IDX 0 #define TOKEN_VERB "tokens" #define TOKEN_SUMM gettext("lists all visible PKCS#11 tokens") #define TOKEN_SYN "tokens" #define SETPIN_IDX 1 #define SETPIN_VERB "setpin" #define SETPIN_SUMM gettext("changes user authentication passphrase "\ "for keystore access") #define SETPIN_SYN \ "setpin [ keystore=pkcs11 ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ usertype=so|user ]\n\t" \ \ "setpin keystore=nss\n\t\t" \ "[ token=token ]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t" #define LIST_IDX 2 #define LIST_VERB "list" #define LIST_SUMM gettext("lists a summary of objects in the keystore") #define LIST_SYN \ "list [ token=token[:manuf[:serial]]]\n\t\t" \ "[ objtype=private|public|both ]\n\t\t" \ "[ label=label ]\n\t" \ \ "list objtype=cert[:[public | private | both ]]\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ keystore=pkcs11 ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ label=cert-label ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "list objtype=key[:[public | private | both ]]\n\t\t" \ "[ keystore=pkcs11 ]\n\t\t" \ "[ label=key-label ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t" \ \ "list keystore=pkcs11 objtype=crl\n\t\t" \ "infile=crl-fn\n\t" \ \ "list keystore=nss objtype=cert\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ nickname=cert-nickname ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "list keystore=nss objtype=key\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ nickname=key-nickname ]\n\t" \ \ "list keystore=file objtype=cert\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ infile=cert-fn ]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "list keystore=file objtype=key\n\t\t" \ "[ infile=key-fn ]\n\t\t" \ "[ dir=directory-path ]\n\t" \ \ "list keystore=file objtype=crl\n\t\t" \ "infile=crl-fn\n\t" #define DELETE_IDX 3 #define DELETE_VERB "delete" #define DELETE_SUMM gettext("deletes objects in the keystore") #define DELETE_SYN \ "delete [ token=token[:manuf[:serial]]]\n\t\t" \ "[ objtype=private|public|both ]\n\t\t" \ "[ label=object-label ]\n\t" \ \ "delete keystore=nss objtype=cert\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ label=cert-label ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "delete keystore=nss objtype=key\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ nickname=key-nickname ]\n\t\t" \ \ "delete keystore=nss objtype=crl\n\t\t" \ "[ nickname=issuer-nickname ]\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t" \ \ "delete keystore=pkcs11 " \ "objtype=cert[:[public | private | both]]\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ label=cert-label ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "delete keystore=pkcs11 " \ "objtype=key[:[public | private | both]]\n\t\t" \ "[ label=key-label ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t" \ \ "delete keystore=pkcs11 objtype=crl\n\t\t" \ "infile=crl-fn\n\t" \ \ "delete keystore=file objtype=cert\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ infile=cert-fn ]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "delete keystore=file objtype=key\n\t\t" \ "[ infile=key-fn ]\n\t\t" \ "[ dir=directory-path ]\n\t" \ \ "delete keystore=file objtype=crl\n\t\t" \ "infile=crl-fn\n\t" #define IMPORT_IDX 4 #define IMPORT_VERB "import" #define IMPORT_SUMM gettext("imports objects from an external source") #define IMPORT_SYN \ "import [token=token[:manuf[:serial]]]\n\t\t" \ "infile=input-fn\n\t" \ \ "import keystore=nss objtype=cert\n\t\t" \ "infile=input-fn\n\t\t" \ "label=cert-label\n\t\t" \ "[ trust=trust-value ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t" \ \ "import keystore=nss objtype=crl\n\t\t" \ "infile=input-fn\n\t\t" \ "[ verifycrl=y|n ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t" \ \ "import keystore=pkcs11\n\t\t" \ "infile=input-fn\n\t\t" \ "label=label\n\t\t" \ "[ objtype=cert|key ]\n\t\t" \ "[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" \ "[ sensitive=y|n ]\n\t\t" \ "[ extractable=y|n ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t" \ \ "import keystore=pkcs11 objtype=crl\n\t\t" \ "infile=input-crl-fn\n\t\t" \ "outcrl=output-crl-fn\n\t\t" \ "outformat=pem|der\n\t" \ \ "import keystore=file\n\t\t" \ "infile=input-fn\n\t\t" \ "outkey=output-key-fn\n\t\t" \ "outcert=output-cert-fn\n\t\t" \ "[ outformat=pem|der|pkcs12 ]\n\t" \ \ "import keystore=file objtype=crl\n\t\t" \ "infile=input-crl-fn\n\t\t" \ "outcrl=output-crl-fn\n\t\t" \ "outformat=pem|der\n\t" #define EXPORT_IDX 5 #define EXPORT_VERB "export" #define EXPORT_SUMM gettext("exports objects from the keystore to a file") #define EXPORT_SYN \ "export [token=token[:manuf[:serial]]]\n\t\t" \ "outfile=output-fn\n\t" \ \ "export keystore=nss\n\t\t" \ "outfile=output-fn\n\t\t" \ "[ objtype=cert|key ]\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ nickname=cert-nickname ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBPrefix ]\n\t\t" \ "[ outformat=pem|der|pkcs12 ]\n\t" \ \ "export keystore=pkcs11\n\t\t" \ "outfile=output-fn\n\t\t" \ "[ objtype=cert|key ]\n\t\t" \ "[ label=label ]\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ outformat=pem|der|pkcs12|raw ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t" \ \ "export keystore=file\n\t\t" \ "certfile=cert-input-fn\n\t\t" \ "keyfile=key-input-fn\n\t\t" \ "outfile=output-pkcs12-fn\n\t" #define GENCERT_IDX 6 #define GENCERT_VERB "gencert" #define GENCERT_SUMM gettext("creates a self-signed X.509v3 certificate") #define GENCERT_SYN \ "gencert listcurves\n\t" \ \ "gencert keystore=nss\n\t\t" \ "label=cert-nickname\n\t\t" \ "serial=serial number hex string\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ keytype=rsa | ec [curve=ECC Curve Name] " \ "[hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ trust=trust-value ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t" \ \ "gencert [ keystore=pkcs11 ]\n\t\t" \ "label=key/cert-label\n\t\t" \ "serial=serial number hex string\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ keytype=rsa | ec [curve=ECC Curve Name] " \ "[hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1 | sha256 ]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t" \ \ "gencert keystore=file\n\t\t" \ "outcert=cert_filename\n\t\t" \ "outkey=key_filename\n\t\t" \ "serial=serial number hex string\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ format=der|pem ]\n\t\t" \ "[ keytype=rsa [hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1 | sha256 ]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t" #define GENCSR_IDX 7 #define GENCSR_VERB "gencsr" #define GENCSR_SUMM gettext("creates a PKCS#10 certificate signing " \ "request file") #define GENCSR_SYN \ "gencsr listcurves\n\t" \ \ "gencsr keystore=nss \n\t\t" \ "nickname=cert-nickname\n\t\t" \ "outcsr=csr-fn\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ keytype=rsa | ec [curve=ECC Curve Name] " \ "[hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ format=pem|der ]\n\t" \ \ "gencsr [ keystore=pkcs11 ]\n\t\t" \ "label=key-label\n\t\t" \ "outcsr=csr-fn\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ keytype=rsa | ec [curve=ECC Curve Name] " \ "[hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1 | sha256 ]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ format=pem|der ]]\n\t" \ \ "gencsr keystore=file\n\t\t" \ "outcsr=csr-fn\n\t\t" \ "outkey=key-fn\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ keytype=rsa [hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1 | sha256 ]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ format=pem|der ]\n\t" #define DOWNLOAD_IDX 8 #define DOWNLOAD_VERB "download" #define DOWNLOAD_SUMM gettext("downloads a CRL or certificate file " \ "from an external source") #define DOWNLOAD_SYN \ "download url=url_str\n\t\t" \ "[ objtype=crl|cert ]\n\t\t" \ "[ http_proxy=proxy_str ]\n\t\t" \ "[ outfile = outfile ]\n\t" #define GENKEY_IDX 9 #define GENKEY_VERB "genkey" #define GENKEY_SUMM gettext("creates a symmetric key in the keystore") #define GENKEY_SYN \ "genkey [ keystore=pkcs11 ]\n\t\t" \ "label=key-label\n\t\t" \ "[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" \ "[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ sensitive=y|n ]\n\t\t" \ "[ extractable=y|n ]\n\t\t" \ "[ print=y|n ]\n\t" \ \ "genkey keystore=nss\n\t\t" \ "label=key-label\n\t\t" \ "[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" \ "[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t" \ \ "genkey keystore=file\n\t\t" \ "outkey=key-fn\n\t\t" \ "[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" \ "[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t" \ "[ print=y|n ]\n\t" #define SIGNCSR_IDX 10 #define SIGNCSR_VERB "signcsr" #define SIGNCSR_SUMM gettext("Sign a PKCS#10 Certificate Signing Request") #define SIGNCSR_SYN \ "signcsr keystore=pkcs11\n\t\t" \ "signkey=label (label of signing key)\n\t\t" \ "csr=CSR filename\n\t\t" \ "serial=serial number hex string\n\t\t" \ "outcert=filename for final certificate\n\t\t" \ "issuer=issuer-DN\n\t\t" \ "[ store=y|n ] (store the new cert on the token, default=n)\n\t\t" \ "[ outlabel=certificate label ]\n\t\t" \ "[ format=pem|der ] (output format)\n\t\t" \ "[ subject=subject-DN ] (new subject name)\n\t\t" \ "[ altname=subjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,...]\n\t\t" \ "[ eku=[critical:]EKU Name,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t" \ \ "signcsr keystore=file\n\t\t" \ "signkey=filename\n\t\t" \ "csr=CSR filename\n\t\t" \ "serial=serial number hex string\n\t\t" \ "outcert=filename for final certificate\n\t\t" \ "issuer=issuer-DN\n\t\t" \ "[ format=pem|der ] (output format)\n\t\t" \ "[ subject=subject-DN ] (new subject name)\n\t\t" \ "[ altname=subjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t\t" \ "[ eku=[critical:]EKU Name,...]\n\t" \ \ "signcsr keystore=nss\n\t\t" \ "signkey=label (label of signing key)\n\t\t" \ "csr=CSR filename\n\t\t" \ "serial=serial number hex string\n\t\t" \ "outcert=filename for final certificate\n\t\t" \ "issuer=issuer-DN\n\t\t" \ "[ store=y|n ] (store the new cert in NSS DB, default=n)\n\t\t" \ "[ outlabel=certificate label ]\n\t\t" \ "[ format=pem|der ] (output format)\n\t\t" \ "[ subject=subject-DN ] (new subject name)\n\t\t" \ "[ altname=subjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,...]\n\t\t" \ "[ eku=[critical:]EKU Name,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t" #define INITTOKEN_IDX 11 #define INITTOKEN_VERB "inittoken" #define INITTOKEN_SUMM gettext("Initialize a PKCS11 token") #define INITTOKEN_SYN \ "inittoken \n\t\t" \ "[ currlabel=token[:manuf[:serial]]]\n\t\t" \ "[ newlabel=new token label ]\n\t" #define GENKEYPAIR_IDX 12 #define GENKEYPAIR_VERB "genkeypair" #define GENKEYPAIR_SUMM gettext("creates an asymmetric keypair") #define GENKEYPAIR_SYN \ "genkeypair listcurves\n\t" \ \ "genkeypair keystore=nss\n\t\t" \ "label=key-nickname\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ keytype=rsa | dsa | ec [curve=ECC Curve Name]]\n\t\t" \ "[ keylen=key-size ]\n\t" \ \ "genkeypair [ keystore=pkcs11 ]\n\t\t" \ "label=key-label\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ keytype=rsa | dsa | ec [curve=ECC Curve Name]]\n\t\t" \ "[ keylen=key-size ]\n\t" \ \ "genkeypair keystore=file\n\t\t" \ "outkey=key_filename\n\t\t" \ "[ format=der|pem ]\n\t\t" \ "[ keytype=rsa|dsa ]\n\t\t" \ "[ keylen=key-size ]\n\t" #define HELP_IDX 13 #define HELP_VERB "help" #define HELP_SUMM gettext("displays help message") #define HELP_SYN "help\t(help and usage)" /* Command structure for verbs and their actions. Do NOT i18n/l10n. */ static verbcmd cmds[] = { { NULL, pk_tokens, 0, NULL, NULL }, { NULL, pk_setpin, 0, NULL, NULL }, { NULL, pk_list, 0, NULL, NULL }, { NULL, pk_delete, 0, NULL, NULL }, { NULL, pk_import, 0, NULL, NULL }, { NULL, pk_export, 0, NULL, NULL }, { NULL, pk_gencert, 0, NULL, NULL }, { NULL, pk_gencsr, 0, NULL, NULL }, { NULL, pk_download, 0, NULL, NULL }, { NULL, pk_genkey, 0, NULL, NULL }, { NULL, pk_signcsr, 0, NULL, NULL }, { NULL, pk_inittoken, 0, NULL, NULL }, { NULL, pk_genkeypair, 0, NULL, NULL }, { NULL, pk_help, 0, NULL, NULL } }; static int num_cmds = sizeof (cmds) / sizeof (verbcmd); static char *prog; static void usage(int); static void init_command_list() { cmds[TOKEN_IDX].verb = TOKEN_VERB; cmds[TOKEN_IDX].summary = TOKEN_SUMM; cmds[TOKEN_IDX].synopsis = TOKEN_SYN; cmds[SETPIN_IDX].verb = SETPIN_VERB; cmds[SETPIN_IDX].summary = SETPIN_SUMM; cmds[SETPIN_IDX].synopsis = SETPIN_SYN; cmds[LIST_IDX].verb = LIST_VERB; cmds[LIST_IDX].summary = LIST_SUMM; cmds[LIST_IDX].synopsis = LIST_SYN; cmds[DELETE_IDX].verb = DELETE_VERB; cmds[DELETE_IDX].summary = DELETE_SUMM; cmds[DELETE_IDX].synopsis = DELETE_SYN; cmds[IMPORT_IDX].verb = IMPORT_VERB; cmds[IMPORT_IDX].summary = IMPORT_SUMM; cmds[IMPORT_IDX].synopsis = IMPORT_SYN; cmds[EXPORT_IDX].verb = EXPORT_VERB; cmds[EXPORT_IDX].summary = EXPORT_SUMM; cmds[EXPORT_IDX].synopsis = EXPORT_SYN; cmds[GENCERT_IDX].verb = GENCERT_VERB; cmds[GENCERT_IDX].summary = GENCERT_SUMM; cmds[GENCERT_IDX].synopsis = GENCERT_SYN; cmds[GENCSR_IDX].verb = GENCSR_VERB; cmds[GENCSR_IDX].summary = GENCSR_SUMM; cmds[GENCSR_IDX].synopsis = GENCSR_SYN; cmds[DOWNLOAD_IDX].verb = DOWNLOAD_VERB; cmds[DOWNLOAD_IDX].summary = DOWNLOAD_SUMM; cmds[DOWNLOAD_IDX].synopsis = DOWNLOAD_SYN; cmds[GENKEY_IDX].verb = GENKEY_VERB; cmds[GENKEY_IDX].summary = GENKEY_SUMM; cmds[GENKEY_IDX].synopsis = GENKEY_SYN; cmds[SIGNCSR_IDX].verb = SIGNCSR_VERB; cmds[SIGNCSR_IDX].summary = SIGNCSR_SUMM; cmds[SIGNCSR_IDX].synopsis = SIGNCSR_SYN; cmds[INITTOKEN_IDX].verb = INITTOKEN_VERB; cmds[INITTOKEN_IDX].summary = INITTOKEN_SUMM; cmds[INITTOKEN_IDX].synopsis = INITTOKEN_SYN; cmds[GENKEYPAIR_IDX].verb = GENKEYPAIR_VERB; cmds[GENKEYPAIR_IDX].summary = GENKEYPAIR_SUMM; cmds[GENKEYPAIR_IDX].synopsis = GENKEYPAIR_SYN; cmds[HELP_IDX].verb = HELP_VERB; cmds[HELP_IDX].summary = HELP_SUMM; cmds[HELP_IDX].synopsis = HELP_SYN; } /* * Usage information. This function must be updated when new verbs or * options are added. */ static void usage(int idx) { int i; /* Display this block only in command-line mode. */ (void) fprintf(stdout, gettext("Usage:\n")); (void) fprintf(stdout, gettext(" %s -?\t(help and usage)\n"), prog); (void) fprintf(stdout, gettext(" %s -f option_file\n"), prog); (void) fprintf(stdout, gettext(" %s subcommand [options...]\n"), prog); (void) fprintf(stdout, gettext("where subcommands may be:\n")); /* Display only those verbs that match the current tool mode. */ if (idx == -1) { for (i = 0; i < num_cmds; i++) { /* Do NOT i18n/l10n. */ (void) fprintf(stdout, " %-8s - %s\n", cmds[i].verb, cmds[i].summary); } (void) fprintf(stdout, "%s \'help\'.\n" "Ex: pktool gencert help\n\n", gettext("\nFurther details on the " "subcommands can be found by adding")); } else { (void) fprintf(stdout, "\t%s\n", cmds[idx].synopsis); } } /* * Provide help, in the form of displaying the usage. */ static int pk_help(int argc, char *argv[]) /* ARGSUSED */ { usage(-1); return (0); } /* * Process arguments from the argfile and create a new * argv/argc list to be processed later. */ static int process_arg_file(char *argfile, char ***argv, int *argc) { FILE *fp; char argline[2 * BUFSIZ]; /* 2048 bytes should be plenty */ char *p; int nargs = 0; if ((fp = fopen(argfile, "rF")) == NULL) { (void) fprintf(stderr, gettext("Cannot read argfile %s: %s\n"), argfile, strerror(errno)); return (errno); } while (fgets(argline, sizeof (argline), fp) != NULL) { int j; /* remove trailing whitespace */ j = strlen(argline) - 1; while (j >= 0 && isspace(argline[j])) { argline[j] = 0; j--; } /* If it was a blank line, get the next one. */ if (!strlen(argline)) continue; (*argv) = realloc((*argv), (nargs + 1) * sizeof (char *)); if ((*argv) == NULL) { perror("memory error"); (void) fclose(fp); return (errno); } p = (char *)strdup(argline); if (p == NULL) { perror("memory error"); (void) fclose(fp); return (errno); } (*argv)[nargs] = p; nargs++; } *argc = nargs; (void) fclose(fp); return (0); } /* * 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); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * This file implements the setpin operation for this tool. * The basic flow of the process is to load the PKCS#11 module, * finds the soft token, prompt the user for the old PIN (if * any) and the new PIN, change the token's PIN, and clean up. */ #include #include #include #include #include #include #include "common.h" static int setpin_nss(KMF_HANDLE_T handle, char *token_spec, char *dir, char *prefix) { int rv = 0; KMF_CREDENTIAL oldcred = { NULL, 0 }; KMF_CREDENTIAL newpincred = { NULL, 0 }; CK_UTF8CHAR_PTR old_pin = NULL, new_pin = NULL; CK_ULONG old_pinlen = 0, new_pinlen = 0; KMF_ATTRIBUTE setpinattrs[6]; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; int numattrs = 0; rv = configure_nss(handle, dir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(setpinattrs, numattrs, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattrs++; if (token_spec != NULL) { kmf_set_attr_at_index(setpinattrs, numattrs, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattrs++; } if ((rv = get_pin(gettext("Enter current token passphrase " "( if not set):"), NULL, &old_pin, &old_pinlen)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get token passphrase.")); return (PK_ERR_NSS); } /* Get the user's new PIN. */ if ((rv = get_pin(gettext("Create new passphrase:"), gettext( "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) { if (rv == CKR_PIN_INCORRECT) cryptoerror(LOG_STDERR, gettext( "Passphrases do not match.")); else cryptoerror(LOG_STDERR, gettext( "Unable to get and confirm new passphrase.")); if (old_pin != NULL) free(old_pin); return (PK_ERR_NSS); } oldcred.cred = (char *)old_pin; oldcred.credlen = old_pinlen; kmf_set_attr_at_index(setpinattrs, numattrs, KMF_CREDENTIAL_ATTR, &oldcred, sizeof (oldcred)); numattrs++; newpincred.cred = (char *)new_pin; newpincred.credlen = new_pinlen; kmf_set_attr_at_index(setpinattrs, numattrs, KMF_NEWPIN_ATTR, &newpincred, sizeof (newpincred)); numattrs++; rv = kmf_set_token_pin(handle, numattrs, setpinattrs); if (new_pin) free(new_pin); if (old_pin) free(old_pin); return (rv); } static int setpin_pkcs11(KMF_HANDLE_T handle, char *token_spec, boolean_t souser) { CK_SLOT_ID slot_id; CK_FLAGS pin_state; CK_UTF8CHAR_PTR old_pin = NULL, new_pin = NULL; CK_ULONG old_pinlen = 0, new_pinlen = 0; CK_RV rv = CKR_OK; char *token_name = NULL; CK_TOKEN_INFO token_info; KMF_CREDENTIAL newpincred = { NULL, 0 }; KMF_CREDENTIAL oldcred = { NULL, 0 }; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_ATTRIBUTE attrlist[6]; CK_USER_TYPE user = CKU_USER; int numattr = 0; /* If nothing is specified, default is to use softtoken. */ if (token_spec == NULL) { token_spec = SOFT_TOKEN_LABEL ":" SOFT_MANUFACTURER_ID; token_name = SOFT_TOKEN_LABEL; } rv = kmf_pk11_token_lookup(NULL, token_spec, &slot_id); if (rv == KMF_OK) { /* find the pin state for the selected token */ if (C_GetTokenInfo(slot_id, &token_info) != CKR_OK) return (PK_ERR_PK11); pin_state = token_info.flags & CKF_USER_PIN_TO_BE_CHANGED; if (token_name == NULL) token_name = (char *)token_info.label; } /* * If the token is the softtoken, check if the token flags show the * PIN has not been set yet. If not then set the old PIN to the * default "changeme". Otherwise, let user type in the correct old * PIN to unlock token. */ if (pin_state == CKF_USER_PIN_TO_BE_CHANGED && strcmp(token_name, SOFT_TOKEN_LABEL) == 0) { if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) == NULL) { cryptoerror(LOG_STDERR, "%s.", strerror(errno)); final_pk11(0); return (PK_ERR_PK11); } old_pinlen = strlen(SOFT_DEFAULT_PIN); } else { if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &old_pin, &old_pinlen)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get token passphrase (%s)."), pkcs11_strerror(rv)); final_pk11(0); return (PK_ERR_PK11); } } /* Get the user's new PIN. */ if ((rv = get_pin(gettext("Create new passphrase:"), gettext( "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) { if (rv == CKR_PIN_INCORRECT) cryptoerror(LOG_STDERR, gettext( "Passphrases do not match.")); else cryptoerror(LOG_STDERR, gettext( "Unable to get and confirm new passphrase (%s)."), pkcs11_strerror(rv)); free(old_pin); final_pk11(0); return (PK_ERR_PK11); } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (token_name != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_name, strlen(token_name)); numattr++; } oldcred.cred = (char *)old_pin; oldcred.credlen = old_pinlen; kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, &oldcred, sizeof (oldcred)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_SLOT_ID_ATTR, &slot_id, sizeof (slot_id)); numattr++; newpincred.cred = (char *)new_pin; newpincred.credlen = new_pinlen; kmf_set_attr_at_index(attrlist, numattr, KMF_NEWPIN_ATTR, &newpincred, sizeof (newpincred)); numattr++; if (souser) { user = CKU_SO; kmf_set_attr_at_index(attrlist, numattr, KMF_PK11_USER_TYPE_ATTR, &user, sizeof (user)); numattr++; } rv = kmf_set_token_pin(handle, numattr, attrlist); /* Clean up. */ if (old_pin != NULL) free(old_pin); if (new_pin != NULL) free(new_pin); return (rv); } /* * Changes the token's PIN. */ int pk_setpin(int argc, char *argv[]) /* ARGSUSED */ { int opt; int rv; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *dir = NULL; char *prefix = NULL; char *utype = NULL; KMF_HANDLE_T handle; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; boolean_t souser = 0; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "T:(token)k:(keystore)d:(dir)" "p:(prefix)u:(usertype)")) != EOF) { switch (opt) { case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = 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 'u': utype = optarg_av; break; default: return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc != 0) return (PK_ERR_USAGE); /* Done parsing command line options. */ if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) { token_spec = PK_DEFAULT_PK11TOKEN; } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) { token_spec = DEFAULT_NSS_TOKEN; } if ((rv = kmf_initialize(&handle, NULL, NULL)) != KMF_OK) return (rv); if (utype != NULL) { if (strcmp(utype, "so") == 0) souser = 1; else if (strcmp(utype, "user") == 0) souser = 0; else /* Wrong option string */ return (PK_ERR_USAGE); } switch (kstype) { case KMF_KEYSTORE_PK11TOKEN: rv = setpin_pkcs11(handle, token_spec, souser); break; case KMF_KEYSTORE_NSS: rv = setpin_nss(handle, token_spec, dir, prefix); break; default: cryptoerror(LOG_STDERR, gettext("incorrect keystore.")); return (PK_ERR_USAGE); } (void) kmf_finalize(handle); 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 change passphrase.")); return (PK_ERR_SYSTEM); } else { (void) fprintf(stdout, gettext("Passphrase changed.\n")); } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * This file implements the sign CSR operation for this tool. */ #include #include #include #include #include #include "common.h" #include #include #define SET_VALUE(f, s) \ rv = f; \ if (rv != KMF_OK) { \ cryptoerror(LOG_STDERR, \ gettext("Failed to set %s: 0x%02x\n"), s, rv); \ goto cleanup; \ } static int read_csrdata(KMF_HANDLE_T handle, char *csrfile, KMF_CSR_DATA *csrdata) { KMF_RETURN rv = KMF_OK; KMF_ENCODE_FORMAT csrfmt; KMF_DATA csrfiledata = { 0, NULL }; KMF_DATA rawcsr = { 0, NULL }; rv = kmf_get_file_format(csrfile, &csrfmt); if (rv != KMF_OK) return (rv); rv = kmf_read_input_file(handle, csrfile, &csrfiledata); if (rv != KMF_OK) return (rv); if (csrfmt == KMF_FORMAT_PEM) { rv = kmf_pem_to_der(csrfiledata.Data, csrfiledata.Length, &rawcsr.Data, (int *)&rawcsr.Length); if (rv != KMF_OK) return (rv); kmf_free_data(&csrfiledata); } else { rawcsr.Data = csrfiledata.Data; rawcsr.Length = csrfiledata.Length; } rv = kmf_decode_csr(handle, &rawcsr, csrdata); kmf_free_data(&rawcsr); return (rv); } static KMF_RETURN find_csr_extn(KMF_X509_EXTENSIONS *extnlist, KMF_OID *extoid, KMF_X509_EXTENSION *outextn) { int i, found = 0; KMF_X509_EXTENSION *eptr; KMF_RETURN rv = KMF_OK; (void) memset(outextn, 0, sizeof (KMF_X509_EXTENSION)); for (i = 0; !found && i < extnlist->numberOfExtensions; i++) { eptr = &extnlist->extensions[i]; if (IsEqualOid(extoid, &eptr->extnId)) { rv = copy_extension_data(outextn, eptr); found++; } } if (found == 0 || rv != KMF_OK) return (1); else return (rv); } static int build_cert_from_csr(KMF_CSR_DATA *csrdata, KMF_X509_CERTIFICATE *signedCert, KMF_BIGINT *serial, uint32_t ltime, char *issuer, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, uint16_t kubits, int kucrit, EKU_LIST *ekulist) { KMF_RETURN rv = KMF_OK; KMF_X509_NAME issuerDN, subjectDN; /* * If the CSR is ok, now we can generate the final certificate. */ (void) memset(signedCert, 0, sizeof (KMF_X509_CERTIFICATE)); (void) memset(&issuerDN, 0, sizeof (issuerDN)); (void) memset(&subjectDN, 0, sizeof (subjectDN)); 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, 0, ltime), "validity time"); if (issuer) { if (kmf_dn_parser(issuer, &issuerDN) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Issuer name cannot be parsed\n")); return (PK_ERR_USAGE); } SET_VALUE(kmf_set_cert_issuer(signedCert, &issuerDN), "Issuer Name"); } if (subject) { if (kmf_dn_parser(subject, &subjectDN) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed\n")); return (PK_ERR_USAGE); } SET_VALUE(kmf_set_cert_subject(signedCert, &subjectDN), "Subject Name"); } else { signedCert->certificate.subject = csrdata->csr.subject; } signedCert->certificate.subjectPublicKeyInfo = csrdata->csr.subjectPublicKeyInfo; signedCert->certificate.extensions = csrdata->csr.extensions; signedCert->certificate.signature = csrdata->signature.algorithmIdentifier; if (kubits != 0) { KMF_X509_EXTENSION extn; uint16_t oldbits; /* * If the CSR already has KU, merge them. */ rv = find_csr_extn(&csrdata->csr.extensions, (KMF_OID *)&KMFOID_KeyUsage, &extn); if (rv == KMF_OK) { extn.critical |= kucrit; if (extn.value.tagAndValue->value.Length > 1) { oldbits = extn.value.tagAndValue->value.Data[1] << 8; } else { oldbits = extn.value.tagAndValue->value.Data[0]; } oldbits |= kubits; } else { SET_VALUE(kmf_set_cert_ku(signedCert, kucrit, kubits), "KeyUsage"); } } if (altname != NULL) { SET_VALUE(kmf_set_cert_subject_altname(signedCert, altcrit, alttype, altname), "subjectAltName"); } if (ekulist != NULL) { int i; for (i = 0; rv == KMF_OK && i < ekulist->eku_count; i++) { SET_VALUE(kmf_add_cert_eku(signedCert, &ekulist->ekulist[i], ekulist->critlist[i]), "Extended Key Usage"); } } cleanup: if (issuer != NULL) kmf_free_dn(&issuerDN); if (subject != NULL) kmf_free_dn(&subjectDN); return (rv); } static int pk_sign_cert(KMF_HANDLE_T handle, KMF_X509_CERTIFICATE *cert, KMF_KEY_HANDLE *key, KMF_OID *sigoid, KMF_DATA *outdata) { KMF_RETURN rv; int numattr; KMF_ATTRIBUTE attrlist[4]; numattr = 0; kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYSTORE_TYPE_ATTR, &key->kstype, sizeof (KMF_KEYSTORE_TYPE)); kmf_set_attr_at_index(attrlist, numattr++, KMF_KEY_HANDLE_ATTR, key, sizeof (KMF_KEY_HANDLE_ATTR)); /* cert data that is to be signed */ kmf_set_attr_at_index(attrlist, numattr++, KMF_X509_CERTIFICATE_ATTR, cert, sizeof (KMF_X509_CERTIFICATE)); /* output buffer for the signed cert */ kmf_set_attr_at_index(attrlist, numattr++, KMF_CERT_DATA_ATTR, outdata, sizeof (KMF_DATA)); /* Set the signature OID value so KMF knows how to generate the sig */ if (sigoid) { kmf_set_attr_at_index(attrlist, numattr++, KMF_OID_ATTR, sigoid, sizeof (KMF_OID)); } if ((rv = kmf_sign_cert(handle, numattr, attrlist)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Failed to sign certificate.\n")); return (rv); } return (rv); } static int pk_signcsr_files(KMF_HANDLE_T handle, char *signkey, char *csrfile, KMF_BIGINT *serial, char *certfile, char *issuer, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, uint16_t kubits, int kucrit, EKU_LIST *ekulist, uint32_t ltime, KMF_ENCODE_FORMAT fmt) { KMF_RETURN rv = KMF_OK; KMF_CSR_DATA csrdata; KMF_ATTRIBUTE attrlist[16]; KMF_X509_CERTIFICATE signedCert; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; KMF_KEY_CLASS keyclass = KMF_ASYM_PRI; KMF_KEY_HANDLE cakey; KMF_DATA certdata = { 0, NULL }; int numattr, count; (void) memset(&cakey, 0, sizeof (cakey)); (void) memset(&signedCert, 0, sizeof (signedCert)); rv = read_csrdata(handle, csrfile, &csrdata); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error reading CSR data\n")); return (rv); } /* verify the signature first */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_CSR_DATA_ATTR, &csrdata, sizeof (csrdata)); numattr++; rv = kmf_verify_csr(handle, numattr, attrlist); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("CSR signature " "verification failed.\n")); goto cleanup; } rv = build_cert_from_csr(&csrdata, &signedCert, serial, ltime, issuer, subject, altname, alttype, altcrit, kubits, kucrit, ekulist); if (rv != KMF_OK) goto cleanup; /* * Find the signing key. */ (void) memset(&cakey, 0, sizeof (cakey)); 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_FILENAME_ATTR, signkey, strlen(signkey)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &cakey, sizeof (cakey)); numattr++; count = 1; kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &count, sizeof (count)); numattr++; rv = kmf_find_key(handle, numattr, attrlist); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext( "Error finding CA signing key\n")); goto cleanup; } rv = pk_sign_cert(handle, &signedCert, &cakey, NULL, &certdata); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext( "Error signing certificate.\n")); goto cleanup; } rv = kmf_create_cert_file(&certdata, fmt, certfile); cleanup: kmf_free_signed_csr(&csrdata); kmf_free_data(&certdata); kmf_free_kmf_key(handle, &cakey); return (rv); } static int pk_signcsr_pk11_nss(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE kstype, char *dir, char *prefix, char *token, KMF_CREDENTIAL *cred, char *signkey, char *csrfile, KMF_BIGINT *serial, char *certfile, char *issuer, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, uint16_t kubits, int kucrit, EKU_LIST *ekulist, uint32_t ltime, KMF_ENCODE_FORMAT fmt, int store, char *outlabel) { KMF_RETURN rv = KMF_OK; KMF_DATA outcert = { 0, NULL }; KMF_CSR_DATA csrdata = { 0, NULL }; KMF_KEY_HANDLE casignkey; KMF_KEY_CLASS keyclass = KMF_ASYM_PRI; KMF_ATTRIBUTE attrlist[16]; KMF_X509_CERTIFICATE signedCert; boolean_t token_bool = B_TRUE; boolean_t private_bool = B_TRUE; int numattr = 0; int keys = 1; (void) memset(&casignkey, 0, sizeof (KMF_KEY_HANDLE)); (void) memset(&signedCert, 0, sizeof (signedCert)); rv = read_csrdata(handle, csrfile, &csrdata); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error reading CSR data\n")); return (rv); } if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = select_token(handle, token, FALSE); } else if (kstype == KMF_KEYSTORE_NSS) { rv = configure_nss(handle, dir, prefix); } /* verify the signature first */ kmf_set_attr_at_index(attrlist, numattr, KMF_CSR_DATA_ATTR, &csrdata, sizeof (csrdata)); numattr++; rv = kmf_verify_csr(handle, numattr, attrlist); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("CSR signature " "verification failed.\n")); goto cleanup; } rv = build_cert_from_csr(&csrdata, &signedCert, serial, ltime, issuer, subject, altname, alttype, altcrit, kubits, kucrit, ekulist); if (rv != KMF_OK) goto cleanup; /* * Find the signing key. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (kstype == KMF_KEYSTORE_NSS) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, signkey, strlen(signkey)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVATE_BOOL_ATTR, &private_bool, sizeof (private_bool)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR, &token_bool, sizeof (token_bool)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL_ATTR)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &keys, sizeof (keys)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &casignkey, sizeof (casignkey)); numattr++; rv = kmf_find_key(handle, numattr, attrlist); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Failed to find signing key\n")); goto cleanup; } /* * If we found the key, now we can sign the cert. */ rv = pk_sign_cert(handle, &signedCert, &casignkey, NULL, &outcert); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext( "Error signing certificate.\n")); goto cleanup; } /* * Store it on the token if the user asked for it. */ if (store) { 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, &outcert, sizeof (KMF_DATA)); numattr++; if (outlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, outlabel, strlen(outlabel)); numattr++; } if (kstype == KMF_KEYSTORE_NSS) { if (token != NULL) kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } rv = kmf_store_cert(handle, numattr, attrlist); if (rv != KMF_OK) { display_error(handle, rv, gettext("Failed to store cert " "on PKCS#11 token.\n")); rv = KMF_OK; /* Not fatal, we can still write it to a file. */ } } rv = kmf_create_cert_file(&outcert, fmt, certfile); cleanup: kmf_free_signed_csr(&csrdata); kmf_free_data(&outcert); kmf_free_kmf_key(handle, &casignkey); return (rv); } /* * sign a CSR and generate an x509v3 certificate file. */ int pk_signcsr(int argc, char *argv[]) { int opt; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *subject = NULL; char *issuer = NULL; char *dir = NULL; char *prefix = NULL; char *csrfile = NULL; char *serstr = NULL; char *ekustr = NULL; char *kustr = NULL; char *format = NULL; char *storestr = NULL; char *altname = NULL; char *certfile = NULL; char *lifetime = NULL; char *signkey = NULL; char *outlabel = NULL; uint32_t ltime = 365 * 24 * 60 * 60; /* 1 Year */ int store = 0; uint16_t kubits = 0; int altcrit = 0, kucrit = 0; KMF_BIGINT serial = { NULL, 0 }; EKU_LIST *ekulist = NULL; KMF_KEYSTORE_TYPE kstype = 0; KMF_RETURN rv = KMF_OK; KMF_HANDLE_T kmfhandle = NULL; KMF_CREDENTIAL tokencred = { NULL, 0 }; KMF_GENERALNAMECHOICES alttype = 0; KMF_ENCODE_FORMAT fmt = KMF_FORMAT_PEM; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "k:(keystore)c:(csr)T:(token)d:(dir)" "p:(prefix)S:(serial)s:(subject)a:(altname)" "t:(store)F:(format)K:(keyusage)l:(signkey)" "L:(lifetime)e:(eku)i:(issuer)" "n:(outlabel)o:(outcert)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'k': if (kstype != 0) return (PK_ERR_USAGE); kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 't': if (storestr != NULL) return (PK_ERR_USAGE); storestr = optarg_av; store = yn_to_int(optarg_av); if (store == -1) return (PK_ERR_USAGE); break; case 'a': if (altname) return (PK_ERR_USAGE); altname = optarg_av; break; case 's': if (subject) return (PK_ERR_USAGE); subject = optarg_av; break; case 'i': if (issuer) return (PK_ERR_USAGE); issuer = 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 'S': if (serstr != NULL) return (PK_ERR_USAGE); serstr = optarg_av; break; case 'c': if (csrfile) return (PK_ERR_USAGE); csrfile = optarg_av; break; case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = optarg_av; break; case 'l': /* object with specific label */ if (signkey) return (PK_ERR_USAGE); signkey = optarg_av; break; case 'e': if (ekustr != NULL) return (PK_ERR_USAGE); ekustr = optarg_av; break; case 'K': if (kustr != NULL) return (PK_ERR_USAGE); kustr = optarg_av; break; case 'F': if (format != NULL) return (PK_ERR_USAGE); format = optarg_av; break; case 'o': if (certfile != NULL) return (PK_ERR_USAGE); certfile = optarg_av; break; case 'L': if (lifetime != NULL) return (PK_ERR_USAGE); lifetime = optarg_av; break; case 'n': if (outlabel != NULL) return (PK_ERR_USAGE); outlabel = optarg_av; break; default: 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 (signkey == NULL) { (void) fprintf(stderr, gettext("The signing key label " "or filename was not specified\n")); return (PK_ERR_USAGE); } if (csrfile == NULL) { (void) fprintf(stderr, gettext("The CSR filename was not" " specified\n")); return (PK_ERR_USAGE); } if (certfile == NULL) { (void) fprintf(stderr, gettext("The output certificate file " "was not specified\n")); return (PK_ERR_USAGE); } if (issuer == NULL) { (void) fprintf(stderr, gettext("The issuer DN " "was not specified\n")); return (PK_ERR_USAGE); } if (lifetime != NULL) { if (Str2Lifetime(lifetime, <ime) != 0) { cryptoerror(LOG_STDERR, gettext("Error parsing lifetime string\n")); return (PK_ERR_USAGE); } } if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) { token_spec = PK_DEFAULT_PK11TOKEN; } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) { token_spec = DEFAULT_NSS_TOKEN; } if (serstr != NULL) { 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")); return (PK_ERR_USAGE); } serial.val = bytes; serial.len = bytelen; } else { (void) fprintf(stderr, gettext("The serial number was not" " specified\n")); return (PK_ERR_USAGE); } if ((kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS)) { /* Need to get password for private key access */ (void) get_token_password(kstype, token_spec, &tokencred); } if (kustr != NULL) { rv = verify_keyusage(kustr, &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 (altname != NULL) { char *p; 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; } /* advance the altname past the '=' sign */ p = strchr(altname, '='); if (p != NULL) altname = p + 1; } if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) { cryptoerror(LOG_STDERR, gettext("Error parsing format string (%s).\n"), format); return (PK_ERR_USAGE); } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { return (rv); } if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = pk_signcsr_pk11_nss(kmfhandle, kstype, dir, prefix, token_spec, &tokencred, signkey, csrfile, &serial, certfile, issuer, subject, altname, alttype, altcrit, kubits, kucrit, ekulist, ltime, fmt, store, outlabel); } else if (kstype == KMF_KEYSTORE_NSS) { if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; rv = pk_signcsr_pk11_nss(kmfhandle, kstype, dir, prefix, token_spec, &tokencred, signkey, csrfile, &serial, certfile, issuer, subject, altname, alttype, altcrit, kubits, kucrit, ekulist, ltime, fmt, store, outlabel); } else if (kstype == KMF_KEYSTORE_OPENSSL) { rv = pk_signcsr_files(kmfhandle, signkey, csrfile, &serial, certfile, issuer, subject, altname, alttype, altcrit, kubits, kucrit, ekulist, ltime, fmt); } end: if (rv != KMF_OK) { display_error(kmfhandle, rv, gettext("Error listing objects")); } if (serial.val != NULL) free(serial.val); if (tokencred.cred != NULL) free(tokencred.cred); free_eku_list(ekulist); (void) kmf_finalize(kmfhandle); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * This file implements the token list operation for this tool. * It loads the PKCS#11 modules, gets the list of slots with * tokens in them, displays the list, and cleans up. */ #include #include #include #include #include "common.h" /* * Lists all slots with tokens in them. */ int pk_tokens(int argc, char *argv[]) { CK_SLOT_ID_PTR slots = NULL; CK_ULONG slot_count = 0; CK_TOKEN_INFO token_info; const char *fmt = NULL; CK_RV rv = CKR_OK; int i; /* Get rid of subcommand word "tokens". */ argc--; argv++; /* No additional args allowed. */ if (argc != 0) return (PK_ERR_USAGE); /* Done parsing command line options. */ /* Get the list of slots with tokens in them. */ if ((rv = get_token_slots(&slots, &slot_count)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get token slot list (%s)."), pkcs11_strerror(rv)); return (PK_ERR_PK11); } /* Make sure we have something to display. */ if (slot_count == 0) { cryptoerror(LOG_STDERR, gettext("No slots with tokens found.")); return (0); } /* Display the list. */ fmt = "%-30.30s %-15.15s %-15.15s %-10.10s\n"; /* No I18N/L10N. */ (void) fprintf(stdout, fmt, gettext("Token Label"), gettext("Manuf ID"), gettext("Serial No"), gettext("PIN State")); for (i = 0; i < slot_count; i++) { if ((rv = C_GetTokenInfo(slots[i], &token_info)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get slot %d token info (%s)."), i, pkcs11_strerror(rv)); continue; } (void) fprintf(stdout, fmt, token_info.label, token_info.manufacturerID, token_info.serialNumber, (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ? gettext("default") : gettext("user set")); } /* Clean up. */ free(slots); (void) C_Finalize(NULL); return (0); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # MANIFEST = cryptosvc.xml include ../../Makefile.cmd .KEEP_STATE: ROOTMANIFESTDIR = $(ROOTSVCSYSTEM) install: $(ROOTMANIFEST) check: $(CHKMANIFEST) include ../../Makefile.targ # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # ident "%Z%%M% %I% %E% SMI" # # Class action script for "kcfconf" class files. # # This script appends the input file from the package to the # /etc/crypto/kcf.conf file. # # The syntax of the input file for a kernel software provider package is # :supportedlist= # where # ::= the kernel software module base name # ::= {,}* # ::= a mechanism name as specified by the RSA PKCS#11 spec. # # The syntax of the input file for a cryptographic provider device driver(s) # package is # driver_names= # where # ::= {,}* # ::= a device driver name # pkg_start="# Start $PKGINST" pkg_end="# End $PKGINST" tmpfile=/tmp/$$kcfconf error=no while read src dest do [ "$src" = /dev/null ] && continue if [ -f "$dest" ] then # For multiple input files; exit if error occurred in previous # input file. if [ "$error" = yes ] then echo "$0: failed to update $lastdest for $PKGINST." exit 2 fi lastdest=$dest # # If the package has been already installed, remove old entries # start=0; end=0; egrep -s "$pkg_start" $dest && start=1 egrep -s "$pkg_end" $dest && end=1 if [ $start -ne $end ] then echo "$0: missing Start or End delimiters for \ $PKGINST in $dest." echo "$0: $dest may be corrupted and was not updated." error=yes continue fi if [ $start -eq 1 ] then sed -e "/$pkg_start/,/$pkg_end/d" $dest > $tmpfile \ || error=yes else cp $dest $tmpfile || error=yes fi # # Check the input file syntax and append the input entries # with the package delimiters. # line_count=`wc -l $src | awk '{ print $1}'` grep "driver_names" $src > /dev/null if [ $? -eq 0 ] then # # This is a device driver package. # - $src should contain only one line. # - If syntax of $src is correct, append the package # start delimiter with the driver_names string. # if [ $line_count -ne 1 ]; then echo "$0: Syntax Error - $src for $PKGINST." error=yes continue else echo "$pkg_start `cat $src`" >> $tmpfile \ || error=yes fi else # # This is a kernel software provider package. # - Each line in $src should contain "supportedlist". # - If syntax of $src is correct, append the package # start delimiter and the $src file. # supported_count=`grep supportedlist $src |wc -l` if [ $line_count -ne $supported_count ] then echo "$0: Syntax Error - $src for $PKGINST." error=yes continue else echo "$pkg_start" >> $tmpfile || error=yes cat $src >> $tmpfile || error=yes fi fi echo "$pkg_end" >> $tmpfile || error=yes # Install the updated config file and clean up the tmp file if [ "$error" = no ] then mv $tmpfile $dest || error=yes fi rm -f $tmpfile else echo "$0: ERROR - $dest doesn't exist for $PKGINST." exit 2 fi done if [ "$error" = yes ] then echo "$0: ERROR - failed to update $lastdest for $PKGINST." exit 2 fi exit 0 # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # ident "%Z%%M% %I% %E% SMI" # # Class action script for "kmfconf" class files. # # This script appends the input file from the package to the # /etc/crypto/kmf.conf file. # # The syntax of the input file is # keystore:modulepath=path[;option=option_str] # # pkg_start="# Start $PKGINST" pkg_end="# End $PKGINST" tmpfile=/tmp/$$kmfconf error=no while read src dest do [ "$src" = /dev/null ] && continue if [ -f "$dest" ] then # For multiple input files; exit if error occurred in previous # input file. if [ "$error" = yes ] then echo "$0: failed to update $lastdest for $PKGINST." exit 2 fi lastdest=$dest # # If the package has been already installed, remove old entries # start=0; end=0; egrep -s "$pkg_start" $dest && start=1 egrep -s "$pkg_end" $dest && end=1 if [ $start -ne $end ] then echo "$0: missing Start or End delimiters for \ $PKGINST in $dest." echo "$0: $dest may be corrupted and was not updated." error=yes continue fi if [ $start -eq 1 ] then sed -e "/$pkg_start/,/$pkg_end/d" $dest > $tmpfile \ || error=yes else cp $dest $tmpfile || error=yes fi # # Check the input file syntax (should at least contain # ":module_path="). Then append the input entries with the #scc package delimiters. # line_count=`wc -l $src | awk '{ print $1}'` file_count=`grep ":modulepath=" $src | wc -l` if [ $line_count -ne $file_count ] then echo "$0: Syntax Error - $src for $PKGINST." error=yes continue else echo "$pkg_start" >> $tmpfile || error=yes cat $src >> $tmpfile || error=yes echo "$pkg_end" >> $tmpfile || error=yes fi # Install the updated config file and clean up the tmp file if [ "$error" = no ] then mv $tmpfile $dest || error=yes fi rm -f $tmpfile else echo "$0: ERROR - $dest doesn't exist for $PKGINST." exit 2 fi done if [ "$error" = yes ] then echo "$0: ERROR - failed to update $lastdest for $PKGINST." exit 2 fi exit 0 # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # ident "%Z%%M% %I% %E% SMI" # # Class action script for "pkcs11conf" class files. # # This script appends the input file from the package to the # /etc/crypto/pkcs11.conf file. # # The syntax of the input file is # Where # The file name should contain the full path. # One entry per file name. # pkg_start="# Start $PKGINST" pkg_end="# End $PKGINST" tmpfile=/tmp/$$pkcs11conf error=no while read src dest do [ "$src" = /dev/null ] && continue if [ -f "$dest" ] then # For multiple input files; exit if error occurred in previous # input file. if [ "$error" = yes ] then echo "$0: failed to update $lastdest for $PKGINST." exit 2 fi lastdest=$dest # # If the package has been already installed, remove old entries # start=0; end=0; egrep -s "$pkg_start" $dest && start=1 egrep -s "$pkg_end" $dest && end=1 if [ $start -ne $end ] then echo "$0: missing Start or End delimiters for \ $PKGINST in $dest." echo "$0: $dest may be corrupted and was not updated." error=yes continue fi if [ $start -eq 1 ] then sed -e "/$pkg_start/,/$pkg_end/d" $dest > $tmpfile \ || error=yes else cp $dest $tmpfile || error=yes fi # # Check the input file syntax (each line should start with /) # and append the input entries with the package delimiters. # line_count=`wc -l $src | awk '{ print $1}'` file_count=`grep "^/" $src | wc -l` if [ $line_count -ne $file_count ] then echo "$0: Syntax Error - $src for $PKGINST." error=yes continue else echo "$pkg_start" >> $tmpfile || error=yes cat $src >> $tmpfile || error=yes echo "$pkg_end" >> $tmpfile || error=yes fi # Install the updated config file and clean up the tmp file if [ "$error" = no ] then mv $tmpfile $dest || error=yes fi rm -f $tmpfile else echo "$0: ERROR - $dest doesn't exist for $PKGINST." exit 2 fi done if [ "$error" = yes ] then echo "$0: ERROR - failed to update $lastdest for $PKGINST." exit 2 fi exit 0 # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # ident "%Z%%M% %I% %E% SMI" # # Removal class action script for "kcfconf" class files. # # This script removes entries belonging to the package from the # /etc/crypto/kcf.conf file. # pkg_start="# Start $PKGINST" pkg_end="# End $PKGINST" tmpfile=/tmp/$$kcfconf error=no while read dest do # For multiple input files; exit if error occurred in previous # input file. if [ "$error" = yes ] then echo "$0: failed to update $lastdest for $PKGINST." exit 2 fi lastdest=$dest # Strip all entries belonging to this package start=0 end=0 egrep -s "$pkg_start" $dest && start=1 egrep -s "$pkg_end" $dest && end=1 if [ $start -ne $end ] ; then echo "$0: missing Start or End delimiters for $PKGINST in \ $dest." echo "$0: $dest may be corrupted and was not updated." error=yes continue fi if [ $start -eq 1 ] then sed -e "/$pkg_start/,/$pkg_end/d" $dest > $tmpfile || error=yes if [ "$error" = no ] then mv $tmpfile $dest || error=yes fi rm -f $tmpfile else echo "$0: WARNING - no entries found in $dest for $PKGINST." exit 0 fi done if [ "$error" = yes ] then echo "$0: ERROR - failed to update $lastdest for $PKGINST." exit 2 fi exit 0 # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # ident "%Z%%M% %I% %E% SMI" # # Removal class action script for "kmfconf" class files. # # This script removes entries belonging to the package from the # /etc/crypto/kmf.conf file. # pkg_start="# Start $PKGINST" pkg_end="# End $PKGINST" tmpfile=/tmp/$$kmfconf error=no while read dest do # For multiple input files; exit if error occurred in preious # input file. if [ "$error" = yes ] then echo "$0: failed to update $lastdest for $PKGINST." exit 2 fi lastdest=$dest # Strip all entries belonging to this package start=0 end=0 egrep -s "$pkg_start" $dest && start=1 egrep -s "$pkg_end" $dest && end=1 if [ $start -ne $end ] ; then echo "$0: missing Start or End delimiters for $PKGINST in \ $dest." echo "$0: $dest may be corrupted and was not updated." error=yes continue fi if [ $start -eq 1 ] then sed -e "/$pkg_start/,/$pkg_end/d" $dest > $tmpfile || error=yes if [ "$error" = no ] then mv $tmpfile $dest || error=yes fi rm -f $tmpfile else echo "$0: WARNING - no entries found in $dest for $PKGINST." exit 0 fi done if [ "$error" = yes ] then echo "$0: ERROR - failed to update $lastdest for $PKGINST." exit 2 fi exit 0 # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # ident "%Z%%M% %I% %E% SMI" # # Removal class action script for "pkcs11conf" class files. # # This script removes entries belonging to the package from the # /etc/crypto/pkcs11.conf file. # pkg_start="# Start $PKGINST" pkg_end="# End $PKGINST" tmpfile=/tmp/$$pkcs11conf error=no while read dest do # For multiple input files; exit if error occurred in preious # input file. if [ "$error" = yes ] then echo "$0: failed to update $lastdest for $PKGINST." exit 2 fi lastdest=$dest # Strip all entries belonging to this package start=0 end=0 egrep -s "$pkg_start" $dest && start=1 egrep -s "$pkg_end" $dest && end=1 if [ $start -ne $end ] ; then echo "$0: missing Start or End delimiters for $PKGINST in \ $dest." echo "$0: $dest may be corrupted and was not updated." error=yes continue fi if [ $start -eq 1 ] then sed -e "/$pkg_start/,/$pkg_end/d" $dest > $tmpfile || error=yes if [ "$error" = no ] then mv $tmpfile $dest || error=yes fi rm -f $tmpfile else echo "$0: WARNING - no entries found in $dest for $PKGINST." exit 0 fi done if [ "$error" = yes ] then echo "$0: ERROR - failed to update $lastdest for $PKGINST." exit 2 fi exit 0 # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # PROG = tpmadm OBJS = main.o \ admin_cmds.o include ../../Makefile.cmd SRCS = $(OBJS:%.o=%.c) POFILES = $(OBJS:%.o=%.po) POFILE = $(PROG)_msg.po MSGFILES = $(SRCS:%.c=%.i) LDLIBS += -ltspi -luuid NATIVE_LIBS += libtspi.so CLOBBERFILES = $(POFILE) $(POFILES) .KEEP_STATE: all : $(PROG) $(PROG) : $(OBJS) $(LINK.c) -o $@ $(OBJS) $(DYNFLAGS) $(LDLIBS) $(POST_PROCESS) $(POFILE) : $(POFILES) $(RM) $@; $(CAT) $(POFILES) > $@ install : all $(ROOTPROG) clean : $(RM) $(OBJS) include ../../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tpmadm.h" int cmd_status(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); int cmd_init(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); int cmd_clear(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); int cmd_auth(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); int cmd_keyinfo(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); int cmd_deletekey(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); cmdtable_t commands[] = { { "status", "", cmd_status }, { "init", "", cmd_init }, { "clear", "[owner | lock]", cmd_clear }, { "auth", "", cmd_auth }, { "keyinfo", "[uuid]", cmd_keyinfo }, { "deletekey", "uuid", cmd_deletekey }, { NULL, NULL, NULL }, }; BYTE well_known[] = TSS_WELL_KNOWN_SECRET; TSS_UUID srk_uuid = TSS_UUID_SRK; /* * TPM status */ static int print_tpm_version(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM) { struct { TPM_CAP_VERSION_INFO vers_info; char extra[20]; /* vendor extensions */ } info; if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_VERSION_VAL, 0, &info, sizeof (info))) return (ERR_FAIL); (void) printf(gettext("TPM Version: %d.%d (%c%c%c%c Rev: %d.%d, " "SpecLevel: %d, ErrataRev: %d)\n"), info.vers_info.version.major, info.vers_info.version.minor, info.vers_info.tpmVendorID[0], info.vers_info.tpmVendorID[1], info.vers_info.tpmVendorID[2], info.vers_info.tpmVendorID[3], info.vers_info.version.revMajor, info.vers_info.version.revMinor, (int)ntohs(info.vers_info.specLevel), info.vers_info.errataRev); return (0); } static int tpm_is_owned(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM) { BYTE owned; if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_OWNER, &owned, sizeof (owned))) return (0); return (owned); } static int print_tpm_resources(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM) { UINT32 avail, max; (void) printf(gettext("TPM resources\n")); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_MAXCONTEXTS, &max, sizeof (max))) return (ERR_FAIL); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_CONTEXTS, &avail, sizeof (avail))) return (ERR_FAIL); (void) printf(gettext("\tContexts: %d/%d available\n"), avail, max); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_MAXSESSIONS, &max, sizeof (max))) return (ERR_FAIL); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_SESSIONS, &avail, sizeof (avail))) return (ERR_FAIL); (void) printf(gettext("\tSessions: %d/%d available\n"), avail, max); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_MAXAUTHSESSIONS, &max, sizeof (max))) return (ERR_FAIL); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_AUTHSESSIONS, &avail, sizeof (avail))) return (ERR_FAIL); (void) printf(gettext("\tAuth Sessions: %d/%d available\n"), avail, max); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_MAXKEYS, &max, sizeof (max))) return (ERR_FAIL); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_KEYS, &avail, sizeof (avail))) return (ERR_FAIL); (void) printf(gettext("\tLoaded Keys: %d/%d available\n"), avail, max); return (0); } static int print_tpm_pcrs(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM) { UINT32 num_pcrs; int i; if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_PCR, &num_pcrs, sizeof (num_pcrs))) return (ERR_FAIL); (void) printf(gettext("Platform Configuration Registers (%u)\n"), num_pcrs); /* Print each PCR */ for (i = 0; i < num_pcrs; i++) { TSS_RESULT ret; UINT32 datalen; BYTE *data; ret = Tspi_TPM_PcrRead(hTPM, i, &datalen, &data); if (ret) { print_error(ret, gettext("Read PCR")); return (ret); } (void) printf("\tPCR %u:\t", i); print_bytes(data, datalen, FALSE); ret = Tspi_Context_FreeMemory(hContext, data); if (ret) { print_error(ret, gettext("Free PCR memory")); return (ret); } } return (0); } /*ARGSUSED*/ int cmd_status(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP, NULL, 0, NULL)) return (ERR_FAIL); (void) print_tpm_version(hContext, hTPM); if (tpm_is_owned(hContext, hTPM)) { (void) print_tpm_resources(hContext, hTPM); (void) print_tpm_pcrs(hContext, hTPM); } else { (void) printf(gettext("No TPM owner installed.\n")); } return (0); } /* * Key Information */ typedef struct { UINT32 code; char *str; } decode_map_t; decode_map_t key_usage[] = { { TSS_KEYUSAGE_SIGN, "Signing" }, { TSS_KEYUSAGE_STORAGE, "Storage" }, { TSS_KEYUSAGE_IDENTITY, "Identity" }, { TSS_KEYUSAGE_AUTHCHANGE, "Authchange" }, { TSS_KEYUSAGE_BIND, "Bind" }, { TSS_KEYUSAGE_LEGACY, "Legacy" }, { TSS_KEYUSAGE_MIGRATE, "Migrate" }, { 0, NULL }, }; decode_map_t key_algorithm[] = { { TSS_ALG_RSA, "RSA" }, { TSS_ALG_DES, "DES" }, { TSS_ALG_3DES, "3-DES" }, { TSS_ALG_SHA, "SHA" }, { TSS_ALG_HMAC, "HMAC" }, { TSS_ALG_AES, "AES" }, { TSS_ALG_MGF1, "MGF1" }, { TSS_ALG_AES192, "AES192" }, { TSS_ALG_AES256, "AES256" }, { TSS_ALG_XOR, "XOR" }, { 0, NULL }, }; decode_map_t key_sigscheme[] = { { TSS_SS_NONE, "None" }, { TSS_SS_RSASSAPKCS1V15_SHA1, "RSASSAPKCS1v15_SHA1" }, { TSS_SS_RSASSAPKCS1V15_DER, "RSASSAPKCS1v15_DER" }, { 0, NULL }, }; decode_map_t key_encscheme[] = { { TSS_ES_NONE, "None" }, { TSS_ES_RSAESPKCSV15, "RSAESPKCSv15" }, { TSS_ES_RSAESOAEP_SHA1_MGF1, "RSAESOAEP_SHA1_MGF1" }, { TSS_ES_SYM_CNT, "SYM_CNT" }, { TSS_ES_SYM_OFB, "SYM_OFB" }, { 0, NULL }, }; static char * decode(decode_map_t *table, UINT32 code) { static char buf[20]; int i; for (i = 0; table[i].str != NULL; i++) { if (table[i].code == code) return (table[i].str); } (void) snprintf(buf, sizeof (buf), gettext("Unknown (%u)"), code); return (buf); } static void print_key_info(TSS_HCONTEXT hContext, TSS_HOBJECT hKey) { TSS_RESULT ret; UINT32 attrib; UINT32 keyInfoSize; BYTE *keyInfo; /* Key size */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIZE, &attrib); if (ret) { print_error(ret, gettext("Get key size")); } (void) printf(gettext("Key Size: %d bits\n"), attrib); /* Key usage */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_USAGE, &attrib); if (ret) { print_error(ret, gettext("Get key usage")); } (void) printf(gettext("Key Usage: %s\n"), decode(key_usage, attrib)); /* Algorithm */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_ALGORITHM, &attrib); if (ret) { print_error(ret, gettext("Get key algorithm")); } (void) printf(gettext("Algorithm: %s\n"), decode(key_algorithm, attrib)); /* Authorization required */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_AUTHUSAGE, &attrib); if (ret) { print_error(ret, gettext("Get key authusage")); } (void) printf(gettext("Authorization required: %s\n"), attrib ? gettext("Yes") : gettext("No")); /* Signature scheme */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIGSCHEME, &attrib); if (ret) { print_error(ret, gettext("Get key signature scheme")); } (void) printf(gettext("Signature scheme: %s\n"), decode(key_sigscheme, attrib)); /* Encoding scheme */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_ENCSCHEME, &attrib); if (ret) { print_error(ret, gettext("Get key encoding scheme")); } (void) printf(gettext("Encoding scheme: %s\n"), decode(key_encscheme, attrib)); /* Key blob */ ret = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB, &keyInfoSize, &keyInfo); if (ret) { print_error(ret, gettext("Get key blob")); } (void) printf(gettext("TPM Key Blob:\n")); print_bytes(keyInfo, keyInfoSize, TRUE); ret = Tspi_Context_FreeMemory(hContext, keyInfo); if (ret) { print_error(ret, gettext("Free key info buffer")); } } typedef struct hash_node { struct hash_node *next, *sibling, *child; TSS_UUID uuid; TSS_KM_KEYINFO2 *key_data; } hash_node_t; #define HASHSIZE 17 hash_node_t *hash_table[HASHSIZE]; static hash_node_t * hash_insert(TSS_UUID uuid, TSS_KM_KEYINFO2 *key_data) { UINT32 i, index = 0; hash_node_t *node; char *cp; cp = (char *)&uuid; for (i = 0; i < sizeof (TSS_UUID); i++) index += cp[i]; index = index % HASHSIZE; for (node = hash_table[index]; node != NULL; node = node->next) { if (memcmp(&(node->uuid), &uuid, sizeof (TSS_UUID)) == 0) break; } if (node == NULL) { node = calloc(1, sizeof (hash_node_t)); node->uuid = uuid; node->next = hash_table[index]; hash_table[index] = node; } if (node->key_data == NULL) node->key_data = key_data; return (node); } static void add_child(hash_node_t *parent, hash_node_t *child) { hash_node_t *node; for (node = parent->child; node != NULL; node = node->next) { if (node == child) return; } child->sibling = parent->child; parent->child = child; } static void print_all(hash_node_t *parent, int indent) { char uuidstr[UUID_PRINTABLE_STRING_LENGTH]; hash_node_t *node; char *type, *loaded; uuid_unparse(*(uuid_t *)&parent->uuid, uuidstr); type = (parent->key_data->persistentStorageType == TSS_PS_TYPE_USER) ? "USER" : "SYSTEM"; loaded = parent->key_data->fIsLoaded ? "(loaded)" : ""; (void) printf("%*s[%s] %s %s\n", indent, "", type, uuidstr, loaded); for (node = parent->child; node != NULL; node = node->sibling) print_all(node, indent + 4); } /*ARGSUSED*/ int cmd_keyinfo(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { TSS_RESULT ret; UINT32 i, num_keys; TSS_KM_KEYINFO2 *keys; hash_node_t *parent, *child, *srk = NULL; TSS_HKEY hKey; union { uuid_t arr_uuid; TSS_UUID tss_uuid; } uuid; switch (argc) { case 1: /* Print key hierarchy */ ret = Tspi_Context_GetRegisteredKeysByUUID2(hContext, TSS_PS_TYPE_USER, NULL, &num_keys, &keys); if (ret) { print_error(ret, gettext("Get key hierarchy")); return (ERR_FAIL); } for (i = 0; i < num_keys; i++) { parent = hash_insert(keys[i].parentKeyUUID, NULL); child = hash_insert(keys[i].keyUUID, &keys[i]); add_child(parent, child); if (memcmp(&(keys[i].keyUUID), &srk_uuid, sizeof (TSS_UUID)) == 0) srk = child; } if (srk != NULL) print_all(srk, 0); ret = Tspi_Context_FreeMemory(hContext, (BYTE *) keys); if (ret) { print_error(ret, gettext("Free key list")); return (ERR_FAIL); } return (0); case 2: /* Print detailed info about a single key */ if (uuid_parse(argv[1], uuid.arr_uuid)) return (ERR_FAIL); ret = Tspi_Context_GetKeyByUUID(hContext, TSS_PS_TYPE_USER, uuid.tss_uuid, &hKey); if (ret == TSP_ERROR(TSS_E_PS_KEY_NOTFOUND)) { ret = Tspi_Context_GetKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, uuid.tss_uuid, &hKey); } if (ret) { print_error(ret, gettext("Get key by UUID")); return (ERR_FAIL); } print_key_info(hContext, hKey); return (0); default: (void) fprintf(stderr, gettext("Usage:\n")); (void) fprintf(stderr, "\tkeyinfo [uuid]\n"); return (ERR_USAGE); } } /*ARGSUSED*/ int cmd_deletekey(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { TSS_RESULT ret; TSS_HOBJECT hKey; union { uuid_t arr_uuid; TSS_UUID tss_uuid; } uuid; if (argc < 2) { (void) fprintf(stderr, gettext("Usage:\n")); (void) fprintf(stderr, "\tdeletekey [uuid]\n"); return (ERR_USAGE); } if (uuid_parse(argv[1], uuid.arr_uuid)) return (ERR_FAIL); ret = Tspi_Context_UnregisterKey(hContext, TSS_PS_TYPE_USER, uuid.tss_uuid, &hKey); if (ret == TSP_ERROR(TSS_E_PS_KEY_NOTFOUND)) { ret = Tspi_Context_UnregisterKey(hContext, TSS_PS_TYPE_SYSTEM, uuid.tss_uuid, &hKey); } if (ret) { print_error(ret, gettext("Unregister key")); return (ERR_FAIL); } return (0); } /* * Clear */ static int clearowner(TSS_HTPM hTPM) { TSS_RESULT ret; if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP, gettext("= TPM owner passphrase ="), 0, NULL)) return (ERR_FAIL); ret = Tspi_TPM_ClearOwner(hTPM, FALSE); if (ret) { print_error(ret, gettext("Clear TPM owner")); return (ERR_FAIL); } return (0); } static int resetlock(TSS_HTPM hTPM) { TSS_RESULT ret; if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP, gettext("= TPM owner passphrase ="), 0, NULL)) return (ERR_FAIL); ret = Tspi_TPM_SetStatus(hTPM, TSS_TPMSTATUS_RESETLOCK, TRUE); if (ret) { print_error(ret, gettext("Reset Lock")); return (ERR_FAIL); } return (0); } /*ARGSUSED*/ int cmd_clear(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { char *subcmd = argv[1]; if (subcmd && strcmp(subcmd, "lock") == 0) { return (resetlock(hTPM)); } else if (subcmd && strcmp(subcmd, "owner") == 0) { return (clearowner(hTPM)); } else { (void) fprintf(stderr, gettext("Usage:\n")); (void) fprintf(stderr, "\tclear owner\n"); (void) fprintf(stderr, "\tclear lock\n"); return (ERR_USAGE); } } /* * TPM initialization */ static int get_random(UINT32 size, BYTE *randomBytes) { int fd, len; BYTE *buf; fd = open("/dev/random", O_RDONLY); if (fd == -1) { (void) fprintf(stderr, gettext("Unable to open /dev/random")); return (-1); } buf = randomBytes; while (size > 0) { len = read(fd, buf, size); if (len <= 0) { (void) close(fd); (void) fprintf(stderr, gettext("Error reading /dev/random")); return (-1); } size -= len; buf += len; } (void) close(fd); return (0); } static int createek(TSS_HCONTEXT hContext, TSS_HTPM hTPM) { TSS_RESULT ret; TSS_HOBJECT hKeyEK; TSS_VALIDATION ValidationData; TPM_NONCE nonce; TPM_DIGEST digest; /* Create the empty key struct for EK */ ret = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY, (TSS_KEY_NO_AUTHORIZATION | TSS_KEY_NON_VOLATILE | TSS_KEY_NOT_MIGRATABLE | TSS_KEY_TYPE_STORAGE | TSS_KEY_SIZE_2048 | TSS_KEY_NOT_CERTIFIED_MIGRATABLE | TSS_KEY_STRUCT_KEY12 | TSS_KEY_EMPTY_KEY), &hKeyEK); if (ret) { print_error(ret, gettext("Create endorsement key object")); return (ERR_FAIL); } ValidationData.ulExternalDataLength = sizeof (nonce); ValidationData.rgbExternalData = (BYTE *) &nonce; ret = get_random(sizeof (nonce), (BYTE *) &nonce); if (ret) return (ERR_FAIL); ValidationData.ulValidationDataLength = sizeof (digest); ValidationData.rgbValidationData = (BYTE *) &digest; ret = Tspi_TPM_CreateEndorsementKey(hTPM, hKeyEK, &ValidationData); if (ret) { print_error(ret, gettext("Create endorsement key")); return (ERR_FAIL); } return (0); } /*ARGSUSED*/ int cmd_init(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { TSS_RESULT ret; TSS_HOBJECT hKeySRK; if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP, gettext("= TPM owner passphrase ="), 0, NULL)) return (ERR_FAIL); ret = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY, TSS_KEY_TSP_SRK | TSS_KEY_AUTHORIZATION, &hKeySRK); if (ret) { print_error(ret, gettext("Create storage root key")); return (ERR_FAIL); } if (set_object_policy(hKeySRK, TSS_SECRET_MODE_SHA1, NULL, sizeof (well_known), well_known)) return (ERR_FAIL); ret = Tspi_TPM_TakeOwnership(hTPM, hKeySRK, 0); if (ret == TPM_E_NO_ENDORSEMENT) { if (createek(hContext, hTPM)) return (ERR_FAIL); ret = Tspi_TPM_TakeOwnership(hTPM, hKeySRK, 0); } if (ret) { print_error(ret, gettext("Take ownership")); return (ERR_FAIL); } return (0); } /* * Auth */ /*ARGSUSED*/ int cmd_auth(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { TSS_RESULT ret; TSS_HPOLICY hNewPolicy; if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP, gettext("= TPM owner passphrase ="), 0, NULL)) return (ERR_FAIL); /* policy object for new passphrase */ ret = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &hNewPolicy); if (ret) { print_error(ret, gettext("Create policy object")); return (ERR_FAIL); } if (set_policy_options(hNewPolicy, TSS_SECRET_MODE_POPUP, gettext("= New TPM owner passphrase ="), 0, NULL)) return (ERR_FAIL); ret = Tspi_ChangeAuth(hTPM, 0, hNewPolicy); if (ret && ret != TSP_ERROR(TSS_E_POLICY_NO_SECRET)) { print_error(ret, gettext("Change authorization")); return (ERR_FAIL); } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include "tpmadm.h" extern cmdtable_t commands[]; static void print_usage(char *progname, cmdtable_t cmds[]) { cmdtable_t *p; (void) fprintf(stderr, gettext("usage: %s command args ...\n"), progname); (void) fprintf(stderr, gettext("where 'command' is one of the following:\n")); for (p = &cmds[0]; p->name != NULL; p++) { (void) fprintf(stderr, "\t%s %s\n", p->name, p->args); } } int main(int argc, char *argv[]) { char *progname; cmdtable_t *p; cmdfunc_t fptr = NULL; int ret; TSS_HCONTEXT hContext; TSS_HOBJECT hTPM; /* Set up for i18n/l10n. */ #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D. */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */ #endif (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); progname = argv[0]; argc--; argv++; if (argc <= 0) { print_usage(progname, commands); return (ERR_USAGE); } for (p = &commands[0]; p->name != NULL; p++) { if (0 == strcmp(p->name, argv[0])) { fptr = p->func; break; } } if (fptr == NULL) { print_usage(progname, commands); return (ERR_USAGE); } if (tpm_preamble(&hContext, &hTPM)) return (ERR_FAIL); ret = fptr(hContext, hTPM, argc, argv); (void) tpm_postamble(hContext); return (ret); } /* * Utility functions */ void print_bytes(BYTE *bytes, size_t len, int formatted) { int i; for (i = 0; i < len; i++) { (void) printf("%02X ", bytes[i]); if (formatted && i % 16 == 7) (void) printf(" "); if (formatted && i % 16 == 15) (void) printf("\n"); } (void) printf("\n"); } /* * TSS convenience functions */ void print_error(TSS_RESULT ret, char *msg) { char *err_string; /* Print the standard error string and error code. */ err_string = Trspi_Error_String(ret); (void) fprintf(stderr, "%s: %s (0x%0x)\n", msg, err_string, ret); /* For a few special cases, add a more verbose error message. */ switch (ret) { case TPM_E_DEACTIVATED: case TPM_E_DISABLED: (void) fprintf(stderr, gettext("Enable the TPM and reboot.\n")); break; case TSP_ERROR(TSS_E_COMM_FAILURE): (void) fprintf(stderr, gettext("Make sure the tcsd service " "(svc:/application/security/tcsd) is running.\n")); break; } } int get_tpm_capability(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM, UINT32 cap, UINT32 subcap, void *buf, size_t bufsize) { TSS_RESULT ret; UINT32 datalen; BYTE *data; ret = Tspi_TPM_GetCapability(hTPM, cap, sizeof (subcap), (BYTE *)&subcap, &datalen, &data); if (ret) { print_error(ret, gettext("Get TPM capability")); return (ERR_FAIL); } if (datalen > bufsize) { (void) fprintf(stderr, gettext("Capability 0x%x returned %u bytes " "(expected %u)\n"), cap, datalen, bufsize); return (ERR_FAIL); } bcopy(data, buf, datalen); ret = Tspi_Context_FreeMemory(hContext, data); if (ret) { print_error(ret, gettext("Free capability buffer")); return (ERR_FAIL); } return (0); } int set_policy_options(TSS_HPOLICY hPolicy, TSS_FLAG mode, char *prompt, UINT32 secret_len, BYTE *secret) { TSS_RESULT ret; BYTE *unicode_prompt; UINT32 len; ret = Tspi_Policy_SetSecret(hPolicy, mode, secret_len, secret); if (ret) { print_error(ret, gettext("Set policy secret")); return (ERR_FAIL); } if (prompt != NULL) { unicode_prompt = Trspi_Native_To_UNICODE((BYTE *)prompt, &len); ret = Tspi_SetAttribData(hPolicy, TSS_TSPATTRIB_POLICY_POPUPSTRING, 0, len, unicode_prompt); if (ret) { print_error(ret, gettext("Set policy prompt")); return (ERR_FAIL); } } return (0); } int set_object_policy(TSS_HOBJECT handle, TSS_FLAG mode, char *prompt, UINT32 secret_len, BYTE *secret) { TSS_HPOLICY hPolicy; TSS_RESULT ret; ret = Tspi_GetPolicyObject(handle, TSS_POLICY_USAGE, &hPolicy); if (ret) { print_error(ret, gettext("Get object policy")); return (ERR_FAIL); } return (set_policy_options(hPolicy, mode, prompt, secret_len, secret)); } int tpm_preamble(TSS_HCONTEXT *hContext, TSS_HOBJECT *hTPM) { TSS_RESULT ret; ret = Tspi_Context_Create(hContext); if (ret) { print_error(ret, gettext("Create context")); return (ERR_FAIL); } ret = Tspi_Context_Connect(*hContext, NULL); if (ret) { print_error(ret, gettext("Connect context")); (void) Tspi_Context_Close(*hContext); return (ERR_FAIL); } ret = Tspi_Context_GetTpmObject(*hContext, hTPM); if (ret) { print_error(ret, gettext("Get TPM object")); (void) Tspi_Context_Close(*hContext); return (ERR_FAIL); } return (0); } int tpm_postamble(TSS_HCONTEXT hContext) { TSS_RESULT ret; ret = Tspi_Context_Close(hContext); if (ret) { print_error(ret, gettext("Close context")); return (ERR_FAIL); } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _TPMADM_H #define _TPMADM_H #define ERR_FAIL 1 #define ERR_USAGE 2 typedef int (*cmdfunc_t)(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); typedef struct { char *name; char *args; cmdfunc_t func; } cmdtable_t; /* Utility functions */ void print_bytes(BYTE *bytes, size_t len, int formatted); void print_error(TSS_RESULT ret, char *msg); int get_tpm_capability(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM, UINT32 cap, UINT32 subcap, void *buf, size_t bufsize); int set_policy_options(TSS_HPOLICY hPolicy, TSS_FLAG mode, char *prompt, UINT32 secret_len, BYTE *secret); int set_object_policy(TSS_HOBJECT handle, TSS_FLAG mode, char *prompt, UINT32 secret_len, BYTE *secret); int tpm_preamble(TSS_HCONTEXT *hContext, TSS_HOBJECT *hTPM); int tpm_postamble(TSS_HCONTEXT hContext); #define UUID_PARSE(str, uuid) uuid_parse(str, *(uuid_t *)&uuid) #define UUID_UNPARSE(uuid, str) uuid_unparse(*(uuid_t *)&uuid, str) #define UUID_COPY(source, dest) \ bcopy((BYTE*)&(source), (BYTE*)&(dest), sizeof (TSS_UUID)) #endif /* _TPMADM_H */