17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
590e0e8c4Sizick  * Common Development and Distribution License (the "License").
690e0e8c4Sizick  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*19193bb6SDina K Nimeh  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Functions used for manipulating the keystore
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <errno.h>
337c478bd9Sstevel@tonic-gate #include <sys/stat.h>
347c478bd9Sstevel@tonic-gate #include <fcntl.h>
357c478bd9Sstevel@tonic-gate #include <time.h>
367c478bd9Sstevel@tonic-gate #include <unistd.h>
377c478bd9Sstevel@tonic-gate #include <pwd.h>
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <dirent.h>
407c478bd9Sstevel@tonic-gate #include <limits.h>
417c478bd9Sstevel@tonic-gate #include <strings.h>
427c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
437c478bd9Sstevel@tonic-gate #include <cryptoutil.h>
447c478bd9Sstevel@tonic-gate #include "softGlobal.h"
457c478bd9Sstevel@tonic-gate #include "softObject.h"
4690e0e8c4Sizick #include "softSession.h"
477c478bd9Sstevel@tonic-gate #include "softKeystore.h"
487c478bd9Sstevel@tonic-gate #include "softKeystoreUtil.h"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #define	MAXPATHLEN	1024
517c478bd9Sstevel@tonic-gate #define	SUNW_PATH	".sunw"		/* top level Sun directory */
527c478bd9Sstevel@tonic-gate #define	KEYSTORE_PATH	"pkcs11_softtoken"	/* keystore directory */
537c478bd9Sstevel@tonic-gate #define	PUB_OBJ_DIR	"public"	/* directory for public objects */
547c478bd9Sstevel@tonic-gate #define	PRI_OBJ_DIR	"private"	/* directory for private objects */
557c478bd9Sstevel@tonic-gate #define	DS_FILE		"objstore_info"	/* keystore description file */
567c478bd9Sstevel@tonic-gate #define	TMP_DS_FILE	"t_info"	/* temp name for keystore desc. file */
577c478bd9Sstevel@tonic-gate #define	OBJ_PREFIX	"obj"	/* prefix of the keystore object file names */
587c478bd9Sstevel@tonic-gate #define	TMP_OBJ_PREFIX	"t_o"	/* prefix of the temp object file names */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate  * KEYSTORE DESCRIPTION FILE:
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  * The following describes the content of the keystore description file
647c478bd9Sstevel@tonic-gate  *
657c478bd9Sstevel@tonic-gate  * The order AND data type of the fields are very important.
667c478bd9Sstevel@tonic-gate  * All the code in this file assume that they are in the order specified
677c478bd9Sstevel@tonic-gate  * below.  If either order of the fields or their data type changed,
687c478bd9Sstevel@tonic-gate  * you must make sure the ALL the pre-define values are still valid
697c478bd9Sstevel@tonic-gate  *
7090e0e8c4Sizick  * 1) PKCS#11 release number.  It's 2.20 in this release (uchar_t[32])
717c478bd9Sstevel@tonic-gate  * 2) keystore version number: used for synchronizing when different
727c478bd9Sstevel@tonic-gate  *    processes access the keystore at the same time.  It is incremented
737c478bd9Sstevel@tonic-gate  *    when there is a change to the keystore. (uint_32)
747c478bd9Sstevel@tonic-gate  * 3) monotonic-counter: last counter value for name of token object file.
757c478bd9Sstevel@tonic-gate  *    used for assigning unique name to each token (uint_32)
767c478bd9Sstevel@tonic-gate  * 4) salt used for generating encryption key (uint_16)
777c478bd9Sstevel@tonic-gate  * 5) salt used for generating key used for doing HMAC (uint_16)
787c478bd9Sstevel@tonic-gate  * 6) Length of salt used for generating hashed pin (length of salt
797c478bd9Sstevel@tonic-gate  *    is variable)
807c478bd9Sstevel@tonic-gate  * 7) Salt used for generating hashed pin.
817c478bd9Sstevel@tonic-gate  * 8) Hashed pin len (length of hashed pin could be variable, the offset of
827c478bd9Sstevel@tonic-gate  *    where this value lives in the file is calculated at run time)
837c478bd9Sstevel@tonic-gate  * 9) Hashed pin
847c478bd9Sstevel@tonic-gate  *
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /* Keystore description file pre-defined values */
88f66d273dSizick #define	KS_PKCS11_VER		"2.20"
897c478bd9Sstevel@tonic-gate #define	KS_PKCS11_OFFSET	0
907c478bd9Sstevel@tonic-gate #define	KS_PKCS11_VER_SIZE	32
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #define	KS_VER_OFFSET		(KS_PKCS11_OFFSET + KS_PKCS11_VER_SIZE)
937c478bd9Sstevel@tonic-gate #define	KS_VER_SIZE	4	/* size in bytes of keystore version value */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate #define	KS_COUNTER_OFFSET	(KS_VER_OFFSET + KS_VER_SIZE)
967c478bd9Sstevel@tonic-gate #define	KS_COUNTER_SIZE	4	/* size in bytes of the monotonic counter */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate #define	KS_KEY_SALT_OFFSET	(KS_COUNTER_OFFSET + KS_COUNTER_SIZE)
997c478bd9Sstevel@tonic-gate #define	KS_KEY_SALT_SIZE	PBKD2_SALT_SIZE
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate #define	KS_HMAC_SALT_OFFSET	(KS_KEY_SALT_OFFSET + KS_KEY_SALT_SIZE)
1027c478bd9Sstevel@tonic-gate #define	KS_HMAC_SALT_SIZE	PBKD2_SALT_SIZE
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /* Salt for hashed pin */
1057c478bd9Sstevel@tonic-gate #define	KS_HASHED_PIN_SALT_LEN_OFFSET (KS_HMAC_SALT_OFFSET + KS_HMAC_SALT_SIZE)
1067c478bd9Sstevel@tonic-gate #define	KS_HASHED_PIN_SALT_LEN_SIZE 8 /* stores length of hashed pin salt */
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate #define	KS_HASHED_PIN_SALT_OFFSET \
1097c478bd9Sstevel@tonic-gate 		(KS_HASHED_PIN_SALT_LEN_OFFSET + KS_HASHED_PIN_SALT_LEN_SIZE)
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * hashed pin
1137c478bd9Sstevel@tonic-gate  *
1147c478bd9Sstevel@tonic-gate  * hashed_pin length offset will be calculated at run time since
1157c478bd9Sstevel@tonic-gate  * there's the hashed pin salt size is variable.
1167c478bd9Sstevel@tonic-gate  *
1177c478bd9Sstevel@tonic-gate  * The offset will be calculated at run time by calling the
1187c478bd9Sstevel@tonic-gate  * function calculate_hashed_pin_offset()
1197c478bd9Sstevel@tonic-gate  */
1207c478bd9Sstevel@tonic-gate static off_t	ks_hashed_pinlen_offset = -1;
1217c478bd9Sstevel@tonic-gate #define	KS_HASHED_PINLEN_SIZE	8
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /* End of Keystore description file pre-defined values */
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * Metadata for each object
1277c478bd9Sstevel@tonic-gate  *
1287c478bd9Sstevel@tonic-gate  * The order AND data type of all the fields is very important.
1297c478bd9Sstevel@tonic-gate  * All the code in this file assume that they are in the order specified
1307c478bd9Sstevel@tonic-gate  * below.  If either order of the fields or their data type is changed,
1317c478bd9Sstevel@tonic-gate  * you must make sure the following pre-define value is still valid
1327c478bd9Sstevel@tonic-gate  * Each object will have the meta data at the beginning of the object file.
1337c478bd9Sstevel@tonic-gate  *
1347c478bd9Sstevel@tonic-gate  * 1) object_version: used by softtoken to see if the object
1357c478bd9Sstevel@tonic-gate  *    has been modified since it last reads it. (uint_32)
1367c478bd9Sstevel@tonic-gate  * 2) iv: initialization vector for encrypted data in the object.  This
1377c478bd9Sstevel@tonic-gate  *    value will be 0 for public objects.  (uchar_t[16])
1387c478bd9Sstevel@tonic-gate  * 3) obj_hmac: keyed hash as verifier to detect private object
1397c478bd9Sstevel@tonic-gate  *    being tampered this value will be 0 for public objects (uchar_t[16])
1407c478bd9Sstevel@tonic-gate  */
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate /* Object metadata pre-defined values */
1437c478bd9Sstevel@tonic-gate #define	OBJ_VER_OFFSET	0
1447c478bd9Sstevel@tonic-gate #define	OBJ_VER_SIZE	4	/* size of object version in bytes */
1457c478bd9Sstevel@tonic-gate #define	OBJ_IV_OFFSET	(OBJ_VER_OFFSET + OBJ_VER_SIZE)
1467c478bd9Sstevel@tonic-gate #define	OBJ_IV_SIZE	16
1477c478bd9Sstevel@tonic-gate #define	OBJ_HMAC_OFFSET	(OBJ_IV_OFFSET + OBJ_IV_SIZE)
1487c478bd9Sstevel@tonic-gate #define	OBJ_HMAC_SIZE	16	/* MD5 HMAC keyed hash */
1497c478bd9Sstevel@tonic-gate #define	OBJ_DATA_OFFSET	(OBJ_HMAC_OFFSET + OBJ_HMAC_SIZE)
1507c478bd9Sstevel@tonic-gate /* End of object metadata pre-defined values */
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate #define	ALTERNATE_KEYSTORE_PATH	"SOFTTOKEN_DIR"
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate static soft_object_t	*enc_key = NULL;
1557c478bd9Sstevel@tonic-gate static soft_object_t	*hmac_key = NULL;
1567c478bd9Sstevel@tonic-gate static char		keystore_path[MAXPATHLEN];
1577c478bd9Sstevel@tonic-gate static boolean_t	keystore_path_initialized = B_FALSE;
1587c478bd9Sstevel@tonic-gate static int		desc_fd = 0;
1597c478bd9Sstevel@tonic-gate 
16090e0e8c4Sizick 
1617c478bd9Sstevel@tonic-gate static char *
1627c478bd9Sstevel@tonic-gate get_user_home_sunw_path(char *home_path)
1637c478bd9Sstevel@tonic-gate {
164e81dd421Sizick 	struct passwd pwd, *user_info;
165e81dd421Sizick 	char pwdbuf[PWD_BUFFER_SIZE];
1667c478bd9Sstevel@tonic-gate 
167e81dd421Sizick 	(void) getpwuid_r(getuid(), &pwd, pwdbuf, PWD_BUFFER_SIZE, &user_info);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	(void) snprintf(home_path, MAXPATHLEN, "%s/%s",
1707c478bd9Sstevel@tonic-gate 	    user_info ? user_info->pw_dir : "", SUNW_PATH);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	return (home_path);
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate static char *
1767c478bd9Sstevel@tonic-gate get_keystore_path()
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate 	char *env_val;
1797c478bd9Sstevel@tonic-gate 	char home_path[MAXPATHLEN];
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	if (!keystore_path_initialized) {
1827c478bd9Sstevel@tonic-gate 		env_val = getenv(ALTERNATE_KEYSTORE_PATH);
1837c478bd9Sstevel@tonic-gate 		bzero(keystore_path, sizeof (keystore_path));
1847c478bd9Sstevel@tonic-gate 		/*
1857c478bd9Sstevel@tonic-gate 		 * If it isn't set or is set to the empty string use the
1867c478bd9Sstevel@tonic-gate 		 * default location.  We need to check for the empty string
1877c478bd9Sstevel@tonic-gate 		 * because some users "unset" environment variables by giving
1887c478bd9Sstevel@tonic-gate 		 * them no value, this isn't the same thing as removing it
1897c478bd9Sstevel@tonic-gate 		 * from the environment.
1907c478bd9Sstevel@tonic-gate 		 *
1917c478bd9Sstevel@tonic-gate 		 * We don't want that to attempt to open /.sunw/pkcs11_sofftoken
1927c478bd9Sstevel@tonic-gate 		 */
1937c478bd9Sstevel@tonic-gate 		if ((env_val == NULL) || (strcmp(env_val, "") == 0)) {
1947c478bd9Sstevel@tonic-gate 			/* alternate path not specified, use user's home dir */
1957c478bd9Sstevel@tonic-gate 			(void) snprintf(keystore_path, MAXPATHLEN, "%s/%s",
1967c478bd9Sstevel@tonic-gate 			    get_user_home_sunw_path(home_path), KEYSTORE_PATH);
1977c478bd9Sstevel@tonic-gate 		} else {
1987c478bd9Sstevel@tonic-gate 			(void) snprintf(keystore_path, MAXPATHLEN, "%s/%s",
1997c478bd9Sstevel@tonic-gate 			    env_val, KEYSTORE_PATH);
2007c478bd9Sstevel@tonic-gate 		}
2017c478bd9Sstevel@tonic-gate 		keystore_path_initialized = B_TRUE;
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 	return (keystore_path);
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate static char *
2077c478bd9Sstevel@tonic-gate get_pub_obj_path(char *name)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate 	bzero(name, sizeof (name));
2107c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
2117c478bd9Sstevel@tonic-gate 	    get_keystore_path(), PUB_OBJ_DIR);
2127c478bd9Sstevel@tonic-gate 	return (name);
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate static char *
2167c478bd9Sstevel@tonic-gate get_pri_obj_path(char *name)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	bzero(name, sizeof (name));
2197c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
2207c478bd9Sstevel@tonic-gate 	    get_keystore_path(), PRI_OBJ_DIR);
2217c478bd9Sstevel@tonic-gate 	return (name);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate static char *
2257c478bd9Sstevel@tonic-gate get_desc_file_path(char *name)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	bzero(name, sizeof (name));
2287c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
2297c478bd9Sstevel@tonic-gate 	    get_keystore_path(), DS_FILE);
2307c478bd9Sstevel@tonic-gate 	return (name);
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate static char *
2347c478bd9Sstevel@tonic-gate get_tmp_desc_file_path(char *name)
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate 	bzero(name, sizeof (name));
2377c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
2387c478bd9Sstevel@tonic-gate 	    get_keystore_path(), TMP_DS_FILE);
2397c478bd9Sstevel@tonic-gate 	return (name);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate /*
2437c478bd9Sstevel@tonic-gate  * Calculates the offset for hashed_pin length and hashed pin
2447c478bd9Sstevel@tonic-gate  *
2457c478bd9Sstevel@tonic-gate  * Returns 0 if successful, -1 if there's any error.
2467c478bd9Sstevel@tonic-gate  *
2477c478bd9Sstevel@tonic-gate  * If successful, global variables "ks_hashed_pinlen_offset" will be set.
2487c478bd9Sstevel@tonic-gate  *
2497c478bd9Sstevel@tonic-gate  */
2507c478bd9Sstevel@tonic-gate static int
2517c478bd9Sstevel@tonic-gate calculate_hashed_pin_offset(int fd)
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	uint64_t salt_length;
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	if (lseek(fd, KS_HASHED_PIN_SALT_LEN_OFFSET, SEEK_SET)
2567c478bd9Sstevel@tonic-gate 	    != KS_HASHED_PIN_SALT_LEN_OFFSET) {
2577c478bd9Sstevel@tonic-gate 		return (-1);
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 
260*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)&salt_length,
2617c478bd9Sstevel@tonic-gate 	    KS_HASHED_PIN_SALT_LEN_SIZE) != KS_HASHED_PIN_SALT_LEN_SIZE) {
2627c478bd9Sstevel@tonic-gate 		return (-1);
2637c478bd9Sstevel@tonic-gate 	}
2647c478bd9Sstevel@tonic-gate 	salt_length = SWAP64(salt_length);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	ks_hashed_pinlen_offset = KS_HASHED_PIN_SALT_LEN_OFFSET
2677c478bd9Sstevel@tonic-gate 	    + KS_HASHED_PIN_SALT_LEN_SIZE + salt_length;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	return (0);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate  * acquire or release read/write lock on a specific file
2757c478bd9Sstevel@tonic-gate  *
2767c478bd9Sstevel@tonic-gate  * read_lock: true for read lock; false for write lock
2777c478bd9Sstevel@tonic-gate  * set_lock:  true to set a lock; false to release a lock
2787c478bd9Sstevel@tonic-gate  */
2797c478bd9Sstevel@tonic-gate static int
2807c478bd9Sstevel@tonic-gate lock_file(int fd, boolean_t read_lock, boolean_t set_lock)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	flock_t lock_info;
2847c478bd9Sstevel@tonic-gate 	int r;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	lock_info.l_whence = SEEK_SET;
2877c478bd9Sstevel@tonic-gate 	lock_info.l_start = 0;
2887c478bd9Sstevel@tonic-gate 	lock_info.l_len = 0; /* l_len == 0 means until end of  file */
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	if (read_lock) {
2917c478bd9Sstevel@tonic-gate 		lock_info.l_type = F_RDLCK;
2927c478bd9Sstevel@tonic-gate 	} else {
2937c478bd9Sstevel@tonic-gate 		lock_info.l_type = F_WRLCK;
2947c478bd9Sstevel@tonic-gate 	}
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	if (set_lock) {
2977c478bd9Sstevel@tonic-gate 		while ((r = fcntl(fd, F_SETLKW, &lock_info)) == -1) {
2987c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
2997c478bd9Sstevel@tonic-gate 				break;
3007c478bd9Sstevel@tonic-gate 		}
3017c478bd9Sstevel@tonic-gate 		if (r == -1) {
3027c478bd9Sstevel@tonic-gate 			return (-1);
3037c478bd9Sstevel@tonic-gate 		}
3047c478bd9Sstevel@tonic-gate 	} else {
3057c478bd9Sstevel@tonic-gate 		lock_info.l_type = F_UNLCK;
3067c478bd9Sstevel@tonic-gate 		while ((r = fcntl(fd, F_SETLKW, &lock_info)) == -1) {
3077c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
3087c478bd9Sstevel@tonic-gate 				break;
3097c478bd9Sstevel@tonic-gate 		}
3107c478bd9Sstevel@tonic-gate 		if (r == -1) {
3117c478bd9Sstevel@tonic-gate 			return (-1);
3127c478bd9Sstevel@tonic-gate 		}
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	return (0);
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate static int
3197c478bd9Sstevel@tonic-gate create_keystore()
3207c478bd9Sstevel@tonic-gate {
3217c478bd9Sstevel@tonic-gate 	int fd, buf;
3227c478bd9Sstevel@tonic-gate 	uint64_t hashed_pin_len, hashed_pin_salt_len, ulong_buf;
3237c478bd9Sstevel@tonic-gate 	uchar_t ver_buf[KS_PKCS11_VER_SIZE];
3247c478bd9Sstevel@tonic-gate 	char pub_obj_path[MAXPATHLEN], pri_obj_path[MAXPATHLEN],
3257c478bd9Sstevel@tonic-gate 	    ks_desc_file[MAXPATHLEN];
3267c478bd9Sstevel@tonic-gate 	CK_BYTE salt[KS_KEY_SALT_SIZE];
3277c478bd9Sstevel@tonic-gate 	char *hashed_pin = NULL, *hashed_pin_salt = NULL;
3287c478bd9Sstevel@tonic-gate 	char *env_val;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	/* keystore doesn't exist, create keystore directory */
3317c478bd9Sstevel@tonic-gate 	if (mkdir(get_keystore_path(), S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3327c478bd9Sstevel@tonic-gate 		if (errno == EEXIST) {
3337c478bd9Sstevel@tonic-gate 			return (0);
3347c478bd9Sstevel@tonic-gate 		}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 		if (errno == EACCES) {
3377c478bd9Sstevel@tonic-gate 			return (-1);
3387c478bd9Sstevel@tonic-gate 		}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 		/* can't create keystore directory */
3417c478bd9Sstevel@tonic-gate 		if (errno == ENOENT) { /* part of the path doesn't exist */
3427c478bd9Sstevel@tonic-gate 			/*
3437c478bd9Sstevel@tonic-gate 			 * try to create $HOME/.sunw if it doesn't
3447c478bd9Sstevel@tonic-gate 			 * exist.  If it is a alternate path provided by the
3457c478bd9Sstevel@tonic-gate 			 * user, it should have existed.  Will not
3467c478bd9Sstevel@tonic-gate 			 * create for them.
3477c478bd9Sstevel@tonic-gate 			 */
3487c478bd9Sstevel@tonic-gate 			env_val = getenv(ALTERNATE_KEYSTORE_PATH);
3497c478bd9Sstevel@tonic-gate 			if ((env_val == NULL) || (strcmp(env_val, "") == 0)) {
3507c478bd9Sstevel@tonic-gate 				char sunw_path[MAXPATHLEN];
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 				/* create $HOME/.sunw */
3537c478bd9Sstevel@tonic-gate 				if (mkdir(get_user_home_sunw_path(sunw_path),
3547c478bd9Sstevel@tonic-gate 				    S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3557c478bd9Sstevel@tonic-gate 					return (-1);
3567c478bd9Sstevel@tonic-gate 				}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 				/* create $HOME/.sunw/pkcs11_softtoken */
3597c478bd9Sstevel@tonic-gate 				if (mkdir(get_keystore_path(),
3607c478bd9Sstevel@tonic-gate 				    S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3617c478bd9Sstevel@tonic-gate 					return (-1);
3627c478bd9Sstevel@tonic-gate 				}
3637c478bd9Sstevel@tonic-gate 			} else {
3647c478bd9Sstevel@tonic-gate 				return (-1);
3657c478bd9Sstevel@tonic-gate 			}
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	/* create keystore description file */
370*19193bb6SDina K Nimeh 	fd = open_nointr(get_desc_file_path(ks_desc_file),
371*19193bb6SDina K Nimeh 	    O_RDWR|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
3727c478bd9Sstevel@tonic-gate 	if (fd < 0) {
3737c478bd9Sstevel@tonic-gate 		if (errno == EEXIST) {
3747c478bd9Sstevel@tonic-gate 			return (0);
3757c478bd9Sstevel@tonic-gate 		} else {
3767c478bd9Sstevel@tonic-gate 			/* can't create keystore description file */
3777c478bd9Sstevel@tonic-gate 			(void) rmdir(get_keystore_path());
3787c478bd9Sstevel@tonic-gate 			return (-1);
3797c478bd9Sstevel@tonic-gate 		}
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (lock_file(fd, B_FALSE, B_TRUE) != 0) {
3837c478bd9Sstevel@tonic-gate 		(void) unlink(ks_desc_file);
3847c478bd9Sstevel@tonic-gate 		(void) close(fd);
3857c478bd9Sstevel@tonic-gate 		(void) rmdir(get_keystore_path());
3867c478bd9Sstevel@tonic-gate 		return (-1);
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	if (mkdir(get_pub_obj_path(pub_obj_path),
3907c478bd9Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3917c478bd9Sstevel@tonic-gate 		/* can't create directory for public objects */
3927c478bd9Sstevel@tonic-gate 		(void) lock_file(fd, B_FALSE, B_FALSE);
3937c478bd9Sstevel@tonic-gate 		(void) unlink(ks_desc_file);
3947c478bd9Sstevel@tonic-gate 		(void) close(fd);
3957c478bd9Sstevel@tonic-gate 		(void) rmdir(get_keystore_path());
3967c478bd9Sstevel@tonic-gate 		return (-1);
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (mkdir(get_pri_obj_path(pri_obj_path),
4007c478bd9Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
4017c478bd9Sstevel@tonic-gate 		/* can't create directory for private objects */
4027c478bd9Sstevel@tonic-gate 		(void) lock_file(fd, B_FALSE, B_FALSE);
4037c478bd9Sstevel@tonic-gate 		(void) unlink(ks_desc_file);
4047c478bd9Sstevel@tonic-gate 		(void) close(fd);
4057c478bd9Sstevel@tonic-gate 		(void) rmdir(get_keystore_path());
4067c478bd9Sstevel@tonic-gate 		(void) rmdir(pub_obj_path);
4077c478bd9Sstevel@tonic-gate 		return (-1);
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	/* write file format release number */
4127c478bd9Sstevel@tonic-gate 	bzero(ver_buf, sizeof (ver_buf));
4137c478bd9Sstevel@tonic-gate 	(void) strcpy((char *)ver_buf, KS_PKCS11_VER);
414*19193bb6SDina K Nimeh 	if ((writen_nointr(fd, (char *)ver_buf, sizeof (ver_buf)))
4157c478bd9Sstevel@tonic-gate 	    != sizeof (ver_buf)) {
4167c478bd9Sstevel@tonic-gate 		goto cleanup;
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	/* write version number, version = 0 since keystore just created */
4207c478bd9Sstevel@tonic-gate 	buf = SWAP32(0);
421*19193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)&buf, KS_VER_SIZE) != KS_VER_SIZE) {
4227c478bd9Sstevel@tonic-gate 		goto cleanup;
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	/* write monotonic-counter.  Counter for keystore objects start at 1 */
4267c478bd9Sstevel@tonic-gate 	buf = SWAP32(1);
427*19193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)&buf, KS_COUNTER_SIZE)
4287c478bd9Sstevel@tonic-gate 	    != KS_COUNTER_SIZE) {
4297c478bd9Sstevel@tonic-gate 		goto cleanup;
4307c478bd9Sstevel@tonic-gate 	}
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	/* initial encryption key salt should be all NULL */
4337c478bd9Sstevel@tonic-gate 	bzero(salt, sizeof (salt));
434*19193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)salt, KS_KEY_SALT_SIZE)
4357c478bd9Sstevel@tonic-gate 	    != KS_KEY_SALT_SIZE) {
4367c478bd9Sstevel@tonic-gate 		goto cleanup;
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	/* initial HMAC key salt should also be all NULL */
440*19193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)salt, KS_HMAC_SALT_SIZE)
4417c478bd9Sstevel@tonic-gate 	    != KS_HMAC_SALT_SIZE) {
4427c478bd9Sstevel@tonic-gate 		goto cleanup;
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	/* generate the hashed pin salt, and MD5 hashed pin of default pin */
4467c478bd9Sstevel@tonic-gate 	if (soft_gen_hashed_pin((CK_CHAR_PTR)SOFT_DEFAULT_PIN, &hashed_pin,
4477c478bd9Sstevel@tonic-gate 	    &hashed_pin_salt) < 0) {
4487c478bd9Sstevel@tonic-gate 		goto cleanup;
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	if ((hashed_pin_salt == NULL) || (hashed_pin == NULL)) {
4527c478bd9Sstevel@tonic-gate 		goto cleanup;
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	hashed_pin_salt_len = (uint64_t)strlen(hashed_pin_salt);
4567c478bd9Sstevel@tonic-gate 	hashed_pin_len = (uint64_t)strlen(hashed_pin);
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	/* write hashed pin salt length */
4597c478bd9Sstevel@tonic-gate 	ulong_buf = SWAP64(hashed_pin_salt_len);
460*19193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)&ulong_buf, KS_HASHED_PIN_SALT_LEN_SIZE)
4617c478bd9Sstevel@tonic-gate 	    != KS_HASHED_PIN_SALT_LEN_SIZE) {
4627c478bd9Sstevel@tonic-gate 		goto cleanup;
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 
465*19193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)hashed_pin_salt,
4667c478bd9Sstevel@tonic-gate 	    hashed_pin_salt_len) != hashed_pin_salt_len) {
4677c478bd9Sstevel@tonic-gate 		goto cleanup;
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	/* write MD5 hashed pin of the default pin */
4717c478bd9Sstevel@tonic-gate 	ulong_buf = SWAP64(hashed_pin_len);
472*19193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)&ulong_buf, KS_HASHED_PINLEN_SIZE)
4737c478bd9Sstevel@tonic-gate 	    != KS_HASHED_PINLEN_SIZE) {
4747c478bd9Sstevel@tonic-gate 		goto cleanup;
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 
477*19193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)hashed_pin, hashed_pin_len)
4787c478bd9Sstevel@tonic-gate 	    != hashed_pin_len) {
4797c478bd9Sstevel@tonic-gate 		goto cleanup;
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	(void) lock_file(fd, B_FALSE, B_FALSE);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	(void) close(fd);
4857c478bd9Sstevel@tonic-gate 	if (hashed_pin_salt)
486*19193bb6SDina K Nimeh 		free(hashed_pin_salt);
4877c478bd9Sstevel@tonic-gate 	return (0);
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate cleanup:
4907c478bd9Sstevel@tonic-gate 	(void) lock_file(fd, B_FALSE, B_FALSE);
4917c478bd9Sstevel@tonic-gate 	(void) unlink(ks_desc_file);
4927c478bd9Sstevel@tonic-gate 	(void) close(fd);
4937c478bd9Sstevel@tonic-gate 	(void) rmdir(get_keystore_path());
4947c478bd9Sstevel@tonic-gate 	(void) rmdir(pub_obj_path);
4957c478bd9Sstevel@tonic-gate 	(void) rmdir(pri_obj_path);
4967c478bd9Sstevel@tonic-gate 	return (-1);
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate /*
5007c478bd9Sstevel@tonic-gate  * Determines if the file referenced by "fd" has the same
5017c478bd9Sstevel@tonic-gate  * inode as the file referenced by "fname".
5027c478bd9Sstevel@tonic-gate  *
5037c478bd9Sstevel@tonic-gate  * The argument "same" contains the result of determining
5047c478bd9Sstevel@tonic-gate  * if the inode is the same or not
5057c478bd9Sstevel@tonic-gate  *
5067c478bd9Sstevel@tonic-gate  * Returns 0 if there's no error.
5077c478bd9Sstevel@tonic-gate  * Returns 1 if there's any error with opening the file.
5087c478bd9Sstevel@tonic-gate  *
5097c478bd9Sstevel@tonic-gate  *
5107c478bd9Sstevel@tonic-gate  */
5117c478bd9Sstevel@tonic-gate static int
5127c478bd9Sstevel@tonic-gate is_inode_same(int fd, char *fname, boolean_t *same)
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate 	struct stat fn_stat, fd_stat;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	if (fstat(fd, &fd_stat) != 0) {
5177c478bd9Sstevel@tonic-gate 		return (-1);
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	if (stat(fname, &fn_stat) != 0) {
5217c478bd9Sstevel@tonic-gate 		return (-1);
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	/* It's the same file if both st_ino and st_dev match */
5257c478bd9Sstevel@tonic-gate 	if ((fd_stat.st_ino == fn_stat.st_ino) &&
5267c478bd9Sstevel@tonic-gate 	    (fd_stat.st_dev == fn_stat.st_dev)) {
5277c478bd9Sstevel@tonic-gate 		*same = B_TRUE;
5287c478bd9Sstevel@tonic-gate 	} else {
5297c478bd9Sstevel@tonic-gate 		*same = B_FALSE;
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 	return (0);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate static int
5357c478bd9Sstevel@tonic-gate acquire_file_lock(int *fd, char *fname, mode_t mode) {
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	boolean_t read_lock = B_TRUE, same_inode;
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	if ((mode == O_RDWR) || (mode == O_WRONLY)) {
5407c478bd9Sstevel@tonic-gate 		read_lock = B_FALSE;
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	if (lock_file(*fd, read_lock, B_TRUE) != 0) {
5447c478bd9Sstevel@tonic-gate 		return (-1);
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	/*
5487c478bd9Sstevel@tonic-gate 	 * make sure another process did not modify the file
5497c478bd9Sstevel@tonic-gate 	 * while we were trying to get the lock
5507c478bd9Sstevel@tonic-gate 	 */
5517c478bd9Sstevel@tonic-gate 	if (is_inode_same(*fd, fname, &same_inode) != 0) {
5527c478bd9Sstevel@tonic-gate 		(void) lock_file(*fd, B_TRUE, B_FALSE); /* unlock file */
5537c478bd9Sstevel@tonic-gate 		return (-1);
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	while (!same_inode) {
5577c478bd9Sstevel@tonic-gate 		/*
5587c478bd9Sstevel@tonic-gate 		 * need to unlock file, close, re-open the file,
5597c478bd9Sstevel@tonic-gate 		 * and re-acquire the lock
5607c478bd9Sstevel@tonic-gate 		 */
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 		/* unlock file */
5637c478bd9Sstevel@tonic-gate 		if (lock_file(*fd, B_TRUE, B_FALSE) != 0) {
5647c478bd9Sstevel@tonic-gate 			return (-1);
5657c478bd9Sstevel@tonic-gate 		}
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 		(void) close(*fd);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 		/* re-open */
570*19193bb6SDina K Nimeh 		*fd = open_nointr(fname, mode|O_NONBLOCK);
5717c478bd9Sstevel@tonic-gate 		if (*fd < 0) {
5727c478bd9Sstevel@tonic-gate 			return (-1);
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 		/* acquire lock again */
5767c478bd9Sstevel@tonic-gate 		if (lock_file(*fd, read_lock, B_TRUE) != 0) {
5777c478bd9Sstevel@tonic-gate 			return (-1);
5787c478bd9Sstevel@tonic-gate 		}
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 		if (is_inode_same(*fd, fname, &same_inode) != 0) {
5817c478bd9Sstevel@tonic-gate 			(void) lock_file(*fd, B_TRUE, B_FALSE); /* unlock */
5827c478bd9Sstevel@tonic-gate 			return (-1);
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	return (0);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate  * Open the keystore description file in the specified mode.
5927c478bd9Sstevel@tonic-gate  * If the keystore doesn't exist, the "do_create_keystore"
5937c478bd9Sstevel@tonic-gate  * argument determines if the keystore should be created
5947c478bd9Sstevel@tonic-gate  */
5957c478bd9Sstevel@tonic-gate static int
5967c478bd9Sstevel@tonic-gate open_and_lock_keystore_desc(mode_t mode, boolean_t do_create_keystore,
5977c478bd9Sstevel@tonic-gate     boolean_t lock_held)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	int fd;
6017c478bd9Sstevel@tonic-gate 	char *fname, ks_desc_file[MAXPATHLEN];
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	/* open the keystore description file in requested mode */
6047c478bd9Sstevel@tonic-gate 	fname = get_desc_file_path(ks_desc_file);
605*19193bb6SDina K Nimeh 	fd = open_nointr(fname, mode|O_NONBLOCK);
6067c478bd9Sstevel@tonic-gate 	if (fd < 0) {
6077c478bd9Sstevel@tonic-gate 		if ((errno == ENOENT) && (do_create_keystore)) {
6087c478bd9Sstevel@tonic-gate 			if (create_keystore() < 0) {
6097c478bd9Sstevel@tonic-gate 				goto done;
6107c478bd9Sstevel@tonic-gate 			}
611*19193bb6SDina K Nimeh 			fd = open_nointr(fname, mode|O_NONBLOCK);
6127c478bd9Sstevel@tonic-gate 			if (fd < 0) {
6137c478bd9Sstevel@tonic-gate 				goto done;
6147c478bd9Sstevel@tonic-gate 			}
6157c478bd9Sstevel@tonic-gate 		} else {
6167c478bd9Sstevel@tonic-gate 			goto done;
6177c478bd9Sstevel@tonic-gate 		}
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	if (lock_held) {
6217c478bd9Sstevel@tonic-gate 		/* already hold the lock */
6227c478bd9Sstevel@tonic-gate 		return (fd);
6237c478bd9Sstevel@tonic-gate 	}
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	if (acquire_file_lock(&fd, fname, mode) != 0) {
6267c478bd9Sstevel@tonic-gate 		if (fd > 0) {
6277c478bd9Sstevel@tonic-gate 			(void) close(fd);
6287c478bd9Sstevel@tonic-gate 		}
6297c478bd9Sstevel@tonic-gate 		return (-1);
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate done:
6337c478bd9Sstevel@tonic-gate 	return (fd);
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate /*
6387c478bd9Sstevel@tonic-gate  * Set or remove read or write lock on keystore description file
6397c478bd9Sstevel@tonic-gate  *
6407c478bd9Sstevel@tonic-gate  * read_lock: true for read lock, false for write lock
6417c478bd9Sstevel@tonic-gate  * set_lock: true for set a lock, false to remove a lock
6427c478bd9Sstevel@tonic-gate  */
6437c478bd9Sstevel@tonic-gate static int
6447c478bd9Sstevel@tonic-gate lock_desc_file(boolean_t read_lock, boolean_t set_lock)
6457c478bd9Sstevel@tonic-gate {
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	char ks_desc_file[MAXPATHLEN];
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	if (set_lock) {
6507c478bd9Sstevel@tonic-gate 		int oflag;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 		/*
6537c478bd9Sstevel@tonic-gate 		 * make sure desc_fd is not already used.  If used, it means
6547c478bd9Sstevel@tonic-gate 		 * some other lock is already set on the file
6557c478bd9Sstevel@tonic-gate 		 */
6567c478bd9Sstevel@tonic-gate 		if (desc_fd > 0) {
6577c478bd9Sstevel@tonic-gate 			return (-1);
6587c478bd9Sstevel@tonic-gate 		}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 		(void) get_desc_file_path(ks_desc_file);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 		if (read_lock) {
6637c478bd9Sstevel@tonic-gate 			oflag = O_RDONLY;
6647c478bd9Sstevel@tonic-gate 		} else {
6657c478bd9Sstevel@tonic-gate 			oflag = O_WRONLY;
6667c478bd9Sstevel@tonic-gate 		}
6677c478bd9Sstevel@tonic-gate 		if ((desc_fd = open_and_lock_keystore_desc(oflag,
6687c478bd9Sstevel@tonic-gate 		    B_FALSE, B_FALSE)) < 0) {
6697c478bd9Sstevel@tonic-gate 			return (-1);
6707c478bd9Sstevel@tonic-gate 		}
6717c478bd9Sstevel@tonic-gate 	} else {
6727c478bd9Sstevel@tonic-gate 		/* make sure we have a valid fd */
6737c478bd9Sstevel@tonic-gate 		if (desc_fd <= 0) {
6747c478bd9Sstevel@tonic-gate 			return (-1);
6757c478bd9Sstevel@tonic-gate 		}
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 		if (lock_file(desc_fd, read_lock, B_FALSE) == 1) {
6787c478bd9Sstevel@tonic-gate 			return (-1);
6797c478bd9Sstevel@tonic-gate 		}
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 		(void) close(desc_fd);
6827c478bd9Sstevel@tonic-gate 		desc_fd = 0;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	}
6857c478bd9Sstevel@tonic-gate 	return (0);
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate static int
6897c478bd9Sstevel@tonic-gate open_and_lock_object_file(ks_obj_handle_t *ks_handle, int oflag,
6907c478bd9Sstevel@tonic-gate     boolean_t lock_held)
6917c478bd9Sstevel@tonic-gate {
6927c478bd9Sstevel@tonic-gate 	char obj_fname[MAXPATHLEN];
6937c478bd9Sstevel@tonic-gate 	int fd;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	if (ks_handle->public) {
6967c478bd9Sstevel@tonic-gate 		char pub_obj_path[MAXPATHLEN];
6977c478bd9Sstevel@tonic-gate 		(void) snprintf(obj_fname, MAXPATHLEN, "%s/%s",
6987c478bd9Sstevel@tonic-gate 		    get_pub_obj_path(pub_obj_path), ks_handle->name);
6997c478bd9Sstevel@tonic-gate 	} else {
7007c478bd9Sstevel@tonic-gate 		char pri_obj_path[MAXPATHLEN];
7017c478bd9Sstevel@tonic-gate 		(void) snprintf(obj_fname, MAXPATHLEN, "%s/%s",
7027c478bd9Sstevel@tonic-gate 		    get_pri_obj_path(pri_obj_path), ks_handle->name);
7037c478bd9Sstevel@tonic-gate 	}
7047c478bd9Sstevel@tonic-gate 
705*19193bb6SDina K Nimeh 	fd = open_nointr(obj_fname, oflag|O_NONBLOCK);
7067c478bd9Sstevel@tonic-gate 	if (fd < 0) {
7077c478bd9Sstevel@tonic-gate 		return (-1);
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	if (lock_held) {
7117c478bd9Sstevel@tonic-gate 		/* already hold the lock */
7127c478bd9Sstevel@tonic-gate 		return (fd);
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	if (acquire_file_lock(&fd, obj_fname, oflag) != 0) {
7167c478bd9Sstevel@tonic-gate 		if (fd > 0) {
7177c478bd9Sstevel@tonic-gate 			(void) close(fd);
7187c478bd9Sstevel@tonic-gate 		}
7197c478bd9Sstevel@tonic-gate 		return (-1);
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	return (fd);
7247c478bd9Sstevel@tonic-gate }
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate /*
7287c478bd9Sstevel@tonic-gate  * Update file version number in a temporary file that's
7297c478bd9Sstevel@tonic-gate  * a copy of the keystore description file.
7307c478bd9Sstevel@tonic-gate  * The update is NOT made to the original keystore description
7317c478bd9Sstevel@tonic-gate  * file.  It makes the update in a tempoary file.
7327c478bd9Sstevel@tonic-gate  *
7337c478bd9Sstevel@tonic-gate  * Name of the temporary file is assumed to be provided, but
7347c478bd9Sstevel@tonic-gate  * the file is assumed to not exist.
7357c478bd9Sstevel@tonic-gate  *
7367c478bd9Sstevel@tonic-gate  * return 0 if creating temp file is successful, returns -1 otherwise
7377c478bd9Sstevel@tonic-gate  */
7387c478bd9Sstevel@tonic-gate static int
7397c478bd9Sstevel@tonic-gate create_updated_keystore_version(int fd, char *tmp_fname)
7407c478bd9Sstevel@tonic-gate {
7417c478bd9Sstevel@tonic-gate 	int version, tmp_fd;
7427c478bd9Sstevel@tonic-gate 	char buf[BUFSIZ];
7437c478bd9Sstevel@tonic-gate 	size_t nread;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	/* first, create the tempoary file */
746*19193bb6SDina K Nimeh 	tmp_fd = open_nointr(tmp_fname,
747*19193bb6SDina K Nimeh 	    O_WRONLY|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
7487c478bd9Sstevel@tonic-gate 	if (tmp_fd < 0) {
7497c478bd9Sstevel@tonic-gate 		return (-1);
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	/*
7537c478bd9Sstevel@tonic-gate 	 * copy everything from keystore version to temp file except
7547c478bd9Sstevel@tonic-gate 	 * the keystore version.  Keystore version is updated
7557c478bd9Sstevel@tonic-gate 	 *
7567c478bd9Sstevel@tonic-gate 	 */
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	/* pkcs11 version */
759*19193bb6SDina K Nimeh 	if (readn_nointr(fd, buf, KS_PKCS11_VER_SIZE) != KS_PKCS11_VER_SIZE) {
7607c478bd9Sstevel@tonic-gate 		goto cleanup;
7617c478bd9Sstevel@tonic-gate 	}
7627c478bd9Sstevel@tonic-gate 
763*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_fd, buf, KS_PKCS11_VER_SIZE) !=
764*19193bb6SDina K Nimeh 	    KS_PKCS11_VER_SIZE) {
7657c478bd9Sstevel@tonic-gate 		goto cleanup;
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	/* version number, it needs to be updated */
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	/* read the current version number */
771*19193bb6SDina K Nimeh 	if (readn_nointr(fd, &version, KS_VER_SIZE) != KS_VER_SIZE) {
7727c478bd9Sstevel@tonic-gate 		goto cleanup;
7737c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
7767c478bd9Sstevel@tonic-gate 	version++;
7777c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	/* write the updated value to the tmp file */
780*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_fd, (void *)&version, KS_VER_SIZE)
7817c478bd9Sstevel@tonic-gate 	    != KS_VER_SIZE) {
7827c478bd9Sstevel@tonic-gate 		goto cleanup;
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	/* read rest of information, nothing needs to be updated */
786*19193bb6SDina K Nimeh 	nread = readn_nointr(fd, buf, BUFSIZ);
7877c478bd9Sstevel@tonic-gate 	while (nread > 0) {
788*19193bb6SDina K Nimeh 		if (writen_nointr(tmp_fd, buf, nread) != nread) {
7897c478bd9Sstevel@tonic-gate 			goto cleanup;
7907c478bd9Sstevel@tonic-gate 		}
791*19193bb6SDina K Nimeh 		nread = readn_nointr(fd, buf, BUFSIZ);
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	(void) close(tmp_fd);
7957c478bd9Sstevel@tonic-gate 	return (0);	/* no error */
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate cleanup:
7987c478bd9Sstevel@tonic-gate 	(void) close(tmp_fd);
7997c478bd9Sstevel@tonic-gate 	(void) remove(tmp_fname);
8007c478bd9Sstevel@tonic-gate 	return (-1);
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate static CK_RV
8047c478bd9Sstevel@tonic-gate get_all_objs_in_dir(DIR *dirp, ks_obj_handle_t *ks_handle,
8054bc0a2efScasper     ks_obj_t **result_obj_list, boolean_t lock_held)
8067c478bd9Sstevel@tonic-gate {
8074bc0a2efScasper 	struct dirent *dp;
8087c478bd9Sstevel@tonic-gate 	ks_obj_t *obj;
8097c478bd9Sstevel@tonic-gate 	CK_RV rv;
8107c478bd9Sstevel@tonic-gate 
8114bc0a2efScasper 	while ((dp = readdir(dirp)) != NULL) {
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 		if ((strcmp(dp->d_name, ".") == 0) ||
8147c478bd9Sstevel@tonic-gate 		    (strcmp(dp->d_name, "..") == 0)) {
8157c478bd9Sstevel@tonic-gate 			continue;
8167c478bd9Sstevel@tonic-gate 		}
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 		(void) strcpy((char *)ks_handle->name, dp->d_name);
8197c478bd9Sstevel@tonic-gate 		rv = soft_keystore_get_single_obj(ks_handle, &obj, lock_held);
8207c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
8217c478bd9Sstevel@tonic-gate 			return (rv);
8227c478bd9Sstevel@tonic-gate 		}
8237c478bd9Sstevel@tonic-gate 		if (obj != NULL) {
8247c478bd9Sstevel@tonic-gate 			if (*result_obj_list == NULL) {
8257c478bd9Sstevel@tonic-gate 				*result_obj_list = obj;
8267c478bd9Sstevel@tonic-gate 			} else {
8277c478bd9Sstevel@tonic-gate 				obj->next = *result_obj_list;
8287c478bd9Sstevel@tonic-gate 				*result_obj_list = obj;
8297c478bd9Sstevel@tonic-gate 			}
8307c478bd9Sstevel@tonic-gate 		}
8317c478bd9Sstevel@tonic-gate 	}
8327c478bd9Sstevel@tonic-gate 	return (CKR_OK);
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate /*
8367c478bd9Sstevel@tonic-gate  * This function prepares the obj data for encryption by prepending
8377c478bd9Sstevel@tonic-gate  * the FULL path of the file that will be used for storing
8387c478bd9Sstevel@tonic-gate  * the object.  Having full path of the file as part of
8397c478bd9Sstevel@tonic-gate  * of the data for the object will prevent an attacker from
8407c478bd9Sstevel@tonic-gate  * copying a "bad" object into the keystore undetected.
8417c478bd9Sstevel@tonic-gate  *
8427c478bd9Sstevel@tonic-gate  * This function will always allocate:
8437c478bd9Sstevel@tonic-gate  *	MAXPATHLEN + buf_len
8447c478bd9Sstevel@tonic-gate  * amount of data.  If the full path of the filename doesn't occupy
8457c478bd9Sstevel@tonic-gate  * the whole MAXPATHLEN, the rest of the space will just be empty.
8467c478bd9Sstevel@tonic-gate  * It is the caller's responsibility to free the buffer allocated here.
8477c478bd9Sstevel@tonic-gate  *
8487c478bd9Sstevel@tonic-gate  * The allocated buffer is returned in the variable "prepared_buf"
8497c478bd9Sstevel@tonic-gate  * if there's no error.
8507c478bd9Sstevel@tonic-gate  *
8517c478bd9Sstevel@tonic-gate  * Returns 0 if there's no error, -1 otherwise.
8527c478bd9Sstevel@tonic-gate  */
8537c478bd9Sstevel@tonic-gate static int
8547c478bd9Sstevel@tonic-gate prepare_data_for_encrypt(char *obj_path, unsigned char *buf, CK_ULONG buf_len,
8557c478bd9Sstevel@tonic-gate     unsigned char **prepared_buf, CK_ULONG *prepared_len)
8567c478bd9Sstevel@tonic-gate {
8577c478bd9Sstevel@tonic-gate 	*prepared_len = MAXPATHLEN + buf_len;
8587c478bd9Sstevel@tonic-gate 	*prepared_buf = malloc(*prepared_len);
8597c478bd9Sstevel@tonic-gate 	if (*prepared_buf == NULL) {
8607c478bd9Sstevel@tonic-gate 		return (-1);
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	/*
8647c478bd9Sstevel@tonic-gate 	 * only zero out the space for the path name.  I could zero out
8657c478bd9Sstevel@tonic-gate 	 * the whole buffer, but that will be a waste of processing
8667c478bd9Sstevel@tonic-gate 	 * cycle since the rest of the buffer will be 100% filled all
8677c478bd9Sstevel@tonic-gate 	 * the time
8687c478bd9Sstevel@tonic-gate 	 */
8697c478bd9Sstevel@tonic-gate 	bzero(*prepared_buf, MAXPATHLEN);
8707c478bd9Sstevel@tonic-gate 	(void) memcpy(*prepared_buf, obj_path, strlen(obj_path));
8717c478bd9Sstevel@tonic-gate 	(void) memcpy(*prepared_buf + MAXPATHLEN, buf, buf_len);
8727c478bd9Sstevel@tonic-gate 	return (0);
8737c478bd9Sstevel@tonic-gate }
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate /*
8767c478bd9Sstevel@tonic-gate  * retrieves the hashed pin from the keystore
8777c478bd9Sstevel@tonic-gate  */
8787c478bd9Sstevel@tonic-gate static CK_RV
8797c478bd9Sstevel@tonic-gate get_hashed_pin(int fd, char **hashed_pin)
8807c478bd9Sstevel@tonic-gate {
8817c478bd9Sstevel@tonic-gate 	uint64_t hashed_pin_size;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	if (ks_hashed_pinlen_offset == -1) {
8847c478bd9Sstevel@tonic-gate 		if (calculate_hashed_pin_offset(fd) != 0) {
8857c478bd9Sstevel@tonic-gate 			return (CKR_FUNCTION_FAILED);
8867c478bd9Sstevel@tonic-gate 		}
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	/* first, get size of the hashed pin */
8907c478bd9Sstevel@tonic-gate 	if (lseek(fd, ks_hashed_pinlen_offset, SEEK_SET)
8917c478bd9Sstevel@tonic-gate 	    != ks_hashed_pinlen_offset) {
8927c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
8937c478bd9Sstevel@tonic-gate 	}
8947c478bd9Sstevel@tonic-gate 
895*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)&hashed_pin_size,
8967c478bd9Sstevel@tonic-gate 	    KS_HASHED_PINLEN_SIZE) != KS_HASHED_PINLEN_SIZE) {
8977c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	hashed_pin_size = SWAP64(hashed_pin_size);
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	*hashed_pin = malloc(hashed_pin_size + 1);
9037c478bd9Sstevel@tonic-gate 	if (*hashed_pin == NULL) {
9047c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
9057c478bd9Sstevel@tonic-gate 	}
9067c478bd9Sstevel@tonic-gate 
907*19193bb6SDina K Nimeh 	if ((readn_nointr(fd, *hashed_pin, hashed_pin_size))
9087c478bd9Sstevel@tonic-gate 	    != (ssize_t)hashed_pin_size) {
9097c478bd9Sstevel@tonic-gate 		free(*hashed_pin);
9107c478bd9Sstevel@tonic-gate 		*hashed_pin = NULL;
9117c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 	(*hashed_pin)[hashed_pin_size] = '\0';
9147c478bd9Sstevel@tonic-gate 	return (CKR_OK);
9157c478bd9Sstevel@tonic-gate }
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate /*
9197c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_lock
9207c478bd9Sstevel@tonic-gate  *
9217c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
9227c478bd9Sstevel@tonic-gate  *		set_lock: TRUE to set readlock on the keystore object file,
9237c478bd9Sstevel@tonic-gate  *		          FALSE to remove readlock on keystore object file.
9247c478bd9Sstevel@tonic-gate  *
9257c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
9267c478bd9Sstevel@tonic-gate  *
9277c478bd9Sstevel@tonic-gate  *		0: success
9287c478bd9Sstevel@tonic-gate  *		-1: failure
9297c478bd9Sstevel@tonic-gate  *
9307c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
9317c478bd9Sstevel@tonic-gate  *
9327c478bd9Sstevel@tonic-gate  *		set or remove readlock on the keystore description file.
9337c478bd9Sstevel@tonic-gate  */
9347c478bd9Sstevel@tonic-gate int
9357c478bd9Sstevel@tonic-gate soft_keystore_readlock(boolean_t set_lock)
9367c478bd9Sstevel@tonic-gate {
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	return (lock_desc_file(B_TRUE, set_lock));
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate /*
9437c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_writelock
9447c478bd9Sstevel@tonic-gate  *
9457c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
9467c478bd9Sstevel@tonic-gate  * 		set_lock: TRUE to set writelock on the keystore description file
9477c478bd9Sstevel@tonic-gate  *		        FALSE to remove write lock on keystore description file.
9487c478bd9Sstevel@tonic-gate  *
9497c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
9507c478bd9Sstevel@tonic-gate  *
9517c478bd9Sstevel@tonic-gate  *		0: no error
9527c478bd9Sstevel@tonic-gate  *		1: some error occurred
9537c478bd9Sstevel@tonic-gate  *
9547c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
9557c478bd9Sstevel@tonic-gate  *		set/reset writelock on the keystore description file.
9567c478bd9Sstevel@tonic-gate  */
9577c478bd9Sstevel@tonic-gate int
9587c478bd9Sstevel@tonic-gate soft_keystore_writelock(boolean_t set_lock)
9597c478bd9Sstevel@tonic-gate {
9607c478bd9Sstevel@tonic-gate 	return (lock_desc_file(B_FALSE, set_lock));
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate /*
9657c478bd9Sstevel@tonic-gate  *
9667c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_lock_object
9677c478bd9Sstevel@tonic-gate  *
9687c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
9697c478bd9Sstevel@tonic-gate  *
9707c478bd9Sstevel@tonic-gate  *		ks_handle: handle of the keystore object file to be accessed.
9717c478bd9Sstevel@tonic-gate  * 		read_lock: TRUE to set readlock on the keystore object file,
9727c478bd9Sstevel@tonic-gate  *			  FALSE to set writelock on keystore object file.
9737c478bd9Sstevel@tonic-gate  *
9747c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
9757c478bd9Sstevel@tonic-gate  *
9767c478bd9Sstevel@tonic-gate  *		If no error, file descriptor of locked file will be returned
9777c478bd9Sstevel@tonic-gate  *		-1: some error occurred
9787c478bd9Sstevel@tonic-gate  *
9797c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
9807c478bd9Sstevel@tonic-gate  *
9817c478bd9Sstevel@tonic-gate  *		set readlock or writelock on the keystore object file.
9827c478bd9Sstevel@tonic-gate  */
9837c478bd9Sstevel@tonic-gate int
9847c478bd9Sstevel@tonic-gate soft_keystore_lock_object(ks_obj_handle_t *ks_handle, boolean_t read_lock)
9857c478bd9Sstevel@tonic-gate {
9867c478bd9Sstevel@tonic-gate 	int fd;
9877c478bd9Sstevel@tonic-gate 	int oflag;
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	if (read_lock) {
9907c478bd9Sstevel@tonic-gate 		oflag = O_RDONLY;
9917c478bd9Sstevel@tonic-gate 	} else {
9927c478bd9Sstevel@tonic-gate 		oflag = O_WRONLY;
9937c478bd9Sstevel@tonic-gate 	}
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_object_file(ks_handle, oflag, B_FALSE)) < 0) {
9967c478bd9Sstevel@tonic-gate 		return (-1);
9977c478bd9Sstevel@tonic-gate 	}
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	return (fd);
10007c478bd9Sstevel@tonic-gate }
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate /*
10037c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_unlock_object
10047c478bd9Sstevel@tonic-gate  *
10057c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
10067c478bd9Sstevel@tonic-gate  *		fd: file descriptor returned from soft_keystore_lock_object
10077c478bd9Sstevel@tonic-gate  *
10087c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
10097c478bd9Sstevel@tonic-gate  *		0: no error
10107c478bd9Sstevel@tonic-gate  *		1: some error occurred while getting the pin
10117c478bd9Sstevel@tonic-gate  *
10127c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
10137c478bd9Sstevel@tonic-gate  *		set/reset writelock on the keystore object file.
10147c478bd9Sstevel@tonic-gate  */
10157c478bd9Sstevel@tonic-gate int
10167c478bd9Sstevel@tonic-gate soft_keystore_unlock_object(int fd)
10177c478bd9Sstevel@tonic-gate {
10187c478bd9Sstevel@tonic-gate 	if (lock_file(fd, B_TRUE, B_FALSE) != 0) {
10197c478bd9Sstevel@tonic-gate 		return (1);
10207c478bd9Sstevel@tonic-gate 	}
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	(void) close(fd);
10237c478bd9Sstevel@tonic-gate 	return (0);
10247c478bd9Sstevel@tonic-gate }
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate /*
10297c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_get_version
10307c478bd9Sstevel@tonic-gate  *
10317c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
10327c478bd9Sstevel@tonic-gate  *		version: pointer to caller allocated memory for storing
10337c478bd9Sstevel@tonic-gate  *			 the version of the keystore.
10347c478bd9Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
10357c478bd9Sstevel@tonic-gate  *
10367c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
10377c478bd9Sstevel@tonic-gate  *
10387c478bd9Sstevel@tonic-gate  *		0: no error
10397c478bd9Sstevel@tonic-gate  *		-1: some error occurred while getting the version number
10407c478bd9Sstevel@tonic-gate  *
10417c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
10427c478bd9Sstevel@tonic-gate  *		get the version number of the keystore from keystore
10437c478bd9Sstevel@tonic-gate  *		description file.
10447c478bd9Sstevel@tonic-gate  */
10457c478bd9Sstevel@tonic-gate int
10467c478bd9Sstevel@tonic-gate soft_keystore_get_version(uint_t *version, boolean_t lock_held)
10477c478bd9Sstevel@tonic-gate {
10487c478bd9Sstevel@tonic-gate 	int fd, ret_val = 0;
10497c478bd9Sstevel@tonic-gate 	uint_t buf;
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDONLY,
10527c478bd9Sstevel@tonic-gate 	    B_TRUE, lock_held)) < 0) {
10537c478bd9Sstevel@tonic-gate 		return (-1);
10547c478bd9Sstevel@tonic-gate 	}
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	if (lseek(fd, KS_VER_OFFSET, SEEK_SET) != KS_VER_OFFSET) {
10577c478bd9Sstevel@tonic-gate 		ret_val = -1;
10587c478bd9Sstevel@tonic-gate 		goto cleanup;
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 
1061*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)&buf, KS_VER_SIZE) != KS_VER_SIZE) {
10627c478bd9Sstevel@tonic-gate 		ret_val = -1;
10637c478bd9Sstevel@tonic-gate 		goto cleanup;
10647c478bd9Sstevel@tonic-gate 	}
10657c478bd9Sstevel@tonic-gate 	*version = SWAP32(buf);
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate cleanup:
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	if (!lock_held) {
10707c478bd9Sstevel@tonic-gate 		if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
10717c478bd9Sstevel@tonic-gate 			ret_val = -1;
10727c478bd9Sstevel@tonic-gate 		}
10737c478bd9Sstevel@tonic-gate 	}
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	(void) close(fd);
10767c478bd9Sstevel@tonic-gate 	return (ret_val);
10777c478bd9Sstevel@tonic-gate }
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate /*
10807c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_get_object_version
10817c478bd9Sstevel@tonic-gate  *
10827c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
10837c478bd9Sstevel@tonic-gate  *
10847c478bd9Sstevel@tonic-gate  *		ks_handle: handle of the key store object to be accessed.
10857c478bd9Sstevel@tonic-gate  *		version:
10867c478bd9Sstevel@tonic-gate  *			pointer to caller allocated memory for storing
10877c478bd9Sstevel@tonic-gate  *			the version of the object.
10887c478bd9Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
10897c478bd9Sstevel@tonic-gate  *
10907c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
10917c478bd9Sstevel@tonic-gate  *
10927c478bd9Sstevel@tonic-gate  *		0: no error
10937c478bd9Sstevel@tonic-gate  *		-1: some error occurred while getting the pin
10947c478bd9Sstevel@tonic-gate  *
10957c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
10967c478bd9Sstevel@tonic-gate  *		get the version number of the specified token object.
10977c478bd9Sstevel@tonic-gate  */
10987c478bd9Sstevel@tonic-gate int
10997c478bd9Sstevel@tonic-gate soft_keystore_get_object_version(ks_obj_handle_t *ks_handle,
11007c478bd9Sstevel@tonic-gate     uint_t *version, boolean_t lock_held)
11017c478bd9Sstevel@tonic-gate {
11027c478bd9Sstevel@tonic-gate 	int fd, ret_val = 0;
11037c478bd9Sstevel@tonic-gate 	uint_t tmp;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_object_file(ks_handle, O_RDONLY,
11067c478bd9Sstevel@tonic-gate 	    lock_held)) < 0) {
11077c478bd9Sstevel@tonic-gate 		return (-1);
11087c478bd9Sstevel@tonic-gate 	}
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	/*
11117c478bd9Sstevel@tonic-gate 	 * read version.  Version is always first item in object file
11127c478bd9Sstevel@tonic-gate 	 * so, no need to do lseek
11137c478bd9Sstevel@tonic-gate 	 */
1114*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)&tmp, OBJ_VER_SIZE) != OBJ_VER_SIZE) {
11157c478bd9Sstevel@tonic-gate 		ret_val = -1;
11167c478bd9Sstevel@tonic-gate 		goto cleanup;
11177c478bd9Sstevel@tonic-gate 	}
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	*version = SWAP32(tmp);
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate cleanup:
11227c478bd9Sstevel@tonic-gate 	if (!lock_held) {
11237c478bd9Sstevel@tonic-gate 		if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
11247c478bd9Sstevel@tonic-gate 			ret_val = -1;
11257c478bd9Sstevel@tonic-gate 		}
11267c478bd9Sstevel@tonic-gate 	}
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	(void) close(fd);
11307c478bd9Sstevel@tonic-gate 	return (ret_val);
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate /*
11347c478bd9Sstevel@tonic-gate  *		FUNCTION: soft_keystore_getpin
11357c478bd9Sstevel@tonic-gate  *
11367c478bd9Sstevel@tonic-gate  *		ARGUMENTS:
11377c478bd9Sstevel@tonic-gate  *			hashed_pin: pointer to caller allocated memory
11387c478bd9Sstevel@tonic-gate  *				for storing the pin to be returned.
11397c478bd9Sstevel@tonic-gate  *			lock_held: TRUE if the lock is held by caller.
11407c478bd9Sstevel@tonic-gate  *
11417c478bd9Sstevel@tonic-gate  *		RETURN VALUE:
11427c478bd9Sstevel@tonic-gate  *
11437c478bd9Sstevel@tonic-gate  *			0: no error
11447c478bd9Sstevel@tonic-gate  *			-1: some error occurred while getting the pin
11457c478bd9Sstevel@tonic-gate  *
11467c478bd9Sstevel@tonic-gate  *		DESCRIPTION:
11477c478bd9Sstevel@tonic-gate  *
11487c478bd9Sstevel@tonic-gate  *			Reads the MD5 hash from the keystore description
11497c478bd9Sstevel@tonic-gate  *			file and return it to the caller in the provided
11507c478bd9Sstevel@tonic-gate  *			buffer. If there is no PIN in the description file
11517c478bd9Sstevel@tonic-gate  *			because the file is just created, this function
11527c478bd9Sstevel@tonic-gate  *			will get a MD5 digest of the string "changeme",
11537c478bd9Sstevel@tonic-gate  *			store it in the file, and also return this
11547c478bd9Sstevel@tonic-gate  *			string to the caller.
11557c478bd9Sstevel@tonic-gate  */
11567c478bd9Sstevel@tonic-gate int
11577c478bd9Sstevel@tonic-gate soft_keystore_getpin(char **hashed_pin, boolean_t lock_held)
11587c478bd9Sstevel@tonic-gate {
11597c478bd9Sstevel@tonic-gate 	int fd, ret_val = -1;
11607c478bd9Sstevel@tonic-gate 	CK_RV rv;
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDONLY, B_TRUE,
11637c478bd9Sstevel@tonic-gate 	    lock_held)) < 0) {
11647c478bd9Sstevel@tonic-gate 		return (-1);
11657c478bd9Sstevel@tonic-gate 	}
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	rv = get_hashed_pin(fd, hashed_pin);
11687c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
11697c478bd9Sstevel@tonic-gate 		ret_val = 0;
11707c478bd9Sstevel@tonic-gate 	}
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate cleanup:
11737c478bd9Sstevel@tonic-gate 	if (!lock_held) {
11747c478bd9Sstevel@tonic-gate 		if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
11757c478bd9Sstevel@tonic-gate 			ret_val = -1;
11767c478bd9Sstevel@tonic-gate 		}
11777c478bd9Sstevel@tonic-gate 	}
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	(void) close(fd);
11807c478bd9Sstevel@tonic-gate 	return (ret_val);
11817c478bd9Sstevel@tonic-gate }
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate /*
11847c478bd9Sstevel@tonic-gate  * This function reads all the data until the end of the file, and
11857c478bd9Sstevel@tonic-gate  * put the data into the "buf" in argument.  Memory for buf will
11867c478bd9Sstevel@tonic-gate  * be allocated in this function.  It is the caller's responsibility
11877c478bd9Sstevel@tonic-gate  * to free it.  The number of bytes read will be returned
11887c478bd9Sstevel@tonic-gate  * in the argument "bytes_read"
11897c478bd9Sstevel@tonic-gate  *
11907c478bd9Sstevel@tonic-gate  * returns CKR_OK if no error.  Other CKR error codes if there's an error
11917c478bd9Sstevel@tonic-gate  */
11927c478bd9Sstevel@tonic-gate static CK_RV
11937c478bd9Sstevel@tonic-gate read_obj_data(int old_fd, char **buf, ssize_t *bytes_read)
11947c478bd9Sstevel@tonic-gate {
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	ssize_t nread, loop_count;
11977c478bd9Sstevel@tonic-gate 	char *buf1 = NULL;
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	*buf = malloc(BUFSIZ);
12007c478bd9Sstevel@tonic-gate 	if (*buf == NULL) {
12017c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
12027c478bd9Sstevel@tonic-gate 	}
12037c478bd9Sstevel@tonic-gate 
1204*19193bb6SDina K Nimeh 	nread = readn_nointr(old_fd, *buf, BUFSIZ);
12057c478bd9Sstevel@tonic-gate 	if (nread < 0) {
12067c478bd9Sstevel@tonic-gate 		free(*buf);
12077c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
12087c478bd9Sstevel@tonic-gate 	}
12097c478bd9Sstevel@tonic-gate 	loop_count = 1;
12107c478bd9Sstevel@tonic-gate 	while (nread == (loop_count * BUFSIZ)) {
12117c478bd9Sstevel@tonic-gate 		ssize_t nread_tmp;
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 		loop_count++;
12147c478bd9Sstevel@tonic-gate 		/* more than BUFSIZ of data */
12157c478bd9Sstevel@tonic-gate 		buf1 = realloc(*buf, loop_count * BUFSIZ);
12167c478bd9Sstevel@tonic-gate 		if (buf1 == NULL) {
12177c478bd9Sstevel@tonic-gate 			free(*buf);
12187c478bd9Sstevel@tonic-gate 			return (CKR_HOST_MEMORY);
12197c478bd9Sstevel@tonic-gate 		}
12207c478bd9Sstevel@tonic-gate 		*buf = buf1;
1221*19193bb6SDina K Nimeh 		nread_tmp = readn_nointr(old_fd,
12227c478bd9Sstevel@tonic-gate 		    *buf + ((loop_count - 1) * BUFSIZ), BUFSIZ);
12237c478bd9Sstevel@tonic-gate 		if (nread_tmp < 0) {
12247c478bd9Sstevel@tonic-gate 			free(*buf);
12257c478bd9Sstevel@tonic-gate 			return (CKR_FUNCTION_FAILED);
12267c478bd9Sstevel@tonic-gate 		}
12277c478bd9Sstevel@tonic-gate 		nread += nread_tmp;
12287c478bd9Sstevel@tonic-gate 	}
12297c478bd9Sstevel@tonic-gate 	*bytes_read = nread;
12307c478bd9Sstevel@tonic-gate 	return (CKR_OK);
12317c478bd9Sstevel@tonic-gate }
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate /*
12347c478bd9Sstevel@tonic-gate  * Re-encrypt an object using the provided new_enc_key.  The new HMAC
12357c478bd9Sstevel@tonic-gate  * is calculated using the new_hmac_key.  The global static variables
12367c478bd9Sstevel@tonic-gate  * enc_key, and hmac_key will be used for decrypting the original
12377c478bd9Sstevel@tonic-gate  * object, and verifying its signature.
12387c478bd9Sstevel@tonic-gate  *
12397c478bd9Sstevel@tonic-gate  * The re-encrypted object will be stored in the file named
12407c478bd9Sstevel@tonic-gate  * in the "new_obj_name" variable.  The content of the "original"
12417c478bd9Sstevel@tonic-gate  * file named in "orig_obj_name" is not disturbed.
12427c478bd9Sstevel@tonic-gate  *
12437c478bd9Sstevel@tonic-gate  * Returns 0 if there's no error, returns -1 otherwise.
12447c478bd9Sstevel@tonic-gate  *
12457c478bd9Sstevel@tonic-gate  */
12467c478bd9Sstevel@tonic-gate static int
12477c478bd9Sstevel@tonic-gate reencrypt_obj(soft_object_t *new_enc_key, soft_object_t *new_hmac_key,
12487c478bd9Sstevel@tonic-gate     char *orig_obj_name, char *new_obj_name) {
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	int old_fd, new_fd, version, ret_val = -1;
12517c478bd9Sstevel@tonic-gate 	CK_BYTE iv[OBJ_IV_SIZE], old_iv[OBJ_IV_SIZE];
12527c478bd9Sstevel@tonic-gate 	ssize_t nread;
12537c478bd9Sstevel@tonic-gate 	CK_ULONG decrypted_len, encrypted_len, hmac_len;
12547c478bd9Sstevel@tonic-gate 	CK_BYTE hmac[OBJ_HMAC_SIZE], *decrypted_buf = NULL, *buf = NULL;
12557c478bd9Sstevel@tonic-gate 
1256*19193bb6SDina K Nimeh 	old_fd = open_nointr(orig_obj_name, O_RDONLY|O_NONBLOCK);
12577c478bd9Sstevel@tonic-gate 	if (old_fd < 0) {
12587c478bd9Sstevel@tonic-gate 		return (-1);
12597c478bd9Sstevel@tonic-gate 	}
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	if (acquire_file_lock(&old_fd, orig_obj_name, O_RDONLY) != 0) {
12627c478bd9Sstevel@tonic-gate 		if (old_fd > 0) {
12637c478bd9Sstevel@tonic-gate 			(void) close(old_fd);
12647c478bd9Sstevel@tonic-gate 		}
12657c478bd9Sstevel@tonic-gate 		return (-1);
12667c478bd9Sstevel@tonic-gate 	}
12677c478bd9Sstevel@tonic-gate 
1268*19193bb6SDina K Nimeh 	new_fd = open_nointr(new_obj_name,
1269*19193bb6SDina K Nimeh 	    O_WRONLY|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
12707c478bd9Sstevel@tonic-gate 	if (new_fd < 0) {
12717c478bd9Sstevel@tonic-gate 		(void) close(old_fd);
12727c478bd9Sstevel@tonic-gate 		return (-1);
12737c478bd9Sstevel@tonic-gate 	}
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 	if (lock_file(new_fd, B_FALSE, B_TRUE) != 0) {
12767c478bd9Sstevel@tonic-gate 		/* unlock old file */
12777c478bd9Sstevel@tonic-gate 		(void) lock_file(old_fd, B_TRUE, B_FALSE);
12787c478bd9Sstevel@tonic-gate 		(void) close(old_fd);
12797c478bd9Sstevel@tonic-gate 		(void) close(new_fd);
12807c478bd9Sstevel@tonic-gate 		return (-1);
12817c478bd9Sstevel@tonic-gate 	}
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	/* read version, increment, and write to tmp file */
1284*19193bb6SDina K Nimeh 	if (readn_nointr(old_fd, (char *)&version, OBJ_VER_SIZE)
12857c478bd9Sstevel@tonic-gate 	    != OBJ_VER_SIZE) {
12867c478bd9Sstevel@tonic-gate 		goto cleanup;
12877c478bd9Sstevel@tonic-gate 	}
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
12907c478bd9Sstevel@tonic-gate 	version++;
12917c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
12927c478bd9Sstevel@tonic-gate 
1293*19193bb6SDina K Nimeh 	if (writen_nointr(new_fd, (char *)&version, OBJ_VER_SIZE)
12947c478bd9Sstevel@tonic-gate 	    != OBJ_VER_SIZE) {
12957c478bd9Sstevel@tonic-gate 		goto cleanup;
12967c478bd9Sstevel@tonic-gate 	}
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	/* read old iv */
1299*19193bb6SDina K Nimeh 	if (readn_nointr(old_fd, (char *)old_iv, OBJ_IV_SIZE) != OBJ_IV_SIZE) {
13007c478bd9Sstevel@tonic-gate 		goto cleanup;
13017c478bd9Sstevel@tonic-gate 	}
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 	/* generate new IV */
13047c478bd9Sstevel@tonic-gate 	if (soft_gen_iv(iv) != CKR_OK) {
13057c478bd9Sstevel@tonic-gate 		goto cleanup;
13067c478bd9Sstevel@tonic-gate 	}
13077c478bd9Sstevel@tonic-gate 
1308*19193bb6SDina K Nimeh 	if (writen_nointr(new_fd, (char *)iv, OBJ_IV_SIZE) != OBJ_IV_SIZE) {
13097c478bd9Sstevel@tonic-gate 		goto cleanup;
13107c478bd9Sstevel@tonic-gate 	}
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	/* seek to the original encrypted data, and read all of them */
13137c478bd9Sstevel@tonic-gate 	if (lseek(old_fd, OBJ_DATA_OFFSET, SEEK_SET) != OBJ_DATA_OFFSET) {
13147c478bd9Sstevel@tonic-gate 		goto cleanup;
13157c478bd9Sstevel@tonic-gate 	}
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 	if (read_obj_data(old_fd, (char **)&buf, &nread) != CKR_OK) {
13187c478bd9Sstevel@tonic-gate 		goto cleanup;
13197c478bd9Sstevel@tonic-gate 	}
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	/* decrypt data using old key */
13227c478bd9Sstevel@tonic-gate 	decrypted_len = 0;
13237c478bd9Sstevel@tonic-gate 	if (soft_keystore_crypt(enc_key, old_iv, B_FALSE, buf, nread,
13247c478bd9Sstevel@tonic-gate 	    NULL, &decrypted_len) != CKR_OK) {
13257c478bd9Sstevel@tonic-gate 		free(buf);
13267c478bd9Sstevel@tonic-gate 		goto cleanup;
13277c478bd9Sstevel@tonic-gate 	}
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 	decrypted_buf = malloc(decrypted_len);
13307c478bd9Sstevel@tonic-gate 	if (decrypted_buf == NULL) {
13317c478bd9Sstevel@tonic-gate 		free(buf);
13327c478bd9Sstevel@tonic-gate 		goto cleanup;
13337c478bd9Sstevel@tonic-gate 	}
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	if (soft_keystore_crypt(enc_key, old_iv, B_FALSE, buf, nread,
13367c478bd9Sstevel@tonic-gate 	    decrypted_buf, &decrypted_len) != CKR_OK) {
13377c478bd9Sstevel@tonic-gate 		free(buf);
13387c478bd9Sstevel@tonic-gate 		free(decrypted_buf);
13397c478bd9Sstevel@tonic-gate 		goto cleanup;
13407c478bd9Sstevel@tonic-gate 	}
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	free(buf);
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	/* re-encrypt with new key */
13457c478bd9Sstevel@tonic-gate 	encrypted_len = 0;
13467c478bd9Sstevel@tonic-gate 	if (soft_keystore_crypt(new_enc_key, iv, B_TRUE, decrypted_buf,
13477c478bd9Sstevel@tonic-gate 	    decrypted_len, NULL, &encrypted_len) != CKR_OK) {
13487c478bd9Sstevel@tonic-gate 		free(decrypted_buf);
13497c478bd9Sstevel@tonic-gate 		goto cleanup;
13507c478bd9Sstevel@tonic-gate 	}
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	buf = malloc(encrypted_len);
13537c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
13547c478bd9Sstevel@tonic-gate 		free(decrypted_buf);
13557c478bd9Sstevel@tonic-gate 		goto cleanup;
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	if (soft_keystore_crypt(new_enc_key, iv, B_TRUE, decrypted_buf,
13597c478bd9Sstevel@tonic-gate 	    decrypted_len, buf, &encrypted_len) != CKR_OK) {
13607c478bd9Sstevel@tonic-gate 		free(buf);
13617c478bd9Sstevel@tonic-gate 		free(decrypted_buf);
13627c478bd9Sstevel@tonic-gate 		goto cleanup;
13637c478bd9Sstevel@tonic-gate 	}
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 	free(decrypted_buf);
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 	/* calculate hmac on re-encrypted data using new hmac key */
13687c478bd9Sstevel@tonic-gate 	hmac_len = OBJ_HMAC_SIZE;
13697c478bd9Sstevel@tonic-gate 	if (soft_keystore_hmac(new_hmac_key, B_TRUE, buf,
13707c478bd9Sstevel@tonic-gate 	    encrypted_len, hmac, &hmac_len) != CKR_OK) {
13717c478bd9Sstevel@tonic-gate 		free(buf);
13727c478bd9Sstevel@tonic-gate 		goto cleanup;
13737c478bd9Sstevel@tonic-gate 	}
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	/* just for sanity check */
13767c478bd9Sstevel@tonic-gate 	if (hmac_len != OBJ_HMAC_SIZE) {
13777c478bd9Sstevel@tonic-gate 		free(buf);
13787c478bd9Sstevel@tonic-gate 		goto cleanup;
13797c478bd9Sstevel@tonic-gate 	}
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	/* write new hmac */
1382*19193bb6SDina K Nimeh 	if (writen_nointr(new_fd, (char *)hmac, OBJ_HMAC_SIZE)
13837c478bd9Sstevel@tonic-gate 	    != OBJ_HMAC_SIZE) {
13847c478bd9Sstevel@tonic-gate 		free(buf);
13857c478bd9Sstevel@tonic-gate 		goto cleanup;
13867c478bd9Sstevel@tonic-gate 	}
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 	/* write re-encrypted buffer to temp file */
1389*19193bb6SDina K Nimeh 	if (writen_nointr(new_fd, (void *)buf, encrypted_len)
13907c478bd9Sstevel@tonic-gate 	    != encrypted_len) {
13917c478bd9Sstevel@tonic-gate 		free(buf);
13927c478bd9Sstevel@tonic-gate 		goto cleanup;
13937c478bd9Sstevel@tonic-gate 	}
13947c478bd9Sstevel@tonic-gate 	free(buf);
13957c478bd9Sstevel@tonic-gate 	ret_val = 0;
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate cleanup:
13987c478bd9Sstevel@tonic-gate 	/* unlock the files */
13997c478bd9Sstevel@tonic-gate 	(void) lock_file(old_fd, B_TRUE, B_FALSE);
14007c478bd9Sstevel@tonic-gate 	(void) lock_file(new_fd, B_FALSE, B_FALSE);
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 	(void) close(old_fd);
14037c478bd9Sstevel@tonic-gate 	(void) close(new_fd);
14047c478bd9Sstevel@tonic-gate 	if (ret_val != 0) {
14057c478bd9Sstevel@tonic-gate 		(void) remove(new_obj_name);
14067c478bd9Sstevel@tonic-gate 	}
14077c478bd9Sstevel@tonic-gate 	return (ret_val);
14087c478bd9Sstevel@tonic-gate }
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate /*
14117c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_setpin
14127c478bd9Sstevel@tonic-gate  *
14137c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
14147c478bd9Sstevel@tonic-gate  *		newpin: new pin entered by the user.
14157c478bd9Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
14167c478bd9Sstevel@tonic-gate  *
14177c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
14187c478bd9Sstevel@tonic-gate  *		0: no error
14197c478bd9Sstevel@tonic-gate  *		-1: failure
14207c478bd9Sstevel@tonic-gate  *
14217c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
14227c478bd9Sstevel@tonic-gate  *
14237c478bd9Sstevel@tonic-gate  *		This function does the following:
14247c478bd9Sstevel@tonic-gate  *
14257c478bd9Sstevel@tonic-gate  *		1) Generates crypted value of newpin and store it
14267c478bd9Sstevel@tonic-gate  *		   in keystore description file.
14277c478bd9Sstevel@tonic-gate  *		2) Dervies the new encryption key from the newpin.  This key
14287c478bd9Sstevel@tonic-gate  *		   will be used to re-encrypt the private token objects.
14297c478bd9Sstevel@tonic-gate  *		3) Re-encrypt all of this user's existing private token
14307c478bd9Sstevel@tonic-gate  *		   objects (if any).
14317c478bd9Sstevel@tonic-gate  *		4) Increments the keystore version number.
14327c478bd9Sstevel@tonic-gate  */
14337c478bd9Sstevel@tonic-gate int
14347c478bd9Sstevel@tonic-gate soft_keystore_setpin(uchar_t *oldpin, uchar_t *newpin, boolean_t lock_held)
14357c478bd9Sstevel@tonic-gate {
14367c478bd9Sstevel@tonic-gate 	int fd, tmp_ks_fd, version, ret_val = -1;
14377c478bd9Sstevel@tonic-gate 	soft_object_t *new_crypt_key = NULL, *new_hmac_key = NULL;
14387c478bd9Sstevel@tonic-gate 	char filebuf[BUFSIZ];
14397c478bd9Sstevel@tonic-gate 	DIR	*pri_dirp;
14404bc0a2efScasper 	struct dirent *pri_ent;
14417c478bd9Sstevel@tonic-gate 	char pri_obj_path[MAXPATHLEN], ks_desc_file[MAXPATHLEN],
14427c478bd9Sstevel@tonic-gate 	    tmp_ks_desc_name[MAXPATHLEN];
14437c478bd9Sstevel@tonic-gate 	typedef struct priobjs {
14447c478bd9Sstevel@tonic-gate 		char orig_name[MAXPATHLEN];
14457c478bd9Sstevel@tonic-gate 		char tmp_name[MAXPATHLEN];
14467c478bd9Sstevel@tonic-gate 		struct priobjs *next;
14477c478bd9Sstevel@tonic-gate 	} priobjs_t;
14487c478bd9Sstevel@tonic-gate 	priobjs_t *pri_objs = NULL, *tmp;
14497c478bd9Sstevel@tonic-gate 	CK_BYTE *crypt_salt = NULL, *hmac_salt = NULL;
14507c478bd9Sstevel@tonic-gate 	boolean_t pin_never_set = B_FALSE, user_logged_in;
14517c478bd9Sstevel@tonic-gate 	char *new_hashed_pin = NULL;
14527c478bd9Sstevel@tonic-gate 	uint64_t hashed_pin_salt_length, new_hashed_pin_len, swaped_val;
14537c478bd9Sstevel@tonic-gate 	char *hashed_pin_salt = NULL;
14547c478bd9Sstevel@tonic-gate 	priobjs_t *obj;
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	if ((enc_key == NULL) ||
14577c478bd9Sstevel@tonic-gate 	    (enc_key->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
14587c478bd9Sstevel@tonic-gate 		user_logged_in = B_FALSE;
14597c478bd9Sstevel@tonic-gate 	} else {
14607c478bd9Sstevel@tonic-gate 		user_logged_in = B_TRUE;
14617c478bd9Sstevel@tonic-gate 	}
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDWR, B_FALSE,
14647c478bd9Sstevel@tonic-gate 	    lock_held)) < 0) {
14657c478bd9Sstevel@tonic-gate 		return (-1);
14667c478bd9Sstevel@tonic-gate 	}
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	(void) get_desc_file_path(ks_desc_file);
14697c478bd9Sstevel@tonic-gate 	(void) get_tmp_desc_file_path(tmp_ks_desc_name);
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	/*
14727c478bd9Sstevel@tonic-gate 	 * create a tempoary file for the keystore description
14737c478bd9Sstevel@tonic-gate 	 * file for updating version and counter information
14747c478bd9Sstevel@tonic-gate 	 */
1475*19193bb6SDina K Nimeh 	tmp_ks_fd = open_nointr(tmp_ks_desc_name,
1476*19193bb6SDina K Nimeh 	    O_RDWR|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
14777c478bd9Sstevel@tonic-gate 	if (tmp_ks_fd < 0) {
14787c478bd9Sstevel@tonic-gate 		(void) close(fd);
14797c478bd9Sstevel@tonic-gate 		return (-1);
14807c478bd9Sstevel@tonic-gate 	}
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 	/* read and write PKCS version to temp file */
1483*19193bb6SDina K Nimeh 	if (readn_nointr(fd, filebuf, KS_PKCS11_VER_SIZE)
14847c478bd9Sstevel@tonic-gate 	    != KS_PKCS11_VER_SIZE) {
14857c478bd9Sstevel@tonic-gate 		goto cleanup;
14867c478bd9Sstevel@tonic-gate 	}
14877c478bd9Sstevel@tonic-gate 
1488*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_ks_fd, filebuf, KS_PKCS11_VER_SIZE)
14897c478bd9Sstevel@tonic-gate 	    != KS_PKCS11_VER_SIZE) {
14907c478bd9Sstevel@tonic-gate 		goto cleanup;
14917c478bd9Sstevel@tonic-gate 	}
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 	/* get version number, and write updated number to temp file */
1494*19193bb6SDina K Nimeh 	if (readn_nointr(fd, &version, KS_VER_SIZE) != KS_VER_SIZE) {
14957c478bd9Sstevel@tonic-gate 		goto cleanup;
14967c478bd9Sstevel@tonic-gate 	}
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
14997c478bd9Sstevel@tonic-gate 	version++;
15007c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
15017c478bd9Sstevel@tonic-gate 
1502*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_ks_fd, (void *)&version, KS_VER_SIZE)
15037c478bd9Sstevel@tonic-gate 	    != KS_VER_SIZE) {
15047c478bd9Sstevel@tonic-gate 		goto cleanup;
15057c478bd9Sstevel@tonic-gate 	}
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	/* read and write counter, no modification necessary */
1509*19193bb6SDina K Nimeh 	if (readn_nointr(fd, filebuf, KS_COUNTER_SIZE) != KS_COUNTER_SIZE) {
15107c478bd9Sstevel@tonic-gate 		goto cleanup;
15117c478bd9Sstevel@tonic-gate 	}
15127c478bd9Sstevel@tonic-gate 
1513*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_ks_fd, filebuf, KS_COUNTER_SIZE)
15147c478bd9Sstevel@tonic-gate 	    != KS_COUNTER_SIZE) {
15157c478bd9Sstevel@tonic-gate 		goto cleanup;
15167c478bd9Sstevel@tonic-gate 	}
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 	/* read old encryption salt */
15197c478bd9Sstevel@tonic-gate 	crypt_salt = malloc(KS_KEY_SALT_SIZE);
15207c478bd9Sstevel@tonic-gate 	if (crypt_salt == NULL) {
15217c478bd9Sstevel@tonic-gate 		goto cleanup;
15227c478bd9Sstevel@tonic-gate 	}
1523*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)crypt_salt, KS_KEY_SALT_SIZE)
15247c478bd9Sstevel@tonic-gate 	    != KS_KEY_SALT_SIZE) {
15257c478bd9Sstevel@tonic-gate 		goto cleanup;
15267c478bd9Sstevel@tonic-gate 	}
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	/* read old hmac salt */
15297c478bd9Sstevel@tonic-gate 	hmac_salt = malloc(KS_HMAC_SALT_SIZE);
15307c478bd9Sstevel@tonic-gate 	if (hmac_salt == NULL) {
15317c478bd9Sstevel@tonic-gate 		goto cleanup;
15327c478bd9Sstevel@tonic-gate 	}
1533*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)hmac_salt, KS_HMAC_SALT_SIZE)
15347c478bd9Sstevel@tonic-gate 	    != KS_HMAC_SALT_SIZE) {
15357c478bd9Sstevel@tonic-gate 		goto cleanup;
15367c478bd9Sstevel@tonic-gate 	}
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	/* just create some empty bytes */
15397c478bd9Sstevel@tonic-gate 	bzero(filebuf, sizeof (filebuf));
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 	if (memcmp(crypt_salt, filebuf, KS_KEY_SALT_SIZE) == 0) {
15427c478bd9Sstevel@tonic-gate 		/* PIN as never been set */
15437c478bd9Sstevel@tonic-gate 		CK_BYTE *new_crypt_salt = NULL, *new_hmac_salt = NULL;
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 		pin_never_set = B_TRUE;
15467c478bd9Sstevel@tonic-gate 		if (soft_gen_crypt_key(newpin, &new_crypt_key, &new_crypt_salt)
15477c478bd9Sstevel@tonic-gate 		    != CKR_OK) {
15487c478bd9Sstevel@tonic-gate 			goto cleanup;
15497c478bd9Sstevel@tonic-gate 		}
1550*19193bb6SDina K Nimeh 		if (writen_nointr(tmp_ks_fd, (void *)new_crypt_salt,
15517c478bd9Sstevel@tonic-gate 		    KS_KEY_SALT_SIZE) != KS_KEY_SALT_SIZE) {
15527c478bd9Sstevel@tonic-gate 			free(new_crypt_salt);
15537c478bd9Sstevel@tonic-gate 			(void) soft_cleanup_object(new_crypt_key);
15547c478bd9Sstevel@tonic-gate 			goto cleanup;
15557c478bd9Sstevel@tonic-gate 		}
15567c478bd9Sstevel@tonic-gate 		free(new_crypt_salt);
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 		if (soft_gen_hmac_key(newpin, &new_hmac_key, &new_hmac_salt)
15597c478bd9Sstevel@tonic-gate 		    != CKR_OK) {
15607c478bd9Sstevel@tonic-gate 			(void) soft_cleanup_object(new_crypt_key);
15617c478bd9Sstevel@tonic-gate 			goto cleanup;
15627c478bd9Sstevel@tonic-gate 		}
1563*19193bb6SDina K Nimeh 		if (writen_nointr(tmp_ks_fd, (void *)new_hmac_salt,
15647c478bd9Sstevel@tonic-gate 		    KS_HMAC_SALT_SIZE) != KS_HMAC_SALT_SIZE) {
15657c478bd9Sstevel@tonic-gate 			free(new_hmac_salt);
15667c478bd9Sstevel@tonic-gate 			goto cleanup3;
15677c478bd9Sstevel@tonic-gate 		}
15687c478bd9Sstevel@tonic-gate 		free(new_hmac_salt);
15697c478bd9Sstevel@tonic-gate 	} else {
15707c478bd9Sstevel@tonic-gate 		if (soft_gen_crypt_key(newpin, &new_crypt_key,
15717c478bd9Sstevel@tonic-gate 		    (CK_BYTE **)&crypt_salt) != CKR_OK) {
15727c478bd9Sstevel@tonic-gate 			goto cleanup;
15737c478bd9Sstevel@tonic-gate 		}
15747c478bd9Sstevel@tonic-gate 		/* no change to the encryption salt */
1575*19193bb6SDina K Nimeh 		if (writen_nointr(tmp_ks_fd, (void *)crypt_salt,
15767c478bd9Sstevel@tonic-gate 		    KS_KEY_SALT_SIZE) != KS_KEY_SALT_SIZE) {
15777c478bd9Sstevel@tonic-gate 			(void) soft_cleanup_object(new_crypt_key);
15787c478bd9Sstevel@tonic-gate 			goto cleanup;
15797c478bd9Sstevel@tonic-gate 		}
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 		if (soft_gen_hmac_key(newpin, &new_hmac_key,
15827c478bd9Sstevel@tonic-gate 		    (CK_BYTE **)&hmac_salt) != CKR_OK) {
15837c478bd9Sstevel@tonic-gate 			(void) soft_cleanup_object(new_crypt_key);
15847c478bd9Sstevel@tonic-gate 			goto cleanup;
15857c478bd9Sstevel@tonic-gate 		}
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 		/* no change to the hmac salt */
1588*19193bb6SDina K Nimeh 		if (writen_nointr(tmp_ks_fd, (void *)hmac_salt,
15897c478bd9Sstevel@tonic-gate 		    KS_HMAC_SALT_SIZE) != KS_HMAC_SALT_SIZE) {
15907c478bd9Sstevel@tonic-gate 			goto cleanup3;
15917c478bd9Sstevel@tonic-gate 		}
15927c478bd9Sstevel@tonic-gate 	}
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	/*
15957c478bd9Sstevel@tonic-gate 	 * read hashed pin salt, and write to updated keystore description
15967c478bd9Sstevel@tonic-gate 	 * file unmodified.
15977c478bd9Sstevel@tonic-gate 	 */
1598*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)&hashed_pin_salt_length,
15997c478bd9Sstevel@tonic-gate 	    KS_HASHED_PIN_SALT_LEN_SIZE) != KS_HASHED_PIN_SALT_LEN_SIZE) {
16007c478bd9Sstevel@tonic-gate 		goto cleanup3;
16017c478bd9Sstevel@tonic-gate 	}
16027c478bd9Sstevel@tonic-gate 
1603*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_ks_fd, (void *)&hashed_pin_salt_length,
16047c478bd9Sstevel@tonic-gate 	    KS_HASHED_PIN_SALT_LEN_SIZE) != KS_HASHED_PIN_SALT_LEN_SIZE) {
16057c478bd9Sstevel@tonic-gate 		goto cleanup3;
16067c478bd9Sstevel@tonic-gate 	}
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	hashed_pin_salt_length = SWAP64(hashed_pin_salt_length);
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	hashed_pin_salt = malloc(hashed_pin_salt_length + 1);
16117c478bd9Sstevel@tonic-gate 	if (hashed_pin_salt == NULL) {
16127c478bd9Sstevel@tonic-gate 		goto cleanup3;
16137c478bd9Sstevel@tonic-gate 	}
16147c478bd9Sstevel@tonic-gate 
1615*19193bb6SDina K Nimeh 	if ((readn_nointr(fd, hashed_pin_salt, hashed_pin_salt_length)) !=
16167c478bd9Sstevel@tonic-gate 	    (ssize_t)hashed_pin_salt_length) {
16177c478bd9Sstevel@tonic-gate 		free(hashed_pin_salt);
16187c478bd9Sstevel@tonic-gate 		goto cleanup3;
16197c478bd9Sstevel@tonic-gate 	}
16207c478bd9Sstevel@tonic-gate 
1621*19193bb6SDina K Nimeh 	if ((writen_nointr(tmp_ks_fd, hashed_pin_salt, hashed_pin_salt_length))
16227c478bd9Sstevel@tonic-gate 	    != (ssize_t)hashed_pin_salt_length) {
16237c478bd9Sstevel@tonic-gate 		free(hashed_pin_salt);
16247c478bd9Sstevel@tonic-gate 		goto cleanup3;
16257c478bd9Sstevel@tonic-gate 	}
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 	hashed_pin_salt[hashed_pin_salt_length] = '\0';
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 	/* old hashed pin length and value can be ignored, generate new one */
16307c478bd9Sstevel@tonic-gate 	if (soft_gen_hashed_pin(newpin, &new_hashed_pin,
16317c478bd9Sstevel@tonic-gate 	    &hashed_pin_salt) < 0) {
16327c478bd9Sstevel@tonic-gate 		free(hashed_pin_salt);
16337c478bd9Sstevel@tonic-gate 		goto cleanup3;
16347c478bd9Sstevel@tonic-gate 	}
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	free(hashed_pin_salt);
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	if (new_hashed_pin == NULL) {
16397c478bd9Sstevel@tonic-gate 		goto cleanup3;
16407c478bd9Sstevel@tonic-gate 	}
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 	new_hashed_pin_len = strlen(new_hashed_pin);
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	/* write new hashed pin length to file */
16457c478bd9Sstevel@tonic-gate 	swaped_val = SWAP64(new_hashed_pin_len);
1646*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_ks_fd, (void *)&swaped_val,
16477c478bd9Sstevel@tonic-gate 	    KS_HASHED_PINLEN_SIZE) != KS_HASHED_PINLEN_SIZE) {
16487c478bd9Sstevel@tonic-gate 		goto cleanup3;
16497c478bd9Sstevel@tonic-gate 	}
16507c478bd9Sstevel@tonic-gate 
1651*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_ks_fd, (void *)new_hashed_pin,
16527c478bd9Sstevel@tonic-gate 	    new_hashed_pin_len) != (ssize_t)new_hashed_pin_len) {
16537c478bd9Sstevel@tonic-gate 		goto cleanup3;
16547c478bd9Sstevel@tonic-gate 	}
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	if (pin_never_set) {
16577c478bd9Sstevel@tonic-gate 		/* there was no private object, no need to re-encrypt them */
16587c478bd9Sstevel@tonic-gate 		goto rename_desc_file;
16597c478bd9Sstevel@tonic-gate 	}
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate 	/* re-encrypt all the private objects */
16627c478bd9Sstevel@tonic-gate 	pri_dirp = opendir(get_pri_obj_path(pri_obj_path));
16637c478bd9Sstevel@tonic-gate 	if (pri_dirp == NULL) {
16647c478bd9Sstevel@tonic-gate 		/*
16657c478bd9Sstevel@tonic-gate 		 * this directory should exist, even if it doesn't contain
16667c478bd9Sstevel@tonic-gate 		 * any objects.  Don't want to update the pin if the
16677c478bd9Sstevel@tonic-gate 		 * keystore is somehow messed up.
16687c478bd9Sstevel@tonic-gate 		 */
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 		goto cleanup3;
16717c478bd9Sstevel@tonic-gate 	}
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 	/* if user did not login, need to set the old pin */
16747c478bd9Sstevel@tonic-gate 	if (!user_logged_in) {
16757c478bd9Sstevel@tonic-gate 		if (soft_keystore_authpin(oldpin) != 0) {
16767c478bd9Sstevel@tonic-gate 			goto cleanup3;
16777c478bd9Sstevel@tonic-gate 		}
16787c478bd9Sstevel@tonic-gate 	}
16797c478bd9Sstevel@tonic-gate 
16804bc0a2efScasper 	while ((pri_ent = readdir(pri_dirp)) != NULL) {
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 		if ((strcmp(pri_ent->d_name, ".") == 0) ||
16837c478bd9Sstevel@tonic-gate 		    (strcmp(pri_ent->d_name, "..") == 0) ||
16847c478bd9Sstevel@tonic-gate 		    (strncmp(pri_ent->d_name, TMP_OBJ_PREFIX,
16857c478bd9Sstevel@tonic-gate 		    strlen(TMP_OBJ_PREFIX)) == 0)) {
16867c478bd9Sstevel@tonic-gate 			continue;
16877c478bd9Sstevel@tonic-gate 		}
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate 		obj = malloc(sizeof (priobjs_t));
16907c478bd9Sstevel@tonic-gate 		if (obj == NULL) {
16917c478bd9Sstevel@tonic-gate 			goto cleanup2;
16927c478bd9Sstevel@tonic-gate 		}
16937c478bd9Sstevel@tonic-gate 		(void) snprintf(obj->orig_name, MAXPATHLEN,
16947c478bd9Sstevel@tonic-gate 		    "%s/%s", pri_obj_path, pri_ent->d_name);
16957c478bd9Sstevel@tonic-gate 		(void) snprintf(obj->tmp_name, MAXPATHLEN, "%s/%s%s",
16967c478bd9Sstevel@tonic-gate 		    pri_obj_path, TMP_OBJ_PREFIX,
16977c478bd9Sstevel@tonic-gate 		    (pri_ent->d_name) + strlen(OBJ_PREFIX));
16987c478bd9Sstevel@tonic-gate 		if (reencrypt_obj(new_crypt_key, new_hmac_key,
16997c478bd9Sstevel@tonic-gate 		    obj->orig_name, obj->tmp_name) != 0) {
17007c478bd9Sstevel@tonic-gate 			free(obj);
17017c478bd9Sstevel@tonic-gate 			goto cleanup2;
17027c478bd9Sstevel@tonic-gate 		}
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 		/* insert into list of file to be renamed */
17057c478bd9Sstevel@tonic-gate 		if (pri_objs == NULL) {
17067c478bd9Sstevel@tonic-gate 			obj->next = NULL;
17077c478bd9Sstevel@tonic-gate 			pri_objs = obj;
17087c478bd9Sstevel@tonic-gate 		} else {
17097c478bd9Sstevel@tonic-gate 			obj->next = pri_objs;
17107c478bd9Sstevel@tonic-gate 			pri_objs = obj;
17117c478bd9Sstevel@tonic-gate 		}
17127c478bd9Sstevel@tonic-gate 	}
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	/* rename all the private objects */
17157c478bd9Sstevel@tonic-gate 	tmp = pri_objs;
17167c478bd9Sstevel@tonic-gate 	while (tmp) {
17177c478bd9Sstevel@tonic-gate 		(void) rename(tmp->tmp_name, tmp->orig_name);
17187c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
17197c478bd9Sstevel@tonic-gate 	}
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate rename_desc_file:
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	/* destroy the old encryption key, and hmac key */
17247c478bd9Sstevel@tonic-gate 	if ((!pin_never_set) && (user_logged_in)) {
17257c478bd9Sstevel@tonic-gate 		(void) soft_cleanup_object(enc_key);
17267c478bd9Sstevel@tonic-gate 		(void) soft_cleanup_object(hmac_key);
17277c478bd9Sstevel@tonic-gate 	}
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 	if (user_logged_in) {
17307c478bd9Sstevel@tonic-gate 		enc_key = new_crypt_key;
17317c478bd9Sstevel@tonic-gate 		hmac_key = new_hmac_key;
17327c478bd9Sstevel@tonic-gate 	}
17337c478bd9Sstevel@tonic-gate 	(void) rename(tmp_ks_desc_name, ks_desc_file);
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 	ret_val = 0;
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate cleanup2:
17387c478bd9Sstevel@tonic-gate 	if (pri_objs != NULL) {
17397c478bd9Sstevel@tonic-gate 		priobjs_t *p = pri_objs;
17407c478bd9Sstevel@tonic-gate 		while (p) {
17417c478bd9Sstevel@tonic-gate 			tmp = p->next;
17427c478bd9Sstevel@tonic-gate 			free(p);
17437c478bd9Sstevel@tonic-gate 			p = tmp;
17447c478bd9Sstevel@tonic-gate 		}
17457c478bd9Sstevel@tonic-gate 	}
17467c478bd9Sstevel@tonic-gate 	if (!pin_never_set) {
17477c478bd9Sstevel@tonic-gate 		(void) closedir(pri_dirp);
17487c478bd9Sstevel@tonic-gate 	}
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 	if ((!user_logged_in) && (!pin_never_set)) {
17517c478bd9Sstevel@tonic-gate 		(void) soft_cleanup_object(enc_key);
17527c478bd9Sstevel@tonic-gate 		(void) soft_cleanup_object(hmac_key);
17537c478bd9Sstevel@tonic-gate 		enc_key = NULL;
17547c478bd9Sstevel@tonic-gate 		hmac_key = NULL;
17557c478bd9Sstevel@tonic-gate 	}
17567c478bd9Sstevel@tonic-gate cleanup3:
17577c478bd9Sstevel@tonic-gate 	if ((ret_val != 0) || (!user_logged_in)) {
17587c478bd9Sstevel@tonic-gate 		(void) soft_cleanup_object(new_crypt_key);
17597c478bd9Sstevel@tonic-gate 		(void) soft_cleanup_object(new_hmac_key);
17607c478bd9Sstevel@tonic-gate 	}
17617c478bd9Sstevel@tonic-gate 
17627c478bd9Sstevel@tonic-gate cleanup:
17637c478bd9Sstevel@tonic-gate 	if (!lock_held) {
17647c478bd9Sstevel@tonic-gate 		if (lock_file(fd, B_FALSE, B_FALSE) < 0) {
17657c478bd9Sstevel@tonic-gate 			ret_val = 1;
17667c478bd9Sstevel@tonic-gate 		}
17677c478bd9Sstevel@tonic-gate 	}
17687c478bd9Sstevel@tonic-gate 	if (crypt_salt != NULL) {
17697c478bd9Sstevel@tonic-gate 		free(crypt_salt);
17707c478bd9Sstevel@tonic-gate 	}
17717c478bd9Sstevel@tonic-gate 	if (hmac_salt != NULL) {
17727c478bd9Sstevel@tonic-gate 		free(hmac_salt);
17737c478bd9Sstevel@tonic-gate 	}
17747c478bd9Sstevel@tonic-gate 	(void) close(fd);
17757c478bd9Sstevel@tonic-gate 	(void) close(tmp_ks_fd);
17767c478bd9Sstevel@tonic-gate 	if (ret_val != 0) {
17777c478bd9Sstevel@tonic-gate 		(void) remove(tmp_ks_desc_name);
17787c478bd9Sstevel@tonic-gate 	}
17797c478bd9Sstevel@tonic-gate 	return (ret_val);
17807c478bd9Sstevel@tonic-gate }
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate /*
17837c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_authpin
17847c478bd9Sstevel@tonic-gate  *
17857c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
17867c478bd9Sstevel@tonic-gate  *		pin: pin specified by the user for logging into
17877c478bd9Sstevel@tonic-gate  *		     the keystore.
17887c478bd9Sstevel@tonic-gate  *
17897c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
17907c478bd9Sstevel@tonic-gate  *		0: if no error
17917c478bd9Sstevel@tonic-gate  *		-1: if there is any error
17927c478bd9Sstevel@tonic-gate  *
17937c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
17947c478bd9Sstevel@tonic-gate  *
17957c478bd9Sstevel@tonic-gate  *		This function takes the pin specified in the argument
17967c478bd9Sstevel@tonic-gate  *		and generates an encryption key based on the pin.
17977c478bd9Sstevel@tonic-gate  *		The generated encryption key will be used for
17987c478bd9Sstevel@tonic-gate  *		all future encryption and decryption for private
17997c478bd9Sstevel@tonic-gate  *		objects.  Before this function is called, none
18007c478bd9Sstevel@tonic-gate  *		of the keystore related interfaces is able
18017c478bd9Sstevel@tonic-gate  *		to decrypt/encrypt any private object.
18027c478bd9Sstevel@tonic-gate  */
18037c478bd9Sstevel@tonic-gate int
18047c478bd9Sstevel@tonic-gate soft_keystore_authpin(uchar_t  *pin)
18057c478bd9Sstevel@tonic-gate {
18067c478bd9Sstevel@tonic-gate 	int fd;
18077c478bd9Sstevel@tonic-gate 	int ret_val = -1;
18087c478bd9Sstevel@tonic-gate 	CK_BYTE *crypt_salt = NULL, *hmac_salt;
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	/* get the salt from the keystore description file */
18117c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDONLY,
18127c478bd9Sstevel@tonic-gate 	    B_FALSE, B_FALSE)) < 0) {
18137c478bd9Sstevel@tonic-gate 		return (-1);
18147c478bd9Sstevel@tonic-gate 	}
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 	crypt_salt = malloc(KS_KEY_SALT_SIZE);
18177c478bd9Sstevel@tonic-gate 	if (crypt_salt == NULL) {
18187c478bd9Sstevel@tonic-gate 		goto cleanup;
18197c478bd9Sstevel@tonic-gate 	}
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate 	if (lseek(fd, KS_KEY_SALT_OFFSET, SEEK_SET) != KS_KEY_SALT_OFFSET) {
18227c478bd9Sstevel@tonic-gate 		goto cleanup;
18237c478bd9Sstevel@tonic-gate 	}
18247c478bd9Sstevel@tonic-gate 
1825*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)crypt_salt, KS_KEY_SALT_SIZE)
18267c478bd9Sstevel@tonic-gate 	    != KS_KEY_SALT_SIZE) {
18277c478bd9Sstevel@tonic-gate 		goto cleanup;
18287c478bd9Sstevel@tonic-gate 	}
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 	if (soft_gen_crypt_key(pin, &enc_key, (CK_BYTE **)&crypt_salt)
18317c478bd9Sstevel@tonic-gate 	    != CKR_OK) {
18327c478bd9Sstevel@tonic-gate 		goto cleanup;
18337c478bd9Sstevel@tonic-gate 	}
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 	hmac_salt = malloc(KS_HMAC_SALT_SIZE);
18367c478bd9Sstevel@tonic-gate 	if (hmac_salt == NULL) {
18377c478bd9Sstevel@tonic-gate 		goto cleanup;
18387c478bd9Sstevel@tonic-gate 	}
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate 	if (lseek(fd, KS_HMAC_SALT_OFFSET, SEEK_SET) != KS_HMAC_SALT_OFFSET) {
18417c478bd9Sstevel@tonic-gate 		goto cleanup;
18427c478bd9Sstevel@tonic-gate 	}
18437c478bd9Sstevel@tonic-gate 
1844*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)hmac_salt, KS_HMAC_SALT_SIZE)
18457c478bd9Sstevel@tonic-gate 	    != KS_HMAC_SALT_SIZE) {
18467c478bd9Sstevel@tonic-gate 		goto cleanup;
18477c478bd9Sstevel@tonic-gate 	}
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 	if (soft_gen_hmac_key(pin, &hmac_key, (CK_BYTE **)&hmac_salt)
18507c478bd9Sstevel@tonic-gate 	    != CKR_OK) {
18517c478bd9Sstevel@tonic-gate 		goto cleanup;
18527c478bd9Sstevel@tonic-gate 	}
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 	ret_val = 0;
18557c478bd9Sstevel@tonic-gate 
18567c478bd9Sstevel@tonic-gate cleanup:
18577c478bd9Sstevel@tonic-gate 	/* unlock the file */
18587c478bd9Sstevel@tonic-gate 	(void) lock_file(fd, B_TRUE, B_FALSE);
18597c478bd9Sstevel@tonic-gate 	(void) close(fd);
18607c478bd9Sstevel@tonic-gate 	if (crypt_salt != NULL) {
18617c478bd9Sstevel@tonic-gate 		free(crypt_salt);
18627c478bd9Sstevel@tonic-gate 	}
18637c478bd9Sstevel@tonic-gate 	if (hmac_salt != NULL) {
18647c478bd9Sstevel@tonic-gate 		free(hmac_salt);
18657c478bd9Sstevel@tonic-gate 	}
18667c478bd9Sstevel@tonic-gate 	return (ret_val);
18677c478bd9Sstevel@tonic-gate }
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate /*
18707c478bd9Sstevel@tonic-gate  * 	FUNCTION: soft_keystore_get_objs
18717c478bd9Sstevel@tonic-gate  *
18727c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
18737c478bd9Sstevel@tonic-gate  *
18747c478bd9Sstevel@tonic-gate  *		search_type: Specify type of objects to return.
18757c478bd9Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
18767c478bd9Sstevel@tonic-gate  *
18777c478bd9Sstevel@tonic-gate  *
18787c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
18797c478bd9Sstevel@tonic-gate  *
18807c478bd9Sstevel@tonic-gate  *		NULL: if there are no object in the database.
18817c478bd9Sstevel@tonic-gate  *
18827c478bd9Sstevel@tonic-gate  *		Otherwise, linked list of objects as requested
18837c478bd9Sstevel@tonic-gate  *		in search type.
18847c478bd9Sstevel@tonic-gate  *
18857c478bd9Sstevel@tonic-gate  *		The linked list returned will need to be freed
18867c478bd9Sstevel@tonic-gate  *		by the caller.
18877c478bd9Sstevel@tonic-gate  *
18887c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
18897c478bd9Sstevel@tonic-gate  *
18907c478bd9Sstevel@tonic-gate  *		Returns objects as requested.
18917c478bd9Sstevel@tonic-gate  *
18927c478bd9Sstevel@tonic-gate  *		If private objects is requested, and the caller
18937c478bd9Sstevel@tonic-gate  *		has not previously passed in the pin or if the pin
18947c478bd9Sstevel@tonic-gate  *		passed in is wrong, private objects will not
18957c478bd9Sstevel@tonic-gate  *		be returned.
18967c478bd9Sstevel@tonic-gate  *
18977c478bd9Sstevel@tonic-gate  *		The buffers returned for private objects are already
18987c478bd9Sstevel@tonic-gate  *		decrypted.
18997c478bd9Sstevel@tonic-gate  */
19007c478bd9Sstevel@tonic-gate CK_RV
19017c478bd9Sstevel@tonic-gate soft_keystore_get_objs(ks_search_type_t search_type,
19027c478bd9Sstevel@tonic-gate     ks_obj_t **result_obj_list, boolean_t lock_held)
19037c478bd9Sstevel@tonic-gate {
19047c478bd9Sstevel@tonic-gate 	DIR *dirp;
19057c478bd9Sstevel@tonic-gate 	ks_obj_handle_t ks_handle;
19067c478bd9Sstevel@tonic-gate 	CK_RV rv;
19077c478bd9Sstevel@tonic-gate 	ks_obj_t *tmp;
19087c478bd9Sstevel@tonic-gate 	int ks_fd;
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 	*result_obj_list = NULL;
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	/*
19137c478bd9Sstevel@tonic-gate 	 * lock the keystore description file in "read" mode so that
19147c478bd9Sstevel@tonic-gate 	 * objects won't get added/deleted/modified while we are
19157c478bd9Sstevel@tonic-gate 	 * doing the search
19167c478bd9Sstevel@tonic-gate 	 */
19177c478bd9Sstevel@tonic-gate 	if ((ks_fd = open_and_lock_keystore_desc(O_RDONLY, B_TRUE,
19187c478bd9Sstevel@tonic-gate 	    B_FALSE)) < 0) {
19197c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
19207c478bd9Sstevel@tonic-gate 	}
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 	if ((search_type == ALL_TOKENOBJS) || (search_type == PUB_TOKENOBJS)) {
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate 		char pub_obj_path[MAXPATHLEN];
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 		ks_handle.public = B_TRUE;
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate 		if ((dirp = opendir(get_pub_obj_path(pub_obj_path))) == NULL) {
19297c478bd9Sstevel@tonic-gate 			(void) lock_file(ks_fd, B_TRUE, B_FALSE);
19307c478bd9Sstevel@tonic-gate 			(void) close(ks_fd);
19317c478bd9Sstevel@tonic-gate 			return (CKR_FUNCTION_FAILED);
19327c478bd9Sstevel@tonic-gate 		}
19337c478bd9Sstevel@tonic-gate 		rv = get_all_objs_in_dir(dirp, &ks_handle, result_obj_list,
19344bc0a2efScasper 		    lock_held);
19357c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
19367c478bd9Sstevel@tonic-gate 			(void) closedir(dirp);
19377c478bd9Sstevel@tonic-gate 			goto cleanup;
19387c478bd9Sstevel@tonic-gate 		}
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 		(void) closedir(dirp);
19417c478bd9Sstevel@tonic-gate 	}
19427c478bd9Sstevel@tonic-gate 
19437c478bd9Sstevel@tonic-gate 	if ((search_type == ALL_TOKENOBJS) || (search_type == PRI_TOKENOBJS)) {
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 		char pri_obj_path[MAXPATHLEN];
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 		if ((enc_key == NULL) ||
19487c478bd9Sstevel@tonic-gate 		    (enc_key->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
19497c478bd9Sstevel@tonic-gate 			/* has not login - no need to go any further */
19507c478bd9Sstevel@tonic-gate 			(void) lock_file(ks_fd, B_TRUE, B_FALSE);
19517c478bd9Sstevel@tonic-gate 			(void) close(ks_fd);
19527c478bd9Sstevel@tonic-gate 			return (CKR_OK);
19537c478bd9Sstevel@tonic-gate 		}
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 		ks_handle.public = B_FALSE;
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 		if ((dirp = opendir(get_pri_obj_path(pri_obj_path))) == NULL) {
19587c478bd9Sstevel@tonic-gate 			(void) lock_file(ks_fd, B_TRUE, B_FALSE);
19597c478bd9Sstevel@tonic-gate 			(void) close(ks_fd);
19607c478bd9Sstevel@tonic-gate 			return (CKR_OK);
19617c478bd9Sstevel@tonic-gate 		}
19627c478bd9Sstevel@tonic-gate 		rv = get_all_objs_in_dir(dirp, &ks_handle, result_obj_list,
19634bc0a2efScasper 		    lock_held);
19647c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
19657c478bd9Sstevel@tonic-gate 			(void) closedir(dirp);
19667c478bd9Sstevel@tonic-gate 			goto cleanup;
19677c478bd9Sstevel@tonic-gate 		}
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate 		(void) closedir(dirp);
19707c478bd9Sstevel@tonic-gate 	}
19717c478bd9Sstevel@tonic-gate 	/* close the keystore description file */
19727c478bd9Sstevel@tonic-gate 	(void) lock_file(ks_fd, B_TRUE, B_FALSE);
19737c478bd9Sstevel@tonic-gate 	(void) close(ks_fd);
19747c478bd9Sstevel@tonic-gate 	return (CKR_OK);
19757c478bd9Sstevel@tonic-gate cleanup:
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate 	/* close the keystore description file */
19787c478bd9Sstevel@tonic-gate 	(void) lock_file(ks_fd, B_TRUE, B_FALSE);
19797c478bd9Sstevel@tonic-gate 	(void) close(ks_fd);
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate 	/* free all the objects found before hitting the error */
19827c478bd9Sstevel@tonic-gate 	tmp = *result_obj_list;
19837c478bd9Sstevel@tonic-gate 	while (tmp) {
19847c478bd9Sstevel@tonic-gate 		*result_obj_list = tmp->next;
19857c478bd9Sstevel@tonic-gate 		free(tmp->buf);
19867c478bd9Sstevel@tonic-gate 		free(tmp);
19877c478bd9Sstevel@tonic-gate 		tmp = *result_obj_list;
19887c478bd9Sstevel@tonic-gate 	}
19897c478bd9Sstevel@tonic-gate 	*result_obj_list = NULL;
19907c478bd9Sstevel@tonic-gate 	return (rv);
19917c478bd9Sstevel@tonic-gate }
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate /*
19957c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_get_single_obj
19967c478bd9Sstevel@tonic-gate  *
19977c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
19987c478bd9Sstevel@tonic-gate  *		ks_handle: handle of the key store object to be accessed
19997c478bd9Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
20007c478bd9Sstevel@tonic-gate  *
20017c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
20027c478bd9Sstevel@tonic-gate  *
20037c478bd9Sstevel@tonic-gate  *		NULL: if handle doesn't match any object
20047c478bd9Sstevel@tonic-gate  *
20057c478bd9Sstevel@tonic-gate  *		Otherwise, the object is returned in
20067c478bd9Sstevel@tonic-gate  *		the same structure used in soft_keystore_get_objs().
20077c478bd9Sstevel@tonic-gate  *		The structure need to be freed by the caller.
20087c478bd9Sstevel@tonic-gate  *
20097c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
20107c478bd9Sstevel@tonic-gate  *
20117c478bd9Sstevel@tonic-gate  *		Retrieves the object specified by the object
20127c478bd9Sstevel@tonic-gate  *		handle to the caller.
20137c478bd9Sstevel@tonic-gate  *
20147c478bd9Sstevel@tonic-gate  *		If a private object is requested, and the caller
20157c478bd9Sstevel@tonic-gate  *		has not previously passed in the pin or if the pin
20167c478bd9Sstevel@tonic-gate  *		passed in is wrong, the requested private object will not
20177c478bd9Sstevel@tonic-gate  *		be returned.
20187c478bd9Sstevel@tonic-gate  *
20197c478bd9Sstevel@tonic-gate  *		The buffer returned for the requested private object
20207c478bd9Sstevel@tonic-gate  *		is already decrypted.
20217c478bd9Sstevel@tonic-gate  */
20227c478bd9Sstevel@tonic-gate CK_RV
20237c478bd9Sstevel@tonic-gate soft_keystore_get_single_obj(ks_obj_handle_t *ks_handle,
20247c478bd9Sstevel@tonic-gate     ks_obj_t **return_obj, boolean_t lock_held)
20257c478bd9Sstevel@tonic-gate {
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 	ks_obj_t *obj;
20287c478bd9Sstevel@tonic-gate 	uchar_t iv[OBJ_IV_SIZE], obj_hmac[OBJ_HMAC_SIZE];
20297c478bd9Sstevel@tonic-gate 	uchar_t *buf, *decrypted_buf;
20307c478bd9Sstevel@tonic-gate 	int fd;
20317c478bd9Sstevel@tonic-gate 	ssize_t nread;
20327c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_FUNCTION_FAILED;
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate 	if (!(ks_handle->public)) {
20357c478bd9Sstevel@tonic-gate 		if ((enc_key == NULL) ||
20367c478bd9Sstevel@tonic-gate 		    (enc_key->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
20377c478bd9Sstevel@tonic-gate 			return (CKR_FUNCTION_FAILED);
20387c478bd9Sstevel@tonic-gate 		}
20397c478bd9Sstevel@tonic-gate 	}
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_object_file(ks_handle, O_RDONLY,
20427c478bd9Sstevel@tonic-gate 	    lock_held)) < 0) {
20437c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
20447c478bd9Sstevel@tonic-gate 	}
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate 	obj = malloc(sizeof (ks_obj_t));
20477c478bd9Sstevel@tonic-gate 	if (obj == NULL) {
20487c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
20497c478bd9Sstevel@tonic-gate 	}
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 	obj->next = NULL;
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 	(void) strcpy((char *)((obj->ks_handle).name),
20547c478bd9Sstevel@tonic-gate 	    (char *)ks_handle->name);
20557c478bd9Sstevel@tonic-gate 	(obj->ks_handle).public = ks_handle->public;
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 	/* 1st get the version */
2058*19193bb6SDina K Nimeh 	if (readn_nointr(fd, &(obj->obj_version), OBJ_VER_SIZE)
20597c478bd9Sstevel@tonic-gate 	    != OBJ_VER_SIZE) {
20607c478bd9Sstevel@tonic-gate 		goto cleanup;
20617c478bd9Sstevel@tonic-gate 	}
20627c478bd9Sstevel@tonic-gate 	obj->obj_version = SWAP32(obj->obj_version);
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	/* Then, read the IV */
2065*19193bb6SDina K Nimeh 	if (readn_nointr(fd, iv, OBJ_IV_SIZE) != OBJ_IV_SIZE) {
20667c478bd9Sstevel@tonic-gate 		goto cleanup;
20677c478bd9Sstevel@tonic-gate 	}
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	/* Then, read the HMAC */
2070*19193bb6SDina K Nimeh 	if (readn_nointr(fd, obj_hmac, OBJ_HMAC_SIZE) != OBJ_HMAC_SIZE) {
20717c478bd9Sstevel@tonic-gate 		goto cleanup;
20727c478bd9Sstevel@tonic-gate 	}
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 	/* read the object */
20757c478bd9Sstevel@tonic-gate 	rv = read_obj_data(fd, (char **)&buf, &nread);
20767c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
20777c478bd9Sstevel@tonic-gate 		goto cleanup;
20787c478bd9Sstevel@tonic-gate 	}
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 	if (ks_handle->public) {
20817c478bd9Sstevel@tonic-gate 		obj->size = nread;
20827c478bd9Sstevel@tonic-gate 		obj->buf = buf;
20837c478bd9Sstevel@tonic-gate 		*return_obj = obj;
20847c478bd9Sstevel@tonic-gate 	} else {
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 		CK_ULONG out_len = 0, hmac_size;
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate 		/* verify HMAC of the object, make sure it matches */
20897c478bd9Sstevel@tonic-gate 		hmac_size = OBJ_HMAC_SIZE;
20907c478bd9Sstevel@tonic-gate 		if (soft_keystore_hmac(hmac_key, B_FALSE, buf,
20917c478bd9Sstevel@tonic-gate 		    nread, obj_hmac, &hmac_size) != CKR_OK) {
20927c478bd9Sstevel@tonic-gate 			free(buf);
20937c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
20947c478bd9Sstevel@tonic-gate 			goto cleanup;
20957c478bd9Sstevel@tonic-gate 		}
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate 		/* decrypt object */
20987c478bd9Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv, B_FALSE, buf, nread,
20997c478bd9Sstevel@tonic-gate 		    NULL, &out_len) != CKR_OK) {
21007c478bd9Sstevel@tonic-gate 			free(buf);
21017c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
21027c478bd9Sstevel@tonic-gate 			goto cleanup;
21037c478bd9Sstevel@tonic-gate 		}
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate 		decrypted_buf = malloc(sizeof (uchar_t) * out_len);
21067c478bd9Sstevel@tonic-gate 		if (decrypted_buf == NULL) {
21077c478bd9Sstevel@tonic-gate 			free(buf);
21087c478bd9Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
21097c478bd9Sstevel@tonic-gate 			goto cleanup;
21107c478bd9Sstevel@tonic-gate 		}
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv, B_FALSE, buf, nread,
21137c478bd9Sstevel@tonic-gate 		    decrypted_buf, &out_len) != CKR_OK) {
21147c478bd9Sstevel@tonic-gate 			free(decrypted_buf);
21157c478bd9Sstevel@tonic-gate 			free(buf);
21167c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
21177c478bd9Sstevel@tonic-gate 			goto cleanup;
21187c478bd9Sstevel@tonic-gate 		}
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 		obj->size = out_len - MAXPATHLEN;
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate 		/*
21237c478bd9Sstevel@tonic-gate 		 * decrypted buf here actually contains full path name of
21247c478bd9Sstevel@tonic-gate 		 * object plus the actual data.  so, need to skip the
21257c478bd9Sstevel@tonic-gate 		 * full pathname.
21267c478bd9Sstevel@tonic-gate 		 * See prepare_data_for_encrypt() function in the file
21277c478bd9Sstevel@tonic-gate 		 * to understand how and why the pathname is added.
21287c478bd9Sstevel@tonic-gate 		 */
21297c478bd9Sstevel@tonic-gate 		obj->buf = malloc(sizeof (uchar_t) * (out_len - MAXPATHLEN));
21307c478bd9Sstevel@tonic-gate 		if (obj->buf == NULL) {
21317c478bd9Sstevel@tonic-gate 			free(decrypted_buf);
21327c478bd9Sstevel@tonic-gate 			free(buf);
21337c478bd9Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
21347c478bd9Sstevel@tonic-gate 			goto cleanup;
21357c478bd9Sstevel@tonic-gate 		}
21367c478bd9Sstevel@tonic-gate 		(void) memcpy(obj->buf, decrypted_buf + MAXPATHLEN, obj->size);
21377c478bd9Sstevel@tonic-gate 		free(decrypted_buf);
21387c478bd9Sstevel@tonic-gate 		free(buf);
21397c478bd9Sstevel@tonic-gate 		*return_obj = obj;
21407c478bd9Sstevel@tonic-gate 	}
21417c478bd9Sstevel@tonic-gate 
21427c478bd9Sstevel@tonic-gate cleanup:
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
21457c478bd9Sstevel@tonic-gate 		free(obj);
21467c478bd9Sstevel@tonic-gate 	}
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate 	/* unlock the file after reading */
21497c478bd9Sstevel@tonic-gate 	if (!lock_held) {
21507c478bd9Sstevel@tonic-gate 		(void) lock_file(fd, B_TRUE, B_FALSE);
21517c478bd9Sstevel@tonic-gate 	}
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 	(void) close(fd);
21547c478bd9Sstevel@tonic-gate 
21557c478bd9Sstevel@tonic-gate 	return (rv);
21567c478bd9Sstevel@tonic-gate }
21577c478bd9Sstevel@tonic-gate 
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate /*
21607c478bd9Sstevel@tonic-gate  * 	FUNCTION: soft_keystore_put_new_obj
21617c478bd9Sstevel@tonic-gate  *
21627c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
21637c478bd9Sstevel@tonic-gate  *		buf: buffer containing un-encrypted data
21647c478bd9Sstevel@tonic-gate  *		     to be stored in keystore.
21657c478bd9Sstevel@tonic-gate  *		len: length of data
21667c478bd9Sstevel@tonic-gate  *		public:  TRUE if it is a public object,
21677c478bd9Sstevel@tonic-gate  *			 FALSE if it is private obj
21687c478bd9Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
21697c478bd9Sstevel@tonic-gate  *		keyhandle: pointer to object handle to
21707c478bd9Sstevel@tonic-gate  *			   receive keyhandle for new object
21717c478bd9Sstevel@tonic-gate  *
21727c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
21737c478bd9Sstevel@tonic-gate  *		0: object successfully stored in file
21747c478bd9Sstevel@tonic-gate  *		-1: some error occurred, object is not stored in file.
21757c478bd9Sstevel@tonic-gate  *
21767c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
21777c478bd9Sstevel@tonic-gate  *		This API is used to write a newly created token object
21787c478bd9Sstevel@tonic-gate  *		to keystore.
21797c478bd9Sstevel@tonic-gate  *
21807c478bd9Sstevel@tonic-gate  *		This function does the following:
21817c478bd9Sstevel@tonic-gate  *
21827c478bd9Sstevel@tonic-gate  *		1) Creates a token object file based on "public" parameter.
21837c478bd9Sstevel@tonic-gate  *		2) Generates a new IV and stores it in obj_meta_data_t if it is
21847c478bd9Sstevel@tonic-gate  *		   private object.
21857c478bd9Sstevel@tonic-gate  *		3) Set object version number to 1.
21867c478bd9Sstevel@tonic-gate  *		4) If it is a private object, it will be encrypted before
21877c478bd9Sstevel@tonic-gate  *		   being written to the newly created keystore token object
21887c478bd9Sstevel@tonic-gate  *		   file.
21897c478bd9Sstevel@tonic-gate  *		5) Calculates the obj_chksum in obj_meta_data_t.
21907c478bd9Sstevel@tonic-gate  *		6) Calculates the pin_chksum in obj_meta_data_t.
21917c478bd9Sstevel@tonic-gate  *		7) Increments the keystore version number.
21927c478bd9Sstevel@tonic-gate  */
21937c478bd9Sstevel@tonic-gate int
21947c478bd9Sstevel@tonic-gate soft_keystore_put_new_obj(uchar_t *buf, size_t len, boolean_t public,
21957c478bd9Sstevel@tonic-gate     boolean_t lock_held, ks_obj_handle_t *keyhandle)
21967c478bd9Sstevel@tonic-gate {
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate 	int fd, tmp_ks_fd, obj_fd;
21997c478bd9Sstevel@tonic-gate 	unsigned int counter, version;
22007c478bd9Sstevel@tonic-gate 	uchar_t obj_hmac[OBJ_HMAC_SIZE];
22017c478bd9Sstevel@tonic-gate 	CK_BYTE iv[OBJ_IV_SIZE];
22027c478bd9Sstevel@tonic-gate 	char obj_name[MAXPATHLEN], tmp_ks_desc_name[MAXPATHLEN];
22037c478bd9Sstevel@tonic-gate 	char filebuf[BUFSIZ];
22047c478bd9Sstevel@tonic-gate 	char pub_obj_path[MAXPATHLEN], pri_obj_path[MAXPATHLEN],
22057c478bd9Sstevel@tonic-gate 	    ks_desc_file[MAXPATHLEN];
22067c478bd9Sstevel@tonic-gate 	CK_ULONG hmac_size;
22077c478bd9Sstevel@tonic-gate 	ssize_t nread;
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	if (keyhandle == NULL) {
22107c478bd9Sstevel@tonic-gate 		return (-1);
22117c478bd9Sstevel@tonic-gate 	}
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 	/* if it is private object, make sure we have the key */
22147c478bd9Sstevel@tonic-gate 	if (!public) {
22157c478bd9Sstevel@tonic-gate 		if ((enc_key == NULL) ||
22167c478bd9Sstevel@tonic-gate 		    (enc_key->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
22177c478bd9Sstevel@tonic-gate 			return (-1);
22187c478bd9Sstevel@tonic-gate 		}
22197c478bd9Sstevel@tonic-gate 	}
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 	/* open keystore, and set write lock */
22227c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDWR, B_TRUE,
22237c478bd9Sstevel@tonic-gate 	    lock_held)) < 0) {
22247c478bd9Sstevel@tonic-gate 		return (-1);
22257c478bd9Sstevel@tonic-gate 	}
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate 	(void) get_desc_file_path(ks_desc_file);
22287c478bd9Sstevel@tonic-gate 	(void) get_tmp_desc_file_path(tmp_ks_desc_name);
22297c478bd9Sstevel@tonic-gate 
22307c478bd9Sstevel@tonic-gate 	/*
22317c478bd9Sstevel@tonic-gate 	 * create a tempoary file for the keystore description
22327c478bd9Sstevel@tonic-gate 	 * file for updating version and counter information
22337c478bd9Sstevel@tonic-gate 	 */
2234*19193bb6SDina K Nimeh 	tmp_ks_fd = open_nointr(tmp_ks_desc_name,
2235*19193bb6SDina K Nimeh 	    O_RDWR|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
22367c478bd9Sstevel@tonic-gate 	if (tmp_ks_fd < 0) {
22377c478bd9Sstevel@tonic-gate 		(void) close(fd);
22387c478bd9Sstevel@tonic-gate 		return (-1);
22397c478bd9Sstevel@tonic-gate 	}
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate 	/* read and write pkcs11 version */
2242*19193bb6SDina K Nimeh 	if (readn_nointr(fd, filebuf, KS_PKCS11_VER_SIZE)
22437c478bd9Sstevel@tonic-gate 	    != KS_PKCS11_VER_SIZE) {
22447c478bd9Sstevel@tonic-gate 		goto cleanup;
22457c478bd9Sstevel@tonic-gate 	}
22467c478bd9Sstevel@tonic-gate 
2247*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_ks_fd, filebuf, KS_PKCS11_VER_SIZE)
22487c478bd9Sstevel@tonic-gate 	    != KS_PKCS11_VER_SIZE) {
22497c478bd9Sstevel@tonic-gate 		goto cleanup;
22507c478bd9Sstevel@tonic-gate 	}
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 	/* get version number, and write updated number to temp file */
2253*19193bb6SDina K Nimeh 	if (readn_nointr(fd, &version, KS_VER_SIZE) != KS_VER_SIZE) {
22547c478bd9Sstevel@tonic-gate 		goto cleanup;
22557c478bd9Sstevel@tonic-gate 	}
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
22587c478bd9Sstevel@tonic-gate 	version++;
22597c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
22607c478bd9Sstevel@tonic-gate 
2261*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_ks_fd, (void *)&version,
22627c478bd9Sstevel@tonic-gate 	    KS_VER_SIZE) != KS_VER_SIZE) {
22637c478bd9Sstevel@tonic-gate 		goto cleanup;
22647c478bd9Sstevel@tonic-gate 	}
22657c478bd9Sstevel@tonic-gate 
22667c478bd9Sstevel@tonic-gate 	/* get object count value */
2267*19193bb6SDina K Nimeh 	if (readn_nointr(fd, &counter, KS_COUNTER_SIZE) != KS_COUNTER_SIZE) {
22687c478bd9Sstevel@tonic-gate 		goto cleanup;
22697c478bd9Sstevel@tonic-gate 	}
22707c478bd9Sstevel@tonic-gate 	counter = SWAP32(counter);
22717c478bd9Sstevel@tonic-gate 
22727c478bd9Sstevel@tonic-gate 	bzero(obj_name, sizeof (obj_name));
22737c478bd9Sstevel@tonic-gate 	if (public) {
22747c478bd9Sstevel@tonic-gate 		(void) snprintf(obj_name, MAXPATHLEN,  "%s/%s%d",
22757c478bd9Sstevel@tonic-gate 		    get_pub_obj_path(pub_obj_path), OBJ_PREFIX, counter);
22767c478bd9Sstevel@tonic-gate 	} else {
22777c478bd9Sstevel@tonic-gate 		(void) snprintf(obj_name, MAXPATHLEN,  "%s/%s%d",
22787c478bd9Sstevel@tonic-gate 		    get_pri_obj_path(pri_obj_path), OBJ_PREFIX, counter);
22797c478bd9Sstevel@tonic-gate 	}
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate 	/* create object file */
2282*19193bb6SDina K Nimeh 	obj_fd = open_nointr(obj_name,
2283*19193bb6SDina K Nimeh 	    O_WRONLY|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
22847c478bd9Sstevel@tonic-gate 	if (obj_fd < 0) {
22857c478bd9Sstevel@tonic-gate 		/* can't create object file */
22867c478bd9Sstevel@tonic-gate 		goto cleanup;
22877c478bd9Sstevel@tonic-gate 	}
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 	/* lock object file for writing */
22907c478bd9Sstevel@tonic-gate 	if (lock_file(obj_fd, B_FALSE, B_TRUE) != 0) {
22917c478bd9Sstevel@tonic-gate 		(void) close(obj_fd);
22927c478bd9Sstevel@tonic-gate 		goto cleanup2;
22937c478bd9Sstevel@tonic-gate 	}
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate 	/* write object meta data */
22967c478bd9Sstevel@tonic-gate 	version = SWAP32(1);
2297*19193bb6SDina K Nimeh 	if (writen_nointr(obj_fd, (void *)&version, sizeof (version))
22987c478bd9Sstevel@tonic-gate 	    != sizeof (version)) {
22997c478bd9Sstevel@tonic-gate 		goto cleanup2;
23007c478bd9Sstevel@tonic-gate 	}
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	if (public) {
23037c478bd9Sstevel@tonic-gate 		bzero(iv, sizeof (iv));
23047c478bd9Sstevel@tonic-gate 	} else {
23057c478bd9Sstevel@tonic-gate 		/* generate an IV */
23067c478bd9Sstevel@tonic-gate 		if (soft_gen_iv(iv) != CKR_OK) {
23077c478bd9Sstevel@tonic-gate 			goto cleanup2;
23087c478bd9Sstevel@tonic-gate 		}
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate 	}
23117c478bd9Sstevel@tonic-gate 
2312*19193bb6SDina K Nimeh 	if (writen_nointr(obj_fd, (void *)iv, sizeof (iv)) != sizeof (iv)) {
23137c478bd9Sstevel@tonic-gate 		goto cleanup2;
23147c478bd9Sstevel@tonic-gate 	}
23157c478bd9Sstevel@tonic-gate 
23167c478bd9Sstevel@tonic-gate 	if (public) {
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 		bzero(obj_hmac, sizeof (obj_hmac));
2319*19193bb6SDina K Nimeh 		if (writen_nointr(obj_fd, (void *)obj_hmac,
23207c478bd9Sstevel@tonic-gate 		    sizeof (obj_hmac)) != sizeof (obj_hmac)) {
23217c478bd9Sstevel@tonic-gate 			goto cleanup2;
23227c478bd9Sstevel@tonic-gate 		}
23237c478bd9Sstevel@tonic-gate 
2324*19193bb6SDina K Nimeh 		if (writen_nointr(obj_fd, (char *)buf, len) != len) {
23257c478bd9Sstevel@tonic-gate 			goto cleanup2;
23267c478bd9Sstevel@tonic-gate 		}
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate 	} else {
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate 		uchar_t *encrypted_buf, *prepared_buf;
23317c478bd9Sstevel@tonic-gate 		CK_ULONG out_len = 0, prepared_len;
23327c478bd9Sstevel@tonic-gate 
23337c478bd9Sstevel@tonic-gate 		if (prepare_data_for_encrypt(obj_name, buf, len,
23347c478bd9Sstevel@tonic-gate 		    &prepared_buf, &prepared_len) != 0) {
23357c478bd9Sstevel@tonic-gate 			goto cleanup2;
23367c478bd9Sstevel@tonic-gate 		}
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv,
23397c478bd9Sstevel@tonic-gate 		    B_TRUE, prepared_buf, prepared_len,
23407c478bd9Sstevel@tonic-gate 		    NULL, &out_len) != CKR_OK) {
23417c478bd9Sstevel@tonic-gate 			free(prepared_buf);
23427c478bd9Sstevel@tonic-gate 			goto cleanup2;
23437c478bd9Sstevel@tonic-gate 		}
23447c478bd9Sstevel@tonic-gate 
23457c478bd9Sstevel@tonic-gate 		encrypted_buf = malloc(out_len * sizeof (char));
23467c478bd9Sstevel@tonic-gate 		if (encrypted_buf == NULL) {
23477c478bd9Sstevel@tonic-gate 			free(prepared_buf);
23487c478bd9Sstevel@tonic-gate 			goto cleanup2;
23497c478bd9Sstevel@tonic-gate 		}
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv,
23527c478bd9Sstevel@tonic-gate 		    B_TRUE, prepared_buf, prepared_len,
23537c478bd9Sstevel@tonic-gate 		    encrypted_buf, &out_len) != CKR_OK) {
23547c478bd9Sstevel@tonic-gate 			free(encrypted_buf);
23557c478bd9Sstevel@tonic-gate 			free(prepared_buf);
23567c478bd9Sstevel@tonic-gate 			goto cleanup2;
23577c478bd9Sstevel@tonic-gate 		}
23587c478bd9Sstevel@tonic-gate 		free(prepared_buf);
23597c478bd9Sstevel@tonic-gate 
23607c478bd9Sstevel@tonic-gate 		/* calculate HMAC of encrypted object */
23617c478bd9Sstevel@tonic-gate 		hmac_size = OBJ_HMAC_SIZE;
23627c478bd9Sstevel@tonic-gate 		if (soft_keystore_hmac(hmac_key, B_TRUE, encrypted_buf,
23637c478bd9Sstevel@tonic-gate 		    out_len, obj_hmac, &hmac_size) != CKR_OK) {
23647c478bd9Sstevel@tonic-gate 			free(encrypted_buf);
23657c478bd9Sstevel@tonic-gate 			goto cleanup2;
23667c478bd9Sstevel@tonic-gate 		}
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate 		if (hmac_size != OBJ_HMAC_SIZE) {
23697c478bd9Sstevel@tonic-gate 			free(encrypted_buf);
23707c478bd9Sstevel@tonic-gate 			goto cleanup2;
23717c478bd9Sstevel@tonic-gate 		}
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate 		/* write hmac */
2374*19193bb6SDina K Nimeh 		if (writen_nointr(obj_fd, (void *)obj_hmac,
23757c478bd9Sstevel@tonic-gate 		    sizeof (obj_hmac)) != sizeof (obj_hmac)) {
23767c478bd9Sstevel@tonic-gate 			free(encrypted_buf);
23777c478bd9Sstevel@tonic-gate 			goto cleanup2;
23787c478bd9Sstevel@tonic-gate 		}
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate 		/* write encrypted object */
2381*19193bb6SDina K Nimeh 		if (writen_nointr(obj_fd, (void *)encrypted_buf, out_len)
23827c478bd9Sstevel@tonic-gate 		    != out_len) {
23837c478bd9Sstevel@tonic-gate 			free(encrypted_buf);
23847c478bd9Sstevel@tonic-gate 			goto cleanup2;
23857c478bd9Sstevel@tonic-gate 		}
23867c478bd9Sstevel@tonic-gate 
23877c478bd9Sstevel@tonic-gate 		free(encrypted_buf);
23887c478bd9Sstevel@tonic-gate 	}
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 	(void) close(obj_fd);
23927c478bd9Sstevel@tonic-gate 	(void) snprintf((char *)keyhandle->name, sizeof (keyhandle->name),
23937c478bd9Sstevel@tonic-gate 	    "obj%d", counter);
23947c478bd9Sstevel@tonic-gate 	keyhandle->public = public;
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate 	/*
23977c478bd9Sstevel@tonic-gate 	 * store new counter to temp keystore description file.
23987c478bd9Sstevel@tonic-gate 	 */
23997c478bd9Sstevel@tonic-gate 	counter++;
24007c478bd9Sstevel@tonic-gate 	counter = SWAP32(counter);
2401*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_ks_fd, (void *)&counter,
24027c478bd9Sstevel@tonic-gate 	    sizeof (counter)) != sizeof (counter)) {
24037c478bd9Sstevel@tonic-gate 		goto cleanup2;
24047c478bd9Sstevel@tonic-gate 	}
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	/* read rest of keystore description file and store into temp file */
2407*19193bb6SDina K Nimeh 	nread = readn_nointr(fd, filebuf, sizeof (filebuf));
24087c478bd9Sstevel@tonic-gate 	while (nread > 0) {
2409*19193bb6SDina K Nimeh 		if (writen_nointr(tmp_ks_fd, filebuf, nread) != nread) {
24107c478bd9Sstevel@tonic-gate 			goto cleanup2;
24117c478bd9Sstevel@tonic-gate 		}
2412*19193bb6SDina K Nimeh 		nread = readn_nointr(fd, filebuf, sizeof (filebuf));
24137c478bd9Sstevel@tonic-gate 	}
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate 	(void) close(tmp_ks_fd);
24167c478bd9Sstevel@tonic-gate 	(void) rename(tmp_ks_desc_name, ks_desc_file);
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 	if (!lock_held) {
24197c478bd9Sstevel@tonic-gate 		/* release lock on description file */
24207c478bd9Sstevel@tonic-gate 		if (lock_file(fd, B_FALSE, B_FALSE) != 0) {
24217c478bd9Sstevel@tonic-gate 			(void) close(fd);
24227c478bd9Sstevel@tonic-gate 			return (-1);
24237c478bd9Sstevel@tonic-gate 		}
24247c478bd9Sstevel@tonic-gate 	}
24257c478bd9Sstevel@tonic-gate 	(void) close(fd);
24267c478bd9Sstevel@tonic-gate 	return (0);
24277c478bd9Sstevel@tonic-gate 
24287c478bd9Sstevel@tonic-gate cleanup2:
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate 	/* remove object file.  No need to remove lock first */
24317c478bd9Sstevel@tonic-gate 	(void) unlink(obj_name);
24327c478bd9Sstevel@tonic-gate 
24337c478bd9Sstevel@tonic-gate cleanup:
24347c478bd9Sstevel@tonic-gate 
24357c478bd9Sstevel@tonic-gate 	(void) close(tmp_ks_fd);
24367c478bd9Sstevel@tonic-gate 	(void) remove(tmp_ks_desc_name);
24377c478bd9Sstevel@tonic-gate 	if (!lock_held) {
24387c478bd9Sstevel@tonic-gate 		/* release lock on description file */
24397c478bd9Sstevel@tonic-gate 		(void) lock_file(fd, B_FALSE, B_FALSE);
24407c478bd9Sstevel@tonic-gate 	}
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate 	(void) close(fd);
24437c478bd9Sstevel@tonic-gate 	return (-1);
24447c478bd9Sstevel@tonic-gate }
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate /*
24477c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_modify_obj
24487c478bd9Sstevel@tonic-gate  *
24497c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
24507c478bd9Sstevel@tonic-gate  *		ks_handle: handle of the key store object to be modified
24517c478bd9Sstevel@tonic-gate  *		buf: buffer containing un-encrypted data
24527c478bd9Sstevel@tonic-gate  *		     to be modified in keystore.
24537c478bd9Sstevel@tonic-gate  *		len: length of data
24547c478bd9Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
24557c478bd9Sstevel@tonic-gate  *
24567c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
24577c478bd9Sstevel@tonic-gate  *		-1: if any error occurred.
24587c478bd9Sstevel@tonic-gate  *		Otherwise, 0 is returned.
24597c478bd9Sstevel@tonic-gate  *
24607c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
24617c478bd9Sstevel@tonic-gate  *
24627c478bd9Sstevel@tonic-gate  *		This API is used to write a modified token object back
24637c478bd9Sstevel@tonic-gate  *		to keystore.   This function will do the following:
24647c478bd9Sstevel@tonic-gate  *
24657c478bd9Sstevel@tonic-gate  *		1) If it is a private object, it will be encrypted before
24667c478bd9Sstevel@tonic-gate  *		   being written to the corresponding keystore token
24677c478bd9Sstevel@tonic-gate  *		   object file.
24687c478bd9Sstevel@tonic-gate  *		2) Record incremented object version number.
24697c478bd9Sstevel@tonic-gate  *		3) Record incremented keystore version number.
24707c478bd9Sstevel@tonic-gate  */
24717c478bd9Sstevel@tonic-gate int
24727c478bd9Sstevel@tonic-gate soft_keystore_modify_obj(ks_obj_handle_t *ks_handle, uchar_t *buf,
24737c478bd9Sstevel@tonic-gate     size_t len, boolean_t lock_held)
24747c478bd9Sstevel@tonic-gate {
24757c478bd9Sstevel@tonic-gate 	int fd, ks_fd, tmp_fd, version;
24767c478bd9Sstevel@tonic-gate 	char orig_name[MAXPATHLEN], tmp_name[MAXPATHLEN],
24777c478bd9Sstevel@tonic-gate 	    tmp_ks_name[MAXPATHLEN];
24787c478bd9Sstevel@tonic-gate 	uchar_t iv[OBJ_IV_SIZE], obj_hmac[OBJ_HMAC_SIZE];
24797c478bd9Sstevel@tonic-gate 	char pub_obj_path[MAXPATHLEN], pri_obj_path[MAXPATHLEN],
24807c478bd9Sstevel@tonic-gate 	    ks_desc_file[MAXPATHLEN];
24817c478bd9Sstevel@tonic-gate 	CK_ULONG hmac_size;
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate 	/* if it is private object, make sure we have the key */
24847c478bd9Sstevel@tonic-gate 	if (!(ks_handle->public)) {
24857c478bd9Sstevel@tonic-gate 		if ((enc_key == NULL) ||
24867c478bd9Sstevel@tonic-gate 		    (enc_key->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
24877c478bd9Sstevel@tonic-gate 			return (-1);
24887c478bd9Sstevel@tonic-gate 		}
24897c478bd9Sstevel@tonic-gate 	}
24907c478bd9Sstevel@tonic-gate 
24917c478bd9Sstevel@tonic-gate 	/* open and lock keystore description file */
24927c478bd9Sstevel@tonic-gate 	if ((ks_fd = open_and_lock_keystore_desc(O_RDWR, B_FALSE,
24937c478bd9Sstevel@tonic-gate 	    B_FALSE)) < 0) {
24947c478bd9Sstevel@tonic-gate 		return (-1);
24957c478bd9Sstevel@tonic-gate 	}
24967c478bd9Sstevel@tonic-gate 
24977c478bd9Sstevel@tonic-gate 	(void) get_desc_file_path(ks_desc_file);
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 	/* update the version of for keystore file in tempoary file */
25007c478bd9Sstevel@tonic-gate 	(void) get_tmp_desc_file_path(tmp_ks_name);
25017c478bd9Sstevel@tonic-gate 	if (create_updated_keystore_version(ks_fd, tmp_ks_name) != 0) {
25027c478bd9Sstevel@tonic-gate 		/* unlock keystore description file */
25037c478bd9Sstevel@tonic-gate 		(void) lock_file(ks_fd, B_FALSE, B_FALSE);
25047c478bd9Sstevel@tonic-gate 		(void) close(ks_fd);
25057c478bd9Sstevel@tonic-gate 		return (-1);
25067c478bd9Sstevel@tonic-gate 	}
25077c478bd9Sstevel@tonic-gate 
25087c478bd9Sstevel@tonic-gate 	/* open object file */
25097c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_object_file(ks_handle, O_RDWR,
25107c478bd9Sstevel@tonic-gate 	    lock_held)) < 0) {
25117c478bd9Sstevel@tonic-gate 		goto cleanup;
25127c478bd9Sstevel@tonic-gate 	}
25137c478bd9Sstevel@tonic-gate 
25147c478bd9Sstevel@tonic-gate 	/*
25157c478bd9Sstevel@tonic-gate 	 * make the change in a temporary file.  Create the temp
25167c478bd9Sstevel@tonic-gate 	 * file in the same directory as the token object.  That
25177c478bd9Sstevel@tonic-gate 	 * way, the "rename" later will be an atomic operation
25187c478bd9Sstevel@tonic-gate 	 */
25197c478bd9Sstevel@tonic-gate 	if (ks_handle->public) {
25207c478bd9Sstevel@tonic-gate 		(void) snprintf(orig_name, MAXPATHLEN, "%s/%s",
25217c478bd9Sstevel@tonic-gate 		    get_pub_obj_path(pub_obj_path), ks_handle->name);
25227c478bd9Sstevel@tonic-gate 		(void) snprintf(tmp_name, MAXPATHLEN, "%s/%s%s",
25237c478bd9Sstevel@tonic-gate 		    pub_obj_path, TMP_OBJ_PREFIX,
25247c478bd9Sstevel@tonic-gate 		    (ks_handle->name) + strlen(OBJ_PREFIX));
25257c478bd9Sstevel@tonic-gate 	} else {
25267c478bd9Sstevel@tonic-gate 		(void) snprintf(orig_name, MAXPATHLEN, "%s/%s",
25277c478bd9Sstevel@tonic-gate 		    get_pri_obj_path(pri_obj_path), ks_handle->name);
25287c478bd9Sstevel@tonic-gate 		(void) snprintf(tmp_name, MAXPATHLEN, "%s/%s%s",
25297c478bd9Sstevel@tonic-gate 		    pri_obj_path, TMP_OBJ_PREFIX,
25307c478bd9Sstevel@tonic-gate 		    (ks_handle->name) + strlen(OBJ_PREFIX));
25317c478bd9Sstevel@tonic-gate 	}
25327c478bd9Sstevel@tonic-gate 
2533*19193bb6SDina K Nimeh 	tmp_fd = open_nointr(tmp_name,
2534*19193bb6SDina K Nimeh 	    O_WRONLY|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
25357c478bd9Sstevel@tonic-gate 	if (tmp_fd < 0) {
25367c478bd9Sstevel@tonic-gate 		/* can't create tmp object file */
25377c478bd9Sstevel@tonic-gate 		goto cleanup1;
25387c478bd9Sstevel@tonic-gate 	}
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 	/* read version, increment, and write to tmp file */
2541*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)&version, OBJ_VER_SIZE) != OBJ_VER_SIZE) {
25427c478bd9Sstevel@tonic-gate 		goto cleanup2;
25437c478bd9Sstevel@tonic-gate 	}
25447c478bd9Sstevel@tonic-gate 
25457c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
25467c478bd9Sstevel@tonic-gate 	version++;
25477c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
25487c478bd9Sstevel@tonic-gate 
2549*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_fd, (char *)&version, OBJ_VER_SIZE)
25507c478bd9Sstevel@tonic-gate 	    != OBJ_VER_SIZE) {
25517c478bd9Sstevel@tonic-gate 		goto cleanup2;
25527c478bd9Sstevel@tonic-gate 	}
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 	/* generate a new IV for the object, old one can be ignored */
25557c478bd9Sstevel@tonic-gate 	if (soft_gen_iv(iv) != CKR_OK) {
25567c478bd9Sstevel@tonic-gate 		goto cleanup2;
25577c478bd9Sstevel@tonic-gate 	}
25587c478bd9Sstevel@tonic-gate 
2559*19193bb6SDina K Nimeh 	if (writen_nointr(tmp_fd, (char *)iv, OBJ_IV_SIZE) != OBJ_IV_SIZE) {
25607c478bd9Sstevel@tonic-gate 		goto cleanup2;
25617c478bd9Sstevel@tonic-gate 	}
25627c478bd9Sstevel@tonic-gate 
25637c478bd9Sstevel@tonic-gate 	if (ks_handle->public) {
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate 		/* hmac is always NULL for public objects */
25667c478bd9Sstevel@tonic-gate 		bzero(obj_hmac, sizeof (obj_hmac));
2567*19193bb6SDina K Nimeh 		if (writen_nointr(tmp_fd, (char *)obj_hmac, OBJ_HMAC_SIZE)
25687c478bd9Sstevel@tonic-gate 		    != OBJ_HMAC_SIZE) {
25697c478bd9Sstevel@tonic-gate 			goto cleanup2;
25707c478bd9Sstevel@tonic-gate 		}
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate 		/* write updated object */
2573*19193bb6SDina K Nimeh 		if (writen_nointr(tmp_fd, (char *)buf, len) != len) {
25747c478bd9Sstevel@tonic-gate 			goto cleanup2;
25757c478bd9Sstevel@tonic-gate 		}
25767c478bd9Sstevel@tonic-gate 
25777c478bd9Sstevel@tonic-gate 	} else {
25787c478bd9Sstevel@tonic-gate 
25797c478bd9Sstevel@tonic-gate 		uchar_t *encrypted_buf, *prepared_buf;
25807c478bd9Sstevel@tonic-gate 		CK_ULONG out_len = 0, prepared_len;
25817c478bd9Sstevel@tonic-gate 
25827c478bd9Sstevel@tonic-gate 		if (prepare_data_for_encrypt(orig_name, buf, len,
25837c478bd9Sstevel@tonic-gate 		    &prepared_buf, &prepared_len) != 0) {
25847c478bd9Sstevel@tonic-gate 			goto cleanup2;
25857c478bd9Sstevel@tonic-gate 		}
25867c478bd9Sstevel@tonic-gate 
25877c478bd9Sstevel@tonic-gate 		/* encrypt the data */
25887c478bd9Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv, B_TRUE, prepared_buf,
25897c478bd9Sstevel@tonic-gate 		    prepared_len, NULL, &out_len) != CKR_OK) {
25907c478bd9Sstevel@tonic-gate 			free(prepared_buf);
25917c478bd9Sstevel@tonic-gate 			goto cleanup2;
25927c478bd9Sstevel@tonic-gate 		}
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 		encrypted_buf = malloc(out_len * sizeof (char));
25957c478bd9Sstevel@tonic-gate 		if (encrypted_buf == NULL) {
25967c478bd9Sstevel@tonic-gate 			free(prepared_buf);
25977c478bd9Sstevel@tonic-gate 			goto cleanup2;
25987c478bd9Sstevel@tonic-gate 		}
25997c478bd9Sstevel@tonic-gate 
26007c478bd9Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv, B_TRUE, prepared_buf,
26017c478bd9Sstevel@tonic-gate 		    prepared_len, encrypted_buf, &out_len) != CKR_OK) {
26027c478bd9Sstevel@tonic-gate 			free(encrypted_buf);
26037c478bd9Sstevel@tonic-gate 			free(prepared_buf);
26047c478bd9Sstevel@tonic-gate 			goto cleanup2;
26057c478bd9Sstevel@tonic-gate 		}
26067c478bd9Sstevel@tonic-gate 
26077c478bd9Sstevel@tonic-gate 		free(prepared_buf);
26087c478bd9Sstevel@tonic-gate 
26097c478bd9Sstevel@tonic-gate 		/* calculate hmac on encrypted buf */
26107c478bd9Sstevel@tonic-gate 		hmac_size = OBJ_HMAC_SIZE;
26117c478bd9Sstevel@tonic-gate 		if (soft_keystore_hmac(hmac_key, B_TRUE, encrypted_buf,
26127c478bd9Sstevel@tonic-gate 		    out_len, obj_hmac, &hmac_size) != CKR_OK) {
26137c478bd9Sstevel@tonic-gate 			free(encrypted_buf);
26147c478bd9Sstevel@tonic-gate 			goto cleanup2;
26157c478bd9Sstevel@tonic-gate 		}
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 		if (hmac_size != OBJ_HMAC_SIZE) {
26187c478bd9Sstevel@tonic-gate 			free(encrypted_buf);
26197c478bd9Sstevel@tonic-gate 			goto cleanup2;
26207c478bd9Sstevel@tonic-gate 		}
26217c478bd9Sstevel@tonic-gate 
2622*19193bb6SDina K Nimeh 		if (writen_nointr(tmp_fd, (char *)obj_hmac, OBJ_HMAC_SIZE)
26237c478bd9Sstevel@tonic-gate 		    != OBJ_HMAC_SIZE) {
26247c478bd9Sstevel@tonic-gate 			free(encrypted_buf);
26257c478bd9Sstevel@tonic-gate 			goto cleanup2;
26267c478bd9Sstevel@tonic-gate 		}
26277c478bd9Sstevel@tonic-gate 
2628*19193bb6SDina K Nimeh 		if (writen_nointr(tmp_fd, (void *)encrypted_buf, out_len)
26297c478bd9Sstevel@tonic-gate 		    != out_len) {
26307c478bd9Sstevel@tonic-gate 			free(encrypted_buf);
26317c478bd9Sstevel@tonic-gate 			goto cleanup2;
26327c478bd9Sstevel@tonic-gate 		}
26337c478bd9Sstevel@tonic-gate 		free(encrypted_buf);
26347c478bd9Sstevel@tonic-gate 	}
26357c478bd9Sstevel@tonic-gate 	(void) close(tmp_fd);
26367c478bd9Sstevel@tonic-gate 
26377c478bd9Sstevel@tonic-gate 	/* rename updated temporary object file */
26387c478bd9Sstevel@tonic-gate 	if (rename(tmp_name, orig_name) != 0) {
26397c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_name);
26407c478bd9Sstevel@tonic-gate 		return (-1);
26417c478bd9Sstevel@tonic-gate 	}
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate 	/* rename updated keystore description file */
26447c478bd9Sstevel@tonic-gate 	if (rename(tmp_ks_name, ks_desc_file) != 0) {
26457c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_name);
26467c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_ks_name);
26477c478bd9Sstevel@tonic-gate 		return (-1);
26487c478bd9Sstevel@tonic-gate 	}
26497c478bd9Sstevel@tonic-gate 
26507c478bd9Sstevel@tonic-gate 	/* determine need to unlock file or not */
26517c478bd9Sstevel@tonic-gate 	if (!lock_held) {
26527c478bd9Sstevel@tonic-gate 		if (lock_file(fd, B_FALSE, B_FALSE) < 0) {
26537c478bd9Sstevel@tonic-gate 			(void) close(fd);
26547c478bd9Sstevel@tonic-gate 			(void) unlink(tmp_name);
26557c478bd9Sstevel@tonic-gate 			return (-1);
26567c478bd9Sstevel@tonic-gate 		}
26577c478bd9Sstevel@tonic-gate 	}
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate 	/* unlock keystore description file */
26607c478bd9Sstevel@tonic-gate 	if (lock_file(ks_fd, B_FALSE, B_FALSE) != 0) {
26617c478bd9Sstevel@tonic-gate 		(void) close(ks_fd);
26627c478bd9Sstevel@tonic-gate 		(void) close(fd);
26637c478bd9Sstevel@tonic-gate 		return (-1);
26647c478bd9Sstevel@tonic-gate 	}
26657c478bd9Sstevel@tonic-gate 
26667c478bd9Sstevel@tonic-gate 	(void) close(ks_fd);
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate 	(void) close(fd);
26697c478bd9Sstevel@tonic-gate 
26707c478bd9Sstevel@tonic-gate 	return (0); /* All operations completed successfully */
26717c478bd9Sstevel@tonic-gate 
26727c478bd9Sstevel@tonic-gate cleanup2:
26737c478bd9Sstevel@tonic-gate 	(void) close(tmp_fd);
26747c478bd9Sstevel@tonic-gate 	(void) remove(tmp_name);
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate cleanup1:
26777c478bd9Sstevel@tonic-gate 	(void) close(fd);
26787c478bd9Sstevel@tonic-gate 
26797c478bd9Sstevel@tonic-gate cleanup:
26807c478bd9Sstevel@tonic-gate 	/* unlock keystore description file */
26817c478bd9Sstevel@tonic-gate 	(void) lock_file(ks_fd, B_FALSE, B_FALSE);
26827c478bd9Sstevel@tonic-gate 	(void) close(ks_fd);
26837c478bd9Sstevel@tonic-gate 	(void) remove(tmp_ks_name);
26847c478bd9Sstevel@tonic-gate 	return (-1);
26857c478bd9Sstevel@tonic-gate }
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate /*
26887c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_del_obj
26897c478bd9Sstevel@tonic-gate  *
26907c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
26917c478bd9Sstevel@tonic-gate  *		ks_handle: handle of the key store object to be deleted
26927c478bd9Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
26937c478bd9Sstevel@tonic-gate  *
26947c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
26957c478bd9Sstevel@tonic-gate  *		-1: if any error occurred.
26967c478bd9Sstevel@tonic-gate  *		0: object successfully deleted from keystore.
26977c478bd9Sstevel@tonic-gate  *
26987c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
26997c478bd9Sstevel@tonic-gate  *		This API is used to delete a particular token object from
27007c478bd9Sstevel@tonic-gate  *		the keystore.  The corresponding token object file will be
27017c478bd9Sstevel@tonic-gate  *		removed from the file system.
27027c478bd9Sstevel@tonic-gate  *		Any future reference to the deleted file will
27037c478bd9Sstevel@tonic-gate  *		return an CKR_OBJECT_HANDLE_INVALID error.
27047c478bd9Sstevel@tonic-gate  */
27057c478bd9Sstevel@tonic-gate int
27067c478bd9Sstevel@tonic-gate soft_keystore_del_obj(ks_obj_handle_t *ks_handle, boolean_t lock_held)
27077c478bd9Sstevel@tonic-gate {
27087c478bd9Sstevel@tonic-gate 	char objname[MAXPATHLEN], tmp_ks_name[MAXPATHLEN];
27097c478bd9Sstevel@tonic-gate 	int fd;
27107c478bd9Sstevel@tonic-gate 	char pub_obj_path[MAXPATHLEN], pri_obj_path[MAXPATHLEN],
27117c478bd9Sstevel@tonic-gate 	    ks_desc_file[MAXPATHLEN];
27127c478bd9Sstevel@tonic-gate 	int ret_val = -1;
27137c478bd9Sstevel@tonic-gate 	int obj_fd;
27147c478bd9Sstevel@tonic-gate 
27157c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDWR, B_FALSE,
27167c478bd9Sstevel@tonic-gate 	    lock_held)) < 0) {
27177c478bd9Sstevel@tonic-gate 		return (-1);
27187c478bd9Sstevel@tonic-gate 	}
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate 	(void) get_desc_file_path(ks_desc_file);
27217c478bd9Sstevel@tonic-gate 	(void) get_tmp_desc_file_path(tmp_ks_name);
27227c478bd9Sstevel@tonic-gate 	if (create_updated_keystore_version(fd, tmp_ks_name) != 0) {
27237c478bd9Sstevel@tonic-gate 		goto cleanup;
27247c478bd9Sstevel@tonic-gate 	}
27257c478bd9Sstevel@tonic-gate 
27267c478bd9Sstevel@tonic-gate 	if (ks_handle->public) {
27277c478bd9Sstevel@tonic-gate 		(void) snprintf(objname, MAXPATHLEN, "%s/%s",
27287c478bd9Sstevel@tonic-gate 		    get_pub_obj_path(pub_obj_path), ks_handle->name);
27297c478bd9Sstevel@tonic-gate 	} else {
27307c478bd9Sstevel@tonic-gate 		(void) snprintf(objname, MAXPATHLEN, "%s/%s",
27317c478bd9Sstevel@tonic-gate 		    get_pri_obj_path(pri_obj_path), ks_handle->name);
27327c478bd9Sstevel@tonic-gate 	}
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate 	/*
27357c478bd9Sstevel@tonic-gate 	 * make sure no other process is reading/writing the file
27367c478bd9Sstevel@tonic-gate 	 * by acquiring the lock on the file
27377c478bd9Sstevel@tonic-gate 	 */
27387c478bd9Sstevel@tonic-gate 	if ((obj_fd = open_and_lock_object_file(ks_handle, O_WRONLY,
27397c478bd9Sstevel@tonic-gate 	    B_FALSE)) < 0) {
27407c478bd9Sstevel@tonic-gate 		return (-1);
27417c478bd9Sstevel@tonic-gate 	}
27427c478bd9Sstevel@tonic-gate 
27437c478bd9Sstevel@tonic-gate 	if (unlink(objname) != 0) {
27447c478bd9Sstevel@tonic-gate 		(void) lock_file(obj_fd, B_FALSE, B_FALSE);
27457c478bd9Sstevel@tonic-gate 		(void) close(obj_fd);
27467c478bd9Sstevel@tonic-gate 		goto cleanup;
27477c478bd9Sstevel@tonic-gate 	}
27487c478bd9Sstevel@tonic-gate 
27497c478bd9Sstevel@tonic-gate 	(void) lock_file(obj_fd, B_FALSE, B_FALSE);
27507c478bd9Sstevel@tonic-gate 	(void) close(obj_fd);
27517c478bd9Sstevel@tonic-gate 
27527c478bd9Sstevel@tonic-gate 	if (rename(tmp_ks_name, ks_desc_file) != 0) {
27537c478bd9Sstevel@tonic-gate 		goto cleanup;
27547c478bd9Sstevel@tonic-gate 	}
27557c478bd9Sstevel@tonic-gate 	ret_val = 0;
27567c478bd9Sstevel@tonic-gate 
27577c478bd9Sstevel@tonic-gate cleanup:
27587c478bd9Sstevel@tonic-gate 	/* unlock keystore description file */
27597c478bd9Sstevel@tonic-gate 	if (!lock_held) {
27607c478bd9Sstevel@tonic-gate 		if (lock_file(fd, B_FALSE, B_FALSE) != 0) {
27617c478bd9Sstevel@tonic-gate 			(void) close(fd);
27627c478bd9Sstevel@tonic-gate 			return (-1);
27637c478bd9Sstevel@tonic-gate 		}
27647c478bd9Sstevel@tonic-gate 	}
27657c478bd9Sstevel@tonic-gate 
27667c478bd9Sstevel@tonic-gate 	(void) close(fd);
27677c478bd9Sstevel@tonic-gate 	return (ret_val);
27687c478bd9Sstevel@tonic-gate }
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate /*
27717c478bd9Sstevel@tonic-gate  * Get the salt used for generating hashed pin from the
27727c478bd9Sstevel@tonic-gate  * keystore description file.
27737c478bd9Sstevel@tonic-gate  *
27747c478bd9Sstevel@tonic-gate  * The result will be stored in the provided buffer "salt" passed
27757c478bd9Sstevel@tonic-gate  * in as an argument.
27767c478bd9Sstevel@tonic-gate  *
27777c478bd9Sstevel@tonic-gate  * Return 0 if no error, return -1 if there's any error.
27787c478bd9Sstevel@tonic-gate  */
27797c478bd9Sstevel@tonic-gate int
27807c478bd9Sstevel@tonic-gate soft_keystore_get_pin_salt(char **salt)
27817c478bd9Sstevel@tonic-gate {
27827c478bd9Sstevel@tonic-gate 	int fd, ret_val = -1;
27837c478bd9Sstevel@tonic-gate 	uint64_t hashed_pin_salt_size;
27847c478bd9Sstevel@tonic-gate 
27857c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDONLY, B_TRUE,
27867c478bd9Sstevel@tonic-gate 	    B_FALSE)) < 0) {
27877c478bd9Sstevel@tonic-gate 		return (-1);
27887c478bd9Sstevel@tonic-gate 	}
27897c478bd9Sstevel@tonic-gate 
27907c478bd9Sstevel@tonic-gate 	if (lseek(fd, KS_HASHED_PIN_SALT_LEN_OFFSET, SEEK_SET)
27917c478bd9Sstevel@tonic-gate 	    != KS_HASHED_PIN_SALT_LEN_OFFSET) {
27927c478bd9Sstevel@tonic-gate 		goto cleanup;
27937c478bd9Sstevel@tonic-gate 	}
27947c478bd9Sstevel@tonic-gate 
2795*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)&hashed_pin_salt_size,
27967c478bd9Sstevel@tonic-gate 	    KS_HASHED_PIN_SALT_LEN_SIZE) != KS_HASHED_PIN_SALT_LEN_SIZE) {
27977c478bd9Sstevel@tonic-gate 		goto cleanup;
27987c478bd9Sstevel@tonic-gate 	}
27997c478bd9Sstevel@tonic-gate 	hashed_pin_salt_size = SWAP64(hashed_pin_salt_size);
28007c478bd9Sstevel@tonic-gate 
28017c478bd9Sstevel@tonic-gate 	*salt = malloc(hashed_pin_salt_size + 1);
28027c478bd9Sstevel@tonic-gate 	if (*salt == NULL) {
28037c478bd9Sstevel@tonic-gate 		goto cleanup;
28047c478bd9Sstevel@tonic-gate 	}
28057c478bd9Sstevel@tonic-gate 
2806*19193bb6SDina K Nimeh 	if ((readn_nointr(fd, *salt, hashed_pin_salt_size))
28077c478bd9Sstevel@tonic-gate 	    != (ssize_t)hashed_pin_salt_size) {
28087c478bd9Sstevel@tonic-gate 		free(*salt);
28097c478bd9Sstevel@tonic-gate 		goto cleanup;
28107c478bd9Sstevel@tonic-gate 	}
28117c478bd9Sstevel@tonic-gate 	(*salt)[hashed_pin_salt_size] = '\0';
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 	ret_val = 0;
28147c478bd9Sstevel@tonic-gate 
28157c478bd9Sstevel@tonic-gate cleanup:
28167c478bd9Sstevel@tonic-gate 	if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
28177c478bd9Sstevel@tonic-gate 		ret_val = -1;
28187c478bd9Sstevel@tonic-gate 	}
28197c478bd9Sstevel@tonic-gate 
28207c478bd9Sstevel@tonic-gate 	(void) close(fd);
28217c478bd9Sstevel@tonic-gate 	return (ret_val);
28227c478bd9Sstevel@tonic-gate }
28237c478bd9Sstevel@tonic-gate 
28247c478bd9Sstevel@tonic-gate /*
28257c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_pin_initialized
28267c478bd9Sstevel@tonic-gate  *
28277c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
28287c478bd9Sstevel@tonic-gate  *		initialized: This value will be set to true if keystore is
28297c478bd9Sstevel@tonic-gate  *			     initialized, and false otherwise.
28307c478bd9Sstevel@tonic-gate  *		hashed_pin: If the keystore is initialized, this will contain
28317c478bd9Sstevel@tonic-gate  *			    the hashed pin.  It will be NULL if the keystore
28327c478bd9Sstevel@tonic-gate  *			    pin is not initialized.  Memory allocated
28337c478bd9Sstevel@tonic-gate  *			    for the hashed pin needs to be freed by
28347c478bd9Sstevel@tonic-gate  *			    the caller.
28357c478bd9Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
28367c478bd9Sstevel@tonic-gate  *
28377c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
28387c478bd9Sstevel@tonic-gate  *		CKR_OK: No error
28397c478bd9Sstevel@tonic-gate  *		any other appropriate CKR_value
28407c478bd9Sstevel@tonic-gate  *
28417c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
28427c478bd9Sstevel@tonic-gate  *		This API is used to determine if the PIN in the keystore
28437c478bd9Sstevel@tonic-gate  *		has been initialized or not.
28447c478bd9Sstevel@tonic-gate  *		It makes the determination using the salt for generating the
28457c478bd9Sstevel@tonic-gate  *		encryption key.  The salt is stored in the keystore
28467c478bd9Sstevel@tonic-gate  *		descryption file.  The salt should be all zero if
28477c478bd9Sstevel@tonic-gate  *		the keystore pin has not been initialized.
28487c478bd9Sstevel@tonic-gate  *		If the pin has been initialized, it is returned in the
28497c478bd9Sstevel@tonic-gate  *		hashed_pin argument.
28507c478bd9Sstevel@tonic-gate  */
28517c478bd9Sstevel@tonic-gate CK_RV
28527c478bd9Sstevel@tonic-gate soft_keystore_pin_initialized(boolean_t *initialized, char **hashed_pin,
28537c478bd9Sstevel@tonic-gate     boolean_t lock_held)
28547c478bd9Sstevel@tonic-gate {
28557c478bd9Sstevel@tonic-gate 	int fd;
28567c478bd9Sstevel@tonic-gate 	CK_BYTE crypt_salt[KS_KEY_SALT_SIZE], tmp_buf[KS_KEY_SALT_SIZE];
28577c478bd9Sstevel@tonic-gate 	CK_RV ret_val = CKR_OK;
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDONLY, B_TRUE,
28607c478bd9Sstevel@tonic-gate 	    lock_held)) < 0) {
28617c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
28627c478bd9Sstevel@tonic-gate 	}
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate 	if (lseek(fd, KS_KEY_SALT_OFFSET, SEEK_SET) != KS_KEY_SALT_OFFSET) {
28657c478bd9Sstevel@tonic-gate 		ret_val = CKR_FUNCTION_FAILED;
28667c478bd9Sstevel@tonic-gate 		goto cleanup;
28677c478bd9Sstevel@tonic-gate 	}
28687c478bd9Sstevel@tonic-gate 
2869*19193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)crypt_salt, KS_KEY_SALT_SIZE)
28707c478bd9Sstevel@tonic-gate 	    != KS_KEY_SALT_SIZE) {
28717c478bd9Sstevel@tonic-gate 		ret_val = CKR_FUNCTION_FAILED;
28727c478bd9Sstevel@tonic-gate 		goto cleanup;
28737c478bd9Sstevel@tonic-gate 	}
28747c478bd9Sstevel@tonic-gate 
28757c478bd9Sstevel@tonic-gate 	(void) bzero(tmp_buf, KS_KEY_SALT_SIZE);
28767c478bd9Sstevel@tonic-gate 
28777c478bd9Sstevel@tonic-gate 	if (memcmp(crypt_salt, tmp_buf, KS_KEY_SALT_SIZE) == 0) {
28787c478bd9Sstevel@tonic-gate 		*initialized = B_FALSE;
28797c478bd9Sstevel@tonic-gate 		hashed_pin = NULL;
28807c478bd9Sstevel@tonic-gate 	} else {
28817c478bd9Sstevel@tonic-gate 		*initialized = B_TRUE;
28827c478bd9Sstevel@tonic-gate 		ret_val = get_hashed_pin(fd, hashed_pin);
28837c478bd9Sstevel@tonic-gate 	}
28847c478bd9Sstevel@tonic-gate 
28857c478bd9Sstevel@tonic-gate cleanup:
28867c478bd9Sstevel@tonic-gate 
28877c478bd9Sstevel@tonic-gate 	if (!lock_held) {
28887c478bd9Sstevel@tonic-gate 		if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
28897c478bd9Sstevel@tonic-gate 			ret_val = CKR_FUNCTION_FAILED;
28907c478bd9Sstevel@tonic-gate 		}
28917c478bd9Sstevel@tonic-gate 	}
28927c478bd9Sstevel@tonic-gate 
28937c478bd9Sstevel@tonic-gate 	(void) close(fd);
28947c478bd9Sstevel@tonic-gate 	return (ret_val);
28957c478bd9Sstevel@tonic-gate }
289690e0e8c4Sizick 
289790e0e8c4Sizick /*
289890e0e8c4Sizick  * This checks if the keystore file exists
289990e0e8c4Sizick  */
290090e0e8c4Sizick 
290190e0e8c4Sizick static int
290290e0e8c4Sizick soft_keystore_exists()
290390e0e8c4Sizick {
290490e0e8c4Sizick 	int ret;
290590e0e8c4Sizick 	struct stat fn_stat;
290690e0e8c4Sizick 	char *fname, ks_desc_file[MAXPATHLEN];
290790e0e8c4Sizick 
290890e0e8c4Sizick 	fname = get_desc_file_path(ks_desc_file);
290990e0e8c4Sizick 	ret = stat(fname, &fn_stat);
291090e0e8c4Sizick 	if (ret == 0)
291190e0e8c4Sizick 		return (0);
291290e0e8c4Sizick 	return (errno);
291390e0e8c4Sizick }
291490e0e8c4Sizick 
291590e0e8c4Sizick /*
291690e0e8c4Sizick  *	FUNCTION: soft_keystore_init
291790e0e8c4Sizick  *
291890e0e8c4Sizick  *	ARGUMENTS:
291990e0e8c4Sizick  *		desired_state:  The keystore state the caller would like
292090e0e8c4Sizick  *				it to be.
292190e0e8c4Sizick  *
292290e0e8c4Sizick  *	RETURN VALUE:
292390e0e8c4Sizick  *		Returns the state the function is in.  If it succeeded, it
292490e0e8c4Sizick  *		will be the same as the desired, if not it will be
292590e0e8c4Sizick  *		KEYSTORE_UNAVAILABLE.
292690e0e8c4Sizick  *
292790e0e8c4Sizick  *	DESCRIPTION:
292890e0e8c4Sizick  *		This function will only load as much keystore data as is
292990e0e8c4Sizick  *		requested at that time. This is for performace by delaying the
293090e0e8c4Sizick  *		reading of token objects until they are needed or never at
293190e0e8c4Sizick  *		all if they are not used.
293290e0e8c4Sizick  *
293390e0e8c4Sizick  *		It is only called by soft_keystore_status() when the
293490e0e8c4Sizick  *		"desired_state" is not the the current load state of keystore.
293590e0e8c4Sizick  *
293690e0e8c4Sizick  */
293790e0e8c4Sizick int
293890e0e8c4Sizick soft_keystore_init(int desired_state)
293990e0e8c4Sizick {
294090e0e8c4Sizick 	int ret;
294190e0e8c4Sizick 
294290e0e8c4Sizick 	(void) pthread_mutex_lock(&soft_slot.keystore_mutex);
294390e0e8c4Sizick 
294490e0e8c4Sizick 	/*
294590e0e8c4Sizick 	 * If more than one session tries to initialize the keystore, the
294690e0e8c4Sizick 	 * second and other following sessions that were waiting for the lock
294790e0e8c4Sizick 	 * will quickly exit if their requirements are satisfied.
294890e0e8c4Sizick 	 */
294990e0e8c4Sizick 	if (desired_state <= soft_slot.keystore_load_status) {
295090e0e8c4Sizick 		(void) pthread_mutex_unlock(&soft_slot.keystore_mutex);
295190e0e8c4Sizick 		return (soft_slot.keystore_load_status);
295290e0e8c4Sizick 	}
295390e0e8c4Sizick 
295490e0e8c4Sizick 	/*
295590e0e8c4Sizick 	 * With 'keystore_load_status' giving the current state of the
295690e0e8c4Sizick 	 * process, this switch will bring it up to the desired state if
295790e0e8c4Sizick 	 * possible.
295890e0e8c4Sizick 	 */
295990e0e8c4Sizick 
296090e0e8c4Sizick 	switch (soft_slot.keystore_load_status) {
296190e0e8c4Sizick 	case KEYSTORE_UNINITIALIZED:
296290e0e8c4Sizick 		ret = soft_keystore_exists();
296390e0e8c4Sizick 		if (ret == 0)
296490e0e8c4Sizick 			soft_slot.keystore_load_status = KEYSTORE_PRESENT;
296590e0e8c4Sizick 		else if (ret == ENOENT)
296690e0e8c4Sizick 			if (create_keystore() == 0)
296790e0e8c4Sizick 				soft_slot.keystore_load_status =
296890e0e8c4Sizick 				    KEYSTORE_PRESENT;
296990e0e8c4Sizick 			else {
297090e0e8c4Sizick 				soft_slot.keystore_load_status =
297190e0e8c4Sizick 				    KEYSTORE_UNAVAILABLE;
29724c21f043Sizick 				cryptoerror(LOG_DEBUG,
297390e0e8c4Sizick 				    "pkcs11_softtoken: "
297490e0e8c4Sizick 				    "Cannot create keystore.");
297590e0e8c4Sizick 				break;
297690e0e8c4Sizick 			}
297790e0e8c4Sizick 
297890e0e8c4Sizick 		if (desired_state <= KEYSTORE_PRESENT)
297990e0e8c4Sizick 			break;
298090e0e8c4Sizick 
298190e0e8c4Sizick 	/* FALLTHRU */
298290e0e8c4Sizick 	case KEYSTORE_PRESENT:
298390e0e8c4Sizick 		if (soft_keystore_get_version(&soft_slot.ks_version, B_FALSE)
298490e0e8c4Sizick 		    != 0) {
298590e0e8c4Sizick 			soft_slot.keystore_load_status = KEYSTORE_UNAVAILABLE;
29864c21f043Sizick 			cryptoerror(LOG_DEBUG,
29874c21f043Sizick 			    "pkcs11_softtoken: Keystore access failed.");
298890e0e8c4Sizick 			break;
298990e0e8c4Sizick 		}
299090e0e8c4Sizick 
299190e0e8c4Sizick 		soft_slot.keystore_load_status = KEYSTORE_VERSION_OK;
299290e0e8c4Sizick 		if (desired_state <= KEYSTORE_VERSION_OK)
299390e0e8c4Sizick 			break;
299490e0e8c4Sizick 
299590e0e8c4Sizick 	/* FALLTHRU */
299690e0e8c4Sizick 	case KEYSTORE_VERSION_OK:
299790e0e8c4Sizick 		/* Load all the public token objects from keystore */
299890e0e8c4Sizick 		if (soft_get_token_objects_from_keystore(PUB_TOKENOBJS)
299990e0e8c4Sizick 		    != CKR_OK) {
300090e0e8c4Sizick 			(void) soft_destroy_token_session();
300190e0e8c4Sizick 			soft_slot.keystore_load_status = KEYSTORE_UNAVAILABLE;
30024c21f043Sizick 			cryptoerror(LOG_DEBUG,
300390e0e8c4Sizick 			    "pkcs11_softtoken: Cannot initialize keystore.");
300490e0e8c4Sizick 			break;
300590e0e8c4Sizick 		}
300690e0e8c4Sizick 
300790e0e8c4Sizick 		soft_slot.keystore_load_status = KEYSTORE_INITIALIZED;
300890e0e8c4Sizick 	};
300990e0e8c4Sizick 
301090e0e8c4Sizick 	(void) pthread_mutex_unlock(&soft_slot.keystore_mutex);
301190e0e8c4Sizick 	return (soft_slot.keystore_load_status);
301290e0e8c4Sizick }
301390e0e8c4Sizick 
301490e0e8c4Sizick /*
301590e0e8c4Sizick  *	FUNCTION: soft_keystore_status
301690e0e8c4Sizick  *
301790e0e8c4Sizick  *	ARGUMENTS:
301890e0e8c4Sizick  *		desired_state:  The keystore state the caller would like
301990e0e8c4Sizick  *				it to be.
302090e0e8c4Sizick  *
302190e0e8c4Sizick  *	RETURN VALUE:
302290e0e8c4Sizick  *		B_TRUE if keystore is ready and at the desired state.
302390e0e8c4Sizick  *		B_FALSE if keystore had an error and is not available.
302490e0e8c4Sizick  *
302590e0e8c4Sizick  *	DESCRIPTION:
302690e0e8c4Sizick  *		The calling function wants to make sure the keystore load
302790e0e8c4Sizick  *		status to in a state it requires.  If it is not at that
302890e0e8c4Sizick  *		state it will call the load function.
302990e0e8c4Sizick  *		If keystore is at the desired state or has just been
303090e0e8c4Sizick  *		loaded to that state, it will return TRUE.  If there has been
303190e0e8c4Sizick  *		load failure, it will return FALSE.
303290e0e8c4Sizick  *
303390e0e8c4Sizick  */
303490e0e8c4Sizick boolean_t
303590e0e8c4Sizick soft_keystore_status(int desired_state)
303690e0e8c4Sizick {
303790e0e8c4Sizick 
303890e0e8c4Sizick 	if (soft_slot.keystore_load_status == KEYSTORE_UNAVAILABLE)
303990e0e8c4Sizick 		return (B_FALSE);
304090e0e8c4Sizick 
304190e0e8c4Sizick 	return ((desired_state <= soft_slot.keystore_load_status) ||
304290e0e8c4Sizick 	    (soft_keystore_init(desired_state) == desired_state));
304390e0e8c4Sizick }
3044