10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51937Sizick  * Common Development and Distribution License (the "License").
61937Sizick  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
2212256SPeter.Shoults@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate  * Functions used for manipulating the keystore
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <stdio.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <errno.h>
320Sstevel@tonic-gate #include <sys/stat.h>
330Sstevel@tonic-gate #include <fcntl.h>
340Sstevel@tonic-gate #include <time.h>
350Sstevel@tonic-gate #include <unistd.h>
360Sstevel@tonic-gate #include <pwd.h>
370Sstevel@tonic-gate #include <sys/types.h>
380Sstevel@tonic-gate #include <dirent.h>
390Sstevel@tonic-gate #include <limits.h>
4012256SPeter.Shoults@Sun.COM #include <libgen.h>
410Sstevel@tonic-gate #include <strings.h>
420Sstevel@tonic-gate #include <security/cryptoki.h>
430Sstevel@tonic-gate #include <cryptoutil.h>
440Sstevel@tonic-gate #include "softGlobal.h"
450Sstevel@tonic-gate #include "softObject.h"
461937Sizick #include "softSession.h"
470Sstevel@tonic-gate #include "softKeystore.h"
480Sstevel@tonic-gate #include "softKeystoreUtil.h"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #define	MAXPATHLEN	1024
510Sstevel@tonic-gate #define	SUNW_PATH	".sunw"		/* top level Sun directory */
520Sstevel@tonic-gate #define	KEYSTORE_PATH	"pkcs11_softtoken"	/* keystore directory */
530Sstevel@tonic-gate #define	PUB_OBJ_DIR	"public"	/* directory for public objects */
540Sstevel@tonic-gate #define	PRI_OBJ_DIR	"private"	/* directory for private objects */
550Sstevel@tonic-gate #define	DS_FILE		"objstore_info"	/* keystore description file */
560Sstevel@tonic-gate #define	TMP_DS_FILE	"t_info"	/* temp name for keystore desc. file */
570Sstevel@tonic-gate #define	OBJ_PREFIX	"obj"	/* prefix of the keystore object file names */
589341SAnthony.Scarpino@Sun.COM #define	OBJ_PREFIX_LEN	sizeof (OBJ_PREFIX) - 1	/* length of prefix */
590Sstevel@tonic-gate #define	TMP_OBJ_PREFIX	"t_o"	/* prefix of the temp object file names */
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate  * KEYSTORE DESCRIPTION FILE:
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  * The following describes the content of the keystore description file
650Sstevel@tonic-gate  *
660Sstevel@tonic-gate  * The order AND data type of the fields are very important.
670Sstevel@tonic-gate  * All the code in this file assume that they are in the order specified
680Sstevel@tonic-gate  * below.  If either order of the fields or their data type changed,
690Sstevel@tonic-gate  * you must make sure the ALL the pre-define values are still valid
700Sstevel@tonic-gate  *
711937Sizick  * 1) PKCS#11 release number.  It's 2.20 in this release (uchar_t[32])
720Sstevel@tonic-gate  * 2) keystore version number: used for synchronizing when different
730Sstevel@tonic-gate  *    processes access the keystore at the same time.  It is incremented
740Sstevel@tonic-gate  *    when there is a change to the keystore. (uint_32)
750Sstevel@tonic-gate  * 3) monotonic-counter: last counter value for name of token object file.
760Sstevel@tonic-gate  *    used for assigning unique name to each token (uint_32)
770Sstevel@tonic-gate  * 4) salt used for generating encryption key (uint_16)
780Sstevel@tonic-gate  * 5) salt used for generating key used for doing HMAC (uint_16)
790Sstevel@tonic-gate  * 6) Length of salt used for generating hashed pin (length of salt
800Sstevel@tonic-gate  *    is variable)
810Sstevel@tonic-gate  * 7) Salt used for generating hashed pin.
820Sstevel@tonic-gate  * 8) Hashed pin len (length of hashed pin could be variable, the offset of
830Sstevel@tonic-gate  *    where this value lives in the file is calculated at run time)
840Sstevel@tonic-gate  * 9) Hashed pin
850Sstevel@tonic-gate  *
860Sstevel@tonic-gate  */
870Sstevel@tonic-gate 
880Sstevel@tonic-gate /* Keystore description file pre-defined values */
89676Sizick #define	KS_PKCS11_VER		"2.20"
900Sstevel@tonic-gate #define	KS_PKCS11_OFFSET	0
910Sstevel@tonic-gate #define	KS_PKCS11_VER_SIZE	32
920Sstevel@tonic-gate 
930Sstevel@tonic-gate #define	KS_VER_OFFSET		(KS_PKCS11_OFFSET + KS_PKCS11_VER_SIZE)
940Sstevel@tonic-gate #define	KS_VER_SIZE	4	/* size in bytes of keystore version value */
950Sstevel@tonic-gate 
960Sstevel@tonic-gate #define	KS_COUNTER_OFFSET	(KS_VER_OFFSET + KS_VER_SIZE)
970Sstevel@tonic-gate #define	KS_COUNTER_SIZE	4	/* size in bytes of the monotonic counter */
980Sstevel@tonic-gate 
990Sstevel@tonic-gate #define	KS_KEY_SALT_OFFSET	(KS_COUNTER_OFFSET + KS_COUNTER_SIZE)
1000Sstevel@tonic-gate #define	KS_KEY_SALT_SIZE	PBKD2_SALT_SIZE
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate #define	KS_HMAC_SALT_OFFSET	(KS_KEY_SALT_OFFSET + KS_KEY_SALT_SIZE)
1030Sstevel@tonic-gate #define	KS_HMAC_SALT_SIZE	PBKD2_SALT_SIZE
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate /* Salt for hashed pin */
1060Sstevel@tonic-gate #define	KS_HASHED_PIN_SALT_LEN_OFFSET (KS_HMAC_SALT_OFFSET + KS_HMAC_SALT_SIZE)
1070Sstevel@tonic-gate #define	KS_HASHED_PIN_SALT_LEN_SIZE 8 /* stores length of hashed pin salt */
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate #define	KS_HASHED_PIN_SALT_OFFSET \
1100Sstevel@tonic-gate 		(KS_HASHED_PIN_SALT_LEN_OFFSET + KS_HASHED_PIN_SALT_LEN_SIZE)
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate  * hashed pin
1140Sstevel@tonic-gate  *
1150Sstevel@tonic-gate  * hashed_pin length offset will be calculated at run time since
1160Sstevel@tonic-gate  * there's the hashed pin salt size is variable.
1170Sstevel@tonic-gate  *
1180Sstevel@tonic-gate  * The offset will be calculated at run time by calling the
1190Sstevel@tonic-gate  * function calculate_hashed_pin_offset()
1200Sstevel@tonic-gate  */
1210Sstevel@tonic-gate static off_t	ks_hashed_pinlen_offset = -1;
1220Sstevel@tonic-gate #define	KS_HASHED_PINLEN_SIZE	8
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /* End of Keystore description file pre-defined values */
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate  * Metadata for each object
1280Sstevel@tonic-gate  *
1290Sstevel@tonic-gate  * The order AND data type of all the fields is very important.
1300Sstevel@tonic-gate  * All the code in this file assume that they are in the order specified
1310Sstevel@tonic-gate  * below.  If either order of the fields or their data type is changed,
1320Sstevel@tonic-gate  * you must make sure the following pre-define value is still valid
1330Sstevel@tonic-gate  * Each object will have the meta data at the beginning of the object file.
1340Sstevel@tonic-gate  *
1350Sstevel@tonic-gate  * 1) object_version: used by softtoken to see if the object
1360Sstevel@tonic-gate  *    has been modified since it last reads it. (uint_32)
1370Sstevel@tonic-gate  * 2) iv: initialization vector for encrypted data in the object.  This
1380Sstevel@tonic-gate  *    value will be 0 for public objects.  (uchar_t[16])
1390Sstevel@tonic-gate  * 3) obj_hmac: keyed hash as verifier to detect private object
1400Sstevel@tonic-gate  *    being tampered this value will be 0 for public objects (uchar_t[16])
1410Sstevel@tonic-gate  */
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /* Object metadata pre-defined values */
1440Sstevel@tonic-gate #define	OBJ_VER_OFFSET	0
1450Sstevel@tonic-gate #define	OBJ_VER_SIZE	4	/* size of object version in bytes */
1460Sstevel@tonic-gate #define	OBJ_IV_OFFSET	(OBJ_VER_OFFSET + OBJ_VER_SIZE)
1470Sstevel@tonic-gate #define	OBJ_IV_SIZE	16
1480Sstevel@tonic-gate #define	OBJ_HMAC_OFFSET	(OBJ_IV_OFFSET + OBJ_IV_SIZE)
1490Sstevel@tonic-gate #define	OBJ_HMAC_SIZE	16	/* MD5 HMAC keyed hash */
1500Sstevel@tonic-gate #define	OBJ_DATA_OFFSET	(OBJ_HMAC_OFFSET + OBJ_HMAC_SIZE)
1510Sstevel@tonic-gate /* End of object metadata pre-defined values */
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate #define	ALTERNATE_KEYSTORE_PATH	"SOFTTOKEN_DIR"
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate static soft_object_t	*enc_key = NULL;
1560Sstevel@tonic-gate static soft_object_t	*hmac_key = NULL;
1570Sstevel@tonic-gate static char		keystore_path[MAXPATHLEN];
1580Sstevel@tonic-gate static boolean_t	keystore_path_initialized = B_FALSE;
1590Sstevel@tonic-gate static int		desc_fd = 0;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static char *
get_keystore_path()1620Sstevel@tonic-gate get_keystore_path()
1630Sstevel@tonic-gate {
16412256SPeter.Shoults@Sun.COM 	char *home = getenv("HOME");
16512256SPeter.Shoults@Sun.COM 	char *alt = getenv(ALTERNATE_KEYSTORE_PATH);
16612256SPeter.Shoults@Sun.COM 
16712256SPeter.Shoults@Sun.COM 	if (keystore_path_initialized) {
16812256SPeter.Shoults@Sun.COM 		return (keystore_path);
16912256SPeter.Shoults@Sun.COM 	}
17012256SPeter.Shoults@Sun.COM 
17112256SPeter.Shoults@Sun.COM 	bzero(keystore_path, sizeof (keystore_path));
17212256SPeter.Shoults@Sun.COM 	/*
17312256SPeter.Shoults@Sun.COM 	 * If it isn't set or is set to the empty string use the
17412256SPeter.Shoults@Sun.COM 	 * default location.  We need to check for the empty string
17512256SPeter.Shoults@Sun.COM 	 * because some users "unset" environment variables by giving
17612256SPeter.Shoults@Sun.COM 	 * them no value, this isn't the same thing as removing it
17712256SPeter.Shoults@Sun.COM 	 * from the environment.
17812256SPeter.Shoults@Sun.COM 	 *
17912256SPeter.Shoults@Sun.COM 	 * We don't want that to attempt to open /.sunw/pkcs11_sofftoken
18012256SPeter.Shoults@Sun.COM 	 */
18112256SPeter.Shoults@Sun.COM 	if ((alt != NULL) && (strcmp(alt, "") != 0)) {
18212256SPeter.Shoults@Sun.COM 		(void) snprintf(keystore_path, MAXPATHLEN, "%s/%s",
18312256SPeter.Shoults@Sun.COM 		    alt, KEYSTORE_PATH);
18412256SPeter.Shoults@Sun.COM 		keystore_path_initialized = B_TRUE;
18512256SPeter.Shoults@Sun.COM 	} else if ((home != NULL) && (strcmp(home, "") != 0)) {
18612256SPeter.Shoults@Sun.COM 		/* alternate path not specified, try user's home dir */
18712256SPeter.Shoults@Sun.COM 		(void) snprintf(keystore_path, MAXPATHLEN, "%s/%s/%s",
18812256SPeter.Shoults@Sun.COM 		    home, SUNW_PATH, KEYSTORE_PATH);
1890Sstevel@tonic-gate 		keystore_path_initialized = B_TRUE;
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 	return (keystore_path);
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate static char *
get_pub_obj_path(char * name)1950Sstevel@tonic-gate get_pub_obj_path(char *name)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	bzero(name, sizeof (name));
1980Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
1990Sstevel@tonic-gate 	    get_keystore_path(), PUB_OBJ_DIR);
2000Sstevel@tonic-gate 	return (name);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate static char *
get_pri_obj_path(char * name)2040Sstevel@tonic-gate get_pri_obj_path(char *name)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 	bzero(name, sizeof (name));
2070Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
2080Sstevel@tonic-gate 	    get_keystore_path(), PRI_OBJ_DIR);
2090Sstevel@tonic-gate 	return (name);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate static char *
get_desc_file_path(char * name)2130Sstevel@tonic-gate get_desc_file_path(char *name)
2140Sstevel@tonic-gate {
2150Sstevel@tonic-gate 	bzero(name, sizeof (name));
2160Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
2170Sstevel@tonic-gate 	    get_keystore_path(), DS_FILE);
2180Sstevel@tonic-gate 	return (name);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate static char *
get_tmp_desc_file_path(char * name)2220Sstevel@tonic-gate get_tmp_desc_file_path(char *name)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate 	bzero(name, sizeof (name));
2250Sstevel@tonic-gate 	(void) snprintf(name, MAXPATHLEN, "%s/%s",
2260Sstevel@tonic-gate 	    get_keystore_path(), TMP_DS_FILE);
2270Sstevel@tonic-gate 	return (name);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate /*
2310Sstevel@tonic-gate  * Calculates the offset for hashed_pin length and hashed pin
2320Sstevel@tonic-gate  *
2330Sstevel@tonic-gate  * Returns 0 if successful, -1 if there's any error.
2340Sstevel@tonic-gate  *
2350Sstevel@tonic-gate  * If successful, global variables "ks_hashed_pinlen_offset" will be set.
2360Sstevel@tonic-gate  *
2370Sstevel@tonic-gate  */
2380Sstevel@tonic-gate static int
calculate_hashed_pin_offset(int fd)2390Sstevel@tonic-gate calculate_hashed_pin_offset(int fd)
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate 	uint64_t salt_length;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	if (lseek(fd, KS_HASHED_PIN_SALT_LEN_OFFSET, SEEK_SET)
2440Sstevel@tonic-gate 	    != KS_HASHED_PIN_SALT_LEN_OFFSET) {
2450Sstevel@tonic-gate 		return (-1);
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate 
2488932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)&salt_length,
2490Sstevel@tonic-gate 	    KS_HASHED_PIN_SALT_LEN_SIZE) != KS_HASHED_PIN_SALT_LEN_SIZE) {
2500Sstevel@tonic-gate 		return (-1);
2510Sstevel@tonic-gate 	}
2520Sstevel@tonic-gate 	salt_length = SWAP64(salt_length);
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	ks_hashed_pinlen_offset = KS_HASHED_PIN_SALT_LEN_OFFSET
2550Sstevel@tonic-gate 	    + KS_HASHED_PIN_SALT_LEN_SIZE + salt_length;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	return (0);
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate /*
2620Sstevel@tonic-gate  * acquire or release read/write lock on a specific file
2630Sstevel@tonic-gate  *
2640Sstevel@tonic-gate  * read_lock: true for read lock; false for write lock
2650Sstevel@tonic-gate  * set_lock:  true to set a lock; false to release a lock
2660Sstevel@tonic-gate  */
2670Sstevel@tonic-gate static int
lock_file(int fd,boolean_t read_lock,boolean_t set_lock)2680Sstevel@tonic-gate lock_file(int fd, boolean_t read_lock, boolean_t set_lock)
2690Sstevel@tonic-gate {
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	flock_t lock_info;
2720Sstevel@tonic-gate 	int r;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	lock_info.l_whence = SEEK_SET;
2750Sstevel@tonic-gate 	lock_info.l_start = 0;
2760Sstevel@tonic-gate 	lock_info.l_len = 0; /* l_len == 0 means until end of  file */
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	if (read_lock) {
2790Sstevel@tonic-gate 		lock_info.l_type = F_RDLCK;
2800Sstevel@tonic-gate 	} else {
2810Sstevel@tonic-gate 		lock_info.l_type = F_WRLCK;
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	if (set_lock) {
2850Sstevel@tonic-gate 		while ((r = fcntl(fd, F_SETLKW, &lock_info)) == -1) {
2860Sstevel@tonic-gate 			if (errno != EINTR)
2870Sstevel@tonic-gate 				break;
2880Sstevel@tonic-gate 		}
2890Sstevel@tonic-gate 		if (r == -1) {
2900Sstevel@tonic-gate 			return (-1);
2910Sstevel@tonic-gate 		}
2920Sstevel@tonic-gate 	} else {
2930Sstevel@tonic-gate 		lock_info.l_type = F_UNLCK;
2940Sstevel@tonic-gate 		while ((r = fcntl(fd, F_SETLKW, &lock_info)) == -1) {
2950Sstevel@tonic-gate 			if (errno != EINTR)
2960Sstevel@tonic-gate 				break;
2970Sstevel@tonic-gate 		}
2980Sstevel@tonic-gate 		if (r == -1) {
2990Sstevel@tonic-gate 			return (-1);
3000Sstevel@tonic-gate 		}
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	return (0);
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate 
30612256SPeter.Shoults@Sun.COM int
create_keystore()3070Sstevel@tonic-gate create_keystore()
3080Sstevel@tonic-gate {
3090Sstevel@tonic-gate 	int fd, buf;
3100Sstevel@tonic-gate 	uint64_t hashed_pin_len, hashed_pin_salt_len, ulong_buf;
3110Sstevel@tonic-gate 	uchar_t ver_buf[KS_PKCS11_VER_SIZE];
3120Sstevel@tonic-gate 	char pub_obj_path[MAXPATHLEN], pri_obj_path[MAXPATHLEN],
3130Sstevel@tonic-gate 	    ks_desc_file[MAXPATHLEN];
3140Sstevel@tonic-gate 	CK_BYTE salt[KS_KEY_SALT_SIZE];
3150Sstevel@tonic-gate 	char *hashed_pin = NULL, *hashed_pin_salt = NULL;
31612256SPeter.Shoults@Sun.COM 	char *alt;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	/* keystore doesn't exist, create keystore directory */
3190Sstevel@tonic-gate 	if (mkdir(get_keystore_path(), S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3200Sstevel@tonic-gate 		if (errno == EEXIST) {
3210Sstevel@tonic-gate 			return (0);
3220Sstevel@tonic-gate 		}
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 		if (errno == EACCES) {
3250Sstevel@tonic-gate 			return (-1);
3260Sstevel@tonic-gate 		}
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 		/* can't create keystore directory */
3290Sstevel@tonic-gate 		if (errno == ENOENT) { /* part of the path doesn't exist */
33012256SPeter.Shoults@Sun.COM 			char keystore[MAXPATHLEN];
3310Sstevel@tonic-gate 			/*
33212256SPeter.Shoults@Sun.COM 			 * try to create $HOME/.sunw/pkcs11_softtoken if it
33312256SPeter.Shoults@Sun.COM 			 * doesn't exist.  If it is a alternate path provided
33412256SPeter.Shoults@Sun.COM 			 * by the user, it should have existed.  Will not
3350Sstevel@tonic-gate 			 * create for them.
3360Sstevel@tonic-gate 			 */
33712256SPeter.Shoults@Sun.COM 			alt = getenv(ALTERNATE_KEYSTORE_PATH);
33812256SPeter.Shoults@Sun.COM 			if ((alt == NULL) || (strcmp(alt, "") == 0)) {
33912256SPeter.Shoults@Sun.COM 				char *home = getenv("HOME");
34012256SPeter.Shoults@Sun.COM 
34112256SPeter.Shoults@Sun.COM 				if (home == NULL || strcmp(home, "") == 0) {
3420Sstevel@tonic-gate 					return (-1);
3430Sstevel@tonic-gate 				}
3440Sstevel@tonic-gate 				/* create $HOME/.sunw/pkcs11_softtoken */
34512256SPeter.Shoults@Sun.COM 				(void) snprintf(keystore, sizeof (keystore),
346*12517SPeter.Shoults@Sun.COM 				    "%s/%s/%s", home, SUNW_PATH, KEYSTORE_PATH);
34712256SPeter.Shoults@Sun.COM 				if (mkdirp(keystore,
3480Sstevel@tonic-gate 				    S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3490Sstevel@tonic-gate 					return (-1);
3500Sstevel@tonic-gate 				}
3510Sstevel@tonic-gate 			} else {
3520Sstevel@tonic-gate 				return (-1);
3530Sstevel@tonic-gate 			}
3540Sstevel@tonic-gate 		}
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	/* create keystore description file */
3588932SDina.Nimeh@Sun.COM 	fd = open_nointr(get_desc_file_path(ks_desc_file),
3598932SDina.Nimeh@Sun.COM 	    O_RDWR|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
3600Sstevel@tonic-gate 	if (fd < 0) {
3610Sstevel@tonic-gate 		if (errno == EEXIST) {
3620Sstevel@tonic-gate 			return (0);
3630Sstevel@tonic-gate 		} else {
3640Sstevel@tonic-gate 			/* can't create keystore description file */
3650Sstevel@tonic-gate 			(void) rmdir(get_keystore_path());
3660Sstevel@tonic-gate 			return (-1);
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	if (lock_file(fd, B_FALSE, B_TRUE) != 0) {
3710Sstevel@tonic-gate 		(void) unlink(ks_desc_file);
3720Sstevel@tonic-gate 		(void) close(fd);
3730Sstevel@tonic-gate 		(void) rmdir(get_keystore_path());
3740Sstevel@tonic-gate 		return (-1);
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	if (mkdir(get_pub_obj_path(pub_obj_path),
3780Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3790Sstevel@tonic-gate 		/* can't create directory for public objects */
3800Sstevel@tonic-gate 		(void) lock_file(fd, B_FALSE, B_FALSE);
3810Sstevel@tonic-gate 		(void) unlink(ks_desc_file);
3820Sstevel@tonic-gate 		(void) close(fd);
3830Sstevel@tonic-gate 		(void) rmdir(get_keystore_path());
3840Sstevel@tonic-gate 		return (-1);
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	if (mkdir(get_pri_obj_path(pri_obj_path),
3880Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
3890Sstevel@tonic-gate 		/* can't create directory for private objects */
3900Sstevel@tonic-gate 		(void) lock_file(fd, B_FALSE, B_FALSE);
3910Sstevel@tonic-gate 		(void) unlink(ks_desc_file);
3920Sstevel@tonic-gate 		(void) close(fd);
3930Sstevel@tonic-gate 		(void) rmdir(get_keystore_path());
3940Sstevel@tonic-gate 		(void) rmdir(pub_obj_path);
3950Sstevel@tonic-gate 		return (-1);
3960Sstevel@tonic-gate 	}
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	/* write file format release number */
4000Sstevel@tonic-gate 	bzero(ver_buf, sizeof (ver_buf));
4010Sstevel@tonic-gate 	(void) strcpy((char *)ver_buf, KS_PKCS11_VER);
4028932SDina.Nimeh@Sun.COM 	if ((writen_nointr(fd, (char *)ver_buf, sizeof (ver_buf)))
4030Sstevel@tonic-gate 	    != sizeof (ver_buf)) {
4040Sstevel@tonic-gate 		goto cleanup;
4050Sstevel@tonic-gate 	}
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	/* write version number, version = 0 since keystore just created */
4080Sstevel@tonic-gate 	buf = SWAP32(0);
4098932SDina.Nimeh@Sun.COM 	if (writen_nointr(fd, (void *)&buf, KS_VER_SIZE) != KS_VER_SIZE) {
4100Sstevel@tonic-gate 		goto cleanup;
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	/* write monotonic-counter.  Counter for keystore objects start at 1 */
4140Sstevel@tonic-gate 	buf = SWAP32(1);
4158932SDina.Nimeh@Sun.COM 	if (writen_nointr(fd, (void *)&buf, KS_COUNTER_SIZE)
4160Sstevel@tonic-gate 	    != KS_COUNTER_SIZE) {
4170Sstevel@tonic-gate 		goto cleanup;
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	/* initial encryption key salt should be all NULL */
4210Sstevel@tonic-gate 	bzero(salt, sizeof (salt));
4228932SDina.Nimeh@Sun.COM 	if (writen_nointr(fd, (void *)salt, KS_KEY_SALT_SIZE)
4230Sstevel@tonic-gate 	    != KS_KEY_SALT_SIZE) {
4240Sstevel@tonic-gate 		goto cleanup;
4250Sstevel@tonic-gate 	}
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	/* initial HMAC key salt should also be all NULL */
4288932SDina.Nimeh@Sun.COM 	if (writen_nointr(fd, (void *)salt, KS_HMAC_SALT_SIZE)
4290Sstevel@tonic-gate 	    != KS_HMAC_SALT_SIZE) {
4300Sstevel@tonic-gate 		goto cleanup;
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	/* generate the hashed pin salt, and MD5 hashed pin of default pin */
4340Sstevel@tonic-gate 	if (soft_gen_hashed_pin((CK_CHAR_PTR)SOFT_DEFAULT_PIN, &hashed_pin,
4350Sstevel@tonic-gate 	    &hashed_pin_salt) < 0) {
4360Sstevel@tonic-gate 		goto cleanup;
4370Sstevel@tonic-gate 	}
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	if ((hashed_pin_salt == NULL) || (hashed_pin == NULL)) {
4400Sstevel@tonic-gate 		goto cleanup;
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	hashed_pin_salt_len = (uint64_t)strlen(hashed_pin_salt);
4440Sstevel@tonic-gate 	hashed_pin_len = (uint64_t)strlen(hashed_pin);
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	/* write hashed pin salt length */
4470Sstevel@tonic-gate 	ulong_buf = SWAP64(hashed_pin_salt_len);
4488932SDina.Nimeh@Sun.COM 	if (writen_nointr(fd, (void *)&ulong_buf, KS_HASHED_PIN_SALT_LEN_SIZE)
4490Sstevel@tonic-gate 	    != KS_HASHED_PIN_SALT_LEN_SIZE) {
4500Sstevel@tonic-gate 		goto cleanup;
4510Sstevel@tonic-gate 	}
4520Sstevel@tonic-gate 
4538932SDina.Nimeh@Sun.COM 	if (writen_nointr(fd, (void *)hashed_pin_salt,
4540Sstevel@tonic-gate 	    hashed_pin_salt_len) != hashed_pin_salt_len) {
4550Sstevel@tonic-gate 		goto cleanup;
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/* write MD5 hashed pin of the default pin */
4590Sstevel@tonic-gate 	ulong_buf = SWAP64(hashed_pin_len);
4608932SDina.Nimeh@Sun.COM 	if (writen_nointr(fd, (void *)&ulong_buf, KS_HASHED_PINLEN_SIZE)
4610Sstevel@tonic-gate 	    != KS_HASHED_PINLEN_SIZE) {
4620Sstevel@tonic-gate 		goto cleanup;
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4658932SDina.Nimeh@Sun.COM 	if (writen_nointr(fd, (void *)hashed_pin, hashed_pin_len)
4660Sstevel@tonic-gate 	    != hashed_pin_len) {
4670Sstevel@tonic-gate 		goto cleanup;
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	(void) lock_file(fd, B_FALSE, B_FALSE);
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	(void) close(fd);
4730Sstevel@tonic-gate 	if (hashed_pin_salt)
4748932SDina.Nimeh@Sun.COM 		free(hashed_pin_salt);
4750Sstevel@tonic-gate 	return (0);
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate cleanup:
4780Sstevel@tonic-gate 	(void) lock_file(fd, B_FALSE, B_FALSE);
4790Sstevel@tonic-gate 	(void) unlink(ks_desc_file);
4800Sstevel@tonic-gate 	(void) close(fd);
4810Sstevel@tonic-gate 	(void) rmdir(get_keystore_path());
4820Sstevel@tonic-gate 	(void) rmdir(pub_obj_path);
4830Sstevel@tonic-gate 	(void) rmdir(pri_obj_path);
4840Sstevel@tonic-gate 	return (-1);
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate /*
4880Sstevel@tonic-gate  * Determines if the file referenced by "fd" has the same
4890Sstevel@tonic-gate  * inode as the file referenced by "fname".
4900Sstevel@tonic-gate  *
4910Sstevel@tonic-gate  * The argument "same" contains the result of determining
4920Sstevel@tonic-gate  * if the inode is the same or not
4930Sstevel@tonic-gate  *
4940Sstevel@tonic-gate  * Returns 0 if there's no error.
4950Sstevel@tonic-gate  * Returns 1 if there's any error with opening the file.
4960Sstevel@tonic-gate  *
4970Sstevel@tonic-gate  *
4980Sstevel@tonic-gate  */
4990Sstevel@tonic-gate static int
is_inode_same(int fd,char * fname,boolean_t * same)5000Sstevel@tonic-gate is_inode_same(int fd, char *fname, boolean_t *same)
5010Sstevel@tonic-gate {
5020Sstevel@tonic-gate 	struct stat fn_stat, fd_stat;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	if (fstat(fd, &fd_stat) != 0) {
5050Sstevel@tonic-gate 		return (-1);
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	if (stat(fname, &fn_stat) != 0) {
5090Sstevel@tonic-gate 		return (-1);
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	/* It's the same file if both st_ino and st_dev match */
5130Sstevel@tonic-gate 	if ((fd_stat.st_ino == fn_stat.st_ino) &&
5140Sstevel@tonic-gate 	    (fd_stat.st_dev == fn_stat.st_dev)) {
5150Sstevel@tonic-gate 		*same = B_TRUE;
5160Sstevel@tonic-gate 	} else {
5170Sstevel@tonic-gate 		*same = B_FALSE;
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 	return (0);
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate static int
acquire_file_lock(int * fd,char * fname,mode_t mode)5230Sstevel@tonic-gate acquire_file_lock(int *fd, char *fname, mode_t mode) {
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	boolean_t read_lock = B_TRUE, same_inode;
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	if ((mode == O_RDWR) || (mode == O_WRONLY)) {
5280Sstevel@tonic-gate 		read_lock = B_FALSE;
5290Sstevel@tonic-gate 	}
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	if (lock_file(*fd, read_lock, B_TRUE) != 0) {
5320Sstevel@tonic-gate 		return (-1);
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	/*
5360Sstevel@tonic-gate 	 * make sure another process did not modify the file
5370Sstevel@tonic-gate 	 * while we were trying to get the lock
5380Sstevel@tonic-gate 	 */
5390Sstevel@tonic-gate 	if (is_inode_same(*fd, fname, &same_inode) != 0) {
5400Sstevel@tonic-gate 		(void) lock_file(*fd, B_TRUE, B_FALSE); /* unlock file */
5410Sstevel@tonic-gate 		return (-1);
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	while (!same_inode) {
5450Sstevel@tonic-gate 		/*
5460Sstevel@tonic-gate 		 * need to unlock file, close, re-open the file,
5470Sstevel@tonic-gate 		 * and re-acquire the lock
5480Sstevel@tonic-gate 		 */
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 		/* unlock file */
5510Sstevel@tonic-gate 		if (lock_file(*fd, B_TRUE, B_FALSE) != 0) {
5520Sstevel@tonic-gate 			return (-1);
5530Sstevel@tonic-gate 		}
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 		(void) close(*fd);
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 		/* re-open */
5588932SDina.Nimeh@Sun.COM 		*fd = open_nointr(fname, mode|O_NONBLOCK);
5590Sstevel@tonic-gate 		if (*fd < 0) {
5600Sstevel@tonic-gate 			return (-1);
5610Sstevel@tonic-gate 		}
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 		/* acquire lock again */
5640Sstevel@tonic-gate 		if (lock_file(*fd, read_lock, B_TRUE) != 0) {
5650Sstevel@tonic-gate 			return (-1);
5660Sstevel@tonic-gate 		}
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 		if (is_inode_same(*fd, fname, &same_inode) != 0) {
5690Sstevel@tonic-gate 			(void) lock_file(*fd, B_TRUE, B_FALSE); /* unlock */
5700Sstevel@tonic-gate 			return (-1);
5710Sstevel@tonic-gate 		}
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	}
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	return (0);
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate /*
5790Sstevel@tonic-gate  * Open the keystore description file in the specified mode.
5800Sstevel@tonic-gate  * If the keystore doesn't exist, the "do_create_keystore"
5810Sstevel@tonic-gate  * argument determines if the keystore should be created
5820Sstevel@tonic-gate  */
5830Sstevel@tonic-gate static int
open_and_lock_keystore_desc(mode_t mode,boolean_t do_create_keystore,boolean_t lock_held)5840Sstevel@tonic-gate open_and_lock_keystore_desc(mode_t mode, boolean_t do_create_keystore,
5850Sstevel@tonic-gate     boolean_t lock_held)
5860Sstevel@tonic-gate {
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	int fd;
5890Sstevel@tonic-gate 	char *fname, ks_desc_file[MAXPATHLEN];
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	/* open the keystore description file in requested mode */
5920Sstevel@tonic-gate 	fname = get_desc_file_path(ks_desc_file);
5938932SDina.Nimeh@Sun.COM 	fd = open_nointr(fname, mode|O_NONBLOCK);
5940Sstevel@tonic-gate 	if (fd < 0) {
5950Sstevel@tonic-gate 		if ((errno == ENOENT) && (do_create_keystore)) {
5960Sstevel@tonic-gate 			if (create_keystore() < 0) {
5970Sstevel@tonic-gate 				goto done;
5980Sstevel@tonic-gate 			}
5998932SDina.Nimeh@Sun.COM 			fd = open_nointr(fname, mode|O_NONBLOCK);
6000Sstevel@tonic-gate 			if (fd < 0) {
6010Sstevel@tonic-gate 				goto done;
6020Sstevel@tonic-gate 			}
6030Sstevel@tonic-gate 		} else {
6040Sstevel@tonic-gate 			goto done;
6050Sstevel@tonic-gate 		}
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	if (lock_held) {
6090Sstevel@tonic-gate 		/* already hold the lock */
6100Sstevel@tonic-gate 		return (fd);
6110Sstevel@tonic-gate 	}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	if (acquire_file_lock(&fd, fname, mode) != 0) {
6140Sstevel@tonic-gate 		if (fd > 0) {
6150Sstevel@tonic-gate 			(void) close(fd);
6160Sstevel@tonic-gate 		}
6170Sstevel@tonic-gate 		return (-1);
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate done:
6210Sstevel@tonic-gate 	return (fd);
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate /*
6260Sstevel@tonic-gate  * Set or remove read or write lock on keystore description file
6270Sstevel@tonic-gate  *
6280Sstevel@tonic-gate  * read_lock: true for read lock, false for write lock
6290Sstevel@tonic-gate  * set_lock: true for set a lock, false to remove a lock
6300Sstevel@tonic-gate  */
6310Sstevel@tonic-gate static int
lock_desc_file(boolean_t read_lock,boolean_t set_lock)6320Sstevel@tonic-gate lock_desc_file(boolean_t read_lock, boolean_t set_lock)
6330Sstevel@tonic-gate {
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	char ks_desc_file[MAXPATHLEN];
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	if (set_lock) {
6380Sstevel@tonic-gate 		int oflag;
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 		/*
6410Sstevel@tonic-gate 		 * make sure desc_fd is not already used.  If used, it means
6420Sstevel@tonic-gate 		 * some other lock is already set on the file
6430Sstevel@tonic-gate 		 */
6440Sstevel@tonic-gate 		if (desc_fd > 0) {
6450Sstevel@tonic-gate 			return (-1);
6460Sstevel@tonic-gate 		}
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 		(void) get_desc_file_path(ks_desc_file);
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		if (read_lock) {
6510Sstevel@tonic-gate 			oflag = O_RDONLY;
6520Sstevel@tonic-gate 		} else {
6530Sstevel@tonic-gate 			oflag = O_WRONLY;
6540Sstevel@tonic-gate 		}
6550Sstevel@tonic-gate 		if ((desc_fd = open_and_lock_keystore_desc(oflag,
6560Sstevel@tonic-gate 		    B_FALSE, B_FALSE)) < 0) {
6570Sstevel@tonic-gate 			return (-1);
6580Sstevel@tonic-gate 		}
6590Sstevel@tonic-gate 	} else {
6600Sstevel@tonic-gate 		/* make sure we have a valid fd */
6610Sstevel@tonic-gate 		if (desc_fd <= 0) {
6620Sstevel@tonic-gate 			return (-1);
6630Sstevel@tonic-gate 		}
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 		if (lock_file(desc_fd, read_lock, B_FALSE) == 1) {
6660Sstevel@tonic-gate 			return (-1);
6670Sstevel@tonic-gate 		}
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 		(void) close(desc_fd);
6700Sstevel@tonic-gate 		desc_fd = 0;
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	}
6730Sstevel@tonic-gate 	return (0);
6740Sstevel@tonic-gate }
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate static int
open_and_lock_object_file(ks_obj_handle_t * ks_handle,int oflag,boolean_t lock_held)6770Sstevel@tonic-gate open_and_lock_object_file(ks_obj_handle_t *ks_handle, int oflag,
6780Sstevel@tonic-gate     boolean_t lock_held)
6790Sstevel@tonic-gate {
6800Sstevel@tonic-gate 	char obj_fname[MAXPATHLEN];
6810Sstevel@tonic-gate 	int fd;
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	if (ks_handle->public) {
6840Sstevel@tonic-gate 		char pub_obj_path[MAXPATHLEN];
6850Sstevel@tonic-gate 		(void) snprintf(obj_fname, MAXPATHLEN, "%s/%s",
6860Sstevel@tonic-gate 		    get_pub_obj_path(pub_obj_path), ks_handle->name);
6870Sstevel@tonic-gate 	} else {
6880Sstevel@tonic-gate 		char pri_obj_path[MAXPATHLEN];
6890Sstevel@tonic-gate 		(void) snprintf(obj_fname, MAXPATHLEN, "%s/%s",
6900Sstevel@tonic-gate 		    get_pri_obj_path(pri_obj_path), ks_handle->name);
6910Sstevel@tonic-gate 	}
6920Sstevel@tonic-gate 
6938932SDina.Nimeh@Sun.COM 	fd = open_nointr(obj_fname, oflag|O_NONBLOCK);
6940Sstevel@tonic-gate 	if (fd < 0) {
6950Sstevel@tonic-gate 		return (-1);
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	if (lock_held) {
6990Sstevel@tonic-gate 		/* already hold the lock */
7000Sstevel@tonic-gate 		return (fd);
7010Sstevel@tonic-gate 	}
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	if (acquire_file_lock(&fd, obj_fname, oflag) != 0) {
7040Sstevel@tonic-gate 		if (fd > 0) {
7050Sstevel@tonic-gate 			(void) close(fd);
7060Sstevel@tonic-gate 		}
7070Sstevel@tonic-gate 		return (-1);
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	return (fd);
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate /*
7160Sstevel@tonic-gate  * Update file version number in a temporary file that's
7170Sstevel@tonic-gate  * a copy of the keystore description file.
7180Sstevel@tonic-gate  * The update is NOT made to the original keystore description
7190Sstevel@tonic-gate  * file.  It makes the update in a tempoary file.
7200Sstevel@tonic-gate  *
7210Sstevel@tonic-gate  * Name of the temporary file is assumed to be provided, but
7220Sstevel@tonic-gate  * the file is assumed to not exist.
7230Sstevel@tonic-gate  *
7240Sstevel@tonic-gate  * return 0 if creating temp file is successful, returns -1 otherwise
7250Sstevel@tonic-gate  */
7260Sstevel@tonic-gate static int
create_updated_keystore_version(int fd,char * tmp_fname)7270Sstevel@tonic-gate create_updated_keystore_version(int fd, char *tmp_fname)
7280Sstevel@tonic-gate {
7290Sstevel@tonic-gate 	int version, tmp_fd;
7300Sstevel@tonic-gate 	char buf[BUFSIZ];
7310Sstevel@tonic-gate 	size_t nread;
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	/* first, create the tempoary file */
7348932SDina.Nimeh@Sun.COM 	tmp_fd = open_nointr(tmp_fname,
7358932SDina.Nimeh@Sun.COM 	    O_WRONLY|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
7360Sstevel@tonic-gate 	if (tmp_fd < 0) {
7370Sstevel@tonic-gate 		return (-1);
7380Sstevel@tonic-gate 	}
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	/*
7410Sstevel@tonic-gate 	 * copy everything from keystore version to temp file except
7420Sstevel@tonic-gate 	 * the keystore version.  Keystore version is updated
7430Sstevel@tonic-gate 	 *
7440Sstevel@tonic-gate 	 */
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	/* pkcs11 version */
7478932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, buf, KS_PKCS11_VER_SIZE) != KS_PKCS11_VER_SIZE) {
7480Sstevel@tonic-gate 		goto cleanup;
7490Sstevel@tonic-gate 	}
7500Sstevel@tonic-gate 
7518932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_fd, buf, KS_PKCS11_VER_SIZE) !=
7528932SDina.Nimeh@Sun.COM 	    KS_PKCS11_VER_SIZE) {
7530Sstevel@tonic-gate 		goto cleanup;
7540Sstevel@tonic-gate 	}
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	/* version number, it needs to be updated */
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	/* read the current version number */
7598932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, &version, KS_VER_SIZE) != KS_VER_SIZE) {
7600Sstevel@tonic-gate 		goto cleanup;
7610Sstevel@tonic-gate 	}
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	version = SWAP32(version);
7640Sstevel@tonic-gate 	version++;
7650Sstevel@tonic-gate 	version = SWAP32(version);
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	/* write the updated value to the tmp file */
7688932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_fd, (void *)&version, KS_VER_SIZE)
7690Sstevel@tonic-gate 	    != KS_VER_SIZE) {
7700Sstevel@tonic-gate 		goto cleanup;
7710Sstevel@tonic-gate 	}
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	/* read rest of information, nothing needs to be updated */
7748932SDina.Nimeh@Sun.COM 	nread = readn_nointr(fd, buf, BUFSIZ);
7750Sstevel@tonic-gate 	while (nread > 0) {
7768932SDina.Nimeh@Sun.COM 		if (writen_nointr(tmp_fd, buf, nread) != nread) {
7770Sstevel@tonic-gate 			goto cleanup;
7780Sstevel@tonic-gate 		}
7798932SDina.Nimeh@Sun.COM 		nread = readn_nointr(fd, buf, BUFSIZ);
7800Sstevel@tonic-gate 	}
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	(void) close(tmp_fd);
7830Sstevel@tonic-gate 	return (0);	/* no error */
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate cleanup:
7860Sstevel@tonic-gate 	(void) close(tmp_fd);
7870Sstevel@tonic-gate 	(void) remove(tmp_fname);
7880Sstevel@tonic-gate 	return (-1);
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate 
7910Sstevel@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)7920Sstevel@tonic-gate get_all_objs_in_dir(DIR *dirp, ks_obj_handle_t *ks_handle,
793871Scasper     ks_obj_t **result_obj_list, boolean_t lock_held)
7940Sstevel@tonic-gate {
795871Scasper 	struct dirent *dp;
7960Sstevel@tonic-gate 	ks_obj_t *obj;
7970Sstevel@tonic-gate 	CK_RV rv;
798871Scasper 
799871Scasper 	while ((dp = readdir(dirp)) != NULL) {
8000Sstevel@tonic-gate 
8019341SAnthony.Scarpino@Sun.COM 		if (strncmp(dp->d_name, OBJ_PREFIX, OBJ_PREFIX_LEN) != 0)
8020Sstevel@tonic-gate 			continue;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 		(void) strcpy((char *)ks_handle->name, dp->d_name);
8050Sstevel@tonic-gate 		rv = soft_keystore_get_single_obj(ks_handle, &obj, lock_held);
8060Sstevel@tonic-gate 		if (rv != CKR_OK) {
8070Sstevel@tonic-gate 			return (rv);
8080Sstevel@tonic-gate 		}
8090Sstevel@tonic-gate 		if (obj != NULL) {
8100Sstevel@tonic-gate 			if (*result_obj_list == NULL) {
8110Sstevel@tonic-gate 				*result_obj_list = obj;
8120Sstevel@tonic-gate 			} else {
8130Sstevel@tonic-gate 				obj->next = *result_obj_list;
8140Sstevel@tonic-gate 				*result_obj_list = obj;
8150Sstevel@tonic-gate 			}
8160Sstevel@tonic-gate 		}
8170Sstevel@tonic-gate 	}
8180Sstevel@tonic-gate 	return (CKR_OK);
8190Sstevel@tonic-gate }
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate /*
8220Sstevel@tonic-gate  * This function prepares the obj data for encryption by prepending
8230Sstevel@tonic-gate  * the FULL path of the file that will be used for storing
8240Sstevel@tonic-gate  * the object.  Having full path of the file as part of
8250Sstevel@tonic-gate  * of the data for the object will prevent an attacker from
8260Sstevel@tonic-gate  * copying a "bad" object into the keystore undetected.
8270Sstevel@tonic-gate  *
8280Sstevel@tonic-gate  * This function will always allocate:
8290Sstevel@tonic-gate  *	MAXPATHLEN + buf_len
8300Sstevel@tonic-gate  * amount of data.  If the full path of the filename doesn't occupy
8310Sstevel@tonic-gate  * the whole MAXPATHLEN, the rest of the space will just be empty.
8320Sstevel@tonic-gate  * It is the caller's responsibility to free the buffer allocated here.
8330Sstevel@tonic-gate  *
8340Sstevel@tonic-gate  * The allocated buffer is returned in the variable "prepared_buf"
8350Sstevel@tonic-gate  * if there's no error.
8360Sstevel@tonic-gate  *
8370Sstevel@tonic-gate  * Returns 0 if there's no error, -1 otherwise.
8380Sstevel@tonic-gate  */
8390Sstevel@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)8400Sstevel@tonic-gate prepare_data_for_encrypt(char *obj_path, unsigned char *buf, CK_ULONG buf_len,
8410Sstevel@tonic-gate     unsigned char **prepared_buf, CK_ULONG *prepared_len)
8420Sstevel@tonic-gate {
8430Sstevel@tonic-gate 	*prepared_len = MAXPATHLEN + buf_len;
8440Sstevel@tonic-gate 	*prepared_buf = malloc(*prepared_len);
8450Sstevel@tonic-gate 	if (*prepared_buf == NULL) {
8460Sstevel@tonic-gate 		return (-1);
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	/*
8500Sstevel@tonic-gate 	 * only zero out the space for the path name.  I could zero out
8510Sstevel@tonic-gate 	 * the whole buffer, but that will be a waste of processing
8520Sstevel@tonic-gate 	 * cycle since the rest of the buffer will be 100% filled all
8530Sstevel@tonic-gate 	 * the time
8540Sstevel@tonic-gate 	 */
8550Sstevel@tonic-gate 	bzero(*prepared_buf, MAXPATHLEN);
8560Sstevel@tonic-gate 	(void) memcpy(*prepared_buf, obj_path, strlen(obj_path));
8570Sstevel@tonic-gate 	(void) memcpy(*prepared_buf + MAXPATHLEN, buf, buf_len);
8580Sstevel@tonic-gate 	return (0);
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate /*
8620Sstevel@tonic-gate  * retrieves the hashed pin from the keystore
8630Sstevel@tonic-gate  */
8640Sstevel@tonic-gate static CK_RV
get_hashed_pin(int fd,char ** hashed_pin)8650Sstevel@tonic-gate get_hashed_pin(int fd, char **hashed_pin)
8660Sstevel@tonic-gate {
8670Sstevel@tonic-gate 	uint64_t hashed_pin_size;
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	if (ks_hashed_pinlen_offset == -1) {
8700Sstevel@tonic-gate 		if (calculate_hashed_pin_offset(fd) != 0) {
8710Sstevel@tonic-gate 			return (CKR_FUNCTION_FAILED);
8720Sstevel@tonic-gate 		}
8730Sstevel@tonic-gate 	}
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	/* first, get size of the hashed pin */
8760Sstevel@tonic-gate 	if (lseek(fd, ks_hashed_pinlen_offset, SEEK_SET)
8770Sstevel@tonic-gate 	    != ks_hashed_pinlen_offset) {
8780Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
8790Sstevel@tonic-gate 	}
8800Sstevel@tonic-gate 
8818932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)&hashed_pin_size,
8820Sstevel@tonic-gate 	    KS_HASHED_PINLEN_SIZE) != KS_HASHED_PINLEN_SIZE) {
8830Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
8840Sstevel@tonic-gate 	}
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	hashed_pin_size = SWAP64(hashed_pin_size);
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	*hashed_pin = malloc(hashed_pin_size + 1);
8890Sstevel@tonic-gate 	if (*hashed_pin == NULL) {
8900Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
8910Sstevel@tonic-gate 	}
8920Sstevel@tonic-gate 
8938932SDina.Nimeh@Sun.COM 	if ((readn_nointr(fd, *hashed_pin, hashed_pin_size))
8940Sstevel@tonic-gate 	    != (ssize_t)hashed_pin_size) {
8950Sstevel@tonic-gate 		free(*hashed_pin);
8960Sstevel@tonic-gate 		*hashed_pin = NULL;
8970Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 	(*hashed_pin)[hashed_pin_size] = '\0';
9000Sstevel@tonic-gate 	return (CKR_OK);
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate /*
9050Sstevel@tonic-gate  *	FUNCTION: soft_keystore_lock
9060Sstevel@tonic-gate  *
9070Sstevel@tonic-gate  *	ARGUMENTS:
9080Sstevel@tonic-gate  *		set_lock: TRUE to set readlock on the keystore object file,
9090Sstevel@tonic-gate  *		          FALSE to remove readlock on keystore object file.
9100Sstevel@tonic-gate  *
9110Sstevel@tonic-gate  *	RETURN VALUE:
9120Sstevel@tonic-gate  *
9130Sstevel@tonic-gate  *		0: success
9140Sstevel@tonic-gate  *		-1: failure
9150Sstevel@tonic-gate  *
9160Sstevel@tonic-gate  *	DESCRIPTION:
9170Sstevel@tonic-gate  *
9180Sstevel@tonic-gate  *		set or remove readlock on the keystore description file.
9190Sstevel@tonic-gate  */
9200Sstevel@tonic-gate int
soft_keystore_readlock(boolean_t set_lock)9210Sstevel@tonic-gate soft_keystore_readlock(boolean_t set_lock)
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	return (lock_desc_file(B_TRUE, set_lock));
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate /*
9290Sstevel@tonic-gate  *	FUNCTION: soft_keystore_writelock
9300Sstevel@tonic-gate  *
9310Sstevel@tonic-gate  *	ARGUMENTS:
9320Sstevel@tonic-gate  * 		set_lock: TRUE to set writelock on the keystore description file
9330Sstevel@tonic-gate  *		        FALSE to remove write lock on keystore description file.
9340Sstevel@tonic-gate  *
9350Sstevel@tonic-gate  *	RETURN VALUE:
9360Sstevel@tonic-gate  *
9370Sstevel@tonic-gate  *		0: no error
9380Sstevel@tonic-gate  *		1: some error occurred
9390Sstevel@tonic-gate  *
9400Sstevel@tonic-gate  *	DESCRIPTION:
9410Sstevel@tonic-gate  *		set/reset writelock on the keystore description file.
9420Sstevel@tonic-gate  */
9430Sstevel@tonic-gate int
soft_keystore_writelock(boolean_t set_lock)9440Sstevel@tonic-gate soft_keystore_writelock(boolean_t set_lock)
9450Sstevel@tonic-gate {
9460Sstevel@tonic-gate 	return (lock_desc_file(B_FALSE, set_lock));
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate }
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate /*
9510Sstevel@tonic-gate  *
9520Sstevel@tonic-gate  *	FUNCTION: soft_keystore_lock_object
9530Sstevel@tonic-gate  *
9540Sstevel@tonic-gate  *	ARGUMENTS:
9550Sstevel@tonic-gate  *
9560Sstevel@tonic-gate  *		ks_handle: handle of the keystore object file to be accessed.
9570Sstevel@tonic-gate  * 		read_lock: TRUE to set readlock on the keystore object file,
9580Sstevel@tonic-gate  *			  FALSE to set writelock on keystore object file.
9590Sstevel@tonic-gate  *
9600Sstevel@tonic-gate  *	RETURN VALUE:
9610Sstevel@tonic-gate  *
9620Sstevel@tonic-gate  *		If no error, file descriptor of locked file will be returned
9630Sstevel@tonic-gate  *		-1: some error occurred
9640Sstevel@tonic-gate  *
9650Sstevel@tonic-gate  *	DESCRIPTION:
9660Sstevel@tonic-gate  *
9670Sstevel@tonic-gate  *		set readlock or writelock on the keystore object file.
9680Sstevel@tonic-gate  */
9690Sstevel@tonic-gate int
soft_keystore_lock_object(ks_obj_handle_t * ks_handle,boolean_t read_lock)9700Sstevel@tonic-gate soft_keystore_lock_object(ks_obj_handle_t *ks_handle, boolean_t read_lock)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate 	int fd;
9730Sstevel@tonic-gate 	int oflag;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	if (read_lock) {
9760Sstevel@tonic-gate 		oflag = O_RDONLY;
9770Sstevel@tonic-gate 	} else {
9780Sstevel@tonic-gate 		oflag = O_WRONLY;
9790Sstevel@tonic-gate 	}
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	if ((fd = open_and_lock_object_file(ks_handle, oflag, B_FALSE)) < 0) {
9820Sstevel@tonic-gate 		return (-1);
9830Sstevel@tonic-gate 	}
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	return (fd);
9860Sstevel@tonic-gate }
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate /*
9890Sstevel@tonic-gate  *	FUNCTION: soft_keystore_unlock_object
9900Sstevel@tonic-gate  *
9910Sstevel@tonic-gate  *	ARGUMENTS:
9920Sstevel@tonic-gate  *		fd: file descriptor returned from soft_keystore_lock_object
9930Sstevel@tonic-gate  *
9940Sstevel@tonic-gate  *	RETURN VALUE:
9950Sstevel@tonic-gate  *		0: no error
9960Sstevel@tonic-gate  *		1: some error occurred while getting the pin
9970Sstevel@tonic-gate  *
9980Sstevel@tonic-gate  *	DESCRIPTION:
9990Sstevel@tonic-gate  *		set/reset writelock on the keystore object file.
10000Sstevel@tonic-gate  */
10010Sstevel@tonic-gate int
soft_keystore_unlock_object(int fd)10020Sstevel@tonic-gate soft_keystore_unlock_object(int fd)
10030Sstevel@tonic-gate {
10040Sstevel@tonic-gate 	if (lock_file(fd, B_TRUE, B_FALSE) != 0) {
10050Sstevel@tonic-gate 		return (1);
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	(void) close(fd);
10090Sstevel@tonic-gate 	return (0);
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate /*
10150Sstevel@tonic-gate  *	FUNCTION: soft_keystore_get_version
10160Sstevel@tonic-gate  *
10170Sstevel@tonic-gate  *	ARGUMENTS:
10180Sstevel@tonic-gate  *		version: pointer to caller allocated memory for storing
10190Sstevel@tonic-gate  *			 the version of the keystore.
10200Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
10210Sstevel@tonic-gate  *
10220Sstevel@tonic-gate  *	RETURN VALUE:
10230Sstevel@tonic-gate  *
10240Sstevel@tonic-gate  *		0: no error
10250Sstevel@tonic-gate  *		-1: some error occurred while getting the version number
10260Sstevel@tonic-gate  *
10270Sstevel@tonic-gate  *	DESCRIPTION:
10280Sstevel@tonic-gate  *		get the version number of the keystore from keystore
10290Sstevel@tonic-gate  *		description file.
10300Sstevel@tonic-gate  */
10310Sstevel@tonic-gate int
soft_keystore_get_version(uint_t * version,boolean_t lock_held)10320Sstevel@tonic-gate soft_keystore_get_version(uint_t *version, boolean_t lock_held)
10330Sstevel@tonic-gate {
10340Sstevel@tonic-gate 	int fd, ret_val = 0;
10350Sstevel@tonic-gate 	uint_t buf;
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDONLY,
103812256SPeter.Shoults@Sun.COM 	    B_FALSE, lock_held)) < 0) {
10390Sstevel@tonic-gate 		return (-1);
10400Sstevel@tonic-gate 	}
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	if (lseek(fd, KS_VER_OFFSET, SEEK_SET) != KS_VER_OFFSET) {
10430Sstevel@tonic-gate 		ret_val = -1;
10440Sstevel@tonic-gate 		goto cleanup;
10450Sstevel@tonic-gate 	}
10460Sstevel@tonic-gate 
10478932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)&buf, KS_VER_SIZE) != KS_VER_SIZE) {
10480Sstevel@tonic-gate 		ret_val = -1;
10490Sstevel@tonic-gate 		goto cleanup;
10500Sstevel@tonic-gate 	}
10510Sstevel@tonic-gate 	*version = SWAP32(buf);
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate cleanup:
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	if (!lock_held) {
10560Sstevel@tonic-gate 		if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
10570Sstevel@tonic-gate 			ret_val = -1;
10580Sstevel@tonic-gate 		}
10590Sstevel@tonic-gate 	}
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	(void) close(fd);
10620Sstevel@tonic-gate 	return (ret_val);
10630Sstevel@tonic-gate }
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate /*
10660Sstevel@tonic-gate  *	FUNCTION: soft_keystore_get_object_version
10670Sstevel@tonic-gate  *
10680Sstevel@tonic-gate  *	ARGUMENTS:
10690Sstevel@tonic-gate  *
10700Sstevel@tonic-gate  *		ks_handle: handle of the key store object to be accessed.
10710Sstevel@tonic-gate  *		version:
10720Sstevel@tonic-gate  *			pointer to caller allocated memory for storing
10730Sstevel@tonic-gate  *			the version of the object.
10740Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
10750Sstevel@tonic-gate  *
10760Sstevel@tonic-gate  *	RETURN VALUE:
10770Sstevel@tonic-gate  *
10780Sstevel@tonic-gate  *		0: no error
10790Sstevel@tonic-gate  *		-1: some error occurred while getting the pin
10800Sstevel@tonic-gate  *
10810Sstevel@tonic-gate  *	DESCRIPTION:
10820Sstevel@tonic-gate  *		get the version number of the specified token object.
10830Sstevel@tonic-gate  */
10840Sstevel@tonic-gate int
soft_keystore_get_object_version(ks_obj_handle_t * ks_handle,uint_t * version,boolean_t lock_held)10850Sstevel@tonic-gate soft_keystore_get_object_version(ks_obj_handle_t *ks_handle,
10860Sstevel@tonic-gate     uint_t *version, boolean_t lock_held)
10870Sstevel@tonic-gate {
10880Sstevel@tonic-gate 	int fd, ret_val = 0;
10890Sstevel@tonic-gate 	uint_t tmp;
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	if ((fd = open_and_lock_object_file(ks_handle, O_RDONLY,
10920Sstevel@tonic-gate 	    lock_held)) < 0) {
10930Sstevel@tonic-gate 		return (-1);
10940Sstevel@tonic-gate 	}
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	/*
10970Sstevel@tonic-gate 	 * read version.  Version is always first item in object file
10980Sstevel@tonic-gate 	 * so, no need to do lseek
10990Sstevel@tonic-gate 	 */
11008932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)&tmp, OBJ_VER_SIZE) != OBJ_VER_SIZE) {
11010Sstevel@tonic-gate 		ret_val = -1;
11020Sstevel@tonic-gate 		goto cleanup;
11030Sstevel@tonic-gate 	}
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 	*version = SWAP32(tmp);
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate cleanup:
11080Sstevel@tonic-gate 	if (!lock_held) {
11090Sstevel@tonic-gate 		if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
11100Sstevel@tonic-gate 			ret_val = -1;
11110Sstevel@tonic-gate 		}
11120Sstevel@tonic-gate 	}
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 	(void) close(fd);
11160Sstevel@tonic-gate 	return (ret_val);
11170Sstevel@tonic-gate }
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate /*
11200Sstevel@tonic-gate  *		FUNCTION: soft_keystore_getpin
11210Sstevel@tonic-gate  *
11220Sstevel@tonic-gate  *		ARGUMENTS:
11230Sstevel@tonic-gate  *			hashed_pin: pointer to caller allocated memory
11240Sstevel@tonic-gate  *				for storing the pin to be returned.
11250Sstevel@tonic-gate  *			lock_held: TRUE if the lock is held by caller.
11260Sstevel@tonic-gate  *
11270Sstevel@tonic-gate  *		RETURN VALUE:
11280Sstevel@tonic-gate  *
11290Sstevel@tonic-gate  *			0: no error
11300Sstevel@tonic-gate  *			-1: some error occurred while getting the pin
11310Sstevel@tonic-gate  *
11320Sstevel@tonic-gate  *		DESCRIPTION:
11330Sstevel@tonic-gate  *
11340Sstevel@tonic-gate  *			Reads the MD5 hash from the keystore description
11350Sstevel@tonic-gate  *			file and return it to the caller in the provided
11360Sstevel@tonic-gate  *			buffer. If there is no PIN in the description file
11370Sstevel@tonic-gate  *			because the file is just created, this function
11380Sstevel@tonic-gate  *			will get a MD5 digest of the string "changeme",
11390Sstevel@tonic-gate  *			store it in the file, and also return this
11400Sstevel@tonic-gate  *			string to the caller.
11410Sstevel@tonic-gate  */
11420Sstevel@tonic-gate int
soft_keystore_getpin(char ** hashed_pin,boolean_t lock_held)11430Sstevel@tonic-gate soft_keystore_getpin(char **hashed_pin, boolean_t lock_held)
11440Sstevel@tonic-gate {
11450Sstevel@tonic-gate 	int fd, ret_val = -1;
11460Sstevel@tonic-gate 	CK_RV rv;
11470Sstevel@tonic-gate 
114812256SPeter.Shoults@Sun.COM 	if ((fd = open_and_lock_keystore_desc(O_RDONLY, B_FALSE,
11490Sstevel@tonic-gate 	    lock_held)) < 0) {
11500Sstevel@tonic-gate 		return (-1);
11510Sstevel@tonic-gate 	}
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	rv = get_hashed_pin(fd, hashed_pin);
11540Sstevel@tonic-gate 	if (rv == CKR_OK) {
11550Sstevel@tonic-gate 		ret_val = 0;
11560Sstevel@tonic-gate 	}
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate cleanup:
11590Sstevel@tonic-gate 	if (!lock_held) {
11600Sstevel@tonic-gate 		if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
11610Sstevel@tonic-gate 			ret_val = -1;
11620Sstevel@tonic-gate 		}
11630Sstevel@tonic-gate 	}
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	(void) close(fd);
11660Sstevel@tonic-gate 	return (ret_val);
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate 
11699127SDina.Nimeh@Sun.COM 
11709127SDina.Nimeh@Sun.COM /*
11719127SDina.Nimeh@Sun.COM  * Generate a 16-byte Initialization Vector (IV).
11729127SDina.Nimeh@Sun.COM  */
11739127SDina.Nimeh@Sun.COM CK_RV
soft_gen_iv(CK_BYTE * iv)11749127SDina.Nimeh@Sun.COM soft_gen_iv(CK_BYTE *iv)
11759127SDina.Nimeh@Sun.COM {
11769127SDina.Nimeh@Sun.COM 	return (pkcs11_get_nzero_urandom(iv, 16) < 0 ?
11779127SDina.Nimeh@Sun.COM 	    CKR_DEVICE_ERROR : CKR_OK);
11789127SDina.Nimeh@Sun.COM }
11799127SDina.Nimeh@Sun.COM 
11809127SDina.Nimeh@Sun.COM 
11810Sstevel@tonic-gate /*
11820Sstevel@tonic-gate  * This function reads all the data until the end of the file, and
11830Sstevel@tonic-gate  * put the data into the "buf" in argument.  Memory for buf will
11840Sstevel@tonic-gate  * be allocated in this function.  It is the caller's responsibility
11850Sstevel@tonic-gate  * to free it.  The number of bytes read will be returned
11860Sstevel@tonic-gate  * in the argument "bytes_read"
11870Sstevel@tonic-gate  *
11880Sstevel@tonic-gate  * returns CKR_OK if no error.  Other CKR error codes if there's an error
11890Sstevel@tonic-gate  */
11900Sstevel@tonic-gate static CK_RV
read_obj_data(int old_fd,char ** buf,ssize_t * bytes_read)11910Sstevel@tonic-gate read_obj_data(int old_fd, char **buf, ssize_t *bytes_read)
11920Sstevel@tonic-gate {
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	ssize_t nread, loop_count;
11950Sstevel@tonic-gate 	char *buf1 = NULL;
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	*buf = malloc(BUFSIZ);
11980Sstevel@tonic-gate 	if (*buf == NULL) {
11990Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
12000Sstevel@tonic-gate 	}
12010Sstevel@tonic-gate 
12028932SDina.Nimeh@Sun.COM 	nread = readn_nointr(old_fd, *buf, BUFSIZ);
12030Sstevel@tonic-gate 	if (nread < 0) {
12040Sstevel@tonic-gate 		free(*buf);
12050Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
12060Sstevel@tonic-gate 	}
12070Sstevel@tonic-gate 	loop_count = 1;
12080Sstevel@tonic-gate 	while (nread == (loop_count * BUFSIZ)) {
12090Sstevel@tonic-gate 		ssize_t nread_tmp;
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 		loop_count++;
12120Sstevel@tonic-gate 		/* more than BUFSIZ of data */
12130Sstevel@tonic-gate 		buf1 = realloc(*buf, loop_count * BUFSIZ);
12140Sstevel@tonic-gate 		if (buf1 == NULL) {
12150Sstevel@tonic-gate 			free(*buf);
12160Sstevel@tonic-gate 			return (CKR_HOST_MEMORY);
12170Sstevel@tonic-gate 		}
12180Sstevel@tonic-gate 		*buf = buf1;
12198932SDina.Nimeh@Sun.COM 		nread_tmp = readn_nointr(old_fd,
12200Sstevel@tonic-gate 		    *buf + ((loop_count - 1) * BUFSIZ), BUFSIZ);
12210Sstevel@tonic-gate 		if (nread_tmp < 0) {
12220Sstevel@tonic-gate 			free(*buf);
12230Sstevel@tonic-gate 			return (CKR_FUNCTION_FAILED);
12240Sstevel@tonic-gate 		}
12250Sstevel@tonic-gate 		nread += nread_tmp;
12260Sstevel@tonic-gate 	}
12270Sstevel@tonic-gate 	*bytes_read = nread;
12280Sstevel@tonic-gate 	return (CKR_OK);
12290Sstevel@tonic-gate }
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate /*
12320Sstevel@tonic-gate  * Re-encrypt an object using the provided new_enc_key.  The new HMAC
12330Sstevel@tonic-gate  * is calculated using the new_hmac_key.  The global static variables
12340Sstevel@tonic-gate  * enc_key, and hmac_key will be used for decrypting the original
12350Sstevel@tonic-gate  * object, and verifying its signature.
12360Sstevel@tonic-gate  *
12370Sstevel@tonic-gate  * The re-encrypted object will be stored in the file named
12380Sstevel@tonic-gate  * in the "new_obj_name" variable.  The content of the "original"
12390Sstevel@tonic-gate  * file named in "orig_obj_name" is not disturbed.
12400Sstevel@tonic-gate  *
12410Sstevel@tonic-gate  * Returns 0 if there's no error, returns -1 otherwise.
12420Sstevel@tonic-gate  *
12430Sstevel@tonic-gate  */
12440Sstevel@tonic-gate static int
reencrypt_obj(soft_object_t * new_enc_key,soft_object_t * new_hmac_key,char * orig_obj_name,char * new_obj_name)12450Sstevel@tonic-gate reencrypt_obj(soft_object_t *new_enc_key, soft_object_t *new_hmac_key,
12460Sstevel@tonic-gate     char *orig_obj_name, char *new_obj_name) {
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	int old_fd, new_fd, version, ret_val = -1;
12490Sstevel@tonic-gate 	CK_BYTE iv[OBJ_IV_SIZE], old_iv[OBJ_IV_SIZE];
12500Sstevel@tonic-gate 	ssize_t nread;
12510Sstevel@tonic-gate 	CK_ULONG decrypted_len, encrypted_len, hmac_len;
12520Sstevel@tonic-gate 	CK_BYTE hmac[OBJ_HMAC_SIZE], *decrypted_buf = NULL, *buf = NULL;
12530Sstevel@tonic-gate 
12548932SDina.Nimeh@Sun.COM 	old_fd = open_nointr(orig_obj_name, O_RDONLY|O_NONBLOCK);
12550Sstevel@tonic-gate 	if (old_fd < 0) {
12560Sstevel@tonic-gate 		return (-1);
12570Sstevel@tonic-gate 	}
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	if (acquire_file_lock(&old_fd, orig_obj_name, O_RDONLY) != 0) {
12600Sstevel@tonic-gate 		if (old_fd > 0) {
12610Sstevel@tonic-gate 			(void) close(old_fd);
12620Sstevel@tonic-gate 		}
12630Sstevel@tonic-gate 		return (-1);
12640Sstevel@tonic-gate 	}
12650Sstevel@tonic-gate 
12668932SDina.Nimeh@Sun.COM 	new_fd = open_nointr(new_obj_name,
12678932SDina.Nimeh@Sun.COM 	    O_WRONLY|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
12680Sstevel@tonic-gate 	if (new_fd < 0) {
12690Sstevel@tonic-gate 		(void) close(old_fd);
12700Sstevel@tonic-gate 		return (-1);
12710Sstevel@tonic-gate 	}
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	if (lock_file(new_fd, B_FALSE, B_TRUE) != 0) {
12740Sstevel@tonic-gate 		/* unlock old file */
12750Sstevel@tonic-gate 		(void) lock_file(old_fd, B_TRUE, B_FALSE);
12760Sstevel@tonic-gate 		(void) close(old_fd);
12770Sstevel@tonic-gate 		(void) close(new_fd);
12780Sstevel@tonic-gate 		return (-1);
12790Sstevel@tonic-gate 	}
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	/* read version, increment, and write to tmp file */
12828932SDina.Nimeh@Sun.COM 	if (readn_nointr(old_fd, (char *)&version, OBJ_VER_SIZE)
12830Sstevel@tonic-gate 	    != OBJ_VER_SIZE) {
12840Sstevel@tonic-gate 		goto cleanup;
12850Sstevel@tonic-gate 	}
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	version = SWAP32(version);
12880Sstevel@tonic-gate 	version++;
12890Sstevel@tonic-gate 	version = SWAP32(version);
12900Sstevel@tonic-gate 
12918932SDina.Nimeh@Sun.COM 	if (writen_nointr(new_fd, (char *)&version, OBJ_VER_SIZE)
12920Sstevel@tonic-gate 	    != OBJ_VER_SIZE) {
12930Sstevel@tonic-gate 		goto cleanup;
12940Sstevel@tonic-gate 	}
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 	/* read old iv */
12978932SDina.Nimeh@Sun.COM 	if (readn_nointr(old_fd, (char *)old_iv, OBJ_IV_SIZE) != OBJ_IV_SIZE) {
12980Sstevel@tonic-gate 		goto cleanup;
12990Sstevel@tonic-gate 	}
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	/* generate new IV */
13020Sstevel@tonic-gate 	if (soft_gen_iv(iv) != CKR_OK) {
13030Sstevel@tonic-gate 		goto cleanup;
13040Sstevel@tonic-gate 	}
13050Sstevel@tonic-gate 
13068932SDina.Nimeh@Sun.COM 	if (writen_nointr(new_fd, (char *)iv, OBJ_IV_SIZE) != OBJ_IV_SIZE) {
13070Sstevel@tonic-gate 		goto cleanup;
13080Sstevel@tonic-gate 	}
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	/* seek to the original encrypted data, and read all of them */
13110Sstevel@tonic-gate 	if (lseek(old_fd, OBJ_DATA_OFFSET, SEEK_SET) != OBJ_DATA_OFFSET) {
13120Sstevel@tonic-gate 		goto cleanup;
13130Sstevel@tonic-gate 	}
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 	if (read_obj_data(old_fd, (char **)&buf, &nread) != CKR_OK) {
13160Sstevel@tonic-gate 		goto cleanup;
13170Sstevel@tonic-gate 	}
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	/* decrypt data using old key */
13200Sstevel@tonic-gate 	decrypted_len = 0;
13210Sstevel@tonic-gate 	if (soft_keystore_crypt(enc_key, old_iv, B_FALSE, buf, nread,
13220Sstevel@tonic-gate 	    NULL, &decrypted_len) != CKR_OK) {
13230Sstevel@tonic-gate 		free(buf);
13240Sstevel@tonic-gate 		goto cleanup;
13250Sstevel@tonic-gate 	}
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	decrypted_buf = malloc(decrypted_len);
13280Sstevel@tonic-gate 	if (decrypted_buf == NULL) {
13290Sstevel@tonic-gate 		free(buf);
13300Sstevel@tonic-gate 		goto cleanup;
13310Sstevel@tonic-gate 	}
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	if (soft_keystore_crypt(enc_key, old_iv, B_FALSE, buf, nread,
13340Sstevel@tonic-gate 	    decrypted_buf, &decrypted_len) != CKR_OK) {
13350Sstevel@tonic-gate 		free(buf);
13360Sstevel@tonic-gate 		free(decrypted_buf);
13370Sstevel@tonic-gate 		goto cleanup;
13380Sstevel@tonic-gate 	}
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	free(buf);
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	/* re-encrypt with new key */
13430Sstevel@tonic-gate 	encrypted_len = 0;
13440Sstevel@tonic-gate 	if (soft_keystore_crypt(new_enc_key, iv, B_TRUE, decrypted_buf,
13450Sstevel@tonic-gate 	    decrypted_len, NULL, &encrypted_len) != CKR_OK) {
13460Sstevel@tonic-gate 		free(decrypted_buf);
13470Sstevel@tonic-gate 		goto cleanup;
13480Sstevel@tonic-gate 	}
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	buf = malloc(encrypted_len);
13510Sstevel@tonic-gate 	if (buf == NULL) {
13520Sstevel@tonic-gate 		free(decrypted_buf);
13530Sstevel@tonic-gate 		goto cleanup;
13540Sstevel@tonic-gate 	}
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 	if (soft_keystore_crypt(new_enc_key, iv, B_TRUE, decrypted_buf,
13570Sstevel@tonic-gate 	    decrypted_len, buf, &encrypted_len) != CKR_OK) {
13580Sstevel@tonic-gate 		free(buf);
13590Sstevel@tonic-gate 		free(decrypted_buf);
13600Sstevel@tonic-gate 		goto cleanup;
13610Sstevel@tonic-gate 	}
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 	free(decrypted_buf);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	/* calculate hmac on re-encrypted data using new hmac key */
13660Sstevel@tonic-gate 	hmac_len = OBJ_HMAC_SIZE;
13670Sstevel@tonic-gate 	if (soft_keystore_hmac(new_hmac_key, B_TRUE, buf,
13680Sstevel@tonic-gate 	    encrypted_len, hmac, &hmac_len) != CKR_OK) {
13690Sstevel@tonic-gate 		free(buf);
13700Sstevel@tonic-gate 		goto cleanup;
13710Sstevel@tonic-gate 	}
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	/* just for sanity check */
13740Sstevel@tonic-gate 	if (hmac_len != OBJ_HMAC_SIZE) {
13750Sstevel@tonic-gate 		free(buf);
13760Sstevel@tonic-gate 		goto cleanup;
13770Sstevel@tonic-gate 	}
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	/* write new hmac */
13808932SDina.Nimeh@Sun.COM 	if (writen_nointr(new_fd, (char *)hmac, OBJ_HMAC_SIZE)
13810Sstevel@tonic-gate 	    != OBJ_HMAC_SIZE) {
13820Sstevel@tonic-gate 		free(buf);
13830Sstevel@tonic-gate 		goto cleanup;
13840Sstevel@tonic-gate 	}
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	/* write re-encrypted buffer to temp file */
13878932SDina.Nimeh@Sun.COM 	if (writen_nointr(new_fd, (void *)buf, encrypted_len)
13880Sstevel@tonic-gate 	    != encrypted_len) {
13890Sstevel@tonic-gate 		free(buf);
13900Sstevel@tonic-gate 		goto cleanup;
13910Sstevel@tonic-gate 	}
13920Sstevel@tonic-gate 	free(buf);
13930Sstevel@tonic-gate 	ret_val = 0;
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate cleanup:
13960Sstevel@tonic-gate 	/* unlock the files */
13970Sstevel@tonic-gate 	(void) lock_file(old_fd, B_TRUE, B_FALSE);
13980Sstevel@tonic-gate 	(void) lock_file(new_fd, B_FALSE, B_FALSE);
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 	(void) close(old_fd);
14010Sstevel@tonic-gate 	(void) close(new_fd);
14020Sstevel@tonic-gate 	if (ret_val != 0) {
14030Sstevel@tonic-gate 		(void) remove(new_obj_name);
14040Sstevel@tonic-gate 	}
14050Sstevel@tonic-gate 	return (ret_val);
14060Sstevel@tonic-gate }
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate /*
14090Sstevel@tonic-gate  *	FUNCTION: soft_keystore_setpin
14100Sstevel@tonic-gate  *
14110Sstevel@tonic-gate  *	ARGUMENTS:
14120Sstevel@tonic-gate  *		newpin: new pin entered by the user.
14130Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
14140Sstevel@tonic-gate  *
14150Sstevel@tonic-gate  *	RETURN VALUE:
14160Sstevel@tonic-gate  *		0: no error
14170Sstevel@tonic-gate  *		-1: failure
14180Sstevel@tonic-gate  *
14190Sstevel@tonic-gate  *	DESCRIPTION:
14200Sstevel@tonic-gate  *
14210Sstevel@tonic-gate  *		This function does the following:
14220Sstevel@tonic-gate  *
14230Sstevel@tonic-gate  *		1) Generates crypted value of newpin and store it
14240Sstevel@tonic-gate  *		   in keystore description file.
14250Sstevel@tonic-gate  *		2) Dervies the new encryption key from the newpin.  This key
14260Sstevel@tonic-gate  *		   will be used to re-encrypt the private token objects.
14270Sstevel@tonic-gate  *		3) Re-encrypt all of this user's existing private token
14280Sstevel@tonic-gate  *		   objects (if any).
14290Sstevel@tonic-gate  *		4) Increments the keystore version number.
14300Sstevel@tonic-gate  */
14310Sstevel@tonic-gate int
soft_keystore_setpin(uchar_t * oldpin,uchar_t * newpin,boolean_t lock_held)14320Sstevel@tonic-gate soft_keystore_setpin(uchar_t *oldpin, uchar_t *newpin, boolean_t lock_held)
14330Sstevel@tonic-gate {
14340Sstevel@tonic-gate 	int fd, tmp_ks_fd, version, ret_val = -1;
14350Sstevel@tonic-gate 	soft_object_t *new_crypt_key = NULL, *new_hmac_key = NULL;
14360Sstevel@tonic-gate 	char filebuf[BUFSIZ];
14370Sstevel@tonic-gate 	DIR	*pri_dirp;
1438871Scasper 	struct dirent *pri_ent;
14390Sstevel@tonic-gate 	char pri_obj_path[MAXPATHLEN], ks_desc_file[MAXPATHLEN],
14400Sstevel@tonic-gate 	    tmp_ks_desc_name[MAXPATHLEN];
14410Sstevel@tonic-gate 	typedef struct priobjs {
14420Sstevel@tonic-gate 		char orig_name[MAXPATHLEN];
14430Sstevel@tonic-gate 		char tmp_name[MAXPATHLEN];
14440Sstevel@tonic-gate 		struct priobjs *next;
14450Sstevel@tonic-gate 	} priobjs_t;
14460Sstevel@tonic-gate 	priobjs_t *pri_objs = NULL, *tmp;
14470Sstevel@tonic-gate 	CK_BYTE *crypt_salt = NULL, *hmac_salt = NULL;
14480Sstevel@tonic-gate 	boolean_t pin_never_set = B_FALSE, user_logged_in;
14490Sstevel@tonic-gate 	char *new_hashed_pin = NULL;
14500Sstevel@tonic-gate 	uint64_t hashed_pin_salt_length, new_hashed_pin_len, swaped_val;
14510Sstevel@tonic-gate 	char *hashed_pin_salt = NULL;
14520Sstevel@tonic-gate 	priobjs_t *obj;
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	if ((enc_key == NULL) ||
14550Sstevel@tonic-gate 	    (enc_key->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
14560Sstevel@tonic-gate 		user_logged_in = B_FALSE;
14570Sstevel@tonic-gate 	} else {
14580Sstevel@tonic-gate 		user_logged_in = B_TRUE;
14590Sstevel@tonic-gate 	}
14600Sstevel@tonic-gate 
146112256SPeter.Shoults@Sun.COM 	if ((fd = open_and_lock_keystore_desc(O_RDWR, B_TRUE,
14620Sstevel@tonic-gate 	    lock_held)) < 0) {
14630Sstevel@tonic-gate 		return (-1);
14640Sstevel@tonic-gate 	}
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate 	(void) get_desc_file_path(ks_desc_file);
14670Sstevel@tonic-gate 	(void) get_tmp_desc_file_path(tmp_ks_desc_name);
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate 	/*
14700Sstevel@tonic-gate 	 * create a tempoary file for the keystore description
14710Sstevel@tonic-gate 	 * file for updating version and counter information
14720Sstevel@tonic-gate 	 */
14738932SDina.Nimeh@Sun.COM 	tmp_ks_fd = open_nointr(tmp_ks_desc_name,
14748932SDina.Nimeh@Sun.COM 	    O_RDWR|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
14750Sstevel@tonic-gate 	if (tmp_ks_fd < 0) {
14760Sstevel@tonic-gate 		(void) close(fd);
14770Sstevel@tonic-gate 		return (-1);
14780Sstevel@tonic-gate 	}
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	/* read and write PKCS version to temp file */
14818932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, filebuf, KS_PKCS11_VER_SIZE)
14820Sstevel@tonic-gate 	    != KS_PKCS11_VER_SIZE) {
14830Sstevel@tonic-gate 		goto cleanup;
14840Sstevel@tonic-gate 	}
14850Sstevel@tonic-gate 
14868932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_ks_fd, filebuf, KS_PKCS11_VER_SIZE)
14870Sstevel@tonic-gate 	    != KS_PKCS11_VER_SIZE) {
14880Sstevel@tonic-gate 		goto cleanup;
14890Sstevel@tonic-gate 	}
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	/* get version number, and write updated number to temp file */
14928932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, &version, KS_VER_SIZE) != KS_VER_SIZE) {
14930Sstevel@tonic-gate 		goto cleanup;
14940Sstevel@tonic-gate 	}
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 	version = SWAP32(version);
14970Sstevel@tonic-gate 	version++;
14980Sstevel@tonic-gate 	version = SWAP32(version);
14990Sstevel@tonic-gate 
15008932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_ks_fd, (void *)&version, KS_VER_SIZE)
15010Sstevel@tonic-gate 	    != KS_VER_SIZE) {
15020Sstevel@tonic-gate 		goto cleanup;
15030Sstevel@tonic-gate 	}
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	/* read and write counter, no modification necessary */
15078932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, filebuf, KS_COUNTER_SIZE) != KS_COUNTER_SIZE) {
15080Sstevel@tonic-gate 		goto cleanup;
15090Sstevel@tonic-gate 	}
15100Sstevel@tonic-gate 
15118932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_ks_fd, filebuf, KS_COUNTER_SIZE)
15120Sstevel@tonic-gate 	    != KS_COUNTER_SIZE) {
15130Sstevel@tonic-gate 		goto cleanup;
15140Sstevel@tonic-gate 	}
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	/* read old encryption salt */
15170Sstevel@tonic-gate 	crypt_salt = malloc(KS_KEY_SALT_SIZE);
15180Sstevel@tonic-gate 	if (crypt_salt == NULL) {
15190Sstevel@tonic-gate 		goto cleanup;
15200Sstevel@tonic-gate 	}
15218932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)crypt_salt, KS_KEY_SALT_SIZE)
15220Sstevel@tonic-gate 	    != KS_KEY_SALT_SIZE) {
15230Sstevel@tonic-gate 		goto cleanup;
15240Sstevel@tonic-gate 	}
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 	/* read old hmac salt */
15270Sstevel@tonic-gate 	hmac_salt = malloc(KS_HMAC_SALT_SIZE);
15280Sstevel@tonic-gate 	if (hmac_salt == NULL) {
15290Sstevel@tonic-gate 		goto cleanup;
15300Sstevel@tonic-gate 	}
15318932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)hmac_salt, KS_HMAC_SALT_SIZE)
15320Sstevel@tonic-gate 	    != KS_HMAC_SALT_SIZE) {
15330Sstevel@tonic-gate 		goto cleanup;
15340Sstevel@tonic-gate 	}
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 	/* just create some empty bytes */
15370Sstevel@tonic-gate 	bzero(filebuf, sizeof (filebuf));
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate 	if (memcmp(crypt_salt, filebuf, KS_KEY_SALT_SIZE) == 0) {
15400Sstevel@tonic-gate 		/* PIN as never been set */
15410Sstevel@tonic-gate 		CK_BYTE *new_crypt_salt = NULL, *new_hmac_salt = NULL;
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 		pin_never_set = B_TRUE;
15440Sstevel@tonic-gate 		if (soft_gen_crypt_key(newpin, &new_crypt_key, &new_crypt_salt)
15450Sstevel@tonic-gate 		    != CKR_OK) {
15460Sstevel@tonic-gate 			goto cleanup;
15470Sstevel@tonic-gate 		}
15488932SDina.Nimeh@Sun.COM 		if (writen_nointr(tmp_ks_fd, (void *)new_crypt_salt,
15490Sstevel@tonic-gate 		    KS_KEY_SALT_SIZE) != KS_KEY_SALT_SIZE) {
15500Sstevel@tonic-gate 			free(new_crypt_salt);
15510Sstevel@tonic-gate 			(void) soft_cleanup_object(new_crypt_key);
15520Sstevel@tonic-gate 			goto cleanup;
15530Sstevel@tonic-gate 		}
15540Sstevel@tonic-gate 		free(new_crypt_salt);
15550Sstevel@tonic-gate 
15560Sstevel@tonic-gate 		if (soft_gen_hmac_key(newpin, &new_hmac_key, &new_hmac_salt)
15570Sstevel@tonic-gate 		    != CKR_OK) {
15580Sstevel@tonic-gate 			(void) soft_cleanup_object(new_crypt_key);
15590Sstevel@tonic-gate 			goto cleanup;
15600Sstevel@tonic-gate 		}
15618932SDina.Nimeh@Sun.COM 		if (writen_nointr(tmp_ks_fd, (void *)new_hmac_salt,
15620Sstevel@tonic-gate 		    KS_HMAC_SALT_SIZE) != KS_HMAC_SALT_SIZE) {
15630Sstevel@tonic-gate 			free(new_hmac_salt);
15640Sstevel@tonic-gate 			goto cleanup3;
15650Sstevel@tonic-gate 		}
15660Sstevel@tonic-gate 		free(new_hmac_salt);
15670Sstevel@tonic-gate 	} else {
15680Sstevel@tonic-gate 		if (soft_gen_crypt_key(newpin, &new_crypt_key,
15690Sstevel@tonic-gate 		    (CK_BYTE **)&crypt_salt) != CKR_OK) {
15700Sstevel@tonic-gate 			goto cleanup;
15710Sstevel@tonic-gate 		}
15720Sstevel@tonic-gate 		/* no change to the encryption salt */
15738932SDina.Nimeh@Sun.COM 		if (writen_nointr(tmp_ks_fd, (void *)crypt_salt,
15740Sstevel@tonic-gate 		    KS_KEY_SALT_SIZE) != KS_KEY_SALT_SIZE) {
15750Sstevel@tonic-gate 			(void) soft_cleanup_object(new_crypt_key);
15760Sstevel@tonic-gate 			goto cleanup;
15770Sstevel@tonic-gate 		}
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 		if (soft_gen_hmac_key(newpin, &new_hmac_key,
15800Sstevel@tonic-gate 		    (CK_BYTE **)&hmac_salt) != CKR_OK) {
15810Sstevel@tonic-gate 			(void) soft_cleanup_object(new_crypt_key);
15820Sstevel@tonic-gate 			goto cleanup;
15830Sstevel@tonic-gate 		}
15840Sstevel@tonic-gate 
15850Sstevel@tonic-gate 		/* no change to the hmac salt */
15868932SDina.Nimeh@Sun.COM 		if (writen_nointr(tmp_ks_fd, (void *)hmac_salt,
15870Sstevel@tonic-gate 		    KS_HMAC_SALT_SIZE) != KS_HMAC_SALT_SIZE) {
15880Sstevel@tonic-gate 			goto cleanup3;
15890Sstevel@tonic-gate 		}
15900Sstevel@tonic-gate 	}
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	/*
15930Sstevel@tonic-gate 	 * read hashed pin salt, and write to updated keystore description
15940Sstevel@tonic-gate 	 * file unmodified.
15950Sstevel@tonic-gate 	 */
15968932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)&hashed_pin_salt_length,
15970Sstevel@tonic-gate 	    KS_HASHED_PIN_SALT_LEN_SIZE) != KS_HASHED_PIN_SALT_LEN_SIZE) {
15980Sstevel@tonic-gate 		goto cleanup3;
15990Sstevel@tonic-gate 	}
16000Sstevel@tonic-gate 
16018932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_ks_fd, (void *)&hashed_pin_salt_length,
16020Sstevel@tonic-gate 	    KS_HASHED_PIN_SALT_LEN_SIZE) != KS_HASHED_PIN_SALT_LEN_SIZE) {
16030Sstevel@tonic-gate 		goto cleanup3;
16040Sstevel@tonic-gate 	}
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 	hashed_pin_salt_length = SWAP64(hashed_pin_salt_length);
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 	hashed_pin_salt = malloc(hashed_pin_salt_length + 1);
16090Sstevel@tonic-gate 	if (hashed_pin_salt == NULL) {
16100Sstevel@tonic-gate 		goto cleanup3;
16110Sstevel@tonic-gate 	}
16120Sstevel@tonic-gate 
16138932SDina.Nimeh@Sun.COM 	if ((readn_nointr(fd, hashed_pin_salt, hashed_pin_salt_length)) !=
16140Sstevel@tonic-gate 	    (ssize_t)hashed_pin_salt_length) {
16150Sstevel@tonic-gate 		free(hashed_pin_salt);
16160Sstevel@tonic-gate 		goto cleanup3;
16170Sstevel@tonic-gate 	}
16180Sstevel@tonic-gate 
16198932SDina.Nimeh@Sun.COM 	if ((writen_nointr(tmp_ks_fd, hashed_pin_salt, hashed_pin_salt_length))
16200Sstevel@tonic-gate 	    != (ssize_t)hashed_pin_salt_length) {
16210Sstevel@tonic-gate 		free(hashed_pin_salt);
16220Sstevel@tonic-gate 		goto cleanup3;
16230Sstevel@tonic-gate 	}
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 	hashed_pin_salt[hashed_pin_salt_length] = '\0';
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 	/* old hashed pin length and value can be ignored, generate new one */
16280Sstevel@tonic-gate 	if (soft_gen_hashed_pin(newpin, &new_hashed_pin,
16290Sstevel@tonic-gate 	    &hashed_pin_salt) < 0) {
16300Sstevel@tonic-gate 		free(hashed_pin_salt);
16310Sstevel@tonic-gate 		goto cleanup3;
16320Sstevel@tonic-gate 	}
16330Sstevel@tonic-gate 
16340Sstevel@tonic-gate 	free(hashed_pin_salt);
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	if (new_hashed_pin == NULL) {
16370Sstevel@tonic-gate 		goto cleanup3;
16380Sstevel@tonic-gate 	}
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 	new_hashed_pin_len = strlen(new_hashed_pin);
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 	/* write new hashed pin length to file */
16430Sstevel@tonic-gate 	swaped_val = SWAP64(new_hashed_pin_len);
16448932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_ks_fd, (void *)&swaped_val,
16450Sstevel@tonic-gate 	    KS_HASHED_PINLEN_SIZE) != KS_HASHED_PINLEN_SIZE) {
16460Sstevel@tonic-gate 		goto cleanup3;
16470Sstevel@tonic-gate 	}
16480Sstevel@tonic-gate 
16498932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_ks_fd, (void *)new_hashed_pin,
16500Sstevel@tonic-gate 	    new_hashed_pin_len) != (ssize_t)new_hashed_pin_len) {
16510Sstevel@tonic-gate 		goto cleanup3;
16520Sstevel@tonic-gate 	}
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	if (pin_never_set) {
16550Sstevel@tonic-gate 		/* there was no private object, no need to re-encrypt them */
16560Sstevel@tonic-gate 		goto rename_desc_file;
16570Sstevel@tonic-gate 	}
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	/* re-encrypt all the private objects */
16600Sstevel@tonic-gate 	pri_dirp = opendir(get_pri_obj_path(pri_obj_path));
16610Sstevel@tonic-gate 	if (pri_dirp == NULL) {
16620Sstevel@tonic-gate 		/*
16630Sstevel@tonic-gate 		 * this directory should exist, even if it doesn't contain
16640Sstevel@tonic-gate 		 * any objects.  Don't want to update the pin if the
16650Sstevel@tonic-gate 		 * keystore is somehow messed up.
16660Sstevel@tonic-gate 		 */
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 		goto cleanup3;
16690Sstevel@tonic-gate 	}
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 	/* if user did not login, need to set the old pin */
16720Sstevel@tonic-gate 	if (!user_logged_in) {
16730Sstevel@tonic-gate 		if (soft_keystore_authpin(oldpin) != 0) {
16740Sstevel@tonic-gate 			goto cleanup3;
16750Sstevel@tonic-gate 		}
16760Sstevel@tonic-gate 	}
16770Sstevel@tonic-gate 
1678871Scasper 	while ((pri_ent = readdir(pri_dirp)) != NULL) {
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 		if ((strcmp(pri_ent->d_name, ".") == 0) ||
16810Sstevel@tonic-gate 		    (strcmp(pri_ent->d_name, "..") == 0) ||
16820Sstevel@tonic-gate 		    (strncmp(pri_ent->d_name, TMP_OBJ_PREFIX,
16830Sstevel@tonic-gate 		    strlen(TMP_OBJ_PREFIX)) == 0)) {
16840Sstevel@tonic-gate 			continue;
16850Sstevel@tonic-gate 		}
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 		obj = malloc(sizeof (priobjs_t));
16880Sstevel@tonic-gate 		if (obj == NULL) {
16890Sstevel@tonic-gate 			goto cleanup2;
16900Sstevel@tonic-gate 		}
16910Sstevel@tonic-gate 		(void) snprintf(obj->orig_name, MAXPATHLEN,
16920Sstevel@tonic-gate 		    "%s/%s", pri_obj_path, pri_ent->d_name);
16930Sstevel@tonic-gate 		(void) snprintf(obj->tmp_name, MAXPATHLEN, "%s/%s%s",
16940Sstevel@tonic-gate 		    pri_obj_path, TMP_OBJ_PREFIX,
16959341SAnthony.Scarpino@Sun.COM 		    (pri_ent->d_name) + OBJ_PREFIX_LEN);
16960Sstevel@tonic-gate 		if (reencrypt_obj(new_crypt_key, new_hmac_key,
16970Sstevel@tonic-gate 		    obj->orig_name, obj->tmp_name) != 0) {
16980Sstevel@tonic-gate 			free(obj);
16990Sstevel@tonic-gate 			goto cleanup2;
17000Sstevel@tonic-gate 		}
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 		/* insert into list of file to be renamed */
17030Sstevel@tonic-gate 		if (pri_objs == NULL) {
17040Sstevel@tonic-gate 			obj->next = NULL;
17050Sstevel@tonic-gate 			pri_objs = obj;
17060Sstevel@tonic-gate 		} else {
17070Sstevel@tonic-gate 			obj->next = pri_objs;
17080Sstevel@tonic-gate 			pri_objs = obj;
17090Sstevel@tonic-gate 		}
17100Sstevel@tonic-gate 	}
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	/* rename all the private objects */
17130Sstevel@tonic-gate 	tmp = pri_objs;
17140Sstevel@tonic-gate 	while (tmp) {
17150Sstevel@tonic-gate 		(void) rename(tmp->tmp_name, tmp->orig_name);
17160Sstevel@tonic-gate 		tmp = tmp->next;
17170Sstevel@tonic-gate 	}
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate rename_desc_file:
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate 	/* destroy the old encryption key, and hmac key */
17220Sstevel@tonic-gate 	if ((!pin_never_set) && (user_logged_in)) {
17230Sstevel@tonic-gate 		(void) soft_cleanup_object(enc_key);
17240Sstevel@tonic-gate 		(void) soft_cleanup_object(hmac_key);
17250Sstevel@tonic-gate 	}
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 	if (user_logged_in) {
17280Sstevel@tonic-gate 		enc_key = new_crypt_key;
17290Sstevel@tonic-gate 		hmac_key = new_hmac_key;
17300Sstevel@tonic-gate 	}
17310Sstevel@tonic-gate 	(void) rename(tmp_ks_desc_name, ks_desc_file);
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate 	ret_val = 0;
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate cleanup2:
17360Sstevel@tonic-gate 	if (pri_objs != NULL) {
17370Sstevel@tonic-gate 		priobjs_t *p = pri_objs;
17380Sstevel@tonic-gate 		while (p) {
17390Sstevel@tonic-gate 			tmp = p->next;
17400Sstevel@tonic-gate 			free(p);
17410Sstevel@tonic-gate 			p = tmp;
17420Sstevel@tonic-gate 		}
17430Sstevel@tonic-gate 	}
17440Sstevel@tonic-gate 	if (!pin_never_set) {
17450Sstevel@tonic-gate 		(void) closedir(pri_dirp);
17460Sstevel@tonic-gate 	}
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	if ((!user_logged_in) && (!pin_never_set)) {
17490Sstevel@tonic-gate 		(void) soft_cleanup_object(enc_key);
17500Sstevel@tonic-gate 		(void) soft_cleanup_object(hmac_key);
17510Sstevel@tonic-gate 		enc_key = NULL;
17520Sstevel@tonic-gate 		hmac_key = NULL;
17530Sstevel@tonic-gate 	}
17540Sstevel@tonic-gate cleanup3:
17550Sstevel@tonic-gate 	if ((ret_val != 0) || (!user_logged_in)) {
17560Sstevel@tonic-gate 		(void) soft_cleanup_object(new_crypt_key);
17570Sstevel@tonic-gate 		(void) soft_cleanup_object(new_hmac_key);
17580Sstevel@tonic-gate 	}
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate cleanup:
17610Sstevel@tonic-gate 	if (!lock_held) {
17620Sstevel@tonic-gate 		if (lock_file(fd, B_FALSE, B_FALSE) < 0) {
17630Sstevel@tonic-gate 			ret_val = 1;
17640Sstevel@tonic-gate 		}
17650Sstevel@tonic-gate 	}
17660Sstevel@tonic-gate 	if (crypt_salt != NULL) {
17670Sstevel@tonic-gate 		free(crypt_salt);
17680Sstevel@tonic-gate 	}
17690Sstevel@tonic-gate 	if (hmac_salt != NULL) {
17700Sstevel@tonic-gate 		free(hmac_salt);
17710Sstevel@tonic-gate 	}
17720Sstevel@tonic-gate 	(void) close(fd);
17730Sstevel@tonic-gate 	(void) close(tmp_ks_fd);
17740Sstevel@tonic-gate 	if (ret_val != 0) {
17750Sstevel@tonic-gate 		(void) remove(tmp_ks_desc_name);
17760Sstevel@tonic-gate 	}
17770Sstevel@tonic-gate 	return (ret_val);
17780Sstevel@tonic-gate }
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate /*
17810Sstevel@tonic-gate  *	FUNCTION: soft_keystore_authpin
17820Sstevel@tonic-gate  *
17830Sstevel@tonic-gate  *	ARGUMENTS:
17840Sstevel@tonic-gate  *		pin: pin specified by the user for logging into
17850Sstevel@tonic-gate  *		     the keystore.
17860Sstevel@tonic-gate  *
17870Sstevel@tonic-gate  *	RETURN VALUE:
17880Sstevel@tonic-gate  *		0: if no error
17890Sstevel@tonic-gate  *		-1: if there is any error
17900Sstevel@tonic-gate  *
17910Sstevel@tonic-gate  *	DESCRIPTION:
17920Sstevel@tonic-gate  *
17930Sstevel@tonic-gate  *		This function takes the pin specified in the argument
17940Sstevel@tonic-gate  *		and generates an encryption key based on the pin.
17950Sstevel@tonic-gate  *		The generated encryption key will be used for
17960Sstevel@tonic-gate  *		all future encryption and decryption for private
17970Sstevel@tonic-gate  *		objects.  Before this function is called, none
17980Sstevel@tonic-gate  *		of the keystore related interfaces is able
17990Sstevel@tonic-gate  *		to decrypt/encrypt any private object.
18000Sstevel@tonic-gate  */
18010Sstevel@tonic-gate int
soft_keystore_authpin(uchar_t * pin)18020Sstevel@tonic-gate soft_keystore_authpin(uchar_t  *pin)
18030Sstevel@tonic-gate {
18040Sstevel@tonic-gate 	int fd;
18050Sstevel@tonic-gate 	int ret_val = -1;
18060Sstevel@tonic-gate 	CK_BYTE *crypt_salt = NULL, *hmac_salt;
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	/* get the salt from the keystore description file */
18090Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDONLY,
18100Sstevel@tonic-gate 	    B_FALSE, B_FALSE)) < 0) {
18110Sstevel@tonic-gate 		return (-1);
18120Sstevel@tonic-gate 	}
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate 	crypt_salt = malloc(KS_KEY_SALT_SIZE);
18150Sstevel@tonic-gate 	if (crypt_salt == NULL) {
18160Sstevel@tonic-gate 		goto cleanup;
18170Sstevel@tonic-gate 	}
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate 	if (lseek(fd, KS_KEY_SALT_OFFSET, SEEK_SET) != KS_KEY_SALT_OFFSET) {
18200Sstevel@tonic-gate 		goto cleanup;
18210Sstevel@tonic-gate 	}
18220Sstevel@tonic-gate 
18238932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)crypt_salt, KS_KEY_SALT_SIZE)
18240Sstevel@tonic-gate 	    != KS_KEY_SALT_SIZE) {
18250Sstevel@tonic-gate 		goto cleanup;
18260Sstevel@tonic-gate 	}
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 	if (soft_gen_crypt_key(pin, &enc_key, (CK_BYTE **)&crypt_salt)
18290Sstevel@tonic-gate 	    != CKR_OK) {
18300Sstevel@tonic-gate 		goto cleanup;
18310Sstevel@tonic-gate 	}
18320Sstevel@tonic-gate 
18330Sstevel@tonic-gate 	hmac_salt = malloc(KS_HMAC_SALT_SIZE);
18340Sstevel@tonic-gate 	if (hmac_salt == NULL) {
18350Sstevel@tonic-gate 		goto cleanup;
18360Sstevel@tonic-gate 	}
18370Sstevel@tonic-gate 
18380Sstevel@tonic-gate 	if (lseek(fd, KS_HMAC_SALT_OFFSET, SEEK_SET) != KS_HMAC_SALT_OFFSET) {
18390Sstevel@tonic-gate 		goto cleanup;
18400Sstevel@tonic-gate 	}
18410Sstevel@tonic-gate 
18428932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)hmac_salt, KS_HMAC_SALT_SIZE)
18430Sstevel@tonic-gate 	    != KS_HMAC_SALT_SIZE) {
18440Sstevel@tonic-gate 		goto cleanup;
18450Sstevel@tonic-gate 	}
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 	if (soft_gen_hmac_key(pin, &hmac_key, (CK_BYTE **)&hmac_salt)
18480Sstevel@tonic-gate 	    != CKR_OK) {
18490Sstevel@tonic-gate 		goto cleanup;
18500Sstevel@tonic-gate 	}
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 	ret_val = 0;
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate cleanup:
18550Sstevel@tonic-gate 	/* unlock the file */
18560Sstevel@tonic-gate 	(void) lock_file(fd, B_TRUE, B_FALSE);
18570Sstevel@tonic-gate 	(void) close(fd);
18580Sstevel@tonic-gate 	if (crypt_salt != NULL) {
18590Sstevel@tonic-gate 		free(crypt_salt);
18600Sstevel@tonic-gate 	}
18610Sstevel@tonic-gate 	if (hmac_salt != NULL) {
18620Sstevel@tonic-gate 		free(hmac_salt);
18630Sstevel@tonic-gate 	}
18640Sstevel@tonic-gate 	return (ret_val);
18650Sstevel@tonic-gate }
18660Sstevel@tonic-gate 
18670Sstevel@tonic-gate /*
18680Sstevel@tonic-gate  * 	FUNCTION: soft_keystore_get_objs
18690Sstevel@tonic-gate  *
18700Sstevel@tonic-gate  *	ARGUMENTS:
18710Sstevel@tonic-gate  *
18720Sstevel@tonic-gate  *		search_type: Specify type of objects to return.
18730Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
18740Sstevel@tonic-gate  *
18750Sstevel@tonic-gate  *
18760Sstevel@tonic-gate  *	RETURN VALUE:
18770Sstevel@tonic-gate  *
18780Sstevel@tonic-gate  *		NULL: if there are no object in the database.
18790Sstevel@tonic-gate  *
18800Sstevel@tonic-gate  *		Otherwise, linked list of objects as requested
18810Sstevel@tonic-gate  *		in search type.
18820Sstevel@tonic-gate  *
18830Sstevel@tonic-gate  *		The linked list returned will need to be freed
18840Sstevel@tonic-gate  *		by the caller.
18850Sstevel@tonic-gate  *
18860Sstevel@tonic-gate  *	DESCRIPTION:
18870Sstevel@tonic-gate  *
18880Sstevel@tonic-gate  *		Returns objects as requested.
18890Sstevel@tonic-gate  *
18900Sstevel@tonic-gate  *		If private objects is requested, and the caller
18910Sstevel@tonic-gate  *		has not previously passed in the pin or if the pin
18920Sstevel@tonic-gate  *		passed in is wrong, private objects will not
18930Sstevel@tonic-gate  *		be returned.
18940Sstevel@tonic-gate  *
18950Sstevel@tonic-gate  *		The buffers returned for private objects are already
18960Sstevel@tonic-gate  *		decrypted.
18970Sstevel@tonic-gate  */
18980Sstevel@tonic-gate CK_RV
soft_keystore_get_objs(ks_search_type_t search_type,ks_obj_t ** result_obj_list,boolean_t lock_held)18990Sstevel@tonic-gate soft_keystore_get_objs(ks_search_type_t search_type,
19000Sstevel@tonic-gate     ks_obj_t **result_obj_list, boolean_t lock_held)
19010Sstevel@tonic-gate {
19020Sstevel@tonic-gate 	DIR *dirp;
19030Sstevel@tonic-gate 	ks_obj_handle_t ks_handle;
19040Sstevel@tonic-gate 	CK_RV rv;
19050Sstevel@tonic-gate 	ks_obj_t *tmp;
19060Sstevel@tonic-gate 	int ks_fd;
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 	*result_obj_list = NULL;
19090Sstevel@tonic-gate 
19100Sstevel@tonic-gate 	/*
19110Sstevel@tonic-gate 	 * lock the keystore description file in "read" mode so that
19120Sstevel@tonic-gate 	 * objects won't get added/deleted/modified while we are
19130Sstevel@tonic-gate 	 * doing the search
19140Sstevel@tonic-gate 	 */
191512256SPeter.Shoults@Sun.COM 	if ((ks_fd = open_and_lock_keystore_desc(O_RDONLY, B_FALSE,
19160Sstevel@tonic-gate 	    B_FALSE)) < 0) {
19170Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
19180Sstevel@tonic-gate 	}
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	if ((search_type == ALL_TOKENOBJS) || (search_type == PUB_TOKENOBJS)) {
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 		char pub_obj_path[MAXPATHLEN];
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate 		ks_handle.public = B_TRUE;
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 		if ((dirp = opendir(get_pub_obj_path(pub_obj_path))) == NULL) {
19270Sstevel@tonic-gate 			(void) lock_file(ks_fd, B_TRUE, B_FALSE);
19280Sstevel@tonic-gate 			(void) close(ks_fd);
19290Sstevel@tonic-gate 			return (CKR_FUNCTION_FAILED);
19300Sstevel@tonic-gate 		}
19310Sstevel@tonic-gate 		rv = get_all_objs_in_dir(dirp, &ks_handle, result_obj_list,
1932871Scasper 		    lock_held);
19330Sstevel@tonic-gate 		if (rv != CKR_OK) {
19340Sstevel@tonic-gate 			(void) closedir(dirp);
19350Sstevel@tonic-gate 			goto cleanup;
19360Sstevel@tonic-gate 		}
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate 		(void) closedir(dirp);
19390Sstevel@tonic-gate 	}
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate 	if ((search_type == ALL_TOKENOBJS) || (search_type == PRI_TOKENOBJS)) {
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 		char pri_obj_path[MAXPATHLEN];
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate 		if ((enc_key == NULL) ||
19460Sstevel@tonic-gate 		    (enc_key->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
19470Sstevel@tonic-gate 			/* has not login - no need to go any further */
19480Sstevel@tonic-gate 			(void) lock_file(ks_fd, B_TRUE, B_FALSE);
19490Sstevel@tonic-gate 			(void) close(ks_fd);
19500Sstevel@tonic-gate 			return (CKR_OK);
19510Sstevel@tonic-gate 		}
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 		ks_handle.public = B_FALSE;
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 		if ((dirp = opendir(get_pri_obj_path(pri_obj_path))) == NULL) {
19560Sstevel@tonic-gate 			(void) lock_file(ks_fd, B_TRUE, B_FALSE);
19570Sstevel@tonic-gate 			(void) close(ks_fd);
19580Sstevel@tonic-gate 			return (CKR_OK);
19590Sstevel@tonic-gate 		}
19600Sstevel@tonic-gate 		rv = get_all_objs_in_dir(dirp, &ks_handle, result_obj_list,
1961871Scasper 		    lock_held);
19620Sstevel@tonic-gate 		if (rv != CKR_OK) {
19630Sstevel@tonic-gate 			(void) closedir(dirp);
19640Sstevel@tonic-gate 			goto cleanup;
19650Sstevel@tonic-gate 		}
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 		(void) closedir(dirp);
19680Sstevel@tonic-gate 	}
19690Sstevel@tonic-gate 	/* close the keystore description file */
19700Sstevel@tonic-gate 	(void) lock_file(ks_fd, B_TRUE, B_FALSE);
19710Sstevel@tonic-gate 	(void) close(ks_fd);
19720Sstevel@tonic-gate 	return (CKR_OK);
19730Sstevel@tonic-gate cleanup:
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate 	/* close the keystore description file */
19760Sstevel@tonic-gate 	(void) lock_file(ks_fd, B_TRUE, B_FALSE);
19770Sstevel@tonic-gate 	(void) close(ks_fd);
19780Sstevel@tonic-gate 
19790Sstevel@tonic-gate 	/* free all the objects found before hitting the error */
19800Sstevel@tonic-gate 	tmp = *result_obj_list;
19810Sstevel@tonic-gate 	while (tmp) {
19820Sstevel@tonic-gate 		*result_obj_list = tmp->next;
19830Sstevel@tonic-gate 		free(tmp->buf);
19840Sstevel@tonic-gate 		free(tmp);
19850Sstevel@tonic-gate 		tmp = *result_obj_list;
19860Sstevel@tonic-gate 	}
19870Sstevel@tonic-gate 	*result_obj_list = NULL;
19880Sstevel@tonic-gate 	return (rv);
19890Sstevel@tonic-gate }
19900Sstevel@tonic-gate 
19910Sstevel@tonic-gate 
19920Sstevel@tonic-gate /*
19930Sstevel@tonic-gate  *	FUNCTION: soft_keystore_get_single_obj
19940Sstevel@tonic-gate  *
19950Sstevel@tonic-gate  *	ARGUMENTS:
19960Sstevel@tonic-gate  *		ks_handle: handle of the key store object to be accessed
19970Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
19980Sstevel@tonic-gate  *
19990Sstevel@tonic-gate  *	RETURN VALUE:
20000Sstevel@tonic-gate  *
20010Sstevel@tonic-gate  *		NULL: if handle doesn't match any object
20020Sstevel@tonic-gate  *
20030Sstevel@tonic-gate  *		Otherwise, the object is returned in
20040Sstevel@tonic-gate  *		the same structure used in soft_keystore_get_objs().
20050Sstevel@tonic-gate  *		The structure need to be freed by the caller.
20060Sstevel@tonic-gate  *
20070Sstevel@tonic-gate  *	DESCRIPTION:
20080Sstevel@tonic-gate  *
20090Sstevel@tonic-gate  *		Retrieves the object specified by the object
20100Sstevel@tonic-gate  *		handle to the caller.
20110Sstevel@tonic-gate  *
20120Sstevel@tonic-gate  *		If a private object is requested, and the caller
20130Sstevel@tonic-gate  *		has not previously passed in the pin or if the pin
20140Sstevel@tonic-gate  *		passed in is wrong, the requested private object will not
20150Sstevel@tonic-gate  *		be returned.
20160Sstevel@tonic-gate  *
20170Sstevel@tonic-gate  *		The buffer returned for the requested private object
20180Sstevel@tonic-gate  *		is already decrypted.
20190Sstevel@tonic-gate  */
20200Sstevel@tonic-gate CK_RV
soft_keystore_get_single_obj(ks_obj_handle_t * ks_handle,ks_obj_t ** return_obj,boolean_t lock_held)20210Sstevel@tonic-gate soft_keystore_get_single_obj(ks_obj_handle_t *ks_handle,
20220Sstevel@tonic-gate     ks_obj_t **return_obj, boolean_t lock_held)
20230Sstevel@tonic-gate {
20240Sstevel@tonic-gate 
20250Sstevel@tonic-gate 	ks_obj_t *obj;
20260Sstevel@tonic-gate 	uchar_t iv[OBJ_IV_SIZE], obj_hmac[OBJ_HMAC_SIZE];
20270Sstevel@tonic-gate 	uchar_t *buf, *decrypted_buf;
20280Sstevel@tonic-gate 	int fd;
20290Sstevel@tonic-gate 	ssize_t nread;
20300Sstevel@tonic-gate 	CK_RV rv = CKR_FUNCTION_FAILED;
20310Sstevel@tonic-gate 
20320Sstevel@tonic-gate 	if (!(ks_handle->public)) {
20330Sstevel@tonic-gate 		if ((enc_key == NULL) ||
20340Sstevel@tonic-gate 		    (enc_key->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
20350Sstevel@tonic-gate 			return (CKR_FUNCTION_FAILED);
20360Sstevel@tonic-gate 		}
20370Sstevel@tonic-gate 	}
20380Sstevel@tonic-gate 
20390Sstevel@tonic-gate 	if ((fd = open_and_lock_object_file(ks_handle, O_RDONLY,
20400Sstevel@tonic-gate 	    lock_held)) < 0) {
20410Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
20420Sstevel@tonic-gate 	}
20430Sstevel@tonic-gate 
20440Sstevel@tonic-gate 	obj = malloc(sizeof (ks_obj_t));
20450Sstevel@tonic-gate 	if (obj == NULL) {
20460Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
20470Sstevel@tonic-gate 	}
20480Sstevel@tonic-gate 
20490Sstevel@tonic-gate 	obj->next = NULL;
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 	(void) strcpy((char *)((obj->ks_handle).name),
20520Sstevel@tonic-gate 	    (char *)ks_handle->name);
20530Sstevel@tonic-gate 	(obj->ks_handle).public = ks_handle->public;
20540Sstevel@tonic-gate 
20550Sstevel@tonic-gate 	/* 1st get the version */
20568932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, &(obj->obj_version), OBJ_VER_SIZE)
20570Sstevel@tonic-gate 	    != OBJ_VER_SIZE) {
20580Sstevel@tonic-gate 		goto cleanup;
20590Sstevel@tonic-gate 	}
20600Sstevel@tonic-gate 	obj->obj_version = SWAP32(obj->obj_version);
20610Sstevel@tonic-gate 
20620Sstevel@tonic-gate 	/* Then, read the IV */
20638932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, iv, OBJ_IV_SIZE) != OBJ_IV_SIZE) {
20640Sstevel@tonic-gate 		goto cleanup;
20650Sstevel@tonic-gate 	}
20660Sstevel@tonic-gate 
20670Sstevel@tonic-gate 	/* Then, read the HMAC */
20688932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, obj_hmac, OBJ_HMAC_SIZE) != OBJ_HMAC_SIZE) {
20690Sstevel@tonic-gate 		goto cleanup;
20700Sstevel@tonic-gate 	}
20710Sstevel@tonic-gate 
20720Sstevel@tonic-gate 	/* read the object */
20730Sstevel@tonic-gate 	rv = read_obj_data(fd, (char **)&buf, &nread);
20740Sstevel@tonic-gate 	if (rv != CKR_OK) {
20750Sstevel@tonic-gate 		goto cleanup;
20760Sstevel@tonic-gate 	}
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	if (ks_handle->public) {
20790Sstevel@tonic-gate 		obj->size = nread;
20800Sstevel@tonic-gate 		obj->buf = buf;
20810Sstevel@tonic-gate 		*return_obj = obj;
20820Sstevel@tonic-gate 	} else {
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 		CK_ULONG out_len = 0, hmac_size;
20850Sstevel@tonic-gate 
20860Sstevel@tonic-gate 		/* verify HMAC of the object, make sure it matches */
20870Sstevel@tonic-gate 		hmac_size = OBJ_HMAC_SIZE;
20880Sstevel@tonic-gate 		if (soft_keystore_hmac(hmac_key, B_FALSE, buf,
20890Sstevel@tonic-gate 		    nread, obj_hmac, &hmac_size) != CKR_OK) {
20900Sstevel@tonic-gate 			free(buf);
20910Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
20920Sstevel@tonic-gate 			goto cleanup;
20930Sstevel@tonic-gate 		}
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 		/* decrypt object */
20960Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv, B_FALSE, buf, nread,
20970Sstevel@tonic-gate 		    NULL, &out_len) != CKR_OK) {
20980Sstevel@tonic-gate 			free(buf);
20990Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
21000Sstevel@tonic-gate 			goto cleanup;
21010Sstevel@tonic-gate 		}
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate 		decrypted_buf = malloc(sizeof (uchar_t) * out_len);
21040Sstevel@tonic-gate 		if (decrypted_buf == NULL) {
21050Sstevel@tonic-gate 			free(buf);
21060Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
21070Sstevel@tonic-gate 			goto cleanup;
21080Sstevel@tonic-gate 		}
21090Sstevel@tonic-gate 
21100Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv, B_FALSE, buf, nread,
21110Sstevel@tonic-gate 		    decrypted_buf, &out_len) != CKR_OK) {
21120Sstevel@tonic-gate 			free(decrypted_buf);
21130Sstevel@tonic-gate 			free(buf);
21140Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
21150Sstevel@tonic-gate 			goto cleanup;
21160Sstevel@tonic-gate 		}
21170Sstevel@tonic-gate 
21180Sstevel@tonic-gate 		obj->size = out_len - MAXPATHLEN;
21190Sstevel@tonic-gate 
21200Sstevel@tonic-gate 		/*
21210Sstevel@tonic-gate 		 * decrypted buf here actually contains full path name of
21220Sstevel@tonic-gate 		 * object plus the actual data.  so, need to skip the
21230Sstevel@tonic-gate 		 * full pathname.
21240Sstevel@tonic-gate 		 * See prepare_data_for_encrypt() function in the file
21250Sstevel@tonic-gate 		 * to understand how and why the pathname is added.
21260Sstevel@tonic-gate 		 */
21270Sstevel@tonic-gate 		obj->buf = malloc(sizeof (uchar_t) * (out_len - MAXPATHLEN));
21280Sstevel@tonic-gate 		if (obj->buf == NULL) {
21290Sstevel@tonic-gate 			free(decrypted_buf);
21300Sstevel@tonic-gate 			free(buf);
21310Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
21320Sstevel@tonic-gate 			goto cleanup;
21330Sstevel@tonic-gate 		}
21340Sstevel@tonic-gate 		(void) memcpy(obj->buf, decrypted_buf + MAXPATHLEN, obj->size);
21350Sstevel@tonic-gate 		free(decrypted_buf);
21360Sstevel@tonic-gate 		free(buf);
21370Sstevel@tonic-gate 		*return_obj = obj;
21380Sstevel@tonic-gate 	}
21390Sstevel@tonic-gate 
21400Sstevel@tonic-gate cleanup:
21410Sstevel@tonic-gate 
21420Sstevel@tonic-gate 	if (rv != CKR_OK) {
21430Sstevel@tonic-gate 		free(obj);
21440Sstevel@tonic-gate 	}
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate 	/* unlock the file after reading */
21470Sstevel@tonic-gate 	if (!lock_held) {
21480Sstevel@tonic-gate 		(void) lock_file(fd, B_TRUE, B_FALSE);
21490Sstevel@tonic-gate 	}
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate 	(void) close(fd);
21520Sstevel@tonic-gate 
21530Sstevel@tonic-gate 	return (rv);
21540Sstevel@tonic-gate }
21550Sstevel@tonic-gate 
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate /*
21580Sstevel@tonic-gate  * 	FUNCTION: soft_keystore_put_new_obj
21590Sstevel@tonic-gate  *
21600Sstevel@tonic-gate  *	ARGUMENTS:
21610Sstevel@tonic-gate  *		buf: buffer containing un-encrypted data
21620Sstevel@tonic-gate  *		     to be stored in keystore.
21630Sstevel@tonic-gate  *		len: length of data
21640Sstevel@tonic-gate  *		public:  TRUE if it is a public object,
21650Sstevel@tonic-gate  *			 FALSE if it is private obj
21660Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
21670Sstevel@tonic-gate  *		keyhandle: pointer to object handle to
21680Sstevel@tonic-gate  *			   receive keyhandle for new object
21690Sstevel@tonic-gate  *
21700Sstevel@tonic-gate  *	RETURN VALUE:
21710Sstevel@tonic-gate  *		0: object successfully stored in file
21720Sstevel@tonic-gate  *		-1: some error occurred, object is not stored in file.
21730Sstevel@tonic-gate  *
21740Sstevel@tonic-gate  *	DESCRIPTION:
21750Sstevel@tonic-gate  *		This API is used to write a newly created token object
21760Sstevel@tonic-gate  *		to keystore.
21770Sstevel@tonic-gate  *
21780Sstevel@tonic-gate  *		This function does the following:
21790Sstevel@tonic-gate  *
21800Sstevel@tonic-gate  *		1) Creates a token object file based on "public" parameter.
21810Sstevel@tonic-gate  *		2) Generates a new IV and stores it in obj_meta_data_t if it is
21820Sstevel@tonic-gate  *		   private object.
21830Sstevel@tonic-gate  *		3) Set object version number to 1.
21840Sstevel@tonic-gate  *		4) If it is a private object, it will be encrypted before
21850Sstevel@tonic-gate  *		   being written to the newly created keystore token object
21860Sstevel@tonic-gate  *		   file.
21870Sstevel@tonic-gate  *		5) Calculates the obj_chksum in obj_meta_data_t.
21880Sstevel@tonic-gate  *		6) Calculates the pin_chksum in obj_meta_data_t.
21890Sstevel@tonic-gate  *		7) Increments the keystore version number.
21900Sstevel@tonic-gate  */
21910Sstevel@tonic-gate int
soft_keystore_put_new_obj(uchar_t * buf,size_t len,boolean_t public,boolean_t lock_held,ks_obj_handle_t * keyhandle)21920Sstevel@tonic-gate soft_keystore_put_new_obj(uchar_t *buf, size_t len, boolean_t public,
21930Sstevel@tonic-gate     boolean_t lock_held, ks_obj_handle_t *keyhandle)
21940Sstevel@tonic-gate {
21950Sstevel@tonic-gate 
21960Sstevel@tonic-gate 	int fd, tmp_ks_fd, obj_fd;
21970Sstevel@tonic-gate 	unsigned int counter, version;
21980Sstevel@tonic-gate 	uchar_t obj_hmac[OBJ_HMAC_SIZE];
21990Sstevel@tonic-gate 	CK_BYTE iv[OBJ_IV_SIZE];
22000Sstevel@tonic-gate 	char obj_name[MAXPATHLEN], tmp_ks_desc_name[MAXPATHLEN];
22010Sstevel@tonic-gate 	char filebuf[BUFSIZ];
22020Sstevel@tonic-gate 	char pub_obj_path[MAXPATHLEN], pri_obj_path[MAXPATHLEN],
22030Sstevel@tonic-gate 	    ks_desc_file[MAXPATHLEN];
22040Sstevel@tonic-gate 	CK_ULONG hmac_size;
22050Sstevel@tonic-gate 	ssize_t nread;
22060Sstevel@tonic-gate 
22070Sstevel@tonic-gate 	if (keyhandle == NULL) {
22080Sstevel@tonic-gate 		return (-1);
22090Sstevel@tonic-gate 	}
22100Sstevel@tonic-gate 
22110Sstevel@tonic-gate 	/* if it is private object, make sure we have the key */
22120Sstevel@tonic-gate 	if (!public) {
22130Sstevel@tonic-gate 		if ((enc_key == NULL) ||
22140Sstevel@tonic-gate 		    (enc_key->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
22150Sstevel@tonic-gate 			return (-1);
22160Sstevel@tonic-gate 		}
22170Sstevel@tonic-gate 	}
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate 	/* open keystore, and set write lock */
222012256SPeter.Shoults@Sun.COM 	if ((fd = open_and_lock_keystore_desc(O_RDWR, B_FALSE,
22210Sstevel@tonic-gate 	    lock_held)) < 0) {
22220Sstevel@tonic-gate 		return (-1);
22230Sstevel@tonic-gate 	}
22240Sstevel@tonic-gate 
22250Sstevel@tonic-gate 	(void) get_desc_file_path(ks_desc_file);
22260Sstevel@tonic-gate 	(void) get_tmp_desc_file_path(tmp_ks_desc_name);
22270Sstevel@tonic-gate 
22280Sstevel@tonic-gate 	/*
22290Sstevel@tonic-gate 	 * create a tempoary file for the keystore description
22300Sstevel@tonic-gate 	 * file for updating version and counter information
22310Sstevel@tonic-gate 	 */
22328932SDina.Nimeh@Sun.COM 	tmp_ks_fd = open_nointr(tmp_ks_desc_name,
22338932SDina.Nimeh@Sun.COM 	    O_RDWR|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
22340Sstevel@tonic-gate 	if (tmp_ks_fd < 0) {
22350Sstevel@tonic-gate 		(void) close(fd);
22360Sstevel@tonic-gate 		return (-1);
22370Sstevel@tonic-gate 	}
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate 	/* read and write pkcs11 version */
22408932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, filebuf, KS_PKCS11_VER_SIZE)
22410Sstevel@tonic-gate 	    != KS_PKCS11_VER_SIZE) {
22420Sstevel@tonic-gate 		goto cleanup;
22430Sstevel@tonic-gate 	}
22440Sstevel@tonic-gate 
22458932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_ks_fd, filebuf, KS_PKCS11_VER_SIZE)
22460Sstevel@tonic-gate 	    != KS_PKCS11_VER_SIZE) {
22470Sstevel@tonic-gate 		goto cleanup;
22480Sstevel@tonic-gate 	}
22490Sstevel@tonic-gate 
22500Sstevel@tonic-gate 	/* get version number, and write updated number to temp file */
22518932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, &version, KS_VER_SIZE) != KS_VER_SIZE) {
22520Sstevel@tonic-gate 		goto cleanup;
22530Sstevel@tonic-gate 	}
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate 	version = SWAP32(version);
22560Sstevel@tonic-gate 	version++;
22570Sstevel@tonic-gate 	version = SWAP32(version);
22580Sstevel@tonic-gate 
22598932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_ks_fd, (void *)&version,
22600Sstevel@tonic-gate 	    KS_VER_SIZE) != KS_VER_SIZE) {
22610Sstevel@tonic-gate 		goto cleanup;
22620Sstevel@tonic-gate 	}
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 	/* get object count value */
22658932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, &counter, KS_COUNTER_SIZE) != KS_COUNTER_SIZE) {
22660Sstevel@tonic-gate 		goto cleanup;
22670Sstevel@tonic-gate 	}
22680Sstevel@tonic-gate 	counter = SWAP32(counter);
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 	bzero(obj_name, sizeof (obj_name));
22710Sstevel@tonic-gate 	if (public) {
22720Sstevel@tonic-gate 		(void) snprintf(obj_name, MAXPATHLEN,  "%s/%s%d",
22730Sstevel@tonic-gate 		    get_pub_obj_path(pub_obj_path), OBJ_PREFIX, counter);
22740Sstevel@tonic-gate 	} else {
22750Sstevel@tonic-gate 		(void) snprintf(obj_name, MAXPATHLEN,  "%s/%s%d",
22760Sstevel@tonic-gate 		    get_pri_obj_path(pri_obj_path), OBJ_PREFIX, counter);
22770Sstevel@tonic-gate 	}
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 	/* create object file */
22808932SDina.Nimeh@Sun.COM 	obj_fd = open_nointr(obj_name,
22818932SDina.Nimeh@Sun.COM 	    O_WRONLY|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
22820Sstevel@tonic-gate 	if (obj_fd < 0) {
22830Sstevel@tonic-gate 		/* can't create object file */
22840Sstevel@tonic-gate 		goto cleanup;
22850Sstevel@tonic-gate 	}
22860Sstevel@tonic-gate 
22870Sstevel@tonic-gate 	/* lock object file for writing */
22880Sstevel@tonic-gate 	if (lock_file(obj_fd, B_FALSE, B_TRUE) != 0) {
22890Sstevel@tonic-gate 		(void) close(obj_fd);
22900Sstevel@tonic-gate 		goto cleanup2;
22910Sstevel@tonic-gate 	}
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 	/* write object meta data */
22940Sstevel@tonic-gate 	version = SWAP32(1);
22958932SDina.Nimeh@Sun.COM 	if (writen_nointr(obj_fd, (void *)&version, sizeof (version))
22960Sstevel@tonic-gate 	    != sizeof (version)) {
22970Sstevel@tonic-gate 		goto cleanup2;
22980Sstevel@tonic-gate 	}
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 	if (public) {
23010Sstevel@tonic-gate 		bzero(iv, sizeof (iv));
23020Sstevel@tonic-gate 	} else {
23030Sstevel@tonic-gate 		/* generate an IV */
23040Sstevel@tonic-gate 		if (soft_gen_iv(iv) != CKR_OK) {
23050Sstevel@tonic-gate 			goto cleanup2;
23060Sstevel@tonic-gate 		}
23070Sstevel@tonic-gate 
23080Sstevel@tonic-gate 	}
23090Sstevel@tonic-gate 
23108932SDina.Nimeh@Sun.COM 	if (writen_nointr(obj_fd, (void *)iv, sizeof (iv)) != sizeof (iv)) {
23110Sstevel@tonic-gate 		goto cleanup2;
23120Sstevel@tonic-gate 	}
23130Sstevel@tonic-gate 
23140Sstevel@tonic-gate 	if (public) {
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 		bzero(obj_hmac, sizeof (obj_hmac));
23178932SDina.Nimeh@Sun.COM 		if (writen_nointr(obj_fd, (void *)obj_hmac,
23180Sstevel@tonic-gate 		    sizeof (obj_hmac)) != sizeof (obj_hmac)) {
23190Sstevel@tonic-gate 			goto cleanup2;
23200Sstevel@tonic-gate 		}
23210Sstevel@tonic-gate 
23228932SDina.Nimeh@Sun.COM 		if (writen_nointr(obj_fd, (char *)buf, len) != len) {
23230Sstevel@tonic-gate 			goto cleanup2;
23240Sstevel@tonic-gate 		}
23250Sstevel@tonic-gate 
23260Sstevel@tonic-gate 	} else {
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate 		uchar_t *encrypted_buf, *prepared_buf;
23290Sstevel@tonic-gate 		CK_ULONG out_len = 0, prepared_len;
23300Sstevel@tonic-gate 
23310Sstevel@tonic-gate 		if (prepare_data_for_encrypt(obj_name, buf, len,
23320Sstevel@tonic-gate 		    &prepared_buf, &prepared_len) != 0) {
23330Sstevel@tonic-gate 			goto cleanup2;
23340Sstevel@tonic-gate 		}
23350Sstevel@tonic-gate 
23360Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv,
23370Sstevel@tonic-gate 		    B_TRUE, prepared_buf, prepared_len,
23380Sstevel@tonic-gate 		    NULL, &out_len) != CKR_OK) {
23390Sstevel@tonic-gate 			free(prepared_buf);
23400Sstevel@tonic-gate 			goto cleanup2;
23410Sstevel@tonic-gate 		}
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate 		encrypted_buf = malloc(out_len * sizeof (char));
23440Sstevel@tonic-gate 		if (encrypted_buf == NULL) {
23450Sstevel@tonic-gate 			free(prepared_buf);
23460Sstevel@tonic-gate 			goto cleanup2;
23470Sstevel@tonic-gate 		}
23480Sstevel@tonic-gate 
23490Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv,
23500Sstevel@tonic-gate 		    B_TRUE, prepared_buf, prepared_len,
23510Sstevel@tonic-gate 		    encrypted_buf, &out_len) != CKR_OK) {
23520Sstevel@tonic-gate 			free(encrypted_buf);
23530Sstevel@tonic-gate 			free(prepared_buf);
23540Sstevel@tonic-gate 			goto cleanup2;
23550Sstevel@tonic-gate 		}
23560Sstevel@tonic-gate 		free(prepared_buf);
23570Sstevel@tonic-gate 
23580Sstevel@tonic-gate 		/* calculate HMAC of encrypted object */
23590Sstevel@tonic-gate 		hmac_size = OBJ_HMAC_SIZE;
23600Sstevel@tonic-gate 		if (soft_keystore_hmac(hmac_key, B_TRUE, encrypted_buf,
23610Sstevel@tonic-gate 		    out_len, obj_hmac, &hmac_size) != CKR_OK) {
23620Sstevel@tonic-gate 			free(encrypted_buf);
23630Sstevel@tonic-gate 			goto cleanup2;
23640Sstevel@tonic-gate 		}
23650Sstevel@tonic-gate 
23660Sstevel@tonic-gate 		if (hmac_size != OBJ_HMAC_SIZE) {
23670Sstevel@tonic-gate 			free(encrypted_buf);
23680Sstevel@tonic-gate 			goto cleanup2;
23690Sstevel@tonic-gate 		}
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 		/* write hmac */
23728932SDina.Nimeh@Sun.COM 		if (writen_nointr(obj_fd, (void *)obj_hmac,
23730Sstevel@tonic-gate 		    sizeof (obj_hmac)) != sizeof (obj_hmac)) {
23740Sstevel@tonic-gate 			free(encrypted_buf);
23750Sstevel@tonic-gate 			goto cleanup2;
23760Sstevel@tonic-gate 		}
23770Sstevel@tonic-gate 
23780Sstevel@tonic-gate 		/* write encrypted object */
23798932SDina.Nimeh@Sun.COM 		if (writen_nointr(obj_fd, (void *)encrypted_buf, out_len)
23800Sstevel@tonic-gate 		    != out_len) {
23810Sstevel@tonic-gate 			free(encrypted_buf);
23820Sstevel@tonic-gate 			goto cleanup2;
23830Sstevel@tonic-gate 		}
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 		free(encrypted_buf);
23860Sstevel@tonic-gate 	}
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 
23890Sstevel@tonic-gate 	(void) close(obj_fd);
23900Sstevel@tonic-gate 	(void) snprintf((char *)keyhandle->name, sizeof (keyhandle->name),
23910Sstevel@tonic-gate 	    "obj%d", counter);
23920Sstevel@tonic-gate 	keyhandle->public = public;
23930Sstevel@tonic-gate 
23940Sstevel@tonic-gate 	/*
23950Sstevel@tonic-gate 	 * store new counter to temp keystore description file.
23960Sstevel@tonic-gate 	 */
23970Sstevel@tonic-gate 	counter++;
23980Sstevel@tonic-gate 	counter = SWAP32(counter);
23998932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_ks_fd, (void *)&counter,
24000Sstevel@tonic-gate 	    sizeof (counter)) != sizeof (counter)) {
24010Sstevel@tonic-gate 		goto cleanup2;
24020Sstevel@tonic-gate 	}
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate 	/* read rest of keystore description file and store into temp file */
24058932SDina.Nimeh@Sun.COM 	nread = readn_nointr(fd, filebuf, sizeof (filebuf));
24060Sstevel@tonic-gate 	while (nread > 0) {
24078932SDina.Nimeh@Sun.COM 		if (writen_nointr(tmp_ks_fd, filebuf, nread) != nread) {
24080Sstevel@tonic-gate 			goto cleanup2;
24090Sstevel@tonic-gate 		}
24108932SDina.Nimeh@Sun.COM 		nread = readn_nointr(fd, filebuf, sizeof (filebuf));
24110Sstevel@tonic-gate 	}
24120Sstevel@tonic-gate 
24130Sstevel@tonic-gate 	(void) close(tmp_ks_fd);
24140Sstevel@tonic-gate 	(void) rename(tmp_ks_desc_name, ks_desc_file);
24150Sstevel@tonic-gate 
24160Sstevel@tonic-gate 	if (!lock_held) {
24170Sstevel@tonic-gate 		/* release lock on description file */
24180Sstevel@tonic-gate 		if (lock_file(fd, B_FALSE, B_FALSE) != 0) {
24190Sstevel@tonic-gate 			(void) close(fd);
24200Sstevel@tonic-gate 			return (-1);
24210Sstevel@tonic-gate 		}
24220Sstevel@tonic-gate 	}
24230Sstevel@tonic-gate 	(void) close(fd);
24240Sstevel@tonic-gate 	return (0);
24250Sstevel@tonic-gate 
24260Sstevel@tonic-gate cleanup2:
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 	/* remove object file.  No need to remove lock first */
24290Sstevel@tonic-gate 	(void) unlink(obj_name);
24300Sstevel@tonic-gate 
24310Sstevel@tonic-gate cleanup:
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate 	(void) close(tmp_ks_fd);
24340Sstevel@tonic-gate 	(void) remove(tmp_ks_desc_name);
24350Sstevel@tonic-gate 	if (!lock_held) {
24360Sstevel@tonic-gate 		/* release lock on description file */
24370Sstevel@tonic-gate 		(void) lock_file(fd, B_FALSE, B_FALSE);
24380Sstevel@tonic-gate 	}
24390Sstevel@tonic-gate 
24400Sstevel@tonic-gate 	(void) close(fd);
24410Sstevel@tonic-gate 	return (-1);
24420Sstevel@tonic-gate }
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate /*
24450Sstevel@tonic-gate  *	FUNCTION: soft_keystore_modify_obj
24460Sstevel@tonic-gate  *
24470Sstevel@tonic-gate  *	ARGUMENTS:
24480Sstevel@tonic-gate  *		ks_handle: handle of the key store object to be modified
24490Sstevel@tonic-gate  *		buf: buffer containing un-encrypted data
24500Sstevel@tonic-gate  *		     to be modified in keystore.
24510Sstevel@tonic-gate  *		len: length of data
24520Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
24530Sstevel@tonic-gate  *
24540Sstevel@tonic-gate  *	RETURN VALUE:
24550Sstevel@tonic-gate  *		-1: if any error occurred.
24560Sstevel@tonic-gate  *		Otherwise, 0 is returned.
24570Sstevel@tonic-gate  *
24580Sstevel@tonic-gate  *	DESCRIPTION:
24590Sstevel@tonic-gate  *
24600Sstevel@tonic-gate  *		This API is used to write a modified token object back
24610Sstevel@tonic-gate  *		to keystore.   This function will do the following:
24620Sstevel@tonic-gate  *
24630Sstevel@tonic-gate  *		1) If it is a private object, it will be encrypted before
24640Sstevel@tonic-gate  *		   being written to the corresponding keystore token
24650Sstevel@tonic-gate  *		   object file.
24660Sstevel@tonic-gate  *		2) Record incremented object version number.
24670Sstevel@tonic-gate  *		3) Record incremented keystore version number.
24680Sstevel@tonic-gate  */
24690Sstevel@tonic-gate int
soft_keystore_modify_obj(ks_obj_handle_t * ks_handle,uchar_t * buf,size_t len,boolean_t lock_held)24700Sstevel@tonic-gate soft_keystore_modify_obj(ks_obj_handle_t *ks_handle, uchar_t *buf,
24710Sstevel@tonic-gate     size_t len, boolean_t lock_held)
24720Sstevel@tonic-gate {
24730Sstevel@tonic-gate 	int fd, ks_fd, tmp_fd, version;
24740Sstevel@tonic-gate 	char orig_name[MAXPATHLEN], tmp_name[MAXPATHLEN],
24750Sstevel@tonic-gate 	    tmp_ks_name[MAXPATHLEN];
24760Sstevel@tonic-gate 	uchar_t iv[OBJ_IV_SIZE], obj_hmac[OBJ_HMAC_SIZE];
24770Sstevel@tonic-gate 	char pub_obj_path[MAXPATHLEN], pri_obj_path[MAXPATHLEN],
24780Sstevel@tonic-gate 	    ks_desc_file[MAXPATHLEN];
24790Sstevel@tonic-gate 	CK_ULONG hmac_size;
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate 	/* if it is private object, make sure we have the key */
24820Sstevel@tonic-gate 	if (!(ks_handle->public)) {
24830Sstevel@tonic-gate 		if ((enc_key == NULL) ||
24840Sstevel@tonic-gate 		    (enc_key->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
24850Sstevel@tonic-gate 			return (-1);
24860Sstevel@tonic-gate 		}
24870Sstevel@tonic-gate 	}
24880Sstevel@tonic-gate 
24890Sstevel@tonic-gate 	/* open and lock keystore description file */
24900Sstevel@tonic-gate 	if ((ks_fd = open_and_lock_keystore_desc(O_RDWR, B_FALSE,
24910Sstevel@tonic-gate 	    B_FALSE)) < 0) {
24920Sstevel@tonic-gate 		return (-1);
24930Sstevel@tonic-gate 	}
24940Sstevel@tonic-gate 
24950Sstevel@tonic-gate 	(void) get_desc_file_path(ks_desc_file);
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate 	/* update the version of for keystore file in tempoary file */
24980Sstevel@tonic-gate 	(void) get_tmp_desc_file_path(tmp_ks_name);
24990Sstevel@tonic-gate 	if (create_updated_keystore_version(ks_fd, tmp_ks_name) != 0) {
25000Sstevel@tonic-gate 		/* unlock keystore description file */
25010Sstevel@tonic-gate 		(void) lock_file(ks_fd, B_FALSE, B_FALSE);
25020Sstevel@tonic-gate 		(void) close(ks_fd);
25030Sstevel@tonic-gate 		return (-1);
25040Sstevel@tonic-gate 	}
25050Sstevel@tonic-gate 
25060Sstevel@tonic-gate 	/* open object file */
25070Sstevel@tonic-gate 	if ((fd = open_and_lock_object_file(ks_handle, O_RDWR,
25080Sstevel@tonic-gate 	    lock_held)) < 0) {
25090Sstevel@tonic-gate 		goto cleanup;
25100Sstevel@tonic-gate 	}
25110Sstevel@tonic-gate 
25120Sstevel@tonic-gate 	/*
25130Sstevel@tonic-gate 	 * make the change in a temporary file.  Create the temp
25140Sstevel@tonic-gate 	 * file in the same directory as the token object.  That
25150Sstevel@tonic-gate 	 * way, the "rename" later will be an atomic operation
25160Sstevel@tonic-gate 	 */
25170Sstevel@tonic-gate 	if (ks_handle->public) {
25180Sstevel@tonic-gate 		(void) snprintf(orig_name, MAXPATHLEN, "%s/%s",
25190Sstevel@tonic-gate 		    get_pub_obj_path(pub_obj_path), ks_handle->name);
25200Sstevel@tonic-gate 		(void) snprintf(tmp_name, MAXPATHLEN, "%s/%s%s",
25210Sstevel@tonic-gate 		    pub_obj_path, TMP_OBJ_PREFIX,
25229341SAnthony.Scarpino@Sun.COM 		    (ks_handle->name) + OBJ_PREFIX_LEN);
25230Sstevel@tonic-gate 	} else {
25240Sstevel@tonic-gate 		(void) snprintf(orig_name, MAXPATHLEN, "%s/%s",
25250Sstevel@tonic-gate 		    get_pri_obj_path(pri_obj_path), ks_handle->name);
25260Sstevel@tonic-gate 		(void) snprintf(tmp_name, MAXPATHLEN, "%s/%s%s",
25270Sstevel@tonic-gate 		    pri_obj_path, TMP_OBJ_PREFIX,
25289341SAnthony.Scarpino@Sun.COM 		    (ks_handle->name) + OBJ_PREFIX_LEN);
25290Sstevel@tonic-gate 	}
25300Sstevel@tonic-gate 
25318932SDina.Nimeh@Sun.COM 	tmp_fd = open_nointr(tmp_name,
25328932SDina.Nimeh@Sun.COM 	    O_WRONLY|O_CREAT|O_EXCL|O_NONBLOCK, S_IRUSR|S_IWUSR);
25330Sstevel@tonic-gate 	if (tmp_fd < 0) {
25340Sstevel@tonic-gate 		/* can't create tmp object file */
25350Sstevel@tonic-gate 		goto cleanup1;
25360Sstevel@tonic-gate 	}
25370Sstevel@tonic-gate 
25380Sstevel@tonic-gate 	/* read version, increment, and write to tmp file */
25398932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)&version, OBJ_VER_SIZE) != OBJ_VER_SIZE) {
25400Sstevel@tonic-gate 		goto cleanup2;
25410Sstevel@tonic-gate 	}
25420Sstevel@tonic-gate 
25430Sstevel@tonic-gate 	version = SWAP32(version);
25440Sstevel@tonic-gate 	version++;
25450Sstevel@tonic-gate 	version = SWAP32(version);
25460Sstevel@tonic-gate 
25478932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_fd, (char *)&version, OBJ_VER_SIZE)
25480Sstevel@tonic-gate 	    != OBJ_VER_SIZE) {
25490Sstevel@tonic-gate 		goto cleanup2;
25500Sstevel@tonic-gate 	}
25510Sstevel@tonic-gate 
25520Sstevel@tonic-gate 	/* generate a new IV for the object, old one can be ignored */
25530Sstevel@tonic-gate 	if (soft_gen_iv(iv) != CKR_OK) {
25540Sstevel@tonic-gate 		goto cleanup2;
25550Sstevel@tonic-gate 	}
25560Sstevel@tonic-gate 
25578932SDina.Nimeh@Sun.COM 	if (writen_nointr(tmp_fd, (char *)iv, OBJ_IV_SIZE) != OBJ_IV_SIZE) {
25580Sstevel@tonic-gate 		goto cleanup2;
25590Sstevel@tonic-gate 	}
25600Sstevel@tonic-gate 
25610Sstevel@tonic-gate 	if (ks_handle->public) {
25620Sstevel@tonic-gate 
25630Sstevel@tonic-gate 		/* hmac is always NULL for public objects */
25640Sstevel@tonic-gate 		bzero(obj_hmac, sizeof (obj_hmac));
25658932SDina.Nimeh@Sun.COM 		if (writen_nointr(tmp_fd, (char *)obj_hmac, OBJ_HMAC_SIZE)
25660Sstevel@tonic-gate 		    != OBJ_HMAC_SIZE) {
25670Sstevel@tonic-gate 			goto cleanup2;
25680Sstevel@tonic-gate 		}
25690Sstevel@tonic-gate 
25700Sstevel@tonic-gate 		/* write updated object */
25718932SDina.Nimeh@Sun.COM 		if (writen_nointr(tmp_fd, (char *)buf, len) != len) {
25720Sstevel@tonic-gate 			goto cleanup2;
25730Sstevel@tonic-gate 		}
25740Sstevel@tonic-gate 
25750Sstevel@tonic-gate 	} else {
25760Sstevel@tonic-gate 
25770Sstevel@tonic-gate 		uchar_t *encrypted_buf, *prepared_buf;
25780Sstevel@tonic-gate 		CK_ULONG out_len = 0, prepared_len;
25790Sstevel@tonic-gate 
25800Sstevel@tonic-gate 		if (prepare_data_for_encrypt(orig_name, buf, len,
25810Sstevel@tonic-gate 		    &prepared_buf, &prepared_len) != 0) {
25820Sstevel@tonic-gate 			goto cleanup2;
25830Sstevel@tonic-gate 		}
25840Sstevel@tonic-gate 
25850Sstevel@tonic-gate 		/* encrypt the data */
25860Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv, B_TRUE, prepared_buf,
25870Sstevel@tonic-gate 		    prepared_len, NULL, &out_len) != CKR_OK) {
25880Sstevel@tonic-gate 			free(prepared_buf);
25890Sstevel@tonic-gate 			goto cleanup2;
25900Sstevel@tonic-gate 		}
25910Sstevel@tonic-gate 
25920Sstevel@tonic-gate 		encrypted_buf = malloc(out_len * sizeof (char));
25930Sstevel@tonic-gate 		if (encrypted_buf == NULL) {
25940Sstevel@tonic-gate 			free(prepared_buf);
25950Sstevel@tonic-gate 			goto cleanup2;
25960Sstevel@tonic-gate 		}
25970Sstevel@tonic-gate 
25980Sstevel@tonic-gate 		if (soft_keystore_crypt(enc_key, iv, B_TRUE, prepared_buf,
25990Sstevel@tonic-gate 		    prepared_len, encrypted_buf, &out_len) != CKR_OK) {
26000Sstevel@tonic-gate 			free(encrypted_buf);
26010Sstevel@tonic-gate 			free(prepared_buf);
26020Sstevel@tonic-gate 			goto cleanup2;
26030Sstevel@tonic-gate 		}
26040Sstevel@tonic-gate 
26050Sstevel@tonic-gate 		free(prepared_buf);
26060Sstevel@tonic-gate 
26070Sstevel@tonic-gate 		/* calculate hmac on encrypted buf */
26080Sstevel@tonic-gate 		hmac_size = OBJ_HMAC_SIZE;
26090Sstevel@tonic-gate 		if (soft_keystore_hmac(hmac_key, B_TRUE, encrypted_buf,
26100Sstevel@tonic-gate 		    out_len, obj_hmac, &hmac_size) != CKR_OK) {
26110Sstevel@tonic-gate 			free(encrypted_buf);
26120Sstevel@tonic-gate 			goto cleanup2;
26130Sstevel@tonic-gate 		}
26140Sstevel@tonic-gate 
26150Sstevel@tonic-gate 		if (hmac_size != OBJ_HMAC_SIZE) {
26160Sstevel@tonic-gate 			free(encrypted_buf);
26170Sstevel@tonic-gate 			goto cleanup2;
26180Sstevel@tonic-gate 		}
26190Sstevel@tonic-gate 
26208932SDina.Nimeh@Sun.COM 		if (writen_nointr(tmp_fd, (char *)obj_hmac, OBJ_HMAC_SIZE)
26210Sstevel@tonic-gate 		    != OBJ_HMAC_SIZE) {
26220Sstevel@tonic-gate 			free(encrypted_buf);
26230Sstevel@tonic-gate 			goto cleanup2;
26240Sstevel@tonic-gate 		}
26250Sstevel@tonic-gate 
26268932SDina.Nimeh@Sun.COM 		if (writen_nointr(tmp_fd, (void *)encrypted_buf, out_len)
26270Sstevel@tonic-gate 		    != out_len) {
26280Sstevel@tonic-gate 			free(encrypted_buf);
26290Sstevel@tonic-gate 			goto cleanup2;
26300Sstevel@tonic-gate 		}
26310Sstevel@tonic-gate 		free(encrypted_buf);
26320Sstevel@tonic-gate 	}
26330Sstevel@tonic-gate 	(void) close(tmp_fd);
26340Sstevel@tonic-gate 
26350Sstevel@tonic-gate 	/* rename updated temporary object file */
26360Sstevel@tonic-gate 	if (rename(tmp_name, orig_name) != 0) {
26370Sstevel@tonic-gate 		(void) unlink(tmp_name);
26380Sstevel@tonic-gate 		return (-1);
26390Sstevel@tonic-gate 	}
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate 	/* rename updated keystore description file */
26420Sstevel@tonic-gate 	if (rename(tmp_ks_name, ks_desc_file) != 0) {
26430Sstevel@tonic-gate 		(void) unlink(tmp_name);
26440Sstevel@tonic-gate 		(void) unlink(tmp_ks_name);
26450Sstevel@tonic-gate 		return (-1);
26460Sstevel@tonic-gate 	}
26470Sstevel@tonic-gate 
26480Sstevel@tonic-gate 	/* determine need to unlock file or not */
26490Sstevel@tonic-gate 	if (!lock_held) {
26500Sstevel@tonic-gate 		if (lock_file(fd, B_FALSE, B_FALSE) < 0) {
26510Sstevel@tonic-gate 			(void) close(fd);
26520Sstevel@tonic-gate 			(void) unlink(tmp_name);
26530Sstevel@tonic-gate 			return (-1);
26540Sstevel@tonic-gate 		}
26550Sstevel@tonic-gate 	}
26560Sstevel@tonic-gate 
26570Sstevel@tonic-gate 	/* unlock keystore description file */
26580Sstevel@tonic-gate 	if (lock_file(ks_fd, B_FALSE, B_FALSE) != 0) {
26590Sstevel@tonic-gate 		(void) close(ks_fd);
26600Sstevel@tonic-gate 		(void) close(fd);
26610Sstevel@tonic-gate 		return (-1);
26620Sstevel@tonic-gate 	}
26630Sstevel@tonic-gate 
26640Sstevel@tonic-gate 	(void) close(ks_fd);
26650Sstevel@tonic-gate 
26660Sstevel@tonic-gate 	(void) close(fd);
26670Sstevel@tonic-gate 
26680Sstevel@tonic-gate 	return (0); /* All operations completed successfully */
26690Sstevel@tonic-gate 
26700Sstevel@tonic-gate cleanup2:
26710Sstevel@tonic-gate 	(void) close(tmp_fd);
26720Sstevel@tonic-gate 	(void) remove(tmp_name);
26730Sstevel@tonic-gate 
26740Sstevel@tonic-gate cleanup1:
26750Sstevel@tonic-gate 	(void) close(fd);
26760Sstevel@tonic-gate 
26770Sstevel@tonic-gate cleanup:
26780Sstevel@tonic-gate 	/* unlock keystore description file */
26790Sstevel@tonic-gate 	(void) lock_file(ks_fd, B_FALSE, B_FALSE);
26800Sstevel@tonic-gate 	(void) close(ks_fd);
26810Sstevel@tonic-gate 	(void) remove(tmp_ks_name);
26820Sstevel@tonic-gate 	return (-1);
26830Sstevel@tonic-gate }
26840Sstevel@tonic-gate 
26850Sstevel@tonic-gate /*
26860Sstevel@tonic-gate  *	FUNCTION: soft_keystore_del_obj
26870Sstevel@tonic-gate  *
26880Sstevel@tonic-gate  *	ARGUMENTS:
26890Sstevel@tonic-gate  *		ks_handle: handle of the key store object to be deleted
26900Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
26910Sstevel@tonic-gate  *
26920Sstevel@tonic-gate  *	RETURN VALUE:
26930Sstevel@tonic-gate  *		-1: if any error occurred.
26940Sstevel@tonic-gate  *		0: object successfully deleted from keystore.
26950Sstevel@tonic-gate  *
26960Sstevel@tonic-gate  *	DESCRIPTION:
26970Sstevel@tonic-gate  *		This API is used to delete a particular token object from
26980Sstevel@tonic-gate  *		the keystore.  The corresponding token object file will be
26990Sstevel@tonic-gate  *		removed from the file system.
27000Sstevel@tonic-gate  *		Any future reference to the deleted file will
27010Sstevel@tonic-gate  *		return an CKR_OBJECT_HANDLE_INVALID error.
27020Sstevel@tonic-gate  */
27030Sstevel@tonic-gate int
soft_keystore_del_obj(ks_obj_handle_t * ks_handle,boolean_t lock_held)27040Sstevel@tonic-gate soft_keystore_del_obj(ks_obj_handle_t *ks_handle, boolean_t lock_held)
27050Sstevel@tonic-gate {
27060Sstevel@tonic-gate 	char objname[MAXPATHLEN], tmp_ks_name[MAXPATHLEN];
27070Sstevel@tonic-gate 	int fd;
27080Sstevel@tonic-gate 	char pub_obj_path[MAXPATHLEN], pri_obj_path[MAXPATHLEN],
27090Sstevel@tonic-gate 	    ks_desc_file[MAXPATHLEN];
27100Sstevel@tonic-gate 	int ret_val = -1;
27110Sstevel@tonic-gate 	int obj_fd;
27120Sstevel@tonic-gate 
27130Sstevel@tonic-gate 	if ((fd = open_and_lock_keystore_desc(O_RDWR, B_FALSE,
27140Sstevel@tonic-gate 	    lock_held)) < 0) {
27150Sstevel@tonic-gate 		return (-1);
27160Sstevel@tonic-gate 	}
27170Sstevel@tonic-gate 
27180Sstevel@tonic-gate 	(void) get_desc_file_path(ks_desc_file);
27190Sstevel@tonic-gate 	(void) get_tmp_desc_file_path(tmp_ks_name);
27200Sstevel@tonic-gate 	if (create_updated_keystore_version(fd, tmp_ks_name) != 0) {
27210Sstevel@tonic-gate 		goto cleanup;
27220Sstevel@tonic-gate 	}
27230Sstevel@tonic-gate 
27240Sstevel@tonic-gate 	if (ks_handle->public) {
27250Sstevel@tonic-gate 		(void) snprintf(objname, MAXPATHLEN, "%s/%s",
27260Sstevel@tonic-gate 		    get_pub_obj_path(pub_obj_path), ks_handle->name);
27270Sstevel@tonic-gate 	} else {
27280Sstevel@tonic-gate 		(void) snprintf(objname, MAXPATHLEN, "%s/%s",
27290Sstevel@tonic-gate 		    get_pri_obj_path(pri_obj_path), ks_handle->name);
27300Sstevel@tonic-gate 	}
27310Sstevel@tonic-gate 
27320Sstevel@tonic-gate 	/*
27330Sstevel@tonic-gate 	 * make sure no other process is reading/writing the file
27340Sstevel@tonic-gate 	 * by acquiring the lock on the file
27350Sstevel@tonic-gate 	 */
27360Sstevel@tonic-gate 	if ((obj_fd = open_and_lock_object_file(ks_handle, O_WRONLY,
27370Sstevel@tonic-gate 	    B_FALSE)) < 0) {
27380Sstevel@tonic-gate 		return (-1);
27390Sstevel@tonic-gate 	}
27400Sstevel@tonic-gate 
27410Sstevel@tonic-gate 	if (unlink(objname) != 0) {
27420Sstevel@tonic-gate 		(void) lock_file(obj_fd, B_FALSE, B_FALSE);
27430Sstevel@tonic-gate 		(void) close(obj_fd);
27440Sstevel@tonic-gate 		goto cleanup;
27450Sstevel@tonic-gate 	}
27460Sstevel@tonic-gate 
27470Sstevel@tonic-gate 	(void) lock_file(obj_fd, B_FALSE, B_FALSE);
27480Sstevel@tonic-gate 	(void) close(obj_fd);
27490Sstevel@tonic-gate 
27500Sstevel@tonic-gate 	if (rename(tmp_ks_name, ks_desc_file) != 0) {
27510Sstevel@tonic-gate 		goto cleanup;
27520Sstevel@tonic-gate 	}
27530Sstevel@tonic-gate 	ret_val = 0;
27540Sstevel@tonic-gate 
27550Sstevel@tonic-gate cleanup:
27560Sstevel@tonic-gate 	/* unlock keystore description file */
27570Sstevel@tonic-gate 	if (!lock_held) {
27580Sstevel@tonic-gate 		if (lock_file(fd, B_FALSE, B_FALSE) != 0) {
27590Sstevel@tonic-gate 			(void) close(fd);
27600Sstevel@tonic-gate 			return (-1);
27610Sstevel@tonic-gate 		}
27620Sstevel@tonic-gate 	}
27630Sstevel@tonic-gate 
27640Sstevel@tonic-gate 	(void) close(fd);
27650Sstevel@tonic-gate 	return (ret_val);
27660Sstevel@tonic-gate }
27670Sstevel@tonic-gate 
27680Sstevel@tonic-gate /*
27690Sstevel@tonic-gate  * Get the salt used for generating hashed pin from the
27700Sstevel@tonic-gate  * keystore description file.
27710Sstevel@tonic-gate  *
27720Sstevel@tonic-gate  * The result will be stored in the provided buffer "salt" passed
27730Sstevel@tonic-gate  * in as an argument.
27740Sstevel@tonic-gate  *
27750Sstevel@tonic-gate  * Return 0 if no error, return -1 if there's any error.
27760Sstevel@tonic-gate  */
27770Sstevel@tonic-gate int
soft_keystore_get_pin_salt(char ** salt)27780Sstevel@tonic-gate soft_keystore_get_pin_salt(char **salt)
27790Sstevel@tonic-gate {
27800Sstevel@tonic-gate 	int fd, ret_val = -1;
27810Sstevel@tonic-gate 	uint64_t hashed_pin_salt_size;
27820Sstevel@tonic-gate 
278312256SPeter.Shoults@Sun.COM 	if ((fd = open_and_lock_keystore_desc(O_RDONLY, B_FALSE,
27840Sstevel@tonic-gate 	    B_FALSE)) < 0) {
27850Sstevel@tonic-gate 		return (-1);
27860Sstevel@tonic-gate 	}
27870Sstevel@tonic-gate 
27880Sstevel@tonic-gate 	if (lseek(fd, KS_HASHED_PIN_SALT_LEN_OFFSET, SEEK_SET)
27890Sstevel@tonic-gate 	    != KS_HASHED_PIN_SALT_LEN_OFFSET) {
27900Sstevel@tonic-gate 		goto cleanup;
27910Sstevel@tonic-gate 	}
27920Sstevel@tonic-gate 
27938932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)&hashed_pin_salt_size,
27940Sstevel@tonic-gate 	    KS_HASHED_PIN_SALT_LEN_SIZE) != KS_HASHED_PIN_SALT_LEN_SIZE) {
27950Sstevel@tonic-gate 		goto cleanup;
27960Sstevel@tonic-gate 	}
27970Sstevel@tonic-gate 	hashed_pin_salt_size = SWAP64(hashed_pin_salt_size);
27980Sstevel@tonic-gate 
27990Sstevel@tonic-gate 	*salt = malloc(hashed_pin_salt_size + 1);
28000Sstevel@tonic-gate 	if (*salt == NULL) {
28010Sstevel@tonic-gate 		goto cleanup;
28020Sstevel@tonic-gate 	}
28030Sstevel@tonic-gate 
28048932SDina.Nimeh@Sun.COM 	if ((readn_nointr(fd, *salt, hashed_pin_salt_size))
28050Sstevel@tonic-gate 	    != (ssize_t)hashed_pin_salt_size) {
28060Sstevel@tonic-gate 		free(*salt);
28070Sstevel@tonic-gate 		goto cleanup;
28080Sstevel@tonic-gate 	}
28090Sstevel@tonic-gate 	(*salt)[hashed_pin_salt_size] = '\0';
28100Sstevel@tonic-gate 
28110Sstevel@tonic-gate 	ret_val = 0;
28120Sstevel@tonic-gate 
28130Sstevel@tonic-gate cleanup:
28140Sstevel@tonic-gate 	if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
28150Sstevel@tonic-gate 		ret_val = -1;
28160Sstevel@tonic-gate 	}
28170Sstevel@tonic-gate 
28180Sstevel@tonic-gate 	(void) close(fd);
28190Sstevel@tonic-gate 	return (ret_val);
28200Sstevel@tonic-gate }
28210Sstevel@tonic-gate 
28220Sstevel@tonic-gate /*
28230Sstevel@tonic-gate  *	FUNCTION: soft_keystore_pin_initialized
28240Sstevel@tonic-gate  *
28250Sstevel@tonic-gate  *	ARGUMENTS:
28260Sstevel@tonic-gate  *		initialized: This value will be set to true if keystore is
28270Sstevel@tonic-gate  *			     initialized, and false otherwise.
28280Sstevel@tonic-gate  *		hashed_pin: If the keystore is initialized, this will contain
28290Sstevel@tonic-gate  *			    the hashed pin.  It will be NULL if the keystore
28300Sstevel@tonic-gate  *			    pin is not initialized.  Memory allocated
28310Sstevel@tonic-gate  *			    for the hashed pin needs to be freed by
28320Sstevel@tonic-gate  *			    the caller.
28330Sstevel@tonic-gate  *		lock_held: TRUE if the lock is held by caller.
28340Sstevel@tonic-gate  *
28350Sstevel@tonic-gate  *	RETURN VALUE:
28360Sstevel@tonic-gate  *		CKR_OK: No error
28370Sstevel@tonic-gate  *		any other appropriate CKR_value
28380Sstevel@tonic-gate  *
28390Sstevel@tonic-gate  *	DESCRIPTION:
28400Sstevel@tonic-gate  *		This API is used to determine if the PIN in the keystore
28410Sstevel@tonic-gate  *		has been initialized or not.
28420Sstevel@tonic-gate  *		It makes the determination using the salt for generating the
28430Sstevel@tonic-gate  *		encryption key.  The salt is stored in the keystore
28440Sstevel@tonic-gate  *		descryption file.  The salt should be all zero if
28450Sstevel@tonic-gate  *		the keystore pin has not been initialized.
28460Sstevel@tonic-gate  *		If the pin has been initialized, it is returned in the
28470Sstevel@tonic-gate  *		hashed_pin argument.
28480Sstevel@tonic-gate  */
28490Sstevel@tonic-gate CK_RV
soft_keystore_pin_initialized(boolean_t * initialized,char ** hashed_pin,boolean_t lock_held)28500Sstevel@tonic-gate soft_keystore_pin_initialized(boolean_t *initialized, char **hashed_pin,
28510Sstevel@tonic-gate     boolean_t lock_held)
28520Sstevel@tonic-gate {
28530Sstevel@tonic-gate 	int fd;
28540Sstevel@tonic-gate 	CK_BYTE crypt_salt[KS_KEY_SALT_SIZE], tmp_buf[KS_KEY_SALT_SIZE];
28550Sstevel@tonic-gate 	CK_RV ret_val = CKR_OK;
28560Sstevel@tonic-gate 
285712256SPeter.Shoults@Sun.COM 	if ((fd = open_and_lock_keystore_desc(O_RDONLY, B_FALSE,
28580Sstevel@tonic-gate 	    lock_held)) < 0) {
28590Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
28600Sstevel@tonic-gate 	}
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate 	if (lseek(fd, KS_KEY_SALT_OFFSET, SEEK_SET) != KS_KEY_SALT_OFFSET) {
28630Sstevel@tonic-gate 		ret_val = CKR_FUNCTION_FAILED;
28640Sstevel@tonic-gate 		goto cleanup;
28650Sstevel@tonic-gate 	}
28660Sstevel@tonic-gate 
28678932SDina.Nimeh@Sun.COM 	if (readn_nointr(fd, (char *)crypt_salt, KS_KEY_SALT_SIZE)
28680Sstevel@tonic-gate 	    != KS_KEY_SALT_SIZE) {
28690Sstevel@tonic-gate 		ret_val = CKR_FUNCTION_FAILED;
28700Sstevel@tonic-gate 		goto cleanup;
28710Sstevel@tonic-gate 	}
28720Sstevel@tonic-gate 
28730Sstevel@tonic-gate 	(void) bzero(tmp_buf, KS_KEY_SALT_SIZE);
28740Sstevel@tonic-gate 
28750Sstevel@tonic-gate 	if (memcmp(crypt_salt, tmp_buf, KS_KEY_SALT_SIZE) == 0) {
28760Sstevel@tonic-gate 		*initialized = B_FALSE;
28770Sstevel@tonic-gate 		hashed_pin = NULL;
28780Sstevel@tonic-gate 	} else {
28790Sstevel@tonic-gate 		*initialized = B_TRUE;
28800Sstevel@tonic-gate 		ret_val = get_hashed_pin(fd, hashed_pin);
28810Sstevel@tonic-gate 	}
28820Sstevel@tonic-gate 
28830Sstevel@tonic-gate cleanup:
28840Sstevel@tonic-gate 
28850Sstevel@tonic-gate 	if (!lock_held) {
28860Sstevel@tonic-gate 		if (lock_file(fd, B_TRUE, B_FALSE) < 0) {
28870Sstevel@tonic-gate 			ret_val = CKR_FUNCTION_FAILED;
28880Sstevel@tonic-gate 		}
28890Sstevel@tonic-gate 	}
28900Sstevel@tonic-gate 
28910Sstevel@tonic-gate 	(void) close(fd);
28920Sstevel@tonic-gate 	return (ret_val);
28930Sstevel@tonic-gate }
28941937Sizick 
28951937Sizick /*
28961937Sizick  * This checks if the keystore file exists
28971937Sizick  */
28981937Sizick 
28991937Sizick static int
soft_keystore_exists()29001937Sizick soft_keystore_exists()
29011937Sizick {
29021937Sizick 	int ret;
29031937Sizick 	struct stat fn_stat;
29041937Sizick 	char *fname, ks_desc_file[MAXPATHLEN];
29051937Sizick 
29061937Sizick 	fname = get_desc_file_path(ks_desc_file);
29071937Sizick 	ret = stat(fname, &fn_stat);
29081937Sizick 	if (ret == 0)
29091937Sizick 		return (0);
29101937Sizick 	return (errno);
29111937Sizick }
29121937Sizick 
29131937Sizick /*
29141937Sizick  *	FUNCTION: soft_keystore_init
29151937Sizick  *
29161937Sizick  *	ARGUMENTS:
29171937Sizick  *		desired_state:  The keystore state the caller would like
29181937Sizick  *				it to be.
29191937Sizick  *
29201937Sizick  *	RETURN VALUE:
29211937Sizick  *		Returns the state the function is in.  If it succeeded, it
29221937Sizick  *		will be the same as the desired, if not it will be
29231937Sizick  *		KEYSTORE_UNAVAILABLE.
29241937Sizick  *
29251937Sizick  *	DESCRIPTION:
29261937Sizick  *		This function will only load as much keystore data as is
29271937Sizick  *		requested at that time. This is for performace by delaying the
29281937Sizick  *		reading of token objects until they are needed or never at
29291937Sizick  *		all if they are not used.
29301937Sizick  *
293112256SPeter.Shoults@Sun.COM  *		Primary use is from C_InitToken().
293212256SPeter.Shoults@Sun.COM  *		It is also called by soft_keystore_status() when the
29331937Sizick  *		"desired_state" is not the the current load state of keystore.
29341937Sizick  *
29351937Sizick  */
29361937Sizick int
soft_keystore_init(int desired_state)29371937Sizick soft_keystore_init(int desired_state)
29381937Sizick {
29391937Sizick 	int ret;
29401937Sizick 
29411937Sizick 	(void) pthread_mutex_lock(&soft_slot.keystore_mutex);
29421937Sizick 
29431937Sizick 	/*
29441937Sizick 	 * If more than one session tries to initialize the keystore, the
29451937Sizick 	 * second and other following sessions that were waiting for the lock
29461937Sizick 	 * will quickly exit if their requirements are satisfied.
29471937Sizick 	 */
29481937Sizick 	if (desired_state <= soft_slot.keystore_load_status) {
29491937Sizick 		(void) pthread_mutex_unlock(&soft_slot.keystore_mutex);
29501937Sizick 		return (soft_slot.keystore_load_status);
29511937Sizick 	}
29521937Sizick 
29531937Sizick 	/*
29541937Sizick 	 * With 'keystore_load_status' giving the current state of the
29551937Sizick 	 * process, this switch will bring it up to the desired state if
29561937Sizick 	 * possible.
29571937Sizick 	 */
29581937Sizick 
29591937Sizick 	switch (soft_slot.keystore_load_status) {
29601937Sizick 	case KEYSTORE_UNINITIALIZED:
29611937Sizick 		ret = soft_keystore_exists();
29621937Sizick 		if (ret == 0)
29631937Sizick 			soft_slot.keystore_load_status = KEYSTORE_PRESENT;
29641937Sizick 		else if (ret == ENOENT)
29651937Sizick 			if (create_keystore() == 0)
29661937Sizick 				soft_slot.keystore_load_status =
29671937Sizick 				    KEYSTORE_PRESENT;
29681937Sizick 			else {
29691937Sizick 				soft_slot.keystore_load_status =
29701937Sizick 				    KEYSTORE_UNAVAILABLE;
29712940Sizick 				cryptoerror(LOG_DEBUG,
29721937Sizick 				    "pkcs11_softtoken: "
29731937Sizick 				    "Cannot create keystore.");
29741937Sizick 				break;
29751937Sizick 			}
29761937Sizick 
29771937Sizick 		if (desired_state <= KEYSTORE_PRESENT)
29781937Sizick 			break;
29791937Sizick 
29801937Sizick 	/* FALLTHRU */
29811937Sizick 	case KEYSTORE_PRESENT:
29821937Sizick 		if (soft_keystore_get_version(&soft_slot.ks_version, B_FALSE)
29831937Sizick 		    != 0) {
29841937Sizick 			soft_slot.keystore_load_status = KEYSTORE_UNAVAILABLE;
29852940Sizick 			cryptoerror(LOG_DEBUG,
29862940Sizick 			    "pkcs11_softtoken: Keystore access failed.");
29871937Sizick 			break;
29881937Sizick 		}
29891937Sizick 
299012256SPeter.Shoults@Sun.COM 		soft_slot.keystore_load_status = KEYSTORE_LOAD;
299112256SPeter.Shoults@Sun.COM 		if (desired_state <= KEYSTORE_LOAD)
29921937Sizick 			break;
29931937Sizick 
29941937Sizick 	/* FALLTHRU */
299512256SPeter.Shoults@Sun.COM 	case KEYSTORE_LOAD:
29961937Sizick 		/* Load all the public token objects from keystore */
29971937Sizick 		if (soft_get_token_objects_from_keystore(PUB_TOKENOBJS)
29981937Sizick 		    != CKR_OK) {
29991937Sizick 			(void) soft_destroy_token_session();
30001937Sizick 			soft_slot.keystore_load_status = KEYSTORE_UNAVAILABLE;
30012940Sizick 			cryptoerror(LOG_DEBUG,
30021937Sizick 			    "pkcs11_softtoken: Cannot initialize keystore.");
30031937Sizick 			break;
30041937Sizick 		}
30051937Sizick 
30061937Sizick 		soft_slot.keystore_load_status = KEYSTORE_INITIALIZED;
30071937Sizick 	};
30081937Sizick 
30091937Sizick 	(void) pthread_mutex_unlock(&soft_slot.keystore_mutex);
30101937Sizick 	return (soft_slot.keystore_load_status);
30111937Sizick }
30121937Sizick 
30131937Sizick /*
30141937Sizick  *	FUNCTION: soft_keystore_status
30151937Sizick  *
30161937Sizick  *	ARGUMENTS:
30171937Sizick  *		desired_state:  The keystore state the caller would like
30181937Sizick  *				it to be.
30191937Sizick  *
30201937Sizick  *	RETURN VALUE:
30211937Sizick  *		B_TRUE if keystore is ready and at the desired state.
30221937Sizick  *		B_FALSE if keystore had an error and is not available.
30231937Sizick  *
30241937Sizick  *	DESCRIPTION:
30251937Sizick  *		The calling function wants to make sure the keystore load
30261937Sizick  *		status to in a state it requires.  If it is not at that
30271937Sizick  *		state it will call the load function.
30281937Sizick  *		If keystore is at the desired state or has just been
30291937Sizick  *		loaded to that state, it will return TRUE.  If there has been
30301937Sizick  *		load failure, it will return FALSE.
30311937Sizick  *
30321937Sizick  */
30331937Sizick boolean_t
soft_keystore_status(int desired_state)30341937Sizick soft_keystore_status(int desired_state)
30351937Sizick {
30361937Sizick 
30371937Sizick 	if (soft_slot.keystore_load_status == KEYSTORE_UNAVAILABLE)
30381937Sizick 		return (B_FALSE);
30391937Sizick 
30401937Sizick 	return ((desired_state <= soft_slot.keystore_load_status) ||
30411937Sizick 	    (soft_keystore_init(desired_state) == desired_state));
30421937Sizick }
3043