xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kms/common/kmsKeystoreUtil.c (revision 12720:3db6e0082404)
1*12720SWyllys.Ingersoll@Sun.COM /*
2*12720SWyllys.Ingersoll@Sun.COM  * CDDL HEADER START
3*12720SWyllys.Ingersoll@Sun.COM  *
4*12720SWyllys.Ingersoll@Sun.COM  * The contents of this file are subject to the terms of the
5*12720SWyllys.Ingersoll@Sun.COM  * Common Development and Distribution License (the "License").
6*12720SWyllys.Ingersoll@Sun.COM  * You may not use this file except in compliance with the License.
7*12720SWyllys.Ingersoll@Sun.COM  *
8*12720SWyllys.Ingersoll@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12720SWyllys.Ingersoll@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*12720SWyllys.Ingersoll@Sun.COM  * See the License for the specific language governing permissions
11*12720SWyllys.Ingersoll@Sun.COM  * and limitations under the License.
12*12720SWyllys.Ingersoll@Sun.COM  *
13*12720SWyllys.Ingersoll@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*12720SWyllys.Ingersoll@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12720SWyllys.Ingersoll@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*12720SWyllys.Ingersoll@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*12720SWyllys.Ingersoll@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*12720SWyllys.Ingersoll@Sun.COM  *
19*12720SWyllys.Ingersoll@Sun.COM  * CDDL HEADER END
20*12720SWyllys.Ingersoll@Sun.COM  *
21*12720SWyllys.Ingersoll@Sun.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
22*12720SWyllys.Ingersoll@Sun.COM  */
23*12720SWyllys.Ingersoll@Sun.COM 
24*12720SWyllys.Ingersoll@Sun.COM #include <stdio.h>
25*12720SWyllys.Ingersoll@Sun.COM #include <malloc.h>
26*12720SWyllys.Ingersoll@Sun.COM #include <memory.h>
27*12720SWyllys.Ingersoll@Sun.COM #include <strings.h>
28*12720SWyllys.Ingersoll@Sun.COM #include <fcntl.h>
29*12720SWyllys.Ingersoll@Sun.COM #include <errno.h>
30*12720SWyllys.Ingersoll@Sun.COM #include <ctype.h>
31*12720SWyllys.Ingersoll@Sun.COM #include <sys/types.h>
32*12720SWyllys.Ingersoll@Sun.COM #include <sys/stat.h>
33*12720SWyllys.Ingersoll@Sun.COM #include <cryptoutil.h>
34*12720SWyllys.Ingersoll@Sun.COM #include <unistd.h>
35*12720SWyllys.Ingersoll@Sun.COM #include <utmpx.h>
36*12720SWyllys.Ingersoll@Sun.COM #include <pthread.h>
37*12720SWyllys.Ingersoll@Sun.COM #include <pwd.h>
38*12720SWyllys.Ingersoll@Sun.COM #include <sha2.h>
39*12720SWyllys.Ingersoll@Sun.COM #include <security/cryptoki.h>
40*12720SWyllys.Ingersoll@Sun.COM #include <aes_impl.h>
41*12720SWyllys.Ingersoll@Sun.COM #include <sys/avl.h>
42*12720SWyllys.Ingersoll@Sun.COM 
43*12720SWyllys.Ingersoll@Sun.COM #include "kmsSession.h"
44*12720SWyllys.Ingersoll@Sun.COM #include "kmsGlobal.h"
45*12720SWyllys.Ingersoll@Sun.COM #include "kmsObject.h"
46*12720SWyllys.Ingersoll@Sun.COM 
47*12720SWyllys.Ingersoll@Sun.COM static CK_RV
48*12720SWyllys.Ingersoll@Sun.COM GetPKCS11StatusFromAgentStatus(KMS_AGENT_STATUS status);
49*12720SWyllys.Ingersoll@Sun.COM 
50*12720SWyllys.Ingersoll@Sun.COM static char		keystore_path[BUFSIZ];
51*12720SWyllys.Ingersoll@Sun.COM static boolean_t	keystore_path_initialized = B_FALSE;
52*12720SWyllys.Ingersoll@Sun.COM static time_t		last_objlist_mtime = 0;
53*12720SWyllys.Ingersoll@Sun.COM pthread_mutex_t		objlist_mutex = PTHREAD_MUTEX_INITIALIZER;
54*12720SWyllys.Ingersoll@Sun.COM pthread_mutex_t		flock_mutex = PTHREAD_MUTEX_INITIALIZER;
55*12720SWyllys.Ingersoll@Sun.COM 
56*12720SWyllys.Ingersoll@Sun.COM static struct flock fl = {
57*12720SWyllys.Ingersoll@Sun.COM 	0,
58*12720SWyllys.Ingersoll@Sun.COM 	0,
59*12720SWyllys.Ingersoll@Sun.COM 	0,
60*12720SWyllys.Ingersoll@Sun.COM 	0,
61*12720SWyllys.Ingersoll@Sun.COM 	0,
62*12720SWyllys.Ingersoll@Sun.COM 	0,
63*12720SWyllys.Ingersoll@Sun.COM 	{0, 0, 0, 0}
64*12720SWyllys.Ingersoll@Sun.COM };
65*12720SWyllys.Ingersoll@Sun.COM 
66*12720SWyllys.Ingersoll@Sun.COM #define	KEYSTORE_PATH			"/var/kms"
67*12720SWyllys.Ingersoll@Sun.COM #define	ALTERNATE_KEYSTORE_PATH		"KMSTOKEN_DIR"
68*12720SWyllys.Ingersoll@Sun.COM #define	KMS_PROFILE_FILENAME		"profile.cfg"
69*12720SWyllys.Ingersoll@Sun.COM #define	KMS_DATAUNIT_DESCRIPTION	"Oracle PKCS11/KMS"
70*12720SWyllys.Ingersoll@Sun.COM #define	KMS_ATTR_DESC_PFX		"PKCS#11v2.20: "
71*12720SWyllys.Ingersoll@Sun.COM #define	KMSTOKEN_CONFIG_FILENAME	"kmstoken.cfg"
72*12720SWyllys.Ingersoll@Sun.COM #define	KMSTOKEN_LABELLIST_FILENAME	"objlabels.lst"
73*12720SWyllys.Ingersoll@Sun.COM 
74*12720SWyllys.Ingersoll@Sun.COM static void
kms_hash_string(char * label,uchar_t * hash)75*12720SWyllys.Ingersoll@Sun.COM kms_hash_string(char *label, uchar_t *hash)
76*12720SWyllys.Ingersoll@Sun.COM {
77*12720SWyllys.Ingersoll@Sun.COM 	SHA2_CTX ctx;
78*12720SWyllys.Ingersoll@Sun.COM 
79*12720SWyllys.Ingersoll@Sun.COM 	SHA2Init(SHA256, &ctx);
80*12720SWyllys.Ingersoll@Sun.COM 	SHA2Update(&ctx, label, strlen(label));
81*12720SWyllys.Ingersoll@Sun.COM 	SHA2Final(hash, &ctx);
82*12720SWyllys.Ingersoll@Sun.COM }
83*12720SWyllys.Ingersoll@Sun.COM 
84*12720SWyllys.Ingersoll@Sun.COM static char *
get_username(char * username,int len)85*12720SWyllys.Ingersoll@Sun.COM get_username(char *username, int len)
86*12720SWyllys.Ingersoll@Sun.COM {
87*12720SWyllys.Ingersoll@Sun.COM 	struct passwd pwd, *user_info;
88*12720SWyllys.Ingersoll@Sun.COM 	long buflen;
89*12720SWyllys.Ingersoll@Sun.COM 	char *pwdbuf = NULL;
90*12720SWyllys.Ingersoll@Sun.COM 
91*12720SWyllys.Ingersoll@Sun.COM 	bzero(username, len);
92*12720SWyllys.Ingersoll@Sun.COM 
93*12720SWyllys.Ingersoll@Sun.COM 	buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
94*12720SWyllys.Ingersoll@Sun.COM 	if (buflen == -1)
95*12720SWyllys.Ingersoll@Sun.COM 		return (username); /* should not happen */
96*12720SWyllys.Ingersoll@Sun.COM 
97*12720SWyllys.Ingersoll@Sun.COM 	pwdbuf = calloc(1, buflen);
98*12720SWyllys.Ingersoll@Sun.COM 	if (pwdbuf == NULL)
99*12720SWyllys.Ingersoll@Sun.COM 		return (username); /* zero-ed earlier */
100*12720SWyllys.Ingersoll@Sun.COM 
101*12720SWyllys.Ingersoll@Sun.COM 	user_info = getpwuid_r(getuid(), &pwd, pwdbuf, buflen);
102*12720SWyllys.Ingersoll@Sun.COM 
103*12720SWyllys.Ingersoll@Sun.COM 	if (user_info != NULL)
104*12720SWyllys.Ingersoll@Sun.COM 		(void) strlcpy(username, user_info->pw_name, len);
105*12720SWyllys.Ingersoll@Sun.COM 
106*12720SWyllys.Ingersoll@Sun.COM 	free(pwdbuf);
107*12720SWyllys.Ingersoll@Sun.COM 	return (username);
108*12720SWyllys.Ingersoll@Sun.COM }
109*12720SWyllys.Ingersoll@Sun.COM 
110*12720SWyllys.Ingersoll@Sun.COM static char *
kms_get_keystore_path()111*12720SWyllys.Ingersoll@Sun.COM kms_get_keystore_path()
112*12720SWyllys.Ingersoll@Sun.COM {
113*12720SWyllys.Ingersoll@Sun.COM 	char *env_val;
114*12720SWyllys.Ingersoll@Sun.COM 	char username[sizeof (((struct utmpx *)0)->ut_user)];
115*12720SWyllys.Ingersoll@Sun.COM 
116*12720SWyllys.Ingersoll@Sun.COM 	if (!keystore_path_initialized) {
117*12720SWyllys.Ingersoll@Sun.COM 		env_val = getenv(ALTERNATE_KEYSTORE_PATH);
118*12720SWyllys.Ingersoll@Sun.COM 		bzero(keystore_path, sizeof (keystore_path));
119*12720SWyllys.Ingersoll@Sun.COM 		/*
120*12720SWyllys.Ingersoll@Sun.COM 		 * If it isn't set or is set to the empty string use the
121*12720SWyllys.Ingersoll@Sun.COM 		 * default location.  We need to check for the empty string
122*12720SWyllys.Ingersoll@Sun.COM 		 * because some users "unset" environment variables by giving
123*12720SWyllys.Ingersoll@Sun.COM 		 * them no value, this isn't the same thing as removing it
124*12720SWyllys.Ingersoll@Sun.COM 		 * from the environment.
125*12720SWyllys.Ingersoll@Sun.COM 		 */
126*12720SWyllys.Ingersoll@Sun.COM 		if ((env_val == NULL) || (strcmp(env_val, "") == 0)) {
127*12720SWyllys.Ingersoll@Sun.COM 			/* alternate path not specified, use /var/kms/$USER */
128*12720SWyllys.Ingersoll@Sun.COM 			(void) snprintf(keystore_path,
129*12720SWyllys.Ingersoll@Sun.COM 			    sizeof (keystore_path), "%s/%s",
130*12720SWyllys.Ingersoll@Sun.COM 			    KEYSTORE_PATH,
131*12720SWyllys.Ingersoll@Sun.COM 			    get_username(username, sizeof (username)));
132*12720SWyllys.Ingersoll@Sun.COM 		} else {
133*12720SWyllys.Ingersoll@Sun.COM 			(void) strlcpy(keystore_path, env_val,
134*12720SWyllys.Ingersoll@Sun.COM 			    sizeof (keystore_path));
135*12720SWyllys.Ingersoll@Sun.COM 		}
136*12720SWyllys.Ingersoll@Sun.COM 		keystore_path_initialized = B_TRUE;
137*12720SWyllys.Ingersoll@Sun.COM 	}
138*12720SWyllys.Ingersoll@Sun.COM 	return (keystore_path);
139*12720SWyllys.Ingersoll@Sun.COM }
140*12720SWyllys.Ingersoll@Sun.COM 
141*12720SWyllys.Ingersoll@Sun.COM static char *
get_non_comment_line(char * cfgbuf,size_t cfglen,char * buf,size_t buflen)142*12720SWyllys.Ingersoll@Sun.COM get_non_comment_line(char *cfgbuf, size_t cfglen, char *buf, size_t buflen)
143*12720SWyllys.Ingersoll@Sun.COM {
144*12720SWyllys.Ingersoll@Sun.COM 	char *s = cfgbuf;
145*12720SWyllys.Ingersoll@Sun.COM 	char *end = cfgbuf + cfglen;
146*12720SWyllys.Ingersoll@Sun.COM 	char *f;
147*12720SWyllys.Ingersoll@Sun.COM 
148*12720SWyllys.Ingersoll@Sun.COM 	/* Skip over blank lines CR/LF */
149*12720SWyllys.Ingersoll@Sun.COM 	while (s < end && (*s == '#' || *s == '\n' || *s == '\r')) {
150*12720SWyllys.Ingersoll@Sun.COM 		/* check for comment sign */
151*12720SWyllys.Ingersoll@Sun.COM 		if (*s == '#') {
152*12720SWyllys.Ingersoll@Sun.COM 			/* skip the rest of the line */
153*12720SWyllys.Ingersoll@Sun.COM 			while ((*s != '\n' || *s == '\r') && s < end)
154*12720SWyllys.Ingersoll@Sun.COM 				s++;
155*12720SWyllys.Ingersoll@Sun.COM 		}
156*12720SWyllys.Ingersoll@Sun.COM 		if ((s < end) && (*s == '\n' || *s == '\r'))
157*12720SWyllys.Ingersoll@Sun.COM 			s++;
158*12720SWyllys.Ingersoll@Sun.COM 	}
159*12720SWyllys.Ingersoll@Sun.COM 
160*12720SWyllys.Ingersoll@Sun.COM 	if (s < end) {
161*12720SWyllys.Ingersoll@Sun.COM 		char save, *e;
162*12720SWyllys.Ingersoll@Sun.COM 		f = s; /* mark the beginning. */
163*12720SWyllys.Ingersoll@Sun.COM 		/* Find the end of the line and null terminate it. */
164*12720SWyllys.Ingersoll@Sun.COM 		while (*s != '\n' && *s != '\r' && *s != '#' && s < end) s++;
165*12720SWyllys.Ingersoll@Sun.COM 		save = *s;
166*12720SWyllys.Ingersoll@Sun.COM 		*s = 0x00;
167*12720SWyllys.Ingersoll@Sun.COM 		(void) strncpy(buf, f, buflen);
168*12720SWyllys.Ingersoll@Sun.COM 		*s = save;
169*12720SWyllys.Ingersoll@Sun.COM 
170*12720SWyllys.Ingersoll@Sun.COM 		/* Strip trailing whitespace */
171*12720SWyllys.Ingersoll@Sun.COM 		f = buf;
172*12720SWyllys.Ingersoll@Sun.COM 		e = f + strlen(buf) - 1;
173*12720SWyllys.Ingersoll@Sun.COM 		while (e >= f && isspace(*e)) {
174*12720SWyllys.Ingersoll@Sun.COM 			*e = 0x00;
175*12720SWyllys.Ingersoll@Sun.COM 			e--;
176*12720SWyllys.Ingersoll@Sun.COM 		}
177*12720SWyllys.Ingersoll@Sun.COM 
178*12720SWyllys.Ingersoll@Sun.COM 	} else {
179*12720SWyllys.Ingersoll@Sun.COM 		/* If we reached the end, return NULL */
180*12720SWyllys.Ingersoll@Sun.COM 		s = NULL;
181*12720SWyllys.Ingersoll@Sun.COM 	}
182*12720SWyllys.Ingersoll@Sun.COM done:
183*12720SWyllys.Ingersoll@Sun.COM 	return (s);
184*12720SWyllys.Ingersoll@Sun.COM }
185*12720SWyllys.Ingersoll@Sun.COM 
186*12720SWyllys.Ingersoll@Sun.COM static int
flock_fd(int fd,int cmd,pthread_mutex_t * mutex)187*12720SWyllys.Ingersoll@Sun.COM flock_fd(int fd, int cmd, pthread_mutex_t *mutex)
188*12720SWyllys.Ingersoll@Sun.COM {
189*12720SWyllys.Ingersoll@Sun.COM 	int ret = 0;
190*12720SWyllys.Ingersoll@Sun.COM 
191*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(mutex);
192*12720SWyllys.Ingersoll@Sun.COM 
193*12720SWyllys.Ingersoll@Sun.COM 	fl.l_type = cmd;
194*12720SWyllys.Ingersoll@Sun.COM 
195*12720SWyllys.Ingersoll@Sun.COM 	while ((ret = fcntl(fd, F_SETLKW, &fl)) == -1) {
196*12720SWyllys.Ingersoll@Sun.COM 		if (errno != EINTR)
197*12720SWyllys.Ingersoll@Sun.COM 			break;
198*12720SWyllys.Ingersoll@Sun.COM 	}
199*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(mutex);
200*12720SWyllys.Ingersoll@Sun.COM 	return (ret);
201*12720SWyllys.Ingersoll@Sun.COM }
202*12720SWyllys.Ingersoll@Sun.COM 
203*12720SWyllys.Ingersoll@Sun.COM /*
204*12720SWyllys.Ingersoll@Sun.COM  * Open the keystore description file in the specified mode.
205*12720SWyllys.Ingersoll@Sun.COM  * If the keystore doesn't exist, the "do_create_keystore"
206*12720SWyllys.Ingersoll@Sun.COM  * argument determines if the keystore should be created
207*12720SWyllys.Ingersoll@Sun.COM  */
208*12720SWyllys.Ingersoll@Sun.COM static int
open_and_lock_file(char * filename,int cmd,mode_t mode,pthread_mutex_t * mutex)209*12720SWyllys.Ingersoll@Sun.COM open_and_lock_file(char *filename, int cmd, mode_t mode,
210*12720SWyllys.Ingersoll@Sun.COM     pthread_mutex_t *mutex)
211*12720SWyllys.Ingersoll@Sun.COM {
212*12720SWyllys.Ingersoll@Sun.COM 	int fd;
213*12720SWyllys.Ingersoll@Sun.COM 
214*12720SWyllys.Ingersoll@Sun.COM 	fd = open_nointr(filename, mode|O_NONBLOCK);
215*12720SWyllys.Ingersoll@Sun.COM 	if (fd < 0)
216*12720SWyllys.Ingersoll@Sun.COM 		return (fd);
217*12720SWyllys.Ingersoll@Sun.COM 
218*12720SWyllys.Ingersoll@Sun.COM 	if (flock_fd(fd, cmd, mutex)) {
219*12720SWyllys.Ingersoll@Sun.COM 		if (fd > 0)
220*12720SWyllys.Ingersoll@Sun.COM 			(void) close(fd);
221*12720SWyllys.Ingersoll@Sun.COM 		return (-1);
222*12720SWyllys.Ingersoll@Sun.COM 	}
223*12720SWyllys.Ingersoll@Sun.COM 
224*12720SWyllys.Ingersoll@Sun.COM 	return (fd);
225*12720SWyllys.Ingersoll@Sun.COM }
226*12720SWyllys.Ingersoll@Sun.COM 
227*12720SWyllys.Ingersoll@Sun.COM static int
kms_slurp_file(char * file,char * buf,size_t buflen)228*12720SWyllys.Ingersoll@Sun.COM kms_slurp_file(char *file, char *buf, size_t buflen)
229*12720SWyllys.Ingersoll@Sun.COM {
230*12720SWyllys.Ingersoll@Sun.COM 	int n, fd, total = 0;
231*12720SWyllys.Ingersoll@Sun.COM 
232*12720SWyllys.Ingersoll@Sun.COM 	fd = open_and_lock_file(file, F_RDLCK, O_RDONLY, &flock_mutex);
233*12720SWyllys.Ingersoll@Sun.COM 	if (fd == -1)
234*12720SWyllys.Ingersoll@Sun.COM 		return (-1);
235*12720SWyllys.Ingersoll@Sun.COM 
236*12720SWyllys.Ingersoll@Sun.COM 	do {
237*12720SWyllys.Ingersoll@Sun.COM 		n = readn_nointr(fd, &buf[total], buflen - total);
238*12720SWyllys.Ingersoll@Sun.COM 		if (n != (buflen - total))
239*12720SWyllys.Ingersoll@Sun.COM 			break;
240*12720SWyllys.Ingersoll@Sun.COM 		else
241*12720SWyllys.Ingersoll@Sun.COM 			total += n;
242*12720SWyllys.Ingersoll@Sun.COM 	} while (total < buflen);
243*12720SWyllys.Ingersoll@Sun.COM 
244*12720SWyllys.Ingersoll@Sun.COM 	if (flock_fd(fd, F_UNLCK, &flock_mutex))
245*12720SWyllys.Ingersoll@Sun.COM 		total = -1;
246*12720SWyllys.Ingersoll@Sun.COM 
247*12720SWyllys.Ingersoll@Sun.COM 	(void) close(fd);
248*12720SWyllys.Ingersoll@Sun.COM 
249*12720SWyllys.Ingersoll@Sun.COM 	return (total);
250*12720SWyllys.Ingersoll@Sun.COM }
251*12720SWyllys.Ingersoll@Sun.COM 
252*12720SWyllys.Ingersoll@Sun.COM /*
253*12720SWyllys.Ingersoll@Sun.COM  * The KMS token is considered "initialized" if the file with the token
254*12720SWyllys.Ingersoll@Sun.COM  * configuration information is present.
255*12720SWyllys.Ingersoll@Sun.COM  */
256*12720SWyllys.Ingersoll@Sun.COM CK_BBOOL
kms_is_initialized()257*12720SWyllys.Ingersoll@Sun.COM kms_is_initialized()
258*12720SWyllys.Ingersoll@Sun.COM {
259*12720SWyllys.Ingersoll@Sun.COM 	CK_BBOOL rv;
260*12720SWyllys.Ingersoll@Sun.COM 	char *ksdir;
261*12720SWyllys.Ingersoll@Sun.COM 	char cfgfile_path[BUFSIZ];
262*12720SWyllys.Ingersoll@Sun.COM 	struct stat statp;
263*12720SWyllys.Ingersoll@Sun.COM 
264*12720SWyllys.Ingersoll@Sun.COM 	ksdir = kms_get_keystore_path();
265*12720SWyllys.Ingersoll@Sun.COM 	if (ksdir == NULL)
266*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_FUNCTION_FAILED);
267*12720SWyllys.Ingersoll@Sun.COM 
268*12720SWyllys.Ingersoll@Sun.COM 	(void) snprintf(cfgfile_path, sizeof (cfgfile_path),
269*12720SWyllys.Ingersoll@Sun.COM 	    "%s/%s", ksdir, KMSTOKEN_CONFIG_FILENAME);
270*12720SWyllys.Ingersoll@Sun.COM 
271*12720SWyllys.Ingersoll@Sun.COM 	if (stat(cfgfile_path, &statp))
272*12720SWyllys.Ingersoll@Sun.COM 		rv = FALSE;
273*12720SWyllys.Ingersoll@Sun.COM 	else
274*12720SWyllys.Ingersoll@Sun.COM 		rv = TRUE;
275*12720SWyllys.Ingersoll@Sun.COM 
276*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
277*12720SWyllys.Ingersoll@Sun.COM }
278*12720SWyllys.Ingersoll@Sun.COM 
279*12720SWyllys.Ingersoll@Sun.COM static CK_RV
kms_read_config_data(char * path,kms_cfg_info_t * cfginfo)280*12720SWyllys.Ingersoll@Sun.COM kms_read_config_data(char *path, kms_cfg_info_t *cfginfo)
281*12720SWyllys.Ingersoll@Sun.COM {
282*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
283*12720SWyllys.Ingersoll@Sun.COM 	char	*cfgbuf = NULL;
284*12720SWyllys.Ingersoll@Sun.COM 	char	*ptr;
285*12720SWyllys.Ingersoll@Sun.COM 	char	buf[BUFSIZ];
286*12720SWyllys.Ingersoll@Sun.COM 	size_t	buflen = 0, remain;
287*12720SWyllys.Ingersoll@Sun.COM 	struct	stat statp;
288*12720SWyllys.Ingersoll@Sun.COM 
289*12720SWyllys.Ingersoll@Sun.COM 	if (path == NULL || cfginfo == NULL)
290*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_ARGUMENTS_BAD);
291*12720SWyllys.Ingersoll@Sun.COM 
292*12720SWyllys.Ingersoll@Sun.COM 	if (stat(path, &statp) == -1) {
293*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_FUNCTION_FAILED);
294*12720SWyllys.Ingersoll@Sun.COM 	}
295*12720SWyllys.Ingersoll@Sun.COM 
296*12720SWyllys.Ingersoll@Sun.COM 	cfgbuf = calloc(1, statp.st_size);
297*12720SWyllys.Ingersoll@Sun.COM 	if (cfgbuf == NULL)
298*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_HOST_MEMORY);
299*12720SWyllys.Ingersoll@Sun.COM 
300*12720SWyllys.Ingersoll@Sun.COM 	buflen = kms_slurp_file(path, cfgbuf, statp.st_size);
301*12720SWyllys.Ingersoll@Sun.COM 	if (buflen != statp.st_size) {
302*12720SWyllys.Ingersoll@Sun.COM 		free(cfgbuf);
303*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_FUNCTION_FAILED);
304*12720SWyllys.Ingersoll@Sun.COM 	}
305*12720SWyllys.Ingersoll@Sun.COM 
306*12720SWyllys.Ingersoll@Sun.COM 	remain = buflen;
307*12720SWyllys.Ingersoll@Sun.COM 	ptr = cfgbuf;
308*12720SWyllys.Ingersoll@Sun.COM 	ptr = get_non_comment_line(ptr, remain,
309*12720SWyllys.Ingersoll@Sun.COM 	    cfginfo->name, sizeof (cfginfo->name));
310*12720SWyllys.Ingersoll@Sun.COM 	if (ptr == NULL) {
311*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_FUNCTION_FAILED;
312*12720SWyllys.Ingersoll@Sun.COM 		goto done;
313*12720SWyllys.Ingersoll@Sun.COM 	}
314*12720SWyllys.Ingersoll@Sun.COM 	remain = buflen - (ptr - cfgbuf);
315*12720SWyllys.Ingersoll@Sun.COM 	ptr = get_non_comment_line(ptr, remain,
316*12720SWyllys.Ingersoll@Sun.COM 	    cfginfo->agentId, sizeof (cfginfo->agentId));
317*12720SWyllys.Ingersoll@Sun.COM 	if (ptr == 0) {
318*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_FUNCTION_FAILED;
319*12720SWyllys.Ingersoll@Sun.COM 		goto done;
320*12720SWyllys.Ingersoll@Sun.COM 	}
321*12720SWyllys.Ingersoll@Sun.COM 	remain = buflen - (ptr - cfgbuf);
322*12720SWyllys.Ingersoll@Sun.COM 	ptr = get_non_comment_line(ptr, remain,
323*12720SWyllys.Ingersoll@Sun.COM 	    cfginfo->agentAddr, sizeof (cfginfo->agentAddr));
324*12720SWyllys.Ingersoll@Sun.COM 	if (ptr == 0) {
325*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_FUNCTION_FAILED;
326*12720SWyllys.Ingersoll@Sun.COM 		goto done;
327*12720SWyllys.Ingersoll@Sun.COM 	}
328*12720SWyllys.Ingersoll@Sun.COM 	remain = buflen - (ptr - cfgbuf);
329*12720SWyllys.Ingersoll@Sun.COM 	ptr = get_non_comment_line(ptr, remain, buf, sizeof (buf));
330*12720SWyllys.Ingersoll@Sun.COM 	if (ptr == 0) {
331*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_FUNCTION_FAILED;
332*12720SWyllys.Ingersoll@Sun.COM 		goto done;
333*12720SWyllys.Ingersoll@Sun.COM 	}
334*12720SWyllys.Ingersoll@Sun.COM 	cfginfo->transTimeout = atoi(buf);
335*12720SWyllys.Ingersoll@Sun.COM 
336*12720SWyllys.Ingersoll@Sun.COM 	remain = buflen - (ptr - cfgbuf);
337*12720SWyllys.Ingersoll@Sun.COM 	ptr = get_non_comment_line(ptr, remain, buf, sizeof (buf));
338*12720SWyllys.Ingersoll@Sun.COM 	if (ptr == 0) {
339*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_FUNCTION_FAILED;
340*12720SWyllys.Ingersoll@Sun.COM 		goto done;
341*12720SWyllys.Ingersoll@Sun.COM 	}
342*12720SWyllys.Ingersoll@Sun.COM 	cfginfo->failoverLimit = atoi(buf);
343*12720SWyllys.Ingersoll@Sun.COM 
344*12720SWyllys.Ingersoll@Sun.COM 	remain = buflen - (ptr - cfgbuf);
345*12720SWyllys.Ingersoll@Sun.COM 	ptr = get_non_comment_line(ptr, remain, buf, sizeof (buf));
346*12720SWyllys.Ingersoll@Sun.COM 	if (ptr == 0) {
347*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_FUNCTION_FAILED;
348*12720SWyllys.Ingersoll@Sun.COM 		goto done;
349*12720SWyllys.Ingersoll@Sun.COM 	}
350*12720SWyllys.Ingersoll@Sun.COM 	cfginfo->discoveryFreq = atoi(buf);
351*12720SWyllys.Ingersoll@Sun.COM 
352*12720SWyllys.Ingersoll@Sun.COM 	remain = buflen - (ptr - cfgbuf);
353*12720SWyllys.Ingersoll@Sun.COM 	ptr = get_non_comment_line(ptr, remain, buf, sizeof (buf));
354*12720SWyllys.Ingersoll@Sun.COM 	if (ptr == 0) {
355*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_FUNCTION_FAILED;
356*12720SWyllys.Ingersoll@Sun.COM 		goto done;
357*12720SWyllys.Ingersoll@Sun.COM 	}
358*12720SWyllys.Ingersoll@Sun.COM 	cfginfo->securityMode = atoi(buf);
359*12720SWyllys.Ingersoll@Sun.COM done:
360*12720SWyllys.Ingersoll@Sun.COM 	if (cfgbuf != NULL)
361*12720SWyllys.Ingersoll@Sun.COM 		free(cfgbuf);
362*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
363*12720SWyllys.Ingersoll@Sun.COM }
364*12720SWyllys.Ingersoll@Sun.COM 
365*12720SWyllys.Ingersoll@Sun.COM CK_BBOOL
kms_is_pin_set()366*12720SWyllys.Ingersoll@Sun.COM kms_is_pin_set()
367*12720SWyllys.Ingersoll@Sun.COM {
368*12720SWyllys.Ingersoll@Sun.COM 	CK_BBOOL rv = TRUE;
369*12720SWyllys.Ingersoll@Sun.COM 	kms_cfg_info_t kmscfg;
370*12720SWyllys.Ingersoll@Sun.COM 	struct stat statp;
371*12720SWyllys.Ingersoll@Sun.COM 	char *ksdir;
372*12720SWyllys.Ingersoll@Sun.COM 	char filepath[BUFSIZ];
373*12720SWyllys.Ingersoll@Sun.COM 
374*12720SWyllys.Ingersoll@Sun.COM 	ksdir = kms_get_keystore_path();
375*12720SWyllys.Ingersoll@Sun.COM 	if (ksdir == NULL)
376*12720SWyllys.Ingersoll@Sun.COM 		return (FALSE);
377*12720SWyllys.Ingersoll@Sun.COM 
378*12720SWyllys.Ingersoll@Sun.COM 	(void) snprintf(filepath, sizeof (filepath),
379*12720SWyllys.Ingersoll@Sun.COM 	    "%s/%s", ksdir, KMSTOKEN_CONFIG_FILENAME);
380*12720SWyllys.Ingersoll@Sun.COM 
381*12720SWyllys.Ingersoll@Sun.COM 	if ((rv = kms_read_config_data(filepath, &kmscfg)))
382*12720SWyllys.Ingersoll@Sun.COM 		return (FALSE);
383*12720SWyllys.Ingersoll@Sun.COM 
384*12720SWyllys.Ingersoll@Sun.COM 	/*
385*12720SWyllys.Ingersoll@Sun.COM 	 * The PK12 file is only established once the user has enrolled
386*12720SWyllys.Ingersoll@Sun.COM 	 * and is thus considered having a PIN set.
387*12720SWyllys.Ingersoll@Sun.COM 	 */
388*12720SWyllys.Ingersoll@Sun.COM 	(void) snprintf(filepath, sizeof (filepath),
389*12720SWyllys.Ingersoll@Sun.COM 	    "%s/%s/%s", ksdir, kmscfg.agentId, CLIENT_PK12_FILE);
390*12720SWyllys.Ingersoll@Sun.COM 
391*12720SWyllys.Ingersoll@Sun.COM 	if (stat(filepath, &statp))
392*12720SWyllys.Ingersoll@Sun.COM 		rv = FALSE; /* file doesn't exist. */
393*12720SWyllys.Ingersoll@Sun.COM 	else
394*12720SWyllys.Ingersoll@Sun.COM 		rv = TRUE; /* File exists, PIN is set */
395*12720SWyllys.Ingersoll@Sun.COM 
396*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
397*12720SWyllys.Ingersoll@Sun.COM }
398*12720SWyllys.Ingersoll@Sun.COM 
399*12720SWyllys.Ingersoll@Sun.COM void
kms_clear_label_list(avl_tree_t * tree)400*12720SWyllys.Ingersoll@Sun.COM kms_clear_label_list(avl_tree_t *tree)
401*12720SWyllys.Ingersoll@Sun.COM {
402*12720SWyllys.Ingersoll@Sun.COM 	void *cookie = NULL;
403*12720SWyllys.Ingersoll@Sun.COM 	objlabel_t *node;
404*12720SWyllys.Ingersoll@Sun.COM 
405*12720SWyllys.Ingersoll@Sun.COM 	while ((node = avl_destroy_nodes(tree, &cookie)) != NULL) {
406*12720SWyllys.Ingersoll@Sun.COM 		free(node->label);
407*12720SWyllys.Ingersoll@Sun.COM 		free(node);
408*12720SWyllys.Ingersoll@Sun.COM 	}
409*12720SWyllys.Ingersoll@Sun.COM }
410*12720SWyllys.Ingersoll@Sun.COM 
411*12720SWyllys.Ingersoll@Sun.COM static void
add_label_node(avl_tree_t * tree,char * label)412*12720SWyllys.Ingersoll@Sun.COM add_label_node(avl_tree_t *tree, char *label)
413*12720SWyllys.Ingersoll@Sun.COM {
414*12720SWyllys.Ingersoll@Sun.COM 	avl_index_t where;
415*12720SWyllys.Ingersoll@Sun.COM 	objlabel_t  *node;
416*12720SWyllys.Ingersoll@Sun.COM 	objlabel_t *newnode;
417*12720SWyllys.Ingersoll@Sun.COM 	int i;
418*12720SWyllys.Ingersoll@Sun.COM 
419*12720SWyllys.Ingersoll@Sun.COM 	if (tree == NULL || label == NULL)
420*12720SWyllys.Ingersoll@Sun.COM 		return;
421*12720SWyllys.Ingersoll@Sun.COM 
422*12720SWyllys.Ingersoll@Sun.COM 	/* Remove trailing CR */
423*12720SWyllys.Ingersoll@Sun.COM 	i = strlen(label) - 1;
424*12720SWyllys.Ingersoll@Sun.COM 	while (i > 0 && label[i] == '\n')
425*12720SWyllys.Ingersoll@Sun.COM 		label[i--] = 0x00;
426*12720SWyllys.Ingersoll@Sun.COM 
427*12720SWyllys.Ingersoll@Sun.COM 	newnode = calloc(1, sizeof (objlabel_t));
428*12720SWyllys.Ingersoll@Sun.COM 	newnode->label = (char *)strdup(label);
429*12720SWyllys.Ingersoll@Sun.COM 	if (newnode->label == NULL) {
430*12720SWyllys.Ingersoll@Sun.COM 		free(newnode);
431*12720SWyllys.Ingersoll@Sun.COM 		return;
432*12720SWyllys.Ingersoll@Sun.COM 	}
433*12720SWyllys.Ingersoll@Sun.COM 	/* see if this entry already exists */
434*12720SWyllys.Ingersoll@Sun.COM 	node = avl_find(tree, newnode, &where);
435*12720SWyllys.Ingersoll@Sun.COM 	if (node == NULL) {
436*12720SWyllys.Ingersoll@Sun.COM 		avl_insert(tree, newnode, where);
437*12720SWyllys.Ingersoll@Sun.COM 	} else {
438*12720SWyllys.Ingersoll@Sun.COM 		/* It's a dup, don't add it */
439*12720SWyllys.Ingersoll@Sun.COM 		free(newnode->label);
440*12720SWyllys.Ingersoll@Sun.COM 		free(newnode);
441*12720SWyllys.Ingersoll@Sun.COM 	}
442*12720SWyllys.Ingersoll@Sun.COM }
443*12720SWyllys.Ingersoll@Sun.COM 
444*12720SWyllys.Ingersoll@Sun.COM CK_RV
kms_reload_labels(kms_session_t * sp)445*12720SWyllys.Ingersoll@Sun.COM kms_reload_labels(kms_session_t *sp)
446*12720SWyllys.Ingersoll@Sun.COM {
447*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
448*12720SWyllys.Ingersoll@Sun.COM 	char *cfgbuf = NULL, *ptr, buffer[BUFSIZ];
449*12720SWyllys.Ingersoll@Sun.COM 	size_t buflen, remain;
450*12720SWyllys.Ingersoll@Sun.COM 	struct stat statp;
451*12720SWyllys.Ingersoll@Sun.COM 	char *ksdir;
452*12720SWyllys.Ingersoll@Sun.COM 	char labelfile[BUFSIZ];
453*12720SWyllys.Ingersoll@Sun.COM 
454*12720SWyllys.Ingersoll@Sun.COM 	ksdir = kms_get_keystore_path();
455*12720SWyllys.Ingersoll@Sun.COM 	if (ksdir == NULL)
456*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_GENERAL_ERROR);
457*12720SWyllys.Ingersoll@Sun.COM 
458*12720SWyllys.Ingersoll@Sun.COM 	(void) snprintf(labelfile, sizeof (labelfile),
459*12720SWyllys.Ingersoll@Sun.COM 	    "%s/%s", ksdir, KMSTOKEN_LABELLIST_FILENAME);
460*12720SWyllys.Ingersoll@Sun.COM 
461*12720SWyllys.Ingersoll@Sun.COM 	bzero(&statp, sizeof (statp));
462*12720SWyllys.Ingersoll@Sun.COM 	if (stat(labelfile, &statp) == -1) {
463*12720SWyllys.Ingersoll@Sun.COM 		if (errno == ENOENT) {
464*12720SWyllys.Ingersoll@Sun.COM 			FILE *fp;
465*12720SWyllys.Ingersoll@Sun.COM 			/* Create it */
466*12720SWyllys.Ingersoll@Sun.COM 			fp = fopen(labelfile, "w");
467*12720SWyllys.Ingersoll@Sun.COM 			if (fp == NULL)
468*12720SWyllys.Ingersoll@Sun.COM 				return (CKR_GENERAL_ERROR);
469*12720SWyllys.Ingersoll@Sun.COM 			(void) fclose(fp);
470*12720SWyllys.Ingersoll@Sun.COM 		}
471*12720SWyllys.Ingersoll@Sun.COM 	}
472*12720SWyllys.Ingersoll@Sun.COM 
473*12720SWyllys.Ingersoll@Sun.COM 	if (statp.st_size == 0) {
474*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_OK);
475*12720SWyllys.Ingersoll@Sun.COM 	}
476*12720SWyllys.Ingersoll@Sun.COM 
477*12720SWyllys.Ingersoll@Sun.COM 	cfgbuf = calloc(1, statp.st_size);
478*12720SWyllys.Ingersoll@Sun.COM 	if (cfgbuf == NULL)
479*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_HOST_MEMORY);
480*12720SWyllys.Ingersoll@Sun.COM 
481*12720SWyllys.Ingersoll@Sun.COM 	buflen = kms_slurp_file(labelfile, cfgbuf, statp.st_size);
482*12720SWyllys.Ingersoll@Sun.COM 	if (buflen != statp.st_size) {
483*12720SWyllys.Ingersoll@Sun.COM 		free(cfgbuf);
484*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_FUNCTION_FAILED);
485*12720SWyllys.Ingersoll@Sun.COM 	}
486*12720SWyllys.Ingersoll@Sun.COM 
487*12720SWyllys.Ingersoll@Sun.COM 	if (statp.st_mtime == last_objlist_mtime) {
488*12720SWyllys.Ingersoll@Sun.COM 		/* No change */
489*12720SWyllys.Ingersoll@Sun.COM 		goto end;
490*12720SWyllys.Ingersoll@Sun.COM 	}
491*12720SWyllys.Ingersoll@Sun.COM 
492*12720SWyllys.Ingersoll@Sun.COM 	/* If we got here, we need to refresh the entire list */
493*12720SWyllys.Ingersoll@Sun.COM 	kms_clear_label_list(&sp->objlabel_tree);
494*12720SWyllys.Ingersoll@Sun.COM 
495*12720SWyllys.Ingersoll@Sun.COM 	/*
496*12720SWyllys.Ingersoll@Sun.COM 	 * Read each line and add it as a label node.
497*12720SWyllys.Ingersoll@Sun.COM 	 */
498*12720SWyllys.Ingersoll@Sun.COM 	remain = buflen;
499*12720SWyllys.Ingersoll@Sun.COM 	ptr = cfgbuf;
500*12720SWyllys.Ingersoll@Sun.COM 	while (remain > 0) {
501*12720SWyllys.Ingersoll@Sun.COM 		ptr = get_non_comment_line(ptr, remain,
502*12720SWyllys.Ingersoll@Sun.COM 		    buffer, sizeof (buffer));
503*12720SWyllys.Ingersoll@Sun.COM 		if (ptr == NULL) {
504*12720SWyllys.Ingersoll@Sun.COM 			goto end;
505*12720SWyllys.Ingersoll@Sun.COM 		}
506*12720SWyllys.Ingersoll@Sun.COM 		add_label_node(&sp->objlabel_tree, buffer);
507*12720SWyllys.Ingersoll@Sun.COM 		remain = buflen - (ptr - cfgbuf);
508*12720SWyllys.Ingersoll@Sun.COM 	}
509*12720SWyllys.Ingersoll@Sun.COM end:
510*12720SWyllys.Ingersoll@Sun.COM 	if (cfgbuf)
511*12720SWyllys.Ingersoll@Sun.COM 		free(cfgbuf);
512*12720SWyllys.Ingersoll@Sun.COM 
513*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
514*12720SWyllys.Ingersoll@Sun.COM }
515*12720SWyllys.Ingersoll@Sun.COM 
516*12720SWyllys.Ingersoll@Sun.COM static CK_RV
kms_get_object_label(kms_object_t * obj,char * label,int len)517*12720SWyllys.Ingersoll@Sun.COM kms_get_object_label(kms_object_t *obj, char *label, int len)
518*12720SWyllys.Ingersoll@Sun.COM {
519*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
520*12720SWyllys.Ingersoll@Sun.COM 	CK_ATTRIBUTE stLabel;
521*12720SWyllys.Ingersoll@Sun.COM 
522*12720SWyllys.Ingersoll@Sun.COM 	bzero(label, len);
523*12720SWyllys.Ingersoll@Sun.COM 
524*12720SWyllys.Ingersoll@Sun.COM 	stLabel.type = CKA_LABEL;
525*12720SWyllys.Ingersoll@Sun.COM 	stLabel.pValue = label;
526*12720SWyllys.Ingersoll@Sun.COM 	stLabel.ulValueLen = len;
527*12720SWyllys.Ingersoll@Sun.COM 
528*12720SWyllys.Ingersoll@Sun.COM 	/*
529*12720SWyllys.Ingersoll@Sun.COM 	 * The caller MUST provide a CKA_LABEL when deleting.
530*12720SWyllys.Ingersoll@Sun.COM 	 */
531*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_get_attribute(obj, &stLabel);
532*12720SWyllys.Ingersoll@Sun.COM 
533*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
534*12720SWyllys.Ingersoll@Sun.COM }
535*12720SWyllys.Ingersoll@Sun.COM 
536*12720SWyllys.Ingersoll@Sun.COM /*
537*12720SWyllys.Ingersoll@Sun.COM  * Retrieve a data unit associated with the label.
538*12720SWyllys.Ingersoll@Sun.COM  */
539*12720SWyllys.Ingersoll@Sun.COM static CK_RV
kms_get_data_unit(kms_session_t * session,char * label,KMSAgent_DataUnit * pDataUnit)540*12720SWyllys.Ingersoll@Sun.COM kms_get_data_unit(kms_session_t *session, char *label,
541*12720SWyllys.Ingersoll@Sun.COM     KMSAgent_DataUnit *pDataUnit)
542*12720SWyllys.Ingersoll@Sun.COM {
543*12720SWyllys.Ingersoll@Sun.COM 	KMS_AGENT_STATUS status;
544*12720SWyllys.Ingersoll@Sun.COM 	const utf8cstr pDescription = KMS_DATAUNIT_DESCRIPTION;
545*12720SWyllys.Ingersoll@Sun.COM 	uchar_t	externalUniqueId[SHA256_DIGEST_LENGTH];
546*12720SWyllys.Ingersoll@Sun.COM 
547*12720SWyllys.Ingersoll@Sun.COM 	/* Find the data unit that holds the key */
548*12720SWyllys.Ingersoll@Sun.COM 	kms_hash_string(label, externalUniqueId);
549*12720SWyllys.Ingersoll@Sun.COM 
550*12720SWyllys.Ingersoll@Sun.COM 	status = KMSAgent_RetrieveDataUnitByExternalUniqueID(
551*12720SWyllys.Ingersoll@Sun.COM 	    &session->kmsProfile,
552*12720SWyllys.Ingersoll@Sun.COM 	    (const unsigned char *)externalUniqueId,
553*12720SWyllys.Ingersoll@Sun.COM 	    sizeof (externalUniqueId),
554*12720SWyllys.Ingersoll@Sun.COM 	    label,
555*12720SWyllys.Ingersoll@Sun.COM 	    pDescription,
556*12720SWyllys.Ingersoll@Sun.COM 	    pDataUnit);
557*12720SWyllys.Ingersoll@Sun.COM 
558*12720SWyllys.Ingersoll@Sun.COM 	if (status != KMS_AGENT_STATUS_OK) {
559*12720SWyllys.Ingersoll@Sun.COM 		return (GetPKCS11StatusFromAgentStatus(status));
560*12720SWyllys.Ingersoll@Sun.COM 	}
561*12720SWyllys.Ingersoll@Sun.COM 
562*12720SWyllys.Ingersoll@Sun.COM 	return (CKR_OK);
563*12720SWyllys.Ingersoll@Sun.COM }
564*12720SWyllys.Ingersoll@Sun.COM 
565*12720SWyllys.Ingersoll@Sun.COM static CK_RV
kms_decode_description(char * description,kms_object_t * pKey)566*12720SWyllys.Ingersoll@Sun.COM kms_decode_description(char *description, kms_object_t *pKey)
567*12720SWyllys.Ingersoll@Sun.COM {
568*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
569*12720SWyllys.Ingersoll@Sun.COM 	char *ptr;
570*12720SWyllys.Ingersoll@Sun.COM 	uint32_t keylen;
571*12720SWyllys.Ingersoll@Sun.COM 	u_longlong_t boolattrs;
572*12720SWyllys.Ingersoll@Sun.COM 
573*12720SWyllys.Ingersoll@Sun.COM 	/* If it doesn't start with the expected prefix, return */
574*12720SWyllys.Ingersoll@Sun.COM 	if (strncmp(description, KMS_ATTR_DESC_PFX,
575*12720SWyllys.Ingersoll@Sun.COM 	    strlen(KMS_ATTR_DESC_PFX)))
576*12720SWyllys.Ingersoll@Sun.COM 		return (rv);
577*12720SWyllys.Ingersoll@Sun.COM 
578*12720SWyllys.Ingersoll@Sun.COM 	ptr = description + strlen(KMS_ATTR_DESC_PFX);
579*12720SWyllys.Ingersoll@Sun.COM 
580*12720SWyllys.Ingersoll@Sun.COM 	/*
581*12720SWyllys.Ingersoll@Sun.COM 	 * Decode as follows:
582*12720SWyllys.Ingersoll@Sun.COM 	 * CK_OBJECT_CLASS (2 bytes)
583*12720SWyllys.Ingersoll@Sun.COM 	 * CK_KEY_TYPE (2 bytes)
584*12720SWyllys.Ingersoll@Sun.COM 	 * CKA_VALUE_LEN (4 bytes)
585*12720SWyllys.Ingersoll@Sun.COM 	 * CK_CERTIFICATE_TYPE (2 bytes - not used)
586*12720SWyllys.Ingersoll@Sun.COM 	 * CK_MECHANISM_TYPE (4 bytes)
587*12720SWyllys.Ingersoll@Sun.COM 	 * boolean attributes (3 bytes)
588*12720SWyllys.Ingersoll@Sun.COM 	 * extra attributes (1 byte)
589*12720SWyllys.Ingersoll@Sun.COM 	 * non-boolean attributes
590*12720SWyllys.Ingersoll@Sun.COM 	 */
591*12720SWyllys.Ingersoll@Sun.COM 	if (sscanf(ptr,
592*12720SWyllys.Ingersoll@Sun.COM 	    "%02lx%02lx%02x00%04lx%06llx00",
593*12720SWyllys.Ingersoll@Sun.COM 	    &pKey->class,
594*12720SWyllys.Ingersoll@Sun.COM 	    &pKey->key_type,
595*12720SWyllys.Ingersoll@Sun.COM 	    &keylen,
596*12720SWyllys.Ingersoll@Sun.COM 	    &pKey->mechanism,
597*12720SWyllys.Ingersoll@Sun.COM 	    &boolattrs) != 5)
598*12720SWyllys.Ingersoll@Sun.COM 		/* We didn't get the full set of attributes */
599*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_ATTRIBUTE_TYPE_INVALID;
600*12720SWyllys.Ingersoll@Sun.COM 	pKey->bool_attr_mask = boolattrs;
601*12720SWyllys.Ingersoll@Sun.COM 
602*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
603*12720SWyllys.Ingersoll@Sun.COM }
604*12720SWyllys.Ingersoll@Sun.COM 
605*12720SWyllys.Ingersoll@Sun.COM /*
606*12720SWyllys.Ingersoll@Sun.COM  * Create a new PKCS#11 object record for the KMSAgent_Key.
607*12720SWyllys.Ingersoll@Sun.COM  */
608*12720SWyllys.Ingersoll@Sun.COM static CK_RV
kms_new_key_object(char * label,KMSAgent_DataUnit * dataUnit,KMSAgent_Key * pKey,kms_object_t ** pObj)609*12720SWyllys.Ingersoll@Sun.COM kms_new_key_object(
610*12720SWyllys.Ingersoll@Sun.COM 	char *label,
611*12720SWyllys.Ingersoll@Sun.COM 	KMSAgent_DataUnit *dataUnit,
612*12720SWyllys.Ingersoll@Sun.COM 	KMSAgent_Key *pKey,
613*12720SWyllys.Ingersoll@Sun.COM 	kms_object_t **pObj)
614*12720SWyllys.Ingersoll@Sun.COM {
615*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
616*12720SWyllys.Ingersoll@Sun.COM 	CK_BBOOL bTrue = B_TRUE;
617*12720SWyllys.Ingersoll@Sun.COM 	CK_KEY_TYPE keytype = CKK_AES;
618*12720SWyllys.Ingersoll@Sun.COM 	CK_OBJECT_CLASS class = CKO_SECRET_KEY;
619*12720SWyllys.Ingersoll@Sun.COM 	CK_ULONG	keylen;
620*12720SWyllys.Ingersoll@Sun.COM 	kms_object_t *newObj;
621*12720SWyllys.Ingersoll@Sun.COM 
622*12720SWyllys.Ingersoll@Sun.COM 	CK_ATTRIBUTE template[] = {
623*12720SWyllys.Ingersoll@Sun.COM 		{CKA_TOKEN, NULL, sizeof (bTrue)},
624*12720SWyllys.Ingersoll@Sun.COM 		{CKA_LABEL, NULL, 0},
625*12720SWyllys.Ingersoll@Sun.COM 		{CKA_KEY_TYPE, NULL, sizeof (keytype)},
626*12720SWyllys.Ingersoll@Sun.COM 		{CKA_CLASS, NULL, sizeof (class)},
627*12720SWyllys.Ingersoll@Sun.COM 		{CKA_VALUE, NULL, NULL},
628*12720SWyllys.Ingersoll@Sun.COM 		{CKA_VALUE_LEN, NULL, NULL},
629*12720SWyllys.Ingersoll@Sun.COM 		{CKA_PRIVATE, NULL, sizeof (bTrue)},
630*12720SWyllys.Ingersoll@Sun.COM 	};
631*12720SWyllys.Ingersoll@Sun.COM 
632*12720SWyllys.Ingersoll@Sun.COM 	keylen = (CK_ULONG)pKey->m_iKeyLength;
633*12720SWyllys.Ingersoll@Sun.COM 
634*12720SWyllys.Ingersoll@Sun.COM 	template[0].pValue = &bTrue;
635*12720SWyllys.Ingersoll@Sun.COM 	template[1].pValue = label;
636*12720SWyllys.Ingersoll@Sun.COM 	template[1].ulValueLen = strlen(label);
637*12720SWyllys.Ingersoll@Sun.COM 	template[2].pValue = &keytype;
638*12720SWyllys.Ingersoll@Sun.COM 	template[3].pValue = &class;
639*12720SWyllys.Ingersoll@Sun.COM 	template[4].pValue = pKey->m_acKey;
640*12720SWyllys.Ingersoll@Sun.COM 	template[4].ulValueLen = pKey->m_iKeyLength;
641*12720SWyllys.Ingersoll@Sun.COM 	template[5].pValue = &keylen;
642*12720SWyllys.Ingersoll@Sun.COM 	template[5].ulValueLen = sizeof (keylen);
643*12720SWyllys.Ingersoll@Sun.COM 	template[6].pValue = &bTrue;
644*12720SWyllys.Ingersoll@Sun.COM 
645*12720SWyllys.Ingersoll@Sun.COM 	newObj = kms_new_object();
646*12720SWyllys.Ingersoll@Sun.COM 	if (newObj == NULL)
647*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_HOST_MEMORY);
648*12720SWyllys.Ingersoll@Sun.COM 
649*12720SWyllys.Ingersoll@Sun.COM 	/*
650*12720SWyllys.Ingersoll@Sun.COM 	 * Decode the DataUnit description field to find various
651*12720SWyllys.Ingersoll@Sun.COM 	 * object attributes.
652*12720SWyllys.Ingersoll@Sun.COM 	 */
653*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_decode_description(dataUnit->m_acDescription, newObj);
654*12720SWyllys.Ingersoll@Sun.COM 	if (rv) {
655*12720SWyllys.Ingersoll@Sun.COM 		free(newObj);
656*12720SWyllys.Ingersoll@Sun.COM 		return (rv);
657*12720SWyllys.Ingersoll@Sun.COM 	}
658*12720SWyllys.Ingersoll@Sun.COM 	/*
659*12720SWyllys.Ingersoll@Sun.COM 	 * Set the template keytype and class according to the
660*12720SWyllys.Ingersoll@Sun.COM 	 * data parsed from the description.
661*12720SWyllys.Ingersoll@Sun.COM 	 */
662*12720SWyllys.Ingersoll@Sun.COM 	if (newObj->key_type)
663*12720SWyllys.Ingersoll@Sun.COM 		keytype = newObj->key_type;
664*12720SWyllys.Ingersoll@Sun.COM 	if (newObj->class)
665*12720SWyllys.Ingersoll@Sun.COM 		class = newObj->class;
666*12720SWyllys.Ingersoll@Sun.COM 
667*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_build_object(template, 7, newObj);
668*12720SWyllys.Ingersoll@Sun.COM 	if (rv) {
669*12720SWyllys.Ingersoll@Sun.COM 		free(newObj);
670*12720SWyllys.Ingersoll@Sun.COM 		return (rv);
671*12720SWyllys.Ingersoll@Sun.COM 	}
672*12720SWyllys.Ingersoll@Sun.COM 
673*12720SWyllys.Ingersoll@Sun.COM 	newObj->bool_attr_mask |= TOKEN_BOOL_ON;
674*12720SWyllys.Ingersoll@Sun.COM 
675*12720SWyllys.Ingersoll@Sun.COM 	*pObj = newObj;
676*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
677*12720SWyllys.Ingersoll@Sun.COM }
678*12720SWyllys.Ingersoll@Sun.COM 
679*12720SWyllys.Ingersoll@Sun.COM static CK_RV
kms_get_data_unit_keys(kms_session_t * sp,KMSAgent_DataUnit * dataUnit,KMSAgent_ArrayOfKeys ** keylist,int * numkeys)680*12720SWyllys.Ingersoll@Sun.COM kms_get_data_unit_keys(kms_session_t *sp, KMSAgent_DataUnit *dataUnit,
681*12720SWyllys.Ingersoll@Sun.COM 	KMSAgent_ArrayOfKeys **keylist, int *numkeys)
682*12720SWyllys.Ingersoll@Sun.COM {
683*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
684*12720SWyllys.Ingersoll@Sun.COM 	KMSAgent_ArrayOfKeys *kmskeys = NULL;
685*12720SWyllys.Ingersoll@Sun.COM 	KMS_AGENT_STATUS status;
686*12720SWyllys.Ingersoll@Sun.COM 	int keysLeft = 0;
687*12720SWyllys.Ingersoll@Sun.COM 
688*12720SWyllys.Ingersoll@Sun.COM 	status = KMSAgent_RetrieveDataUnitKeys(
689*12720SWyllys.Ingersoll@Sun.COM 	    &sp->kmsProfile, dataUnit,
690*12720SWyllys.Ingersoll@Sun.COM 	    KMS_MAX_PAGE_SIZE, 0,
691*12720SWyllys.Ingersoll@Sun.COM 	    (int * const)&keysLeft,
692*12720SWyllys.Ingersoll@Sun.COM 	    NULL, /* KeyID */
693*12720SWyllys.Ingersoll@Sun.COM 	    &kmskeys);
694*12720SWyllys.Ingersoll@Sun.COM 
695*12720SWyllys.Ingersoll@Sun.COM 	if (status != KMS_AGENT_STATUS_OK) {
696*12720SWyllys.Ingersoll@Sun.COM 		return (GetPKCS11StatusFromAgentStatus(status));
697*12720SWyllys.Ingersoll@Sun.COM 	}
698*12720SWyllys.Ingersoll@Sun.COM 
699*12720SWyllys.Ingersoll@Sun.COM 	if (keylist != NULL && kmskeys != NULL)
700*12720SWyllys.Ingersoll@Sun.COM 		*keylist = kmskeys;
701*12720SWyllys.Ingersoll@Sun.COM 
702*12720SWyllys.Ingersoll@Sun.COM 	if (numkeys != NULL && kmskeys != NULL)
703*12720SWyllys.Ingersoll@Sun.COM 		*numkeys = kmskeys->m_iSize;
704*12720SWyllys.Ingersoll@Sun.COM 
705*12720SWyllys.Ingersoll@Sun.COM 	if (keylist == NULL && kmskeys != NULL)
706*12720SWyllys.Ingersoll@Sun.COM 		KMSAgent_FreeArrayOfKeys(kmskeys);
707*12720SWyllys.Ingersoll@Sun.COM 
708*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
709*12720SWyllys.Ingersoll@Sun.COM }
710*12720SWyllys.Ingersoll@Sun.COM 
711*12720SWyllys.Ingersoll@Sun.COM 
712*12720SWyllys.Ingersoll@Sun.COM /*
713*12720SWyllys.Ingersoll@Sun.COM  * Retrieve a key from KMS.  We can't use "RetrieveKey" because
714*12720SWyllys.Ingersoll@Sun.COM  * we don't know the key id.  Instead get all keys associated
715*12720SWyllys.Ingersoll@Sun.COM  * with our data unit (there should be only 1.
716*12720SWyllys.Ingersoll@Sun.COM  */
717*12720SWyllys.Ingersoll@Sun.COM CK_RV
KMS_RetrieveKeyObj(kms_session_t * sp,char * label,kms_object_t ** pobj)718*12720SWyllys.Ingersoll@Sun.COM KMS_RetrieveKeyObj(kms_session_t *sp, char *label, kms_object_t **pobj)
719*12720SWyllys.Ingersoll@Sun.COM {
720*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
721*12720SWyllys.Ingersoll@Sun.COM 	KMSAgent_DataUnit dataUnit;
722*12720SWyllys.Ingersoll@Sun.COM 	KMSAgent_ArrayOfKeys *kmsKeys = NULL;
723*12720SWyllys.Ingersoll@Sun.COM 	KMSAgent_Key *pKey;
724*12720SWyllys.Ingersoll@Sun.COM 
725*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_get_data_unit(sp, label, &dataUnit);
726*12720SWyllys.Ingersoll@Sun.COM 	if (rv != CKR_OK)
727*12720SWyllys.Ingersoll@Sun.COM 		return (rv);
728*12720SWyllys.Ingersoll@Sun.COM 
729*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_get_data_unit_keys(sp, &dataUnit, &kmsKeys, NULL);
730*12720SWyllys.Ingersoll@Sun.COM 
731*12720SWyllys.Ingersoll@Sun.COM 	if (rv != CKR_OK || kmsKeys == NULL || kmsKeys->m_iSize == 0)
732*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_GENERAL_ERROR);
733*12720SWyllys.Ingersoll@Sun.COM 
734*12720SWyllys.Ingersoll@Sun.COM 	pKey = &kmsKeys->m_pKeys[0];
735*12720SWyllys.Ingersoll@Sun.COM 
736*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_new_key_object(label, &dataUnit, pKey, pobj);
737*12720SWyllys.Ingersoll@Sun.COM 
738*12720SWyllys.Ingersoll@Sun.COM 	KMSAgent_FreeArrayOfKeys(kmsKeys);
739*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
740*12720SWyllys.Ingersoll@Sun.COM }
741*12720SWyllys.Ingersoll@Sun.COM 
742*12720SWyllys.Ingersoll@Sun.COM CK_RV
KMS_RefreshObjectList(kms_session_t * sp,kms_slot_t * pslot)743*12720SWyllys.Ingersoll@Sun.COM KMS_RefreshObjectList(kms_session_t *sp, kms_slot_t *pslot)
744*12720SWyllys.Ingersoll@Sun.COM {
745*12720SWyllys.Ingersoll@Sun.COM 	kms_object_t *pObj;
746*12720SWyllys.Ingersoll@Sun.COM 	char label[BUFSIZ];
747*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv;
748*12720SWyllys.Ingersoll@Sun.COM 	objlabel_t  *node;
749*12720SWyllys.Ingersoll@Sun.COM 
750*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_reload_labels(sp);
751*12720SWyllys.Ingersoll@Sun.COM 	if (rv != CKR_OK)
752*12720SWyllys.Ingersoll@Sun.COM 		return (rv);
753*12720SWyllys.Ingersoll@Sun.COM 
754*12720SWyllys.Ingersoll@Sun.COM 	/*
755*12720SWyllys.Ingersoll@Sun.COM 	 * If an object is not in the list, reload it from KMS.
756*12720SWyllys.Ingersoll@Sun.COM 	 */
757*12720SWyllys.Ingersoll@Sun.COM 	node = avl_first(&sp->objlabel_tree);
758*12720SWyllys.Ingersoll@Sun.COM 	while (node != NULL) {
759*12720SWyllys.Ingersoll@Sun.COM 		boolean_t found = FALSE;
760*12720SWyllys.Ingersoll@Sun.COM 		/* Search object list for matching object */
761*12720SWyllys.Ingersoll@Sun.COM 		pObj = pslot->sl_tobj_list;
762*12720SWyllys.Ingersoll@Sun.COM 		while (pObj != NULL && !found) {
763*12720SWyllys.Ingersoll@Sun.COM 			(void) pthread_mutex_lock(&pObj->object_mutex);
764*12720SWyllys.Ingersoll@Sun.COM 			if ((rv = kms_get_object_label(pObj, label,
765*12720SWyllys.Ingersoll@Sun.COM 			    sizeof (label))) != CKR_OK) {
766*12720SWyllys.Ingersoll@Sun.COM 				(void) pthread_mutex_unlock(
767*12720SWyllys.Ingersoll@Sun.COM 				    &pObj->object_mutex);
768*12720SWyllys.Ingersoll@Sun.COM 				return (rv);
769*12720SWyllys.Ingersoll@Sun.COM 			}
770*12720SWyllys.Ingersoll@Sun.COM 			(void) pthread_mutex_unlock(&pObj->object_mutex);
771*12720SWyllys.Ingersoll@Sun.COM 			found = (strcmp(label, node->label) == 0);
772*12720SWyllys.Ingersoll@Sun.COM 			pObj = pObj->next;
773*12720SWyllys.Ingersoll@Sun.COM 		}
774*12720SWyllys.Ingersoll@Sun.COM 		if (!found) {
775*12720SWyllys.Ingersoll@Sun.COM 			/*
776*12720SWyllys.Ingersoll@Sun.COM 			 * Fetch KMS key and prepend it to the
777*12720SWyllys.Ingersoll@Sun.COM 			 * token object list for the slot.
778*12720SWyllys.Ingersoll@Sun.COM 			 */
779*12720SWyllys.Ingersoll@Sun.COM 			rv = KMS_RetrieveKeyObj(sp, node->label, &pObj);
780*12720SWyllys.Ingersoll@Sun.COM 			if (rv == CKR_OK) {
781*12720SWyllys.Ingersoll@Sun.COM 				if (pslot->sl_tobj_list == NULL) {
782*12720SWyllys.Ingersoll@Sun.COM 					pslot->sl_tobj_list = pObj;
783*12720SWyllys.Ingersoll@Sun.COM 					pObj->prev = NULL;
784*12720SWyllys.Ingersoll@Sun.COM 					pObj->next = NULL;
785*12720SWyllys.Ingersoll@Sun.COM 				} else {
786*12720SWyllys.Ingersoll@Sun.COM 					pObj->next = pslot->sl_tobj_list;
787*12720SWyllys.Ingersoll@Sun.COM 					pObj->prev = NULL;
788*12720SWyllys.Ingersoll@Sun.COM 					pslot->sl_tobj_list = pObj;
789*12720SWyllys.Ingersoll@Sun.COM 				}
790*12720SWyllys.Ingersoll@Sun.COM 			}
791*12720SWyllys.Ingersoll@Sun.COM 		}
792*12720SWyllys.Ingersoll@Sun.COM 		node = AVL_NEXT(&sp->objlabel_tree, node);
793*12720SWyllys.Ingersoll@Sun.COM 	}
794*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
795*12720SWyllys.Ingersoll@Sun.COM }
796*12720SWyllys.Ingersoll@Sun.COM 
797*12720SWyllys.Ingersoll@Sun.COM CK_RV
KMS_Initialize(void)798*12720SWyllys.Ingersoll@Sun.COM KMS_Initialize(void)
799*12720SWyllys.Ingersoll@Sun.COM {
800*12720SWyllys.Ingersoll@Sun.COM 	char *ksdir;
801*12720SWyllys.Ingersoll@Sun.COM 	struct stat fn_stat;
802*12720SWyllys.Ingersoll@Sun.COM 	KMS_AGENT_STATUS kmsrv;
803*12720SWyllys.Ingersoll@Sun.COM 
804*12720SWyllys.Ingersoll@Sun.COM 	ksdir = kms_get_keystore_path();
805*12720SWyllys.Ingersoll@Sun.COM 	if (ksdir == NULL)
806*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_GENERAL_ERROR);
807*12720SWyllys.Ingersoll@Sun.COM 
808*12720SWyllys.Ingersoll@Sun.COM 	/*
809*12720SWyllys.Ingersoll@Sun.COM 	 * If the keystore directory doesn't exist, create it.
810*12720SWyllys.Ingersoll@Sun.COM 	 */
811*12720SWyllys.Ingersoll@Sun.COM 	if ((stat(ksdir, &fn_stat) != 0) && (errno == ENOENT)) {
812*12720SWyllys.Ingersoll@Sun.COM 		if (mkdir(ksdir, S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
813*12720SWyllys.Ingersoll@Sun.COM 			if (errno != EEXIST)
814*12720SWyllys.Ingersoll@Sun.COM 				return (CKR_GENERAL_ERROR);
815*12720SWyllys.Ingersoll@Sun.COM 		}
816*12720SWyllys.Ingersoll@Sun.COM 	}
817*12720SWyllys.Ingersoll@Sun.COM 
818*12720SWyllys.Ingersoll@Sun.COM 	if ((kmsrv = KMSAgent_InitializeLibrary(ksdir, FALSE)) !=
819*12720SWyllys.Ingersoll@Sun.COM 	    KMS_AGENT_STATUS_OK) {
820*12720SWyllys.Ingersoll@Sun.COM 		return (GetPKCS11StatusFromAgentStatus(kmsrv));
821*12720SWyllys.Ingersoll@Sun.COM 	}
822*12720SWyllys.Ingersoll@Sun.COM 
823*12720SWyllys.Ingersoll@Sun.COM 	return (CKR_OK);
824*12720SWyllys.Ingersoll@Sun.COM }
825*12720SWyllys.Ingersoll@Sun.COM 
826*12720SWyllys.Ingersoll@Sun.COM CK_RV
KMS_Finalize()827*12720SWyllys.Ingersoll@Sun.COM KMS_Finalize()
828*12720SWyllys.Ingersoll@Sun.COM {
829*12720SWyllys.Ingersoll@Sun.COM 	last_objlist_mtime = 0;
830*12720SWyllys.Ingersoll@Sun.COM 
831*12720SWyllys.Ingersoll@Sun.COM 	return (KMSAgent_FinalizeLibrary() == KMS_AGENT_STATUS_OK) ?
832*12720SWyllys.Ingersoll@Sun.COM 	    CKR_OK : CKR_FUNCTION_FAILED;
833*12720SWyllys.Ingersoll@Sun.COM }
834*12720SWyllys.Ingersoll@Sun.COM 
835*12720SWyllys.Ingersoll@Sun.COM CK_RV
KMS_ChangeLocalPWD(kms_session_t * session,const char * pOldPassword,const char * pNewPassword)836*12720SWyllys.Ingersoll@Sun.COM KMS_ChangeLocalPWD(kms_session_t *session,
837*12720SWyllys.Ingersoll@Sun.COM 	const char *pOldPassword,
838*12720SWyllys.Ingersoll@Sun.COM 	const char *pNewPassword)
839*12720SWyllys.Ingersoll@Sun.COM {
840*12720SWyllys.Ingersoll@Sun.COM 	KMS_AGENT_STATUS status;
841*12720SWyllys.Ingersoll@Sun.COM 
842*12720SWyllys.Ingersoll@Sun.COM 	status = KMSAgent_ChangeLocalPWD(
843*12720SWyllys.Ingersoll@Sun.COM 	    &session->kmsProfile,
844*12720SWyllys.Ingersoll@Sun.COM 	    (char * const)pOldPassword,
845*12720SWyllys.Ingersoll@Sun.COM 	    (char * const)pNewPassword);
846*12720SWyllys.Ingersoll@Sun.COM 
847*12720SWyllys.Ingersoll@Sun.COM 	return (GetPKCS11StatusFromAgentStatus(status));
848*12720SWyllys.Ingersoll@Sun.COM }
849*12720SWyllys.Ingersoll@Sun.COM 
850*12720SWyllys.Ingersoll@Sun.COM CK_RV
KMS_GetConfigInfo(kms_cfg_info_t * cfginfo)851*12720SWyllys.Ingersoll@Sun.COM KMS_GetConfigInfo(kms_cfg_info_t *cfginfo)
852*12720SWyllys.Ingersoll@Sun.COM {
853*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
854*12720SWyllys.Ingersoll@Sun.COM 	char cfgfile_path[BUFSIZ];
855*12720SWyllys.Ingersoll@Sun.COM 	char *ksdir = kms_get_keystore_path();
856*12720SWyllys.Ingersoll@Sun.COM 
857*12720SWyllys.Ingersoll@Sun.COM 	if (ksdir == NULL)
858*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_GENERAL_ERROR);
859*12720SWyllys.Ingersoll@Sun.COM 
860*12720SWyllys.Ingersoll@Sun.COM 	(void) snprintf(cfgfile_path, sizeof (cfgfile_path),
861*12720SWyllys.Ingersoll@Sun.COM 	    "%s/%s", ksdir, KMSTOKEN_CONFIG_FILENAME);
862*12720SWyllys.Ingersoll@Sun.COM 
863*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_read_config_data(cfgfile_path, cfginfo);
864*12720SWyllys.Ingersoll@Sun.COM 
865*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
866*12720SWyllys.Ingersoll@Sun.COM }
867*12720SWyllys.Ingersoll@Sun.COM 
868*12720SWyllys.Ingersoll@Sun.COM CK_RV
KMS_LoadProfile(KMSClientProfile * profile,kms_cfg_info_t * kmscfg,const char * pPassword,size_t iPasswordLength)869*12720SWyllys.Ingersoll@Sun.COM KMS_LoadProfile(KMSClientProfile *profile,
870*12720SWyllys.Ingersoll@Sun.COM 	kms_cfg_info_t *kmscfg,
871*12720SWyllys.Ingersoll@Sun.COM 	const char *pPassword,
872*12720SWyllys.Ingersoll@Sun.COM 	size_t iPasswordLength)
873*12720SWyllys.Ingersoll@Sun.COM {
874*12720SWyllys.Ingersoll@Sun.COM 	KMS_AGENT_STATUS status;
875*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv;
876*12720SWyllys.Ingersoll@Sun.COM 	char *sPassword;
877*12720SWyllys.Ingersoll@Sun.COM 	char cfgfile_path[BUFSIZ];
878*12720SWyllys.Ingersoll@Sun.COM 	char *ksdir;
879*12720SWyllys.Ingersoll@Sun.COM 
880*12720SWyllys.Ingersoll@Sun.COM 	sPassword = calloc(1, iPasswordLength + 1);
881*12720SWyllys.Ingersoll@Sun.COM 	if (sPassword == NULL)
882*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_FUNCTION_FAILED);
883*12720SWyllys.Ingersoll@Sun.COM 
884*12720SWyllys.Ingersoll@Sun.COM 	(void) memcpy(sPassword, pPassword, iPasswordLength);
885*12720SWyllys.Ingersoll@Sun.COM 
886*12720SWyllys.Ingersoll@Sun.COM 	ksdir = kms_get_keystore_path();
887*12720SWyllys.Ingersoll@Sun.COM 	if (ksdir == NULL)
888*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_GENERAL_ERROR);
889*12720SWyllys.Ingersoll@Sun.COM 
890*12720SWyllys.Ingersoll@Sun.COM 	(void) snprintf(cfgfile_path, sizeof (cfgfile_path),
891*12720SWyllys.Ingersoll@Sun.COM 	    "%s/%s", ksdir, KMSTOKEN_CONFIG_FILENAME);
892*12720SWyllys.Ingersoll@Sun.COM 
893*12720SWyllys.Ingersoll@Sun.COM 	if ((rv = kms_read_config_data(cfgfile_path, kmscfg))) {
894*12720SWyllys.Ingersoll@Sun.COM 		free(sPassword);
895*12720SWyllys.Ingersoll@Sun.COM 		return (rv);
896*12720SWyllys.Ingersoll@Sun.COM 	}
897*12720SWyllys.Ingersoll@Sun.COM 
898*12720SWyllys.Ingersoll@Sun.COM 	/* First, try to load existing profile */
899*12720SWyllys.Ingersoll@Sun.COM 	status = KMSAgent_LoadProfile(
900*12720SWyllys.Ingersoll@Sun.COM 	    profile,
901*12720SWyllys.Ingersoll@Sun.COM 	    kmscfg->name,
902*12720SWyllys.Ingersoll@Sun.COM 	    kmscfg->agentId,
903*12720SWyllys.Ingersoll@Sun.COM 	    sPassword,
904*12720SWyllys.Ingersoll@Sun.COM 	    kmscfg->agentAddr,
905*12720SWyllys.Ingersoll@Sun.COM 	    kmscfg->transTimeout,
906*12720SWyllys.Ingersoll@Sun.COM 	    kmscfg->failoverLimit,
907*12720SWyllys.Ingersoll@Sun.COM 	    kmscfg->discoveryFreq,
908*12720SWyllys.Ingersoll@Sun.COM 	    kmscfg->securityMode);
909*12720SWyllys.Ingersoll@Sun.COM 
910*12720SWyllys.Ingersoll@Sun.COM 	free(sPassword);
911*12720SWyllys.Ingersoll@Sun.COM 	return (GetPKCS11StatusFromAgentStatus(status));
912*12720SWyllys.Ingersoll@Sun.COM }
913*12720SWyllys.Ingersoll@Sun.COM 
914*12720SWyllys.Ingersoll@Sun.COM static CK_RV
GetPKCS11StatusFromAgentStatus(KMS_AGENT_STATUS status)915*12720SWyllys.Ingersoll@Sun.COM GetPKCS11StatusFromAgentStatus(KMS_AGENT_STATUS status)
916*12720SWyllys.Ingersoll@Sun.COM {
917*12720SWyllys.Ingersoll@Sun.COM 	switch (status) {
918*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_OK:
919*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_OK);
920*12720SWyllys.Ingersoll@Sun.COM 
921*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_GENERIC_ERROR:
922*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_GENERAL_ERROR);
923*12720SWyllys.Ingersoll@Sun.COM 
924*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_NO_MEMORY:
925*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_HOST_MEMORY);
926*12720SWyllys.Ingersoll@Sun.COM 
927*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_INVALID_PARAMETER:
928*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_ARGUMENTS_BAD);
929*12720SWyllys.Ingersoll@Sun.COM 
930*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_PROFILE_NOT_LOADED:
931*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
932*12720SWyllys.Ingersoll@Sun.COM 
933*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_KMS_UNAVAILABLE:
934*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_KMS_NO_READY_KEYS:
935*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_DEVICE_MEMORY);
936*12720SWyllys.Ingersoll@Sun.COM 
937*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_NO_FIPS_KMAS_AVAILABLE:
938*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_GENERAL_ERROR);
939*12720SWyllys.Ingersoll@Sun.COM 
940*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_PROFILE_ALREADY_LOADED:
941*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_USER_ANOTHER_ALREADY_LOGGED_IN);
942*12720SWyllys.Ingersoll@Sun.COM 
943*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_FIPS_KAT_AES_KEYWRAP_ERROR:
944*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_FIPS_KAT_AES_ECB_ERROR:
945*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_FIPS_KAT_HMAC_SHA1_ERROR:
946*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_DEVICE_ERROR);
947*12720SWyllys.Ingersoll@Sun.COM 
948*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_ACCESS_DENIED:
949*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_LOCAL_AUTH_FAILURE:
950*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_PIN_INCORRECT);
951*12720SWyllys.Ingersoll@Sun.COM 
952*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_SERVER_BUSY:
953*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_EXTERNAL_UNIQUE_ID_EXISTS:
954*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_DATA_UNIT_ID_NOT_FOUND_EXTERNAL_ID_EXISTS:
955*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_KEY_DOES_NOT_EXIST:
956*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_KEY_DESTROYED:
957*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_AES_KEY_UNWRAP_ERROR:
958*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_AES_KEY_WRAP_SETUP_ERROR:
959*12720SWyllys.Ingersoll@Sun.COM 		case KMS_AGENT_STATUS_KEY_CALLOUT_FAILURE:
960*12720SWyllys.Ingersoll@Sun.COM 		default:
961*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_GENERAL_ERROR);
962*12720SWyllys.Ingersoll@Sun.COM 	}
963*12720SWyllys.Ingersoll@Sun.COM }
964*12720SWyllys.Ingersoll@Sun.COM 
965*12720SWyllys.Ingersoll@Sun.COM void
KMS_UnloadProfile(KMSClientProfile * kmsProfile)966*12720SWyllys.Ingersoll@Sun.COM KMS_UnloadProfile(KMSClientProfile *kmsProfile)
967*12720SWyllys.Ingersoll@Sun.COM {
968*12720SWyllys.Ingersoll@Sun.COM 	(void) KMSAgent_UnloadProfile(kmsProfile);
969*12720SWyllys.Ingersoll@Sun.COM }
970*12720SWyllys.Ingersoll@Sun.COM 
971*12720SWyllys.Ingersoll@Sun.COM /*
972*12720SWyllys.Ingersoll@Sun.COM  * kms_update_label_file
973*12720SWyllys.Ingersoll@Sun.COM  *
974*12720SWyllys.Ingersoll@Sun.COM  * KMS doesn't provide an API to allow one to query for available
975*12720SWyllys.Ingersoll@Sun.COM  * data units (which map 1-1 to keys).  To allow for PKCS11 to
976*12720SWyllys.Ingersoll@Sun.COM  * query for a list of available objects, we keep a local list
977*12720SWyllys.Ingersoll@Sun.COM  * and update it when an object is added or deleted.
978*12720SWyllys.Ingersoll@Sun.COM  */
979*12720SWyllys.Ingersoll@Sun.COM static CK_RV
kms_update_label_file(kms_session_t * sp)980*12720SWyllys.Ingersoll@Sun.COM kms_update_label_file(kms_session_t *sp)
981*12720SWyllys.Ingersoll@Sun.COM {
982*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
983*12720SWyllys.Ingersoll@Sun.COM 	objlabel_t *node;
984*12720SWyllys.Ingersoll@Sun.COM 	char *ksdir, *tmpfile, labelfile[BUFSIZ];
985*12720SWyllys.Ingersoll@Sun.COM 	FILE *fp;
986*12720SWyllys.Ingersoll@Sun.COM 	int fd;
987*12720SWyllys.Ingersoll@Sun.COM 	struct stat statp;
988*12720SWyllys.Ingersoll@Sun.COM 
989*12720SWyllys.Ingersoll@Sun.COM 	ksdir = kms_get_keystore_path();
990*12720SWyllys.Ingersoll@Sun.COM 	if (ksdir == NULL)
991*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_GENERAL_ERROR);
992*12720SWyllys.Ingersoll@Sun.COM 
993*12720SWyllys.Ingersoll@Sun.COM 	(void) snprintf(labelfile, sizeof (labelfile),
994*12720SWyllys.Ingersoll@Sun.COM 	    "%s/%s", ksdir, KMSTOKEN_LABELLIST_FILENAME);
995*12720SWyllys.Ingersoll@Sun.COM 
996*12720SWyllys.Ingersoll@Sun.COM 	tmpfile = tempnam(ksdir, "kmspk11");
997*12720SWyllys.Ingersoll@Sun.COM 	if (tmpfile == NULL)
998*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_HOST_MEMORY);
999*12720SWyllys.Ingersoll@Sun.COM 
1000*12720SWyllys.Ingersoll@Sun.COM 	fp = fopen(tmpfile, "w");
1001*12720SWyllys.Ingersoll@Sun.COM 	if (fp == NULL) {
1002*12720SWyllys.Ingersoll@Sun.COM 		free(tmpfile);
1003*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_GENERAL_ERROR);
1004*12720SWyllys.Ingersoll@Sun.COM 	}
1005*12720SWyllys.Ingersoll@Sun.COM 
1006*12720SWyllys.Ingersoll@Sun.COM 	/* Lock it even though its a temporary file */
1007*12720SWyllys.Ingersoll@Sun.COM 	fd = fileno(fp);
1008*12720SWyllys.Ingersoll@Sun.COM 	if ((rv = flock_fd(fd, F_WRLCK, &objlist_mutex))) {
1009*12720SWyllys.Ingersoll@Sun.COM 		(void) fclose(fp);
1010*12720SWyllys.Ingersoll@Sun.COM 		free(tmpfile);
1011*12720SWyllys.Ingersoll@Sun.COM 		return (rv);
1012*12720SWyllys.Ingersoll@Sun.COM 	}
1013*12720SWyllys.Ingersoll@Sun.COM 
1014*12720SWyllys.Ingersoll@Sun.COM 	node = avl_first(&sp->objlabel_tree);
1015*12720SWyllys.Ingersoll@Sun.COM 	while (node != NULL) {
1016*12720SWyllys.Ingersoll@Sun.COM 		if (node->label != NULL)
1017*12720SWyllys.Ingersoll@Sun.COM 			(void) fprintf(fp, "%s\n", node->label);
1018*12720SWyllys.Ingersoll@Sun.COM 		node = AVL_NEXT(&sp->objlabel_tree, node);
1019*12720SWyllys.Ingersoll@Sun.COM 	}
1020*12720SWyllys.Ingersoll@Sun.COM 
1021*12720SWyllys.Ingersoll@Sun.COM 	/* Update the last mtime */
1022*12720SWyllys.Ingersoll@Sun.COM 	if (fstat(fd, &statp) == 0) {
1023*12720SWyllys.Ingersoll@Sun.COM 		last_objlist_mtime = statp.st_mtime;
1024*12720SWyllys.Ingersoll@Sun.COM 	}
1025*12720SWyllys.Ingersoll@Sun.COM 
1026*12720SWyllys.Ingersoll@Sun.COM 	(void) flock_fd(fd, F_UNLCK, &objlist_mutex);
1027*12720SWyllys.Ingersoll@Sun.COM 	(void) fclose(fp);
1028*12720SWyllys.Ingersoll@Sun.COM 
1029*12720SWyllys.Ingersoll@Sun.COM 	(void) unlink(labelfile);
1030*12720SWyllys.Ingersoll@Sun.COM 	if (rename(tmpfile, labelfile))
1031*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_GENERAL_ERROR;
1032*12720SWyllys.Ingersoll@Sun.COM 
1033*12720SWyllys.Ingersoll@Sun.COM 	free(tmpfile);
1034*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
1035*12720SWyllys.Ingersoll@Sun.COM }
1036*12720SWyllys.Ingersoll@Sun.COM 
1037*12720SWyllys.Ingersoll@Sun.COM /*
1038*12720SWyllys.Ingersoll@Sun.COM  * Destroy a key in the KMS by disassociating an entire data unit.
1039*12720SWyllys.Ingersoll@Sun.COM  * The KMSAgent API does not have an interface for destroying an
1040*12720SWyllys.Ingersoll@Sun.COM  * individual key.
1041*12720SWyllys.Ingersoll@Sun.COM  */
1042*12720SWyllys.Ingersoll@Sun.COM CK_RV
KMS_DestroyKey(kms_session_t * session,kms_object_t * i_oKey)1043*12720SWyllys.Ingersoll@Sun.COM KMS_DestroyKey(kms_session_t *session, kms_object_t *i_oKey)
1044*12720SWyllys.Ingersoll@Sun.COM {
1045*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv;
1046*12720SWyllys.Ingersoll@Sun.COM 	KMSAgent_DataUnit oDataUnit;
1047*12720SWyllys.Ingersoll@Sun.COM 	KMS_AGENT_STATUS status;
1048*12720SWyllys.Ingersoll@Sun.COM 	char label[BUFSIZ];
1049*12720SWyllys.Ingersoll@Sun.COM 	objlabel_t  labelnode, *tnode;
1050*12720SWyllys.Ingersoll@Sun.COM 	avl_index_t	where = 0;
1051*12720SWyllys.Ingersoll@Sun.COM 
1052*12720SWyllys.Ingersoll@Sun.COM 	/*
1053*12720SWyllys.Ingersoll@Sun.COM 	 * The caller MUST provide a CKA_LABEL when deleting.
1054*12720SWyllys.Ingersoll@Sun.COM 	 */
1055*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&i_oKey->object_mutex);
1056*12720SWyllys.Ingersoll@Sun.COM 	if ((rv = kms_get_object_label(i_oKey, label, sizeof (label)))) {
1057*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&i_oKey->object_mutex);
1058*12720SWyllys.Ingersoll@Sun.COM 		return (rv);
1059*12720SWyllys.Ingersoll@Sun.COM 	}
1060*12720SWyllys.Ingersoll@Sun.COM 
1061*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_get_data_unit(session, label, &oDataUnit);
1062*12720SWyllys.Ingersoll@Sun.COM 	if (rv != CKR_OK)
1063*12720SWyllys.Ingersoll@Sun.COM 		return (rv);
1064*12720SWyllys.Ingersoll@Sun.COM 
1065*12720SWyllys.Ingersoll@Sun.COM 	status = KMSAgent_DisassociateDataUnitKeys(
1066*12720SWyllys.Ingersoll@Sun.COM 	    &session->kmsProfile, &oDataUnit);
1067*12720SWyllys.Ingersoll@Sun.COM 
1068*12720SWyllys.Ingersoll@Sun.COM 	/*
1069*12720SWyllys.Ingersoll@Sun.COM 	 * Remove the label from the label list and update
1070*12720SWyllys.Ingersoll@Sun.COM 	 * the file that tracks active keys.
1071*12720SWyllys.Ingersoll@Sun.COM 	 */
1072*12720SWyllys.Ingersoll@Sun.COM 	bzero(&labelnode, sizeof (labelnode));
1073*12720SWyllys.Ingersoll@Sun.COM 	labelnode.label = label;
1074*12720SWyllys.Ingersoll@Sun.COM 
1075*12720SWyllys.Ingersoll@Sun.COM 	if ((tnode = avl_find(&session->objlabel_tree,
1076*12720SWyllys.Ingersoll@Sun.COM 	    &labelnode, &where)) != NULL)
1077*12720SWyllys.Ingersoll@Sun.COM 		avl_remove(&session->objlabel_tree, tnode);
1078*12720SWyllys.Ingersoll@Sun.COM 
1079*12720SWyllys.Ingersoll@Sun.COM 	/* rewrite the list of labels to disk */
1080*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_update_label_file(session);
1081*12720SWyllys.Ingersoll@Sun.COM 	if (rv)
1082*12720SWyllys.Ingersoll@Sun.COM 		/* Ignore error here */
1083*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_OK;
1084*12720SWyllys.Ingersoll@Sun.COM 
1085*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&i_oKey->object_mutex);
1086*12720SWyllys.Ingersoll@Sun.COM 
1087*12720SWyllys.Ingersoll@Sun.COM 	return (GetPKCS11StatusFromAgentStatus(status));
1088*12720SWyllys.Ingersoll@Sun.COM }
1089*12720SWyllys.Ingersoll@Sun.COM 
1090*12720SWyllys.Ingersoll@Sun.COM void
kms_encode_attributes(kms_object_t * pKey,char * attrstr,int len)1091*12720SWyllys.Ingersoll@Sun.COM kms_encode_attributes(kms_object_t *pKey, char *attrstr, int len)
1092*12720SWyllys.Ingersoll@Sun.COM {
1093*12720SWyllys.Ingersoll@Sun.COM 	char *ptr;
1094*12720SWyllys.Ingersoll@Sun.COM 
1095*12720SWyllys.Ingersoll@Sun.COM 	bzero(attrstr, len);
1096*12720SWyllys.Ingersoll@Sun.COM 
1097*12720SWyllys.Ingersoll@Sun.COM 	(void) strlcpy(attrstr, KMS_ATTR_DESC_PFX, len);
1098*12720SWyllys.Ingersoll@Sun.COM 	ptr = attrstr + strlen(attrstr);
1099*12720SWyllys.Ingersoll@Sun.COM 
1100*12720SWyllys.Ingersoll@Sun.COM 	/*
1101*12720SWyllys.Ingersoll@Sun.COM 	 * Encode as follows:
1102*12720SWyllys.Ingersoll@Sun.COM 	 * CK_OBJECT_CLASS (2 bytes)
1103*12720SWyllys.Ingersoll@Sun.COM 	 * CK_KEY_TYPE (2 bytes)
1104*12720SWyllys.Ingersoll@Sun.COM 	 * CKA_VALUE_LEN (4 bytes)
1105*12720SWyllys.Ingersoll@Sun.COM 	 * CK_CERTIFICATE_TYPE (2 bytes - not used)
1106*12720SWyllys.Ingersoll@Sun.COM 	 * CK_MECHANISM_TYPE (4 bytes)
1107*12720SWyllys.Ingersoll@Sun.COM 	 * boolean attributes (3 bytes)
1108*12720SWyllys.Ingersoll@Sun.COM 	 * extra attributes (1 byte)
1109*12720SWyllys.Ingersoll@Sun.COM 	 * non-boolean attributes
1110*12720SWyllys.Ingersoll@Sun.COM 	 */
1111*12720SWyllys.Ingersoll@Sun.COM 	(void) snprintf(ptr, len - strlen(attrstr),
1112*12720SWyllys.Ingersoll@Sun.COM 	    "%02x%02x%02x00%04x%06x00",
1113*12720SWyllys.Ingersoll@Sun.COM 	    pKey->class,
1114*12720SWyllys.Ingersoll@Sun.COM 	    pKey->key_type,
1115*12720SWyllys.Ingersoll@Sun.COM 	    32,
1116*12720SWyllys.Ingersoll@Sun.COM 	    pKey->mechanism,
1117*12720SWyllys.Ingersoll@Sun.COM 	    (pKey->bool_attr_mask & 0x00FFFFFF));
1118*12720SWyllys.Ingersoll@Sun.COM }
1119*12720SWyllys.Ingersoll@Sun.COM 
1120*12720SWyllys.Ingersoll@Sun.COM CK_RV
KMS_GenerateKey(kms_session_t * session,kms_object_t * i_oKey)1121*12720SWyllys.Ingersoll@Sun.COM KMS_GenerateKey(kms_session_t *session, kms_object_t *i_oKey)
1122*12720SWyllys.Ingersoll@Sun.COM {
1123*12720SWyllys.Ingersoll@Sun.COM 	CK_RV			rv;
1124*12720SWyllys.Ingersoll@Sun.COM 	CK_ATTRIBUTE		stLabel;
1125*12720SWyllys.Ingersoll@Sun.COM 	KMSAgent_DataUnit	oDataUnit;
1126*12720SWyllys.Ingersoll@Sun.COM 	KMSAgent_Key		oKey;
1127*12720SWyllys.Ingersoll@Sun.COM 	KMS_AGENT_STATUS	status;
1128*12720SWyllys.Ingersoll@Sun.COM 	char			label[128];
1129*12720SWyllys.Ingersoll@Sun.COM 	uchar_t			externalUniqueId[SHA256_DIGEST_LENGTH];
1130*12720SWyllys.Ingersoll@Sun.COM 	char			pDescription[KMS_MAX_DESCRIPTION + 1];
1131*12720SWyllys.Ingersoll@Sun.COM 
1132*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&i_oKey->object_mutex);
1133*12720SWyllys.Ingersoll@Sun.COM 
1134*12720SWyllys.Ingersoll@Sun.COM 	stLabel.type = CKA_LABEL;
1135*12720SWyllys.Ingersoll@Sun.COM 	stLabel.pValue = label;
1136*12720SWyllys.Ingersoll@Sun.COM 	stLabel.ulValueLen = sizeof (label);
1137*12720SWyllys.Ingersoll@Sun.COM 
1138*12720SWyllys.Ingersoll@Sun.COM 	/*
1139*12720SWyllys.Ingersoll@Sun.COM 	 * The caller MUST provide a CKA_LABEL for storing in the KMS.
1140*12720SWyllys.Ingersoll@Sun.COM 	 */
1141*12720SWyllys.Ingersoll@Sun.COM 	if ((rv = kms_get_attribute(i_oKey, &stLabel)) != CKR_OK) {
1142*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&i_oKey->object_mutex);
1143*12720SWyllys.Ingersoll@Sun.COM 		return (rv);
1144*12720SWyllys.Ingersoll@Sun.COM 	}
1145*12720SWyllys.Ingersoll@Sun.COM 
1146*12720SWyllys.Ingersoll@Sun.COM 	label[stLabel.ulValueLen] = '\0';
1147*12720SWyllys.Ingersoll@Sun.COM 
1148*12720SWyllys.Ingersoll@Sun.COM 	kms_hash_string(label, externalUniqueId);
1149*12720SWyllys.Ingersoll@Sun.COM 
1150*12720SWyllys.Ingersoll@Sun.COM 	/* Encode attributes in Description */
1151*12720SWyllys.Ingersoll@Sun.COM 	kms_encode_attributes(i_oKey, pDescription,
1152*12720SWyllys.Ingersoll@Sun.COM 	    sizeof (pDescription));
1153*12720SWyllys.Ingersoll@Sun.COM 
1154*12720SWyllys.Ingersoll@Sun.COM 	status = KMSAgent_CreateDataUnit(
1155*12720SWyllys.Ingersoll@Sun.COM 	    &session->kmsProfile,
1156*12720SWyllys.Ingersoll@Sun.COM 	    (const unsigned char *)externalUniqueId,
1157*12720SWyllys.Ingersoll@Sun.COM 	    sizeof (externalUniqueId),
1158*12720SWyllys.Ingersoll@Sun.COM 	    label,	/* externalTag */
1159*12720SWyllys.Ingersoll@Sun.COM 	    pDescription,
1160*12720SWyllys.Ingersoll@Sun.COM 	    &oDataUnit);
1161*12720SWyllys.Ingersoll@Sun.COM 
1162*12720SWyllys.Ingersoll@Sun.COM 	/*
1163*12720SWyllys.Ingersoll@Sun.COM 	 * If the DataUnit exists, check to see if it has any keys.
1164*12720SWyllys.Ingersoll@Sun.COM 	 * If it has no keys, then it is OK to continue.
1165*12720SWyllys.Ingersoll@Sun.COM 	 */
1166*12720SWyllys.Ingersoll@Sun.COM 	if (status == KMS_AGENT_STATUS_EXTERNAL_UNIQUE_ID_EXISTS) {
1167*12720SWyllys.Ingersoll@Sun.COM 		int numkeys = 0;
1168*12720SWyllys.Ingersoll@Sun.COM 
1169*12720SWyllys.Ingersoll@Sun.COM 		rv = kms_get_data_unit(session, label, &oDataUnit);
1170*12720SWyllys.Ingersoll@Sun.COM 		if (rv != CKR_OK)
1171*12720SWyllys.Ingersoll@Sun.COM 			return (rv);
1172*12720SWyllys.Ingersoll@Sun.COM 
1173*12720SWyllys.Ingersoll@Sun.COM 		rv = kms_get_data_unit_keys(session,
1174*12720SWyllys.Ingersoll@Sun.COM 		    &oDataUnit, NULL, &numkeys);
1175*12720SWyllys.Ingersoll@Sun.COM 
1176*12720SWyllys.Ingersoll@Sun.COM 		if (rv !=  CKR_OK || numkeys > 0)
1177*12720SWyllys.Ingersoll@Sun.COM 			/*
1178*12720SWyllys.Ingersoll@Sun.COM 			 * This would be better if there were PKCS#11
1179*12720SWyllys.Ingersoll@Sun.COM 			 * error codes for duplicate objects or
1180*12720SWyllys.Ingersoll@Sun.COM 			 * something like that.
1181*12720SWyllys.Ingersoll@Sun.COM 			 */
1182*12720SWyllys.Ingersoll@Sun.COM 			return (CKR_ARGUMENTS_BAD);
1183*12720SWyllys.Ingersoll@Sun.COM 
1184*12720SWyllys.Ingersoll@Sun.COM 		/* If no keys associated with data unit, continue */
1185*12720SWyllys.Ingersoll@Sun.COM 		status = KMS_AGENT_STATUS_OK;
1186*12720SWyllys.Ingersoll@Sun.COM 	}
1187*12720SWyllys.Ingersoll@Sun.COM 
1188*12720SWyllys.Ingersoll@Sun.COM 	if (status != KMS_AGENT_STATUS_OK) {
1189*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&i_oKey->object_mutex);
1190*12720SWyllys.Ingersoll@Sun.COM 		return (GetPKCS11StatusFromAgentStatus(status));
1191*12720SWyllys.Ingersoll@Sun.COM 	}
1192*12720SWyllys.Ingersoll@Sun.COM 
1193*12720SWyllys.Ingersoll@Sun.COM 	status = KMSAgent_CreateKey(&session->kmsProfile,
1194*12720SWyllys.Ingersoll@Sun.COM 	    &oDataUnit, "", &oKey);
1195*12720SWyllys.Ingersoll@Sun.COM 
1196*12720SWyllys.Ingersoll@Sun.COM 	if (status != KMS_AGENT_STATUS_OK) {
1197*12720SWyllys.Ingersoll@Sun.COM 		/*
1198*12720SWyllys.Ingersoll@Sun.COM 		 * Clean up the old data unit.
1199*12720SWyllys.Ingersoll@Sun.COM 		 */
1200*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&i_oKey->object_mutex);
1201*12720SWyllys.Ingersoll@Sun.COM 		return (GetPKCS11StatusFromAgentStatus(status));
1202*12720SWyllys.Ingersoll@Sun.COM 	}
1203*12720SWyllys.Ingersoll@Sun.COM 
1204*12720SWyllys.Ingersoll@Sun.COM 	/*
1205*12720SWyllys.Ingersoll@Sun.COM 	 * KMS Agent only creates AES-256 keys, so ignore what the user
1206*12720SWyllys.Ingersoll@Sun.COM 	 * requested at this point.
1207*12720SWyllys.Ingersoll@Sun.COM 	 */
1208*12720SWyllys.Ingersoll@Sun.COM 	OBJ_SEC_VALUE(i_oKey) = malloc(oKey.m_iKeyLength);
1209*12720SWyllys.Ingersoll@Sun.COM 	if (OBJ_SEC_VALUE(i_oKey) == NULL) {
1210*12720SWyllys.Ingersoll@Sun.COM 		(void) pthread_mutex_unlock(&i_oKey->object_mutex);
1211*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_HOST_MEMORY);
1212*12720SWyllys.Ingersoll@Sun.COM 	}
1213*12720SWyllys.Ingersoll@Sun.COM 	(void) memcpy(OBJ_SEC_VALUE(i_oKey), oKey.m_acKey,
1214*12720SWyllys.Ingersoll@Sun.COM 	    oKey.m_iKeyLength);
1215*12720SWyllys.Ingersoll@Sun.COM 	OBJ_SEC_VALUE_LEN(i_oKey) = oKey.m_iKeyLength;
1216*12720SWyllys.Ingersoll@Sun.COM 
1217*12720SWyllys.Ingersoll@Sun.COM 	/*
1218*12720SWyllys.Ingersoll@Sun.COM 	 * Add the label to the local list of available objects
1219*12720SWyllys.Ingersoll@Sun.COM 	 */
1220*12720SWyllys.Ingersoll@Sun.COM 	add_label_node(&session->objlabel_tree, label);
1221*12720SWyllys.Ingersoll@Sun.COM 
1222*12720SWyllys.Ingersoll@Sun.COM 	rv = kms_update_label_file(session);
1223*12720SWyllys.Ingersoll@Sun.COM 
1224*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&i_oKey->object_mutex);
1225*12720SWyllys.Ingersoll@Sun.COM 
1226*12720SWyllys.Ingersoll@Sun.COM 	return (GetPKCS11StatusFromAgentStatus(status));
1227*12720SWyllys.Ingersoll@Sun.COM }
1228