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