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 /*
22c5866e1dSPeter Shoults  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23*a8793c76SJason King  * Copyright 2018, Joyent, Inc.
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>
41c5866e1dSPeter Shoults #include <libgen.h>
427c478bd9Sstevel@tonic-gate #include <strings.h>
437c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
447c478bd9Sstevel@tonic-gate #include <cryptoutil.h>
457c478bd9Sstevel@tonic-gate #include "softGlobal.h"
467c478bd9Sstevel@tonic-gate #include "softObject.h"
4790e0e8c4Sizick #include "softSession.h"
487c478bd9Sstevel@tonic-gate #include "softKeystore.h"
497c478bd9Sstevel@tonic-gate #include "softKeystoreUtil.h"
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #define	MAXPATHLEN	1024
527c478bd9Sstevel@tonic-gate #define	SUNW_PATH	".sunw"		/* top level Sun directory */
537c478bd9Sstevel@tonic-gate #define	KEYSTORE_PATH	"pkcs11_softtoken"	/* keystore directory */
547c478bd9Sstevel@tonic-gate #define	PUB_OBJ_DIR	"public"	/* directory for public objects */
557c478bd9Sstevel@tonic-gate #define	PRI_OBJ_DIR	"private"	/* directory for private objects */
567c478bd9Sstevel@tonic-gate #define	DS_FILE		"objstore_info"	/* keystore description file */
577c478bd9Sstevel@tonic-gate #define	TMP_DS_FILE	"t_info"	/* temp name for keystore desc. file */
587c478bd9Sstevel@tonic-gate #define	OBJ_PREFIX	"obj"	/* prefix of the keystore object file names */
59d288ba74SAnthony Scarpino #define	OBJ_PREFIX_LEN	sizeof (OBJ_PREFIX) - 1	/* length of prefix */
607c478bd9Sstevel@tonic-gate #define	TMP_OBJ_PREFIX	"t_o"	/* prefix of the temp object file names */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * KEYSTORE DESCRIPTION FILE:
647c478bd9Sstevel@tonic-gate  *
657c478bd9Sstevel@tonic-gate  * The following describes the content of the keystore description file
667c478bd9Sstevel@tonic-gate  *
677c478bd9Sstevel@tonic-gate  * The order AND data type of the fields are very important.
687c478bd9Sstevel@tonic-gate  * All the code in this file assume that they are in the order specified
697c478bd9Sstevel@tonic-gate  * below.  If either order of the fields or their data type changed,
707c478bd9Sstevel@tonic-gate  * you must make sure the ALL the pre-define values are still valid
717c478bd9Sstevel@tonic-gate  *
7290e0e8c4Sizick  * 1) PKCS#11 release number.  It's 2.20 in this release (uchar_t[32])
737c478bd9Sstevel@tonic-gate  * 2) keystore version number: used for synchronizing when different
747c478bd9Sstevel@tonic-gate  *    processes access the keystore at the same time.  It is incremented
757c478bd9Sstevel@tonic-gate  *    when there is a change to the keystore. (uint_32)
767c478bd9Sstevel@tonic-gate  * 3) monotonic-counter: last counter value for name of token object file.
777c478bd9Sstevel@tonic-gate  *    used for assigning unique name to each token (uint_32)
787c478bd9Sstevel@tonic-gate  * 4) salt used for generating encryption key (uint_16)
797c478bd9Sstevel@tonic-gate  * 5) salt used for generating key used for doing HMAC (uint_16)
807c478bd9Sstevel@tonic-gate  * 6) Length of salt used for generating hashed pin (length of salt
817c478bd9Sstevel@tonic-gate  *    is variable)
827c478bd9Sstevel@tonic-gate  * 7) Salt used for generating hashed pin.
837c478bd9Sstevel@tonic-gate  * 8) Hashed pin len (length of hashed pin could be variable, the offset of
847c478bd9Sstevel@tonic-gate  *    where this value lives in the file is calculated at run time)
857c478bd9Sstevel@tonic-gate  * 9) Hashed pin
867c478bd9Sstevel@tonic-gate  *
877c478bd9Sstevel@tonic-gate  */
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /* Keystore description file pre-defined values */
90f66d273dSizick #define	KS_PKCS11_VER		"2.20"
917c478bd9Sstevel@tonic-gate #define	KS_PKCS11_OFFSET	0
927c478bd9Sstevel@tonic-gate #define	KS_PKCS11_VER_SIZE	32
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #define	KS_VER_OFFSET		(KS_PKCS11_OFFSET + KS_PKCS11_VER_SIZE)
957c478bd9Sstevel@tonic-gate #define	KS_VER_SIZE	4	/* size in bytes of keystore version value */
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate #define	KS_COUNTER_OFFSET	(KS_VER_OFFSET + KS_VER_SIZE)
987c478bd9Sstevel@tonic-gate #define	KS_COUNTER_SIZE	4	/* size in bytes of the monotonic counter */
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate #define	KS_KEY_SALT_OFFSET	(KS_COUNTER_OFFSET + KS_COUNTER_SIZE)
1017c478bd9Sstevel@tonic-gate #define	KS_KEY_SALT_SIZE	PBKD2_SALT_SIZE
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate #define	KS_HMAC_SALT_OFFSET	(KS_KEY_SALT_OFFSET + KS_KEY_SALT_SIZE)
1047c478bd9Sstevel@tonic-gate #define	KS_HMAC_SALT_SIZE	PBKD2_SALT_SIZE
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /* Salt for hashed pin */
1077c478bd9Sstevel@tonic-gate #define	KS_HASHED_PIN_SALT_LEN_OFFSET (KS_HMAC_SALT_OFFSET + KS_HMAC_SALT_SIZE)
1087c478bd9Sstevel@tonic-gate #define	KS_HASHED_PIN_SALT_LEN_SIZE 8 /* stores length of hashed pin salt */
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate #define	KS_HASHED_PIN_SALT_OFFSET \
1117c478bd9Sstevel@tonic-gate 		(KS_HASHED_PIN_SALT_LEN_OFFSET + KS_HASHED_PIN_SALT_LEN_SIZE)
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate  * hashed pin
1157c478bd9Sstevel@tonic-gate  *
1167c478bd9Sstevel@tonic-gate  * hashed_pin length offset will be calculated at run time since
1177c478bd9Sstevel@tonic-gate  * there's the hashed pin salt size is variable.
1187c478bd9Sstevel@tonic-gate  *
1197c478bd9Sstevel@tonic-gate  * The offset will be calculated at run time by calling the
1207c478bd9Sstevel@tonic-gate  * function calculate_hashed_pin_offset()
1217c478bd9Sstevel@tonic-gate  */
1227c478bd9Sstevel@tonic-gate static off_t	ks_hashed_pinlen_offset = -1;
1237c478bd9Sstevel@tonic-gate #define	KS_HASHED_PINLEN_SIZE	8
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /* End of Keystore description file pre-defined values */
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate  * Metadata for each object
1297c478bd9Sstevel@tonic-gate  *
1307c478bd9Sstevel@tonic-gate  * The order AND data type of all the fields is very important.
1317c478bd9Sstevel@tonic-gate  * All the code in this file assume that they are in the order specified
1327c478bd9Sstevel@tonic-gate  * below.  If either order of the fields or their data type is changed,
1337c478bd9Sstevel@tonic-gate  * you must make sure the following pre-define value is still valid
1347c478bd9Sstevel@tonic-gate  * Each object will have the meta data at the beginning of the object file.
1357c478bd9Sstevel@tonic-gate  *
1367c478bd9Sstevel@tonic-gate  * 1) object_version: used by softtoken to see if the object
1377c478bd9Sstevel@tonic-gate  *    has been modified since it last reads it. (uint_32)
1387c478bd9Sstevel@tonic-gate  * 2) iv: initialization vector for encrypted data in the object.  This
1397c478bd9Sstevel@tonic-gate  *    value will be 0 for public objects.  (uchar_t[16])
1407c478bd9Sstevel@tonic-gate  * 3) obj_hmac: keyed hash as verifier to detect private object
1417c478bd9Sstevel@tonic-gate  *    being tampered this value will be 0 for public objects (uchar_t[16])
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /* Object metadata pre-defined values */
1457c478bd9Sstevel@tonic-gate #define	OBJ_VER_OFFSET	0
1467c478bd9Sstevel@tonic-gate #define	OBJ_VER_SIZE	4	/* size of object version in bytes */
1477c478bd9Sstevel@tonic-gate #define	OBJ_IV_OFFSET	(OBJ_VER_OFFSET + OBJ_VER_SIZE)
1487c478bd9Sstevel@tonic-gate #define	OBJ_IV_SIZE	16
1497c478bd9Sstevel@tonic-gate #define	OBJ_HMAC_OFFSET	(OBJ_IV_OFFSET + OBJ_IV_SIZE)
1507c478bd9Sstevel@tonic-gate #define	OBJ_HMAC_SIZE	16	/* MD5 HMAC keyed hash */
1517c478bd9Sstevel@tonic-gate #define	OBJ_DATA_OFFSET	(OBJ_HMAC_OFFSET + OBJ_HMAC_SIZE)
1527c478bd9Sstevel@tonic-gate /* End of object metadata pre-defined values */
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate #define	ALTERNATE_KEYSTORE_PATH	"SOFTTOKEN_DIR"
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate static soft_object_t	*enc_key = NULL;
1577c478bd9Sstevel@tonic-gate static soft_object_t	*hmac_key = NULL;
1587c478bd9Sstevel@tonic-gate static char		keystore_path[MAXPATHLEN];
1597c478bd9Sstevel@tonic-gate static boolean_t	keystore_path_initialized = B_FALSE;
1607c478bd9Sstevel@tonic-gate static int		desc_fd = 0;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate static char *
get_keystore_path()1637c478bd9Sstevel@tonic-gate get_keystore_path()
1647c478bd9Sstevel@tonic-gate {
165c5866e1dSPeter Shoults 	char *home = getenv("HOME");
166c5866e1dSPeter Shoults 	char *alt = getenv(ALTERNATE_KEYSTORE_PATH);
1677c478bd9Sstevel@tonic-gate 
168c5866e1dSPeter Shoults 	if (keystore_path_initialized) {
169c5866e1dSPeter Shoults 		return (keystore_path);
170c5866e1dSPeter Shoults 	}
171c5866e1dSPeter Shoults 
172c5866e1dSPeter Shoults 	bzero(keystore_path, sizeof (keystore_path));
173c5866e1dSPeter Shoults 	/*
174c5866e1dSPeter Shoults 	 * If it isn't set or is set to the empty string use the
175c5866e1dSPeter Shoults 	 * default location.  We need to check for the empty string
176c5866e1dSPeter Shoults 	 * because some users "unset" environment variables by giving
177c5866e1dSPeter Shoults 	 * them no value, this isn't the same thing as removing it
178c5866e1dSPeter Shoults 	 * from the environment.
179c5866e1dSPeter Shoults 	 *
180c5866e1dSPeter Shoults 	 * We don't want that to attempt to open /.sunw/pkcs11_sofftoken
181c5866e1dSPeter Shoults 	 */
182c5866e1dSPeter Shoults 	if ((alt != NULL) && (strcmp(alt, "") != 0)) {
183c5866e1dSPeter Shoults 		(void) snprintf(keystore_path, MAXPATHLEN, "%s/%s",
184c5866e1dSPeter Shoults 		    alt, KEYSTORE_PATH);
185c5866e1dSPeter Shoults 		keystore_path_initialized = B_TRUE;
186c5866e1dSPeter Shoults 	} else if ((home != NULL) && (strcmp(home, "") != 0)) {
187c5866e1dSPeter Shoults 		/* alternate path not specified, try user's home dir */
188c5866e1dSPeter Shoults 		(void) snprintf(keystore_path, MAXPATHLEN, "%s/%s/%s",
189c5866e1dSPeter Shoults 		    home, SUNW_PATH, KEYSTORE_PATH);
1907c478bd9Sstevel@tonic-gate 		keystore_path_initialized = B_TRUE;
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 	return (keystore_path);
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate static char *
get_pub_obj_path(char * name)1967c478bd9Sstevel@tonic-gate get_pub_obj_path(char *name)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate 	bzero(name, sizeof (name));
1997c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
2007c478bd9Sstevel@tonic-gate 	    get_keystore_path(), PUB_OBJ_DIR);
2017c478bd9Sstevel@tonic-gate 	return (name);
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate static char *
get_pri_obj_path(char * name)2057c478bd9Sstevel@tonic-gate get_pri_obj_path(char *name)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate 	bzero(name, sizeof (name));
2087c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
2097c478bd9Sstevel@tonic-gate 	    get_keystore_path(), PRI_OBJ_DIR);
2107c478bd9Sstevel@tonic-gate 	return (name);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate static char *
get_desc_file_path(char * name)2147c478bd9Sstevel@tonic-gate get_desc_file_path(char *name)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 	bzero(name, sizeof (name));
2177c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
2187c478bd9Sstevel@tonic-gate 	    get_keystore_path(), DS_FILE);
2197c478bd9Sstevel@tonic-gate 	return (name);
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate static char *
get_tmp_desc_file_path(char * name)2237c478bd9Sstevel@tonic-gate get_tmp_desc_file_path(char *name)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate 	bzero(name, sizeof (name));
2267c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
2277c478bd9Sstevel@tonic-gate 	    get_keystore_path(), TMP_DS_FILE);
2287c478bd9Sstevel@tonic-gate 	return (name);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate /*
2327c478bd9Sstevel@tonic-gate  * Calculates the offset for hashed_pin length and hashed pin
2337c478bd9Sstevel@tonic-gate  *
2347c478bd9Sstevel@tonic-gate  * Returns 0 if successful, -1 if there's any error.
2357c478bd9Sstevel@tonic-gate  *
2367c478bd9Sstevel@tonic-gate  * If successful, global variables "ks_hashed_pinlen_offset" will be set.
2377c478bd9Sstevel@tonic-gate  *
2387c478bd9Sstevel@tonic-gate  */
2397c478bd9Sstevel@tonic-gate static int
calculate_hashed_pin_offset(int fd)2407c478bd9Sstevel@tonic-gate calculate_hashed_pin_offset(int fd)
2417c478bd9Sstevel@tonic-gate {
2427c478bd9Sstevel@tonic-gate 	uint64_t salt_length;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	if (lseek(fd, KS_HASHED_PIN_SALT_LEN_OFFSET, SEEK_SET)
2457c478bd9Sstevel@tonic-gate 	    != KS_HASHED_PIN_SALT_LEN_OFFSET) {
2467c478bd9Sstevel@tonic-gate 		return (-1);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
24919193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)&salt_length,
2507c478bd9Sstevel@tonic-gate 	    KS_HASHED_PIN_SALT_LEN_SIZE) != KS_HASHED_PIN_SALT_LEN_SIZE) {
2517c478bd9Sstevel@tonic-gate 		return (-1);
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 	salt_length = SWAP64(salt_length);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	ks_hashed_pinlen_offset = KS_HASHED_PIN_SALT_LEN_OFFSET
2567c478bd9Sstevel@tonic-gate 	    + KS_HASHED_PIN_SALT_LEN_SIZE + salt_length;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	return (0);
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate /*
2637c478bd9Sstevel@tonic-gate  * acquire or release read/write lock on a specific file
2647c478bd9Sstevel@tonic-gate  *
2657c478bd9Sstevel@tonic-gate  * read_lock: true for read lock; false for write lock
2667c478bd9Sstevel@tonic-gate  * set_lock:  true to set a lock; false to release a lock
2677c478bd9Sstevel@tonic-gate  */
2687c478bd9Sstevel@tonic-gate static int
lock_file(int fd,boolean_t read_lock,boolean_t set_lock)2697c478bd9Sstevel@tonic-gate lock_file(int fd, boolean_t read_lock, boolean_t set_lock)
2707c478bd9Sstevel@tonic-gate {
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	flock_t lock_info;
2737c478bd9Sstevel@tonic-gate 	int r;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	lock_info.l_whence = SEEK_SET;
2767c478bd9Sstevel@tonic-gate 	lock_info.l_start = 0;
2777c478bd9Sstevel@tonic-gate 	lock_info.l_len = 0; /* l_len == 0 means until end of  file */
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	if (read_lock) {
2807c478bd9Sstevel@tonic-gate 		lock_info.l_type = F_RDLCK;
2817c478bd9Sstevel@tonic-gate 	} else {
2827c478bd9Sstevel@tonic-gate 		lock_info.l_type = F_WRLCK;
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	if (set_lock) {
2867c478bd9Sstevel@tonic-gate 		while ((r = fcntl(fd, F_SETLKW, &lock_info)) == -1) {
2877c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
2887c478bd9Sstevel@tonic-gate 				break;
2897c478bd9Sstevel@tonic-gate 		}
2907c478bd9Sstevel@tonic-gate 		if (r == -1) {
2917c478bd9Sstevel@tonic-gate 			return (-1);
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate 	} else {
2947c478bd9Sstevel@tonic-gate 		lock_info.l_type = F_UNLCK;
2957c478bd9Sstevel@tonic-gate 		while ((r = fcntl(fd, F_SETLKW, &lock_info)) == -1) {
2967c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
2977c478bd9Sstevel@tonic-gate 				break;
2987c478bd9Sstevel@tonic-gate 		}
2997c478bd9Sstevel@tonic-gate 		if (r == -1) {
3007c478bd9Sstevel@tonic-gate 			return (-1);
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	return (0);
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate 
307c5866e1dSPeter Shoults int
create_keystore()3087c478bd9Sstevel@tonic-gate create_keystore()
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 	int fd, buf;
3117c478bd9Sstevel@tonic-gate 	uint64_t hashed_pin_len, hashed_pin_salt_len, ulong_buf;
3127c478bd9Sstevel@tonic-gate 	uchar_t ver_buf[KS_PKCS11_VER_SIZE];
3137c478bd9Sstevel@tonic-gate 	char pub_obj_path[MAXPATHLEN], pri_obj_path[MAXPATHLEN],
3147c478bd9Sstevel@tonic-gate 	    ks_desc_file[MAXPATHLEN];
3157c478bd9Sstevel@tonic-gate 	CK_BYTE salt[KS_KEY_SALT_SIZE];
3167c478bd9Sstevel@tonic-gate 	char *hashed_pin = NULL, *hashed_pin_salt = NULL;
317c5866e1dSPeter Shoults 	char *alt;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/* keystore doesn't exist, create keystore directory */
3207c478bd9Sstevel@tonic-gate 	if (mkdir(get_keystore_path(), S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3217c478bd9Sstevel@tonic-gate 		if (errno == EEXIST) {
3227c478bd9Sstevel@tonic-gate 			return (0);
3237c478bd9Sstevel@tonic-gate 		}
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 		if (errno == EACCES) {
3267c478bd9Sstevel@tonic-gate 			return (-1);
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 		/* can't create keystore directory */
3307c478bd9Sstevel@tonic-gate 		if (errno == ENOENT) { /* part of the path doesn't exist */
331c5866e1dSPeter Shoults 			char keystore[MAXPATHLEN];
3327c478bd9Sstevel@tonic-gate 			/*
333c5866e1dSPeter Shoults 			 * try to create $HOME/.sunw/pkcs11_softtoken if it
334c5866e1dSPeter Shoults 			 * doesn't exist.  If it is a alternate path provided
335c5866e1dSPeter Shoults 			 * by the user, it should have existed.  Will not
3367c478bd9Sstevel@tonic-gate 			 * create for them.
3377c478bd9Sstevel@tonic-gate 			 */
338c5866e1dSPeter Shoults 			alt = getenv(ALTERNATE_KEYSTORE_PATH);
339c5866e1dSPeter Shoults 			if ((alt == NULL) || (strcmp(alt, "") == 0)) {
340c5866e1dSPeter Shoults 				char *home = getenv("HOME");
3417c478bd9Sstevel@tonic-gate 
342c5866e1dSPeter Shoults 				if (home == NULL || strcmp(home, "") == 0) {
3437c478bd9Sstevel@tonic-gate 					return (-1);
3447c478bd9Sstevel@tonic-gate 				}
3457c478bd9Sstevel@tonic-gate 				/* create $HOME/.sunw/pkcs11_softtoken */
346c5866e1dSPeter Shoults 				(void) snprintf(keystore, sizeof (keystore),
3471fa2a72aSPeter Shoults 				    "%s/%s/%s", home, SUNW_PATH, KEYSTORE_PATH);
348c5866e1dSPeter Shoults 				if (mkdirp(keystore,
3497c478bd9Sstevel@tonic-gate 				    S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3507c478bd9Sstevel@tonic-gate 					return (-1);
3517c478bd9Sstevel@tonic-gate 				}
3527c478bd9Sstevel@tonic-gate 			} else {
3537c478bd9Sstevel@tonic-gate 				return (-1);
3547c478bd9Sstevel@tonic-gate 			}
3557c478bd9Sstevel@tonic-gate 		}
3567c478bd9Sstevel@tonic-gate 	}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	/* create keystore description file */
35919193bb6SDina K Nimeh 	fd = open_nointr(get_desc_file_path(ks_desc_file),
36019193bb6SDina K Nimeh 	    O_RDWR|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
3617c478bd9Sstevel@tonic-gate 	if (fd < 0) {
3627c478bd9Sstevel@tonic-gate 		if (errno == EEXIST) {
3637c478bd9Sstevel@tonic-gate 			return (0);
3647c478bd9Sstevel@tonic-gate 		} else {
3657c478bd9Sstevel@tonic-gate 			/* can't create keystore description file */
3667c478bd9Sstevel@tonic-gate 			(void) rmdir(get_keystore_path());
3677c478bd9Sstevel@tonic-gate 			return (-1);
3687c478bd9Sstevel@tonic-gate 		}
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	if (lock_file(fd, B_FALSE, B_TRUE) != 0) {
3727c478bd9Sstevel@tonic-gate 		(void) unlink(ks_desc_file);
3737c478bd9Sstevel@tonic-gate 		(void) close(fd);
3747c478bd9Sstevel@tonic-gate 		(void) rmdir(get_keystore_path());
3757c478bd9Sstevel@tonic-gate 		return (-1);
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	if (mkdir(get_pub_obj_path(pub_obj_path),
3797c478bd9Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3807c478bd9Sstevel@tonic-gate 		/* can't create directory for public objects */
3817c478bd9Sstevel@tonic-gate 		(void) lock_file(fd, B_FALSE, B_FALSE);
3827c478bd9Sstevel@tonic-gate 		(void) unlink(ks_desc_file);
3837c478bd9Sstevel@tonic-gate 		(void) close(fd);
3847c478bd9Sstevel@tonic-gate 		(void) rmdir(get_keystore_path());
3857c478bd9Sstevel@tonic-gate 		return (-1);
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	if (mkdir(get_pri_obj_path(pri_obj_path),
3897c478bd9Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3907c478bd9Sstevel@tonic-gate 		/* can't create directory for private objects */
3917c478bd9Sstevel@tonic-gate 		(void) lock_file(fd, B_FALSE, B_FALSE);
3927c478bd9Sstevel@tonic-gate 		(void) unlink(ks_desc_file);
3937c478bd9Sstevel@tonic-gate 		(void) close(fd);
3947c478bd9Sstevel@tonic-gate 		(void) rmdir(get_keystore_path());
3957c478bd9Sstevel@tonic-gate 		(void) rmdir(pub_obj_path);
3967c478bd9Sstevel@tonic-gate 		return (-1);
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	/* write file format release number */
4017c478bd9Sstevel@tonic-gate 	bzero(ver_buf, sizeof (ver_buf));
4027c478bd9Sstevel@tonic-gate 	(void) strcpy((char *)ver_buf, KS_PKCS11_VER);
40319193bb6SDina K Nimeh 	if ((writen_nointr(fd, (char *)ver_buf, sizeof (ver_buf)))
4047c478bd9Sstevel@tonic-gate 	    != sizeof (ver_buf)) {
4057c478bd9Sstevel@tonic-gate 		goto cleanup;
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	/* write version number, version = 0 since keystore just created */
4097c478bd9Sstevel@tonic-gate 	buf = SWAP32(0);
41019193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)&buf, KS_VER_SIZE) != KS_VER_SIZE) {
4117c478bd9Sstevel@tonic-gate 		goto cleanup;
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	/* write monotonic-counter.  Counter for keystore objects start at 1 */
4157c478bd9Sstevel@tonic-gate 	buf = SWAP32(1);
41619193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)&buf, KS_COUNTER_SIZE)
4177c478bd9Sstevel@tonic-gate 	    != KS_COUNTER_SIZE) {
4187c478bd9Sstevel@tonic-gate 		goto cleanup;
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	/* initial encryption key salt should be all NULL */
4227c478bd9Sstevel@tonic-gate 	bzero(salt, sizeof (salt));
42319193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)salt, KS_KEY_SALT_SIZE)
4247c478bd9Sstevel@tonic-gate 	    != KS_KEY_SALT_SIZE) {
4257c478bd9Sstevel@tonic-gate 		goto cleanup;
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	/* initial HMAC key salt should also be all NULL */
42919193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)salt, KS_HMAC_SALT_SIZE)
4307c478bd9Sstevel@tonic-gate 	    != KS_HMAC_SALT_SIZE) {
4317c478bd9Sstevel@tonic-gate 		goto cleanup;
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	/* generate the hashed pin salt, and MD5 hashed pin of default pin */
4357c478bd9Sstevel@tonic-gate 	if (soft_gen_hashed_pin((CK_CHAR_PTR)SOFT_DEFAULT_PIN, &hashed_pin,
4367c478bd9Sstevel@tonic-gate 	    &hashed_pin_salt) < 0) {
4377c478bd9Sstevel@tonic-gate 		goto cleanup;
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	if ((hashed_pin_salt == NULL) || (hashed_pin == NULL)) {
4417c478bd9Sstevel@tonic-gate 		goto cleanup;
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	hashed_pin_salt_len = (uint64_t)strlen(hashed_pin_salt);
4457c478bd9Sstevel@tonic-gate 	hashed_pin_len = (uint64_t)strlen(hashed_pin);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	/* write hashed pin salt length */
4487c478bd9Sstevel@tonic-gate 	ulong_buf = SWAP64(hashed_pin_salt_len);
44919193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)&ulong_buf, KS_HASHED_PIN_SALT_LEN_SIZE)
4507c478bd9Sstevel@tonic-gate 	    != KS_HASHED_PIN_SALT_LEN_SIZE) {
4517c478bd9Sstevel@tonic-gate 		goto cleanup;
4527c478bd9Sstevel@tonic-gate 	}
4537c478bd9Sstevel@tonic-gate 
45419193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)hashed_pin_salt,
4557c478bd9Sstevel@tonic-gate 	    hashed_pin_salt_len) != hashed_pin_salt_len) {
4567c478bd9Sstevel@tonic-gate 		goto cleanup;
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	/* write MD5 hashed pin of the default pin */
4607c478bd9Sstevel@tonic-gate 	ulong_buf = SWAP64(hashed_pin_len);
46119193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)&ulong_buf, KS_HASHED_PINLEN_SIZE)
4627c478bd9Sstevel@tonic-gate 	    != KS_HASHED_PINLEN_SIZE) {
4637c478bd9Sstevel@tonic-gate 		goto cleanup;
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 
46619193bb6SDina K Nimeh 	if (writen_nointr(fd, (void *)hashed_pin, hashed_pin_len)
4677c478bd9Sstevel@tonic-gate 	    != hashed_pin_len) {
4687c478bd9Sstevel@tonic-gate 		goto cleanup;
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	(void) lock_file(fd, B_FALSE, B_FALSE);
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	(void) close(fd);
474*a8793c76SJason King 	freezero(hashed_pin_salt, hashed_pin_salt_len);
4757c478bd9Sstevel@tonic-gate 	return (0);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate cleanup:
4787c478bd9Sstevel@tonic-gate 	(void) lock_file(fd, B_FALSE, B_FALSE);
4797c478bd9Sstevel@tonic-gate 	(void) unlink(ks_desc_file);
4807c478bd9Sstevel@tonic-gate 	(void) close(fd);
4817c478bd9Sstevel@tonic-gate 	(void) rmdir(get_keystore_path());
4827c478bd9Sstevel@tonic-gate 	(void) rmdir(pub_obj_path);
4837c478bd9Sstevel@tonic-gate 	(void) rmdir(pri_obj_path);
4847c478bd9Sstevel@tonic-gate 	return (-1);
4857c478bd9Sstevel@tonic-gate }
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate /*
4887c478bd9Sstevel@tonic-gate  * Determines if the file referenced by "fd" has the same
4897c478bd9Sstevel@tonic-gate  * inode as the file referenced by "fname".
4907c478bd9Sstevel@tonic-gate  *
4917c478bd9Sstevel@tonic-gate  * The argument "same" contains the result of determining
4927c478bd9Sstevel@tonic-gate  * if the inode is the same or not
4937c478bd9Sstevel@tonic-gate  *
4947c478bd9Sstevel@tonic-gate  * Returns 0 if there's no error.
4957c478bd9Sstevel@tonic-gate  * Returns 1 if there's any error with opening the file.
4967c478bd9Sstevel@tonic-gate  *
4977c478bd9Sstevel@tonic-gate  *
4987c478bd9Sstevel@tonic-gate  */
4997c478bd9Sstevel@tonic-gate static int
is_inode_same(int fd,char * fname,boolean_t * same)5007c478bd9Sstevel@tonic-gate is_inode_same(int fd, char *fname, boolean_t *same)
5017c478bd9Sstevel@tonic-gate {
5027c478bd9Sstevel@tonic-gate 	struct stat fn_stat, fd_stat;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	if (fstat(fd, &fd_stat) != 0) {
5057c478bd9Sstevel@tonic-gate 		return (-1);
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	if (stat(fname, &fn_stat) != 0) {
5097c478bd9Sstevel@tonic-gate 		return (-1);
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	/* It's the same file if both st_ino and st_dev match */
5137c478bd9Sstevel@tonic-gate 	if ((fd_stat.st_ino == fn_stat.st_ino) &&
5147c478bd9Sstevel@tonic-gate 	    (fd_stat.st_dev == fn_stat.st_dev)) {
5157c478bd9Sstevel@tonic-gate 		*same = B_TRUE;
5167c478bd9Sstevel@tonic-gate 	} else {
5177c478bd9Sstevel@tonic-gate 		*same = B_FALSE;
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 	return (0);
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate static int
acquire_file_lock(int * fd,char * fname,mode_t mode)523*a8793c76SJason King acquire_file_lock(int *fd, char *fname, mode_t mode)
524*a8793c76SJason King {
5257c478bd9Sstevel@tonic-gate 	boolean_t read_lock = B_TRUE, same_inode;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	if ((mode == O_RDWR) || (mode == O_WRONLY)) {
5287c478bd9Sstevel@tonic-gate 		read_lock = B_FALSE;
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if (lock_file(*fd, read_lock, B_TRUE) != 0) {
5327c478bd9Sstevel@tonic-gate 		return (-1);
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	/*
5367c478bd9Sstevel@tonic-gate 	 * make sure another process did not modify the file
5377c478bd9Sstevel@tonic-gate 	 * while we were trying to get the lock
5387c478bd9Sstevel@tonic-gate 	 */
5397c478bd9Sstevel@tonic-gate 	if (is_inode_same(*fd, fname, &same_inode) != 0) {
5407c478bd9Sstevel@tonic-gate 		(void) lock_file(*fd, B_TRUE, B_FALSE); /* unlock file */
5417c478bd9Sstevel@tonic-gate 		return (-1);
5427c478bd9Sstevel@tonic-gate 	}
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	while (!same_inode) {
5457c478bd9Sstevel@tonic-gate 		/*
5467c478bd9Sstevel@tonic-gate 		 * need to unlock file, close, re-open the file,
5477c478bd9Sstevel@tonic-gate 		 * and re-acquire the lock
5487c478bd9Sstevel@tonic-gate 		 */
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 		/* unlock file */
5517c478bd9Sstevel@tonic-gate 		if (lock_file(*fd, B_TRUE, B_FALSE) != 0) {
5527c478bd9Sstevel@tonic-gate 			return (-1);
5537c478bd9Sstevel@tonic-gate 		}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 		(void) close(*fd);
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 		/* re-open */
55819193bb6SDina K Nimeh 		*fd = open_nointr(fname, mode|O_NONBLOCK);
5597c478bd9Sstevel@tonic-gate 		if (*fd < 0) {
5607c478bd9Sstevel@tonic-gate 			return (-1);
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 		/* acquire lock again */
5647c478bd9Sstevel@tonic-gate 		if (lock_file(*fd, read_lock, B_TRUE) != 0) {
5657c478bd9Sstevel@tonic-gate 			return (-1);
5667c478bd9Sstevel@tonic-gate 		}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 		if (is_inode_same(*fd, fname, &same_inode) != 0) {
5697c478bd9Sstevel@tonic-gate 			(void) lock_file(*fd, B_TRUE, B_FALSE); /* unlock */
5707c478bd9Sstevel@tonic-gate 			return (-1);
5717c478bd9Sstevel@tonic-gate 		}
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	return (0);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate /*
5797c478bd9Sstevel@tonic-gate  * Open the keystore description file in the specified mode.
5807c478bd9Sstevel@tonic-gate  * If the keystore doesn't exist, the "do_create_keystore"
5817c478bd9Sstevel@tonic-gate  * argument determines if the keystore should be created
5827c478bd9Sstevel@tonic-gate  */
5837c478bd9Sstevel@tonic-gate static int
open_and_lock_keystore_desc(mode_t mode,boolean_t do_create_keystore,boolean_t lock_held)5847c478bd9Sstevel@tonic-gate open_and_lock_keystore_desc(mode_t mode, boolean_t do_create_keystore,
5857c478bd9Sstevel@tonic-gate     boolean_t lock_held)
5867c478bd9Sstevel@tonic-gate {
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	int fd;
5897c478bd9Sstevel@tonic-gate 	char *fname, ks_desc_file[MAXPATHLEN];
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	/* open the keystore description file in requested mode */
5927c478bd9Sstevel@tonic-gate 	fname = get_desc_file_path(ks_desc_file);
59319193bb6SDina K Nimeh 	fd = open_nointr(fname, mode|O_NONBLOCK);
5947c478bd9Sstevel@tonic-gate 	if (fd < 0) {
5957c478bd9Sstevel@tonic-gate 		if ((errno == ENOENT) && (do_create_keystore)) {
5967c478bd9Sstevel@tonic-gate 			if (create_keystore() < 0) {
5977c478bd9Sstevel@tonic-gate 				goto done;
5987c478bd9Sstevel@tonic-gate 			}
59919193bb6SDina K Nimeh 			fd = open_nointr(fname, mode|O_NONBLOCK);
6007c478bd9Sstevel@tonic-gate 			if (fd < 0) {
6017c478bd9Sstevel@tonic-gate 				goto done;
6027c478bd9Sstevel@tonic-gate 			}
6037c478bd9Sstevel@tonic-gate 		} else {
6047c478bd9Sstevel@tonic-gate 			goto done;
6057c478bd9Sstevel@tonic-gate 		}
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	if (lock_held) {
6097c478bd9Sstevel@tonic-gate 		/* already hold the lock */
6107c478bd9Sstevel@tonic-gate 		return (fd);
6117c478bd9Sstevel@tonic-gate 	}
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	if (acquire_file_lock(&fd, fname, mode) != 0) {
6147c478bd9Sstevel@tonic-gate 		if (fd > 0) {
6157c478bd9Sstevel@tonic-gate 			(void) close(fd);
6167c478bd9Sstevel@tonic-gate 		}
6177c478bd9Sstevel@tonic-gate 		return (-1);
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate done:
6217c478bd9Sstevel@tonic-gate 	return (fd);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate /*
6267c478bd9Sstevel@tonic-gate  * Set or remove read or write lock on keystore description file
6277c478bd9Sstevel@tonic-gate  *
6287c478bd9Sstevel@tonic-gate  * read_lock: true for read lock, false for write lock
6297c478bd9Sstevel@tonic-gate  * set_lock: true for set a lock, false to remove a lock
6307c478bd9Sstevel@tonic-gate  */
6317c478bd9Sstevel@tonic-gate static int
lock_desc_file(boolean_t read_lock,boolean_t set_lock)6327c478bd9Sstevel@tonic-gate lock_desc_file(boolean_t read_lock, boolean_t set_lock)
6337c478bd9Sstevel@tonic-gate {
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	char ks_desc_file[MAXPATHLEN];
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	if (set_lock) {
6387c478bd9Sstevel@tonic-gate 		int oflag;
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 		/*
6417c478bd9Sstevel@tonic-gate 		 * make sure desc_fd is not already used.  If used, it means
6427c478bd9Sstevel@tonic-gate 		 * some other lock is already set on the file
6437c478bd9Sstevel@tonic-gate 		 */
6447c478bd9Sstevel@tonic-gate 		if (desc_fd > 0) {
6457c478bd9Sstevel@tonic-gate 			return (-1);
6467c478bd9Sstevel@tonic-gate 		}
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 		(void) get_desc_file_path(ks_desc_file);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		if (read_lock) {
6517c478bd9Sstevel@tonic-gate 			oflag = O_RDONLY;
6527c478bd9Sstevel@tonic-gate 		} else {
6537c478bd9Sstevel@tonic-gate 			oflag = O_WRONLY;
6547c478bd9Sstevel@tonic-gate 		}
6557c478bd9Sstevel@tonic-gate 		if ((desc_fd = open_and_lock_keystore_desc(oflag,
6567c478bd9Sstevel@tonic-gate 		    B_FALSE, B_FALSE)) < 0) {
6577c478bd9Sstevel@tonic-gate 			return (-1);
6587c478bd9Sstevel@tonic-gate 		}
6597c478bd9Sstevel@tonic-gate 	} else {
6607c478bd9Sstevel@tonic-gate 		/* make sure we have a valid fd */
6617c478bd9Sstevel@tonic-gate 		if (desc_fd <= 0) {
6627c478bd9Sstevel@tonic-gate 			return (-1);
6637c478bd9Sstevel@tonic-gate 		}
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 		if (lock_file(desc_fd, read_lock, B_FALSE) == 1) {
6667c478bd9Sstevel@tonic-gate 			return (-1);
6677c478bd9Sstevel@tonic-gate 		}
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 		(void) close(desc_fd);
6707c478bd9Sstevel@tonic-gate 		desc_fd = 0;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 	return (0);
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate static int
open_and_lock_object_file(ks_obj_handle_t * ks_handle,int oflag,boolean_t lock_held)6777c478bd9Sstevel@tonic-gate open_and_lock_object_file(ks_obj_handle_t *ks_handle, int oflag,
6787c478bd9Sstevel@tonic-gate     boolean_t lock_held)
6797c478bd9Sstevel@tonic-gate {
6807c478bd9Sstevel@tonic-gate 	char obj_fname[MAXPATHLEN];
6817c478bd9Sstevel@tonic-gate 	int fd;
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	if (ks_handle->public) {
6847c478bd9Sstevel@tonic-gate 		char pub_obj_path[MAXPATHLEN];
6857c478bd9Sstevel@tonic-gate 		(void) snprintf(obj_fname, MAXPATHLEN, "%s/%s",
6867c478bd9Sstevel@tonic-gate 		    get_pub_obj_path(pub_obj_path), ks_handle->name);
6877c478bd9Sstevel@tonic-gate 	} else {
6887c478bd9Sstevel@tonic-gate 		char pri_obj_path[MAXPATHLEN];
6897c478bd9Sstevel@tonic-gate 		(void) snprintf(obj_fname, MAXPATHLEN, "%s/%s",
6907c478bd9Sstevel@tonic-gate 		    get_pri_obj_path(pri_obj_path), ks_handle->name);
6917c478bd9Sstevel@tonic-gate 	}
6927c478bd9Sstevel@tonic-gate 
69319193bb6SDina K Nimeh 	fd = open_nointr(obj_fname, oflag|O_NONBLOCK);
6947c478bd9Sstevel@tonic-gate 	if (fd < 0) {
6957c478bd9Sstevel@tonic-gate 		return (-1);
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	if (lock_held) {
6997c478bd9Sstevel@tonic-gate 		/* already hold the lock */
7007c478bd9Sstevel@tonic-gate 		return (fd);
7017c478bd9Sstevel@tonic-gate 	}
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	if (acquire_file_lock(&fd, obj_fname, oflag) != 0) {
7047c478bd9Sstevel@tonic-gate 		if (fd > 0) {
7057c478bd9Sstevel@tonic-gate 			(void) close(fd);
7067c478bd9Sstevel@tonic-gate 		}
7077c478bd9Sstevel@tonic-gate 		return (-1);
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	return (fd);
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate /*
7167c478bd9Sstevel@tonic-gate  * Update file version number in a temporary file that's
7177c478bd9Sstevel@tonic-gate  * a copy of the keystore description file.
7187c478bd9Sstevel@tonic-gate  * The update is NOT made to the original keystore description
7197c478bd9Sstevel@tonic-gate  * file.  It makes the update in a tempoary file.
7207c478bd9Sstevel@tonic-gate  *
7217c478bd9Sstevel@tonic-gate  * Name of the temporary file is assumed to be provided, but
7227c478bd9Sstevel@tonic-gate  * the file is assumed to not exist.
7237c478bd9Sstevel@tonic-gate  *
7247c478bd9Sstevel@tonic-gate  * return 0 if creating temp file is successful, returns -1 otherwise
7257c478bd9Sstevel@tonic-gate  */
7267c478bd9Sstevel@tonic-gate static int
create_updated_keystore_version(int fd,char * tmp_fname)7277c478bd9Sstevel@tonic-gate create_updated_keystore_version(int fd, char *tmp_fname)
7287c478bd9Sstevel@tonic-gate {
7297c478bd9Sstevel@tonic-gate 	int version, tmp_fd;
7307c478bd9Sstevel@tonic-gate 	char buf[BUFSIZ];
7317c478bd9Sstevel@tonic-gate 	size_t nread;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	/* first, create the tempoary file */
73419193bb6SDina K Nimeh 	tmp_fd = open_nointr(tmp_fname,
73519193bb6SDina K Nimeh 	    O_WRONLY|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
7367c478bd9Sstevel@tonic-gate 	if (tmp_fd < 0) {
7377c478bd9Sstevel@tonic-gate 		return (-1);
7387c478bd9Sstevel@tonic-gate 	}
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	/*
7417c478bd9Sstevel@tonic-gate 	 * copy everything from keystore version to temp file except
7427c478bd9Sstevel@tonic-gate 	 * the keystore version.  Keystore version is updated
7437c478bd9Sstevel@tonic-gate 	 *
7447c478bd9Sstevel@tonic-gate 	 */
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	/* pkcs11 version */
74719193bb6SDina K Nimeh 	if (readn_nointr(fd, buf, KS_PKCS11_VER_SIZE) != KS_PKCS11_VER_SIZE) {
7487c478bd9Sstevel@tonic-gate 		goto cleanup;
7497c478bd9Sstevel@tonic-gate 	}
7507c478bd9Sstevel@tonic-gate 
75119193bb6SDina K Nimeh 	if (writen_nointr(tmp_fd, buf, KS_PKCS11_VER_SIZE) !=
75219193bb6SDina K Nimeh 	    KS_PKCS11_VER_SIZE) {
7537c478bd9Sstevel@tonic-gate 		goto cleanup;
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	/* version number, it needs to be updated */
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	/* read the current version number */
75919193bb6SDina K Nimeh 	if (readn_nointr(fd, &version, KS_VER_SIZE) != KS_VER_SIZE) {
7607c478bd9Sstevel@tonic-gate 		goto cleanup;
7617c478bd9Sstevel@tonic-gate 	}
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
7647c478bd9Sstevel@tonic-gate 	version++;
7657c478bd9Sstevel@tonic-gate 	version = SWAP32(version);
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	/* write the updated value to the tmp file */
76819193bb6SDina K Nimeh 	if (writen_nointr(tmp_fd, (void *)&version, KS_VER_SIZE)
7697c478bd9Sstevel@tonic-gate 	    != KS_VER_SIZE) {
7707c478bd9Sstevel@tonic-gate 		goto cleanup;
7717c478bd9Sstevel@tonic-gate 	}
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	/* read rest of information, nothing needs to be updated */
77419193bb6SDina K Nimeh 	nread = readn_nointr(fd, buf, BUFSIZ);
7757c478bd9Sstevel@tonic-gate 	while (nread > 0) {
77619193bb6SDina K Nimeh 		if (writen_nointr(tmp_fd, buf, nread) != nread) {
7777c478bd9Sstevel@tonic-gate 			goto cleanup;
7787c478bd9Sstevel@tonic-gate 		}
77919193bb6SDina K Nimeh 		nread = readn_nointr(fd, buf, BUFSIZ);
7807c478bd9Sstevel@tonic-gate 	}
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	(void) close(tmp_fd);
7837c478bd9Sstevel@tonic-gate 	return (0);	/* no error */
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate cleanup:
7867c478bd9Sstevel@tonic-gate 	(void) close(tmp_fd);
7877c478bd9Sstevel@tonic-gate 	(void) remove(tmp_fname);
7887c478bd9Sstevel@tonic-gate 	return (-1);
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate static CK_RV
get_all_objs_in_dir(DIR * dirp,ks_obj_handle_t * ks_handle,ks_obj_t ** result_obj_list,boolean_t lock_held)7927c478bd9Sstevel@tonic-gate get_all_objs_in_dir(DIR *dirp, ks_obj_handle_t *ks_handle,
7934bc0a2efScasper     ks_obj_t **result_obj_list, boolean_t lock_held)
7947c478bd9Sstevel@tonic-gate {
7954bc0a2efScasper 	struct dirent *dp;
7967c478bd9Sstevel@tonic-gate 	ks_obj_t *obj;
7977c478bd9Sstevel@tonic-gate 	CK_RV rv;
7987c478bd9Sstevel@tonic-gate 
7994bc0a2efScasper 	while ((dp = readdir(dirp)) != NULL) {
8007c478bd9Sstevel@tonic-gate 
801d288ba74SAnthony Scarpino 		if (strncmp(dp->d_name, OBJ_PREFIX, OBJ_PREFIX_LEN) != 0)
8027c478bd9Sstevel@tonic-gate 			continue;
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 		(void) strcpy((char *)ks_handle->name, dp->d_name);
8057c478bd9Sstevel@tonic-gate 		rv = soft_keystore_get_single_obj(ks_handle, &obj, lock_held);
8067c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
8077c478bd9Sstevel@tonic-gate 			return (rv);
8087c478bd9Sstevel@tonic-gate 		}
8097c478bd9Sstevel@tonic-gate 		if (obj != NULL) {
8107c478bd9Sstevel@tonic-gate 			if (*result_obj_list == NULL) {
8117c478bd9Sstevel@tonic-gate 				*result_obj_list = obj;
8127c478bd9Sstevel@tonic-gate 			} else {
8137c478bd9Sstevel@tonic-gate 				obj->next = *result_obj_list;
8147c478bd9Sstevel@tonic-gate 				*result_obj_list = obj;
8157c478bd9Sstevel@tonic-gate 			}
8167c478bd9Sstevel@tonic-gate 		}
8177c478bd9Sstevel@tonic-gate 	}
8187c478bd9Sstevel@tonic-gate 	return (CKR_OK);
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate /*
8227c478bd9Sstevel@tonic-gate  * This function prepares the obj data for encryption by prepending
8237c478bd9Sstevel@tonic-gate  * the FULL path of the file that will be used for storing
8247c478bd9Sstevel@tonic-gate  * the object.  Having full path of the file as part of
8257c478bd9Sstevel@tonic-gate  * of the data for the object will prevent an attacker from
8267c478bd9Sstevel@tonic-gate  * copying a "bad" object into the keystore undetected.
8277c478bd9Sstevel@tonic-gate  *
8287c478bd9Sstevel@tonic-gate  * This function will always allocate:
8297c478bd9Sstevel@tonic-gate  *	MAXPATHLEN + buf_len
8307c478bd9Sstevel@tonic-gate  * amount of data.  If the full path of the filename doesn't occupy
8317c478bd9Sstevel@tonic-gate  * the whole MAXPATHLEN, the rest of the space will just be empty.
8327c478bd9Sstevel@tonic-gate  * It is the caller's responsibility to free the buffer allocated here.
8337c478bd9Sstevel@tonic-gate  *
8347c478bd9Sstevel@tonic-gate  * The allocated buffer is returned in the variable "prepared_buf"
8357c478bd9Sstevel@tonic-gate  * if there's no error.
8367c478bd9Sstevel@tonic-gate  *
8377c478bd9Sstevel@tonic-gate  * Returns 0 if there's no error, -1 otherwise.
8387c478bd9Sstevel@tonic-gate  */
8397c478bd9Sstevel@tonic-gate static int
prepare_data_for_encrypt(char * obj_path,unsigned char * buf,CK_ULONG buf_len,unsigned char ** prepared_buf,CK_ULONG * prepared_len)8407c478bd9Sstevel@tonic-gate prepare_data_for_encrypt(char *obj_path, unsigned char *buf, CK_ULONG buf_len,
8417c478bd9Sstevel@tonic-gate     unsigned char **prepared_buf, CK_ULONG *prepared_len)
8427c478bd9Sstevel@tonic-gate {
8437c478bd9Sstevel@tonic-gate 	*prepared_len = MAXPATHLEN + buf_len;
8447c478bd9Sstevel@tonic-gate 	*prepared_buf = malloc(*prepared_len);
8457c478bd9Sstevel@tonic-gate 	if (*prepared_buf == NULL) {
8467c478bd9Sstevel@tonic-gate 		return (-1);
8477c478bd9Sstevel@tonic-gate 	}
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	/*
8507c478bd9Sstevel@tonic-gate 	 * only zero out the space for the path name.  I could zero out
8517c478bd9Sstevel@tonic-gate 	 * the whole buffer, but that will be a waste of processing
8527c478bd9Sstevel@tonic-gate 	 * cycle since the rest of the buffer will be 100% filled all
8537c478bd9Sstevel@tonic-gate 	 * the time
8547c478bd9Sstevel@tonic-gate 	 */
8557c478bd9Sstevel@tonic-gate 	bzero(*prepared_buf, MAXPATHLEN);
8567c478bd9Sstevel@tonic-gate 	(void) memcpy(*prepared_buf, obj_path, strlen(obj_path));
8577c478bd9Sstevel@tonic-gate 	(void) memcpy(*prepared_buf + MAXPATHLEN, buf, buf_len);
8587c478bd9Sstevel@tonic-gate 	return (0);
8597c478bd9Sstevel@tonic-gate }
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate /*
8627c478bd9Sstevel@tonic-gate  * retrieves the hashed pin from the keystore
8637c478bd9Sstevel@tonic-gate  */
8647c478bd9Sstevel@tonic-gate static CK_RV
get_hashed_pin(int fd,char ** hashed_pin)8657c478bd9Sstevel@tonic-gate get_hashed_pin(int fd, char **hashed_pin)
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate 	uint64_t hashed_pin_size;
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	if (ks_hashed_pinlen_offset == -1) {
8707c478bd9Sstevel@tonic-gate 		if (calculate_hashed_pin_offset(fd) != 0) {
8717c478bd9Sstevel@tonic-gate 			return (CKR_FUNCTION_FAILED);
8727c478bd9Sstevel@tonic-gate 		}
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	/* first, get size of the hashed pin */
8767c478bd9Sstevel@tonic-gate 	if (lseek(fd, ks_hashed_pinlen_offset, SEEK_SET)
8777c478bd9Sstevel@tonic-gate 	    != ks_hashed_pinlen_offset) {
8787c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
8797c478bd9Sstevel@tonic-gate 	}
8807c478bd9Sstevel@tonic-gate 
88119193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)&hashed_pin_size,
8827c478bd9Sstevel@tonic-gate 	    KS_HASHED_PINLEN_SIZE) != KS_HASHED_PINLEN_SIZE) {
8837c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
8847c478bd9Sstevel@tonic-gate 	}
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	hashed_pin_size = SWAP64(hashed_pin_size);
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	*hashed_pin = malloc(hashed_pin_size + 1);
8897c478bd9Sstevel@tonic-gate 	if (*hashed_pin == NULL) {
8907c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
8917c478bd9Sstevel@tonic-gate 	}
8927c478bd9Sstevel@tonic-gate 
89319193bb6SDina K Nimeh 	if ((readn_nointr(fd, *hashed_pin, hashed_pin_size))
8947c478bd9Sstevel@tonic-gate 	    != (ssize_t)hashed_pin_size) {
895*a8793c76SJason King 		freezero(*hashed_pin, hashed_pin_size + 1);
8967c478bd9Sstevel@tonic-gate 		*hashed_pin = NULL;
8977c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate 	(*hashed_pin)[hashed_pin_size] = '\0';
9007c478bd9Sstevel@tonic-gate 	return (CKR_OK);
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate /*
9057c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_lock
9067c478bd9Sstevel@tonic-gate  *
9077c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
9087c478bd9Sstevel@tonic-gate  *		set_lock: TRUE to set readlock on the keystore object file,
9097c478bd9Sstevel@tonic-gate  *		          FALSE to remove readlock on keystore object file.
9107c478bd9Sstevel@tonic-gate  *
9117c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
9127c478bd9Sstevel@tonic-gate  *
9137c478bd9Sstevel@tonic-gate  *		0: success
9147c478bd9Sstevel@tonic-gate  *		-1: failure
9157c478bd9Sstevel@tonic-gate  *
9167c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
9177c478bd9Sstevel@tonic-gate  *
9187c478bd9Sstevel@tonic-gate  *		set or remove readlock on the keystore description file.
9197c478bd9Sstevel@tonic-gate  */
9207c478bd9Sstevel@tonic-gate int
soft_keystore_readlock(boolean_t set_lock)9217c478bd9Sstevel@tonic-gate soft_keystore_readlock(boolean_t set_lock)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	return (lock_desc_file(B_TRUE, set_lock));
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate /*
9297c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_writelock
9307c478bd9Sstevel@tonic-gate  *
9317c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
932*a8793c76SJason King  *		set_lock: TRUE to set writelock on the keystore description file
933*a8793c76SJason King  *			FALSE to remove write lock on keystore description file.
9347c478bd9Sstevel@tonic-gate  *
9357c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
9367c478bd9Sstevel@tonic-gate  *
9377c478bd9Sstevel@tonic-gate  *		0: no error
9387c478bd9Sstevel@tonic-gate  *		1: some error occurred
9397c478bd9Sstevel@tonic-gate  *
9407c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
9417c478bd9Sstevel@tonic-gate  *		set/reset writelock on the keystore description file.
9427c478bd9Sstevel@tonic-gate  */
9437c478bd9Sstevel@tonic-gate int
soft_keystore_writelock(boolean_t set_lock)9447c478bd9Sstevel@tonic-gate soft_keystore_writelock(boolean_t set_lock)
9457c478bd9Sstevel@tonic-gate {
9467c478bd9Sstevel@tonic-gate 	return (lock_desc_file(B_FALSE, set_lock));
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate /*
9517c478bd9Sstevel@tonic-gate  *
9527c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_lock_object
9537c478bd9Sstevel@tonic-gate  *
9547c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
9557c478bd9Sstevel@tonic-gate  *
9567c478bd9Sstevel@tonic-gate  *		ks_handle: handle of the keystore object file to be accessed.
957*a8793c76SJason King  *		read_lock: TRUE to set readlock on the keystore object file,
9587c478bd9Sstevel@tonic-gate  *			  FALSE to set writelock on keystore object file.
9597c478bd9Sstevel@tonic-gate  *
9607c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
9617c478bd9Sstevel@tonic-gate  *
9627c478bd9Sstevel@tonic-gate  *		If no error, file descriptor of locked file will be returned
9637c478bd9Sstevel@tonic-gate  *		-1: some error occurred
9647c478bd9Sstevel@tonic-gate  *
9657c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
9667c478bd9Sstevel@tonic-gate  *
9677c478bd9Sstevel@tonic-gate  *		set readlock or writelock on the keystore object file.
9687c478bd9Sstevel@tonic-gate  */
9697c478bd9Sstevel@tonic-gate int
soft_keystore_lock_object(ks_obj_handle_t * ks_handle,boolean_t read_lock)9707c478bd9Sstevel@tonic-gate soft_keystore_lock_object(ks_obj_handle_t *ks_handle, boolean_t read_lock)
9717c478bd9Sstevel@tonic-gate {
9727c478bd9Sstevel@tonic-gate 	int fd;
9737c478bd9Sstevel@tonic-gate 	int oflag;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	if (read_lock) {
9767c478bd9Sstevel@tonic-gate 		oflag = O_RDONLY;
9777c478bd9Sstevel@tonic-gate 	} else {
9787c478bd9Sstevel@tonic-gate 		oflag = O_WRONLY;
9797c478bd9Sstevel@tonic-gate 	}
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_object_file(ks_handle, oflag, B_FALSE)) < 0) {
9827c478bd9Sstevel@tonic-gate 		return (-1);
9837c478bd9Sstevel@tonic-gate 	}
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	return (fd);
9867c478bd9Sstevel@tonic-gate }
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate /*
9897c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_unlock_object
9907c478bd9Sstevel@tonic-gate  *
9917c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
9927c478bd9Sstevel@tonic-gate  *		fd: file descriptor returned from soft_keystore_lock_object
9937c478bd9Sstevel@tonic-gate  *
9947c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
9957c478bd9Sstevel@tonic-gate  *		0: no error
9967c478bd9Sstevel@tonic-gate  *		1: some error occurred while getting the pin
9977c478bd9Sstevel@tonic-gate  *
9987c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
9997c478bd9Sstevel@tonic-gate  *		set/reset writelock on the keystore object file.
10007c478bd9Sstevel@tonic-gate  */
10017c478bd9Sstevel@tonic-gate int
soft_keystore_unlock_object(int fd)10027c478bd9Sstevel@tonic-gate soft_keystore_unlock_object(int fd)
10037c478bd9Sstevel@tonic-gate {
10047c478bd9Sstevel@tonic-gate 	if (lock_file(fd, B_TRUE, B_FALSE) != 0) {
10057c478bd9Sstevel@tonic-gate 		return (1);
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	(void) close(fd);
10097c478bd9Sstevel@tonic-gate 	return (0);
10107c478bd9Sstevel@tonic-gate }
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate /*
10157c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_get_version
10167c478bd9Sstevel@tonic-gate  *
10177c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
10187c478bd9Sstevel@tonic-gate  *		version: pointer to caller allocated memory for storing
10197c478bd9Sstevel@tonic-gate  *			 the version of the keystore.
10207c478bd9Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
10217c478bd9Sstevel@tonic-gate  *
10227c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
10237c478bd9Sstevel@tonic-gate  *
10247c478bd9Sstevel@tonic-gate  *		0: no error
10257c478bd9Sstevel@tonic-gate  *		-1: some error occurred while getting the version number
10267c478bd9Sstevel@tonic-gate  *
10277c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
10287c478bd9Sstevel@tonic-gate  *		get the version number of the keystore from keystore
10297c478bd9Sstevel@tonic-gate  *		description file.
10307c478bd9Sstevel@tonic-gate  */
10317c478bd9Sstevel@tonic-gate int
soft_keystore_get_version(uint_t * version,boolean_t lock_held)10327c478bd9Sstevel@tonic-gate soft_keystore_get_version(uint_t *version, boolean_t lock_held)
10337c478bd9Sstevel@tonic-gate {
10347c478bd9Sstevel@tonic-gate 	int fd, ret_val = 0;
10357c478bd9Sstevel@tonic-gate 	uint_t buf;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDONLY,
1038c5866e1dSPeter Shoults 	    B_FALSE, lock_held)) < 0) {
10397c478bd9Sstevel@tonic-gate 		return (-1);
10407c478bd9Sstevel@tonic-gate 	}
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	if (lseek(fd, KS_VER_OFFSET, SEEK_SET) != KS_VER_OFFSET) {
10437c478bd9Sstevel@tonic-gate 		ret_val = -1;
10447c478bd9Sstevel@tonic-gate 		goto cleanup;
10457c478bd9Sstevel@tonic-gate 	}
10467c478bd9Sstevel@tonic-gate 
104719193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)&buf, KS_VER_SIZE) != KS_VER_SIZE) {
10487c478bd9Sstevel@tonic-gate 		ret_val = -1;
10497c478bd9Sstevel@tonic-gate 		goto cleanup;
10507c478bd9Sstevel@tonic-gate 	}
10517c478bd9Sstevel@tonic-gate 	*version = SWAP32(buf);
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate cleanup:
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	if (!lock_held) {
10567c478bd9Sstevel@tonic-gate 		if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
10577c478bd9Sstevel@tonic-gate 			ret_val = -1;
10587c478bd9Sstevel@tonic-gate 		}
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	(void) close(fd);
10627c478bd9Sstevel@tonic-gate 	return (ret_val);
10637c478bd9Sstevel@tonic-gate }
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate /*
10667c478bd9Sstevel@tonic-gate  *	FUNCTION: soft_keystore_get_object_version
10677c478bd9Sstevel@tonic-gate  *
10687c478bd9Sstevel@tonic-gate  *	ARGUMENTS:
10697c478bd9Sstevel@tonic-gate  *
10707c478bd9Sstevel@tonic-gate  *		ks_handle: handle of the key store object to be accessed.
10717c478bd9Sstevel@tonic-gate  *		version:
10727c478bd9Sstevel@tonic-gate  *			pointer to caller allocated memory for storing
10737c478bd9Sstevel@tonic-gate  *			the version of the object.
10747c478bd9Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
10757c478bd9Sstevel@tonic-gate  *
10767c478bd9Sstevel@tonic-gate  *	RETURN VALUE:
10777c478bd9Sstevel@tonic-gate  *
10787c478bd9Sstevel@tonic-gate  *		0: no error
10797c478bd9Sstevel@tonic-gate  *		-1: some error occurred while getting the pin
10807c478bd9Sstevel@tonic-gate  *
10817c478bd9Sstevel@tonic-gate  *	DESCRIPTION:
10827c478bd9Sstevel@tonic-gate  *		get the version number of the specified token object.
10837c478bd9Sstevel@tonic-gate  */
10847c478bd9Sstevel@tonic-gate int
soft_keystore_get_object_version(ks_obj_handle_t * ks_handle,uint_t * version,boolean_t lock_held)10857c478bd9Sstevel@tonic-gate soft_keystore_get_object_version(ks_obj_handle_t *ks_handle,
10867c478bd9Sstevel@tonic-gate     uint_t *version, boolean_t lock_held)
10877c478bd9Sstevel@tonic-gate {
10887c478bd9Sstevel@tonic-gate 	int fd, ret_val = 0;
10897c478bd9Sstevel@tonic-gate 	uint_t tmp;
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	if ((fd = open_and_lock_object_file(ks_handle, O_RDONLY,
10927c478bd9Sstevel@tonic-gate 	    lock_held)) < 0) {
10937c478bd9Sstevel@tonic-gate 		return (-1);
10947c478bd9Sstevel@tonic-gate 	}
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	/*
10977c478bd9Sstevel@tonic-gate 	 * read version.  Version is always first item in object file
10987c478bd9Sstevel@tonic-gate 	 * so, no need to do lseek
10997c478bd9Sstevel@tonic-gate 	 */
110019193bb6SDina K Nimeh 	if (readn_nointr(fd, (char *)&tmp, OBJ_VER_SIZE) != OBJ_VER_SIZE) {
11017c478bd9Sstevel@tonic-gate 		ret_val = -1;
11027c478bd9Sstevel@tonic-gate 		goto cleanup;
11037c478bd9Sstevel@tonic-gate 	}
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	*version = SWAP32(tmp);
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate cleanup:
11087c478bd9Sstevel@tonic-gate 	if (!lock_held) {
11097c478bd9Sstevel@tonic-gate 		if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
11107c478bd9Sstevel@tonic-gate 			ret_val = -1;
11117c478bd9Sstevel@tonic-gate 		}
11127c478bd9Sstevel@tonic-gate 	}
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	(void) close(fd);
11167c478bd9Sstevel@tonic-gate 	return (ret_val);
11177c478bd9Sstevel@tonic-gate }
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate /*
11207c478bd9Sstevel@tonic-gate  *		FUNCTION: soft_keystore_getpin
11217c478bd9Sstevel@tonic-gate  *
11227c478bd9Sstevel@tonic-gate  *		ARGUMENTS:
11237c478bd9Sstevel@tonic-gate  *			hashed_pin: pointer to caller allocated memory
11247c478bd9Sstevel@tonic-gate  *				for storing the pin to be returned.
11257c478bd9Sstevel@tonic-gate  *			lock_held: TRUE if the lock is held by caller.
11267c478bd9Sstevel@tonic-gate  *
11277c478bd9Sstevel@tonic-gate  *		RETURN VALUE:
11287c478bd9Sstevel@tonic-gate  *
11297c478bd9Sstevel@tonic-gate  *			0: no error
11307c478bd9Sstevel@tonic-gate  *			-1: some error occurred while getting the pin
11317c478bd9Sstevel@tonic-gate  *
11327c478bd9Sstevel@tonic-gate  *		DESCRIPTION:
11337c478bd9Sstevel@tonic-gate  *
11347c478bd9Sstevel@tonic-gate  *			Reads the MD5 hash from the keystore description
11357c478bd9Sstevel@tonic-gate  *			file and return it to the caller in the provided
11367c478bd9Sstevel@tonic-gate  *			buffer. If there is no PIN in the description file
11377c478bd9Sstevel@tonic-gate  *			because the file is just created, this function
11387c478bd9Sstevel@tonic-gate  *			will get a MD5 digest of the string "changeme",
11397c478bd9Sstevel@tonic-gate  *			store it in the file, and also return this
11407c478bd9Sstevel@tonic-gate  *			string to the caller.
11417c478bd9Sstevel@tonic-gate  */
11427c478bd9Sstevel@tonic-gate int
soft_keystore_getpin(char ** hashed_pin,boolean_t lock_held)11437c478bd9Sstevel@tonic-gate soft_keystore_getpin(char **hashed_pin, boolean_t lock_held)
11447c478bd9Sstevel@tonic-gate {
11457c478bd9Sstevel@tonic-gate 	int fd, ret_val = -1;
11467c478bd9Sstevel@tonic-gate 	CK_RV rv;
11477c478bd9Sstevel@tonic-gate 
1148c5866e1dSPeter Shoults 	if ((fd = open_and_lock_keystore_desc(O_RDONLY, B_FALSE,
11497c478bd9Sstevel@tonic-gate 	    lock_held)) < 0) {
11507c478bd9Sstevel@tonic-gate 		return (-1);
11517c478bd9Sstevel@tonic-gate 	}
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	rv = get_hashed_pin(fd, hashed_pin);
11547c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
11557c478bd9Sstevel@tonic-gate 		ret_val = 0;
11567c478bd9Sstevel@tonic-gate 	}
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate cleanup:
11597c478bd9Sstevel@tonic-gate 	if (!lock_held) {
11607c478bd9Sstevel@tonic-gate 		if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
11617c478bd9Sstevel@tonic-gate 			ret_val = -1;
11627c478bd9Sstevel@tonic-gate 		}
11637c478bd9Sstevel@tonic-gate 	}
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	(void) close(fd);
11667c478bd9Sstevel@tonic-gate 	return (ret_val);
11677c478bd9Sstevel@tonic-gate }
11687c478bd9Sstevel@tonic-gate 
11697b79d846SDina K Nimeh 
11707b79d846SDina K Nimeh /*
11717b79d846SDina K Nimeh  * Generate a 16-byte Initialization Vector (IV).
11727b79d846SDina K Nimeh  */
11737b79d846SDina K Nimeh CK_RV
soft_gen_iv(CK_BYTE * iv)11747b79d846SDina K Nimeh soft_gen_iv(CK_BYTE *iv)
11757b79d846SDina K Nimeh {
11767b79d846SDina K Nimeh 	return (pkcs11_get_nzero_urandom(iv, 16) < 0 ?
11777b79d846SDina K Nimeh 	    CKR_DEVICE_ERROR : CKR_OK);
11787b79d846SDina K Nimeh }
11797b79d846SDina K Nimeh 
11807b79d846SDina K Nimeh 
11817c478bd9Sstevel@tonic-gate /*
11827c478bd9Sstevel@tonic-gate  * This function reads all the data until the end of the file, and
11837c478bd9Sstevel@tonic-gate  * put the data into the "buf" in argument.  Memory for buf will
11847c478bd9Sstevel@tonic-gate  * be allocated in this function.  It is the caller's responsibility
11857c478bd9Sstevel@tonic-gate  * to free it.  The number of bytes read will be returned
11867c478bd9Sstevel@tonic-gate  * in the argument "bytes_read"
11877c478bd9Sstevel@tonic-gate  *
11887c478bd9Sstevel@tonic-gate  * returns CKR_OK if no error.  Other CKR error codes if there's an error
11897c478bd9Sstevel@tonic-gate  */
11907c478bd9Sstevel@tonic-gate static CK_RV
read_obj_data(int old_fd,char ** buf,ssize_t * bytes_read)11917c478bd9Sstevel@tonic-gate read_obj_data(int old_fd, char **buf, ssize_t *bytes_read)
11927c478bd9Sstevel@tonic-gate {
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 	ssize_t nread, loop_count;
11957c478bd9Sstevel@tonic-gate 	char *buf1 = NULL;
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	*buf = malloc(BUFSIZ);
11987c478bd9Sstevel@tonic-gate 	if (*buf == NULL) {
11997c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
12007c478bd9Sstevel@tonic-gate 	}
12017c478bd9Sstevel@tonic-gate 
120219193bb6SDina K Nimeh 	nread = readn_nointr(old_fd, *buf, BUFSIZ);
12037c478bd9Sstevel@tonic-gate 	if (nread < 0) {
12047c478bd9Sstevel@tonic-gate 		free(*buf);
12057c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
12067c478bd9Sstevel@tonic-gate 	}
12077c478bd9Sstevel@tonic-gate 	loop_count = 1;
12087c478bd9Sstevel@tonic-gate 	while (nread == (loop_count * BUFSIZ)) {
12097c478bd9Sstevel@tonic-gate 		ssize_t nread_tmp;
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 		loop_count++;
12127c478bd9Sstevel@tonic-gate 		/* more than BUFSIZ of data */
12137c478bd9Sstevel@tonic-gate 		buf1 = realloc(*buf, loop_count * BUFSIZ);
12147c478bd9Sstevel@tonic-gate 		if (buf1 == NULL) {
12157c478bd9Sstevel@tonic-gate 			free(*buf);
12167c478bd9Sstevel@tonic-gate 			return (CKR_HOST_MEMORY);
12177c478bd9Sstevel@tonic-gate 		}
12187c478bd9