kssladm_create.c revision 3408:67ca9373b99e
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <errno.h>
30#include <sys/sysmacros.h>
31#include <security/cryptoki.h>
32#include <security/pkcs11.h>
33#include <stdio.h>
34#include <strings.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <sys/socket.h>
38#include <netinet/in.h>
39#include <arpa/inet.h>
40#include <netdb.h>
41#include <fcntl.h>
42#include <inet/kssl/kssl.h>
43#include <cryptoutil.h>
44#include <libscf.h>
45#include "kssladm.h"
46
47#include <kmfapi.h>
48
49void
50usage_create(boolean_t do_print)
51{
52	if (do_print)
53		(void) fprintf(stderr, "Usage:\n");
54	(void) fprintf(stderr, "kssladm create"
55		" -f pkcs11 [-d softtoken_directory] -T <token_label>"
56		" -C <certificate_label> -x <proxy_port>"
57		" [-h <ca_certchain_file>]"
58		" [options] [<server_address>] [<server_port>]\n");
59
60	(void) fprintf(stderr, "kssladm create"
61		" -f pkcs12 -i <cert_and_key_pk12file> -x <proxy_port>"
62		" [options] [<server_address>] [<server_port>]\n");
63
64	(void) fprintf(stderr, "kssladm create"
65		" -f pem -i <cert_and_key_pemfile> -x <proxy_port>"
66		" [options] [<server_address>] [<server_port>]\n");
67
68	(void) fprintf(stderr, "options are:\n"
69		"\t[-c <ciphersuites>]\n"
70		"\t[-p <password_file>]\n"
71		"\t[-t <ssl_session_cache_timeout>]\n"
72		"\t[-z <ssl_session_cache_size>]\n"
73		"\t[-v]\n");
74}
75
76/*
77 * Everything is allocated in one single contiguous buffer.
78 * The layout is the following:
79 * . the kssl_params_t structure
80 * . optional buffer containing pin (if key is non extractable)
81 * . the array of key attribute structs, (value of ck_attrs)
82 * . the key attributes values (values of ck_attrs[i].ck_value);
83 * . the array of sizes of the certificates, (referred to as sc_sizes[])
84 * . the certificates values (referred to as sc_certs[])
85 *
86 * The address of the certs and key attributes values are offsets
87 * from the beginning of the big buffer. sc_sizes_offset points
88 * to sc_sizes[0] and sc_certs_offset points to sc_certs[0].
89 */
90static kssl_params_t *
91kmf_to_kssl(int nxkey, KMF_RAW_KEY_DATA *rsa, int ncerts,
92	KMF_DATA *certs, int *paramsize, char *token_label, KMF_DATA *idstr,
93	KMF_CREDENTIAL *creds)
94{
95	int i, tcsize;
96	kssl_params_t *kssl_params;
97	kssl_key_t *key;
98	char *buf;
99	uint32_t bufsize;
100	static CK_BBOOL true = TRUE;
101	static CK_BBOOL false = FALSE;
102	static CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
103	static CK_KEY_TYPE keytype = CKK_RSA;
104	kssl_object_attribute_t kssl_attrs[MAX_ATTR_CNT];
105	CK_ATTRIBUTE exkey_attrs[MAX_ATTR_CNT] = {
106		{CKA_TOKEN, &true, sizeof (true)},
107		{CKA_EXTRACTABLE, &false, sizeof (false)},
108		{CKA_CLASS,	&class, sizeof (class) },
109		{CKA_KEY_TYPE,	&keytype, sizeof (keytype) },
110		{CKA_ID,	NULL, 0}
111	};
112	kssl_object_attribute_t kssl_tmpl_attrs[MAX_ATTR_CNT] = {
113		{SUN_CKA_MODULUS, NULL, 0},
114		{SUN_CKA_PUBLIC_EXPONENT, NULL, 0},
115		{SUN_CKA_PRIVATE_EXPONENT, NULL, 0},
116		{SUN_CKA_PRIME_1, NULL, 0},
117		{SUN_CKA_PRIME_2, NULL, 0},
118		{SUN_CKA_EXPONENT_1, NULL, 0},
119		{SUN_CKA_EXPONENT_2, NULL, 0},
120		{SUN_CKA_COEFFICIENT, NULL, 0}
121	};
122	KMF_BIGINT priv_key_bignums[MAX_ATTR_CNT];
123	int attr_cnt;
124
125	if (nxkey && idstr != NULL) {
126		exkey_attrs[4].pValue = idstr->Data;
127		exkey_attrs[4].ulValueLen = idstr->Length;
128	}
129	tcsize = 0;
130	for (i = 0; i < ncerts; i++)
131		tcsize += certs[i].Length;
132
133	bufsize = sizeof (kssl_params_t);
134	bufsize += (tcsize + (MAX_CHAIN_LENGTH * sizeof (uint32_t)));
135
136	if (!nxkey) {
137		bzero(priv_key_bignums, sizeof (KMF_BIGINT) *
138			MAX_ATTR_CNT);
139		/* and the key attributes */
140		priv_key_bignums[0] = rsa->rawdata.rsa.mod;
141		priv_key_bignums[1] = rsa->rawdata.rsa.pubexp;
142		priv_key_bignums[2] = rsa->rawdata.rsa.priexp;
143		priv_key_bignums[3] = rsa->rawdata.rsa.prime1;
144		priv_key_bignums[4] = rsa->rawdata.rsa.prime2;
145		priv_key_bignums[5] = rsa->rawdata.rsa.exp1;
146		priv_key_bignums[6] = rsa->rawdata.rsa.exp2;
147		priv_key_bignums[7] = rsa->rawdata.rsa.coef;
148
149		if (rsa->rawdata.rsa.mod.val == NULL ||
150			rsa->rawdata.rsa.priexp.val == NULL) {
151			(void) fprintf(stderr,
152			    "missing required attributes in private key.\n");
153			return (NULL);
154		}
155
156		attr_cnt = 0;
157		for (i = 0; i < MAX_ATTR_CNT; i++) {
158			if (priv_key_bignums[i].val == NULL)
159				continue;
160			kssl_attrs[attr_cnt].ka_type =
161				kssl_tmpl_attrs[i].ka_type;
162			kssl_attrs[attr_cnt].ka_value_len =
163				priv_key_bignums[i].len;
164			bufsize += sizeof (crypto_object_attribute_t) +
165			    kssl_attrs[attr_cnt].ka_value_len;
166			attr_cnt++;
167		}
168	} else {
169		/*
170		 * Compute space for the attributes and values that the
171		 * kssl kernel module will need in order to search for
172		 * the private key.
173		 */
174		for (attr_cnt = 0; attr_cnt < 5; attr_cnt++) {
175			bufsize += sizeof (crypto_object_attribute_t) +
176				exkey_attrs[attr_cnt].ulValueLen;
177		}
178		if (creds)
179			bufsize += creds->credlen;
180	}
181
182	/* Add 4-byte cushion as sc_sizes[0] needs 32-bit alignment */
183	bufsize += sizeof (uint32_t);
184
185	/* Now the big memory allocation */
186	if ((buf = calloc(bufsize, 1)) == NULL) {
187		(void) fprintf(stderr,
188		    "Cannot allocate memory for the kssl_params "
189		    "and values\n");
190		return (NULL);
191	}
192
193	/* LINTED */
194	kssl_params = (kssl_params_t *)buf;
195
196	buf = (char *)(kssl_params + 1);
197
198	if (!nxkey) {
199		/* the keys attributes structs array */
200		key = &kssl_params->kssl_privkey;
201		key->ks_format = CRYPTO_KEY_ATTR_LIST;
202		key->ks_count = attr_cnt;
203		key->ks_attrs_offset = buf - (char *)kssl_params;
204		buf += attr_cnt * sizeof (kssl_object_attribute_t);
205
206		attr_cnt = 0;
207		/* then the key attributes values */
208		for (i = 0; i < MAX_ATTR_CNT; i++) {
209			if (priv_key_bignums[i].val == NULL)
210				continue;
211			(void) memcpy(buf, priv_key_bignums[i].val,
212				priv_key_bignums[i].len);
213			kssl_attrs[attr_cnt].ka_value_offset =
214			    buf - (char *)kssl_params;
215			buf += kssl_attrs[attr_cnt].ka_value_len;
216			attr_cnt++;
217		}
218	} else {
219		char tlabel[CRYPTO_EXT_SIZE_LABEL];
220		bzero(tlabel, sizeof (tlabel));
221		(void) strlcpy(tlabel, token_label, sizeof (tlabel));
222
223		/*
224		 * For a non-extractable key, we must provide the PIN
225		 * so the kssl module can access the token to find
226		 * the key handle.
227		 */
228		kssl_params->kssl_is_nxkey = 1;
229		bcopy(tlabel, kssl_params->kssl_token.toklabel,
230			CRYPTO_EXT_SIZE_LABEL);
231		kssl_params->kssl_token.pinlen = creds->credlen;
232		kssl_params->kssl_token.tokpin_offset =
233			buf - (char *)kssl_params;
234		kssl_params->kssl_token.ck_rv = 0;
235		bcopy(creds->cred, buf, creds->credlen);
236		buf += creds->credlen;
237
238		/*
239		 * Next in the buffer, we must provide the attributes
240		 * that the kssl module will use to search in the
241		 * token to find the protected key handle.
242		 */
243		key = &kssl_params->kssl_privkey;
244		key->ks_format = CRYPTO_KEY_ATTR_LIST;
245		key->ks_count = attr_cnt;
246		key->ks_attrs_offset = buf - (char *)kssl_params;
247
248		buf += attr_cnt * sizeof (kssl_object_attribute_t);
249		for (i = 0; i < attr_cnt; i++) {
250			bcopy(exkey_attrs[i].pValue, buf,
251				exkey_attrs[i].ulValueLen);
252
253			kssl_attrs[i].ka_type = exkey_attrs[i].type;
254			kssl_attrs[i].ka_value_offset =
255				buf - (char *)kssl_params;
256			kssl_attrs[i].ka_value_len = exkey_attrs[i].ulValueLen;
257
258			buf += exkey_attrs[i].ulValueLen;
259		}
260	}
261	/* Copy the key attributes array here */
262	bcopy(kssl_attrs, ((char *)kssl_params) + key->ks_attrs_offset,
263		attr_cnt * sizeof (kssl_object_attribute_t));
264
265	buf = (char *)P2ROUNDUP((uintptr_t)buf, sizeof (uint32_t));
266
267	/*
268	 * Finally, add the certificate chain to the buffer.
269	 */
270	kssl_params->kssl_certs.sc_count = ncerts;
271
272	/* First, an array of certificate sizes */
273	for (i = 0; i < ncerts; i++) {
274		uint32_t certsz = (uint32_t)certs[i].Length;
275		char *p = buf + (i * sizeof (uint32_t));
276		bcopy(&certsz, p, sizeof (uint32_t));
277	}
278
279	kssl_params->kssl_certs.sc_sizes_offset = buf - (char *)kssl_params;
280	buf += MAX_CHAIN_LENGTH * sizeof (uint32_t);
281
282	kssl_params->kssl_certs.sc_certs_offset = buf - (char *)kssl_params;
283
284	/* Now add the certificate data (ASN.1 DER encoded) */
285	for (i = 0; i < ncerts; i++) {
286		bcopy(certs[i].Data, buf, certs[i].Length);
287		buf += certs[i].Length;
288	}
289
290	*paramsize = bufsize;
291	return (kssl_params);
292}
293
294/*
295 * Extract a sensitive key via wrap/unwrap operations.
296 *
297 * This function requires that we call PKCS#11 API directly since
298 * KMF does not yet support wrapping/unwrapping of keys.   By extracting
299 * a sensitive key in wrapped form, we then unwrap it into a session key
300 * object.  KMF is then used to find the session key and return it in
301 * KMF_RAW_KEY format which is then passed along to KSSL by the caller.
302 */
303static KMF_RETURN
304get_sensitive_key_data(KMF_HANDLE_T kmfh, KMF_FINDKEY_PARAMS *fkparams,
305	KMF_KEY_HANDLE *key, KMF_KEY_HANDLE *rawkey)
306{
307	KMF_RETURN rv = KMF_OK;
308	static CK_BYTE aes_param[16];
309	static CK_OBJECT_CLASS privkey_class = CKO_PRIVATE_KEY;
310	static CK_KEY_TYPE privkey_type = CKK_RSA;
311	static CK_BBOOL true = TRUE;
312	static CK_BBOOL false = FALSE;
313	char *err = NULL;
314	char wrapkey_label[BUFSIZ];
315	int fd;
316	uint32_t nkeys = 0;
317	CK_RV ckrv;
318	CK_SESSION_HANDLE pk11session;
319	CK_BYTE aes_key_val[16];
320
321	CK_MECHANISM aes_cbc_pad_mech = {CKM_AES_CBC_PAD, aes_param,
322		sizeof (aes_param)};
323	CK_OBJECT_HANDLE aes_key_obj = CK_INVALID_HANDLE;
324	CK_OBJECT_HANDLE sess_privkey_obj = CK_INVALID_HANDLE;
325	CK_BYTE *wrapped_privkey = NULL;
326	CK_ULONG wrapped_privkey_len = 0;
327
328	CK_ATTRIBUTE unwrap_tmpl[] = {
329		/* code below depends on the following attribute order */
330		{CKA_TOKEN, &false, sizeof (false)},
331		{CKA_CLASS, &privkey_class, sizeof (privkey_class)},
332		{CKA_KEY_TYPE, &privkey_type, sizeof (privkey_type)},
333		{CKA_SENSITIVE, &false, sizeof (false)},
334		{CKA_PRIVATE, &false, sizeof (false)},
335		{CKA_LABEL, NULL, 0}
336	};
337
338	/*
339	 * Create a wrap key with random data.
340	 */
341	fd = open("/dev/urandom", O_RDONLY);
342	if (fd == -1) {
343		perror("Error reading /dev/urandom");
344		return (KMF_ERR_INTERNAL);
345	}
346	if (read(fd, aes_key_val, sizeof (aes_key_val)) !=
347		sizeof (aes_key_val)) {
348		perror("Error reading from /dev/urandom");
349		(void) close(fd);
350		return (KMF_ERR_INTERNAL);
351	}
352	(void) close(fd);
353
354	pk11session = KMF_GetPK11Handle(kmfh);
355
356	/*
357	 * Login to create the wrap key stuff.
358	 */
359	ckrv = C_Login(pk11session, CKU_USER,
360		(CK_UTF8CHAR_PTR)fkparams->cred.cred,
361		fkparams->cred.credlen);
362	if (ckrv != CKR_OK && ckrv != CKR_USER_ALREADY_LOGGED_IN) {
363		(void) fprintf(stderr,
364			"Cannot login to the token. error = %s\n",
365			pkcs11_strerror(ckrv));
366		return (KMF_ERR_INTERNAL);
367	}
368
369	/*
370	 * Turn the random key into a PKCS#11 session object.
371	 */
372	ckrv = SUNW_C_KeyToObject(pk11session, CKM_AES_CBC_PAD, aes_key_val,
373		sizeof (aes_key_val), &aes_key_obj);
374	if (ckrv != CKR_OK) {
375		(void) fprintf(stderr,
376			"Cannot create wrapping key. error = %s\n",
377			pkcs11_strerror(ckrv));
378		return (KMF_ERR_INTERNAL);
379	}
380
381	/*
382	 * Find the original private key that we are going to wrap.
383	 */
384	rv = KMF_FindKey(kmfh, fkparams, key, &nkeys);
385	if (rv != KMF_OK) {
386		REPORT_KMF_ERROR(rv, "Error finding private key", err);
387		goto out;
388	}
389
390	/*
391	 * Get the size of the wrapped private key.
392	 */
393	bzero(aes_param, sizeof (aes_param));
394	ckrv = C_WrapKey(pk11session, &aes_cbc_pad_mech,
395		aes_key_obj, (CK_OBJECT_HANDLE)key->keyp,
396		NULL, &wrapped_privkey_len);
397	if (ckrv != CKR_OK) {
398		/*
399		 * Most common error here is that the token doesn't
400		 * support the wrapping mechanism or the key is
401		 * marked non-extractable.  Return an error and let
402		 * the caller deal with it gracefully.
403		 */
404		(void) fprintf(stderr,
405			"Cannot get wrap key size. error = %s\n",
406			pkcs11_strerror(ckrv));
407		rv = KMF_ERR_INTERNAL;
408		goto out;
409	}
410	wrapped_privkey = malloc(wrapped_privkey_len);
411	if (wrapped_privkey == NULL) {
412		rv = KMF_ERR_MEMORY;
413		goto out;
414	}
415	/*
416	 * Now get the actual wrapped key data.
417	 */
418	ckrv = C_WrapKey(pk11session, &aes_cbc_pad_mech,
419		aes_key_obj, (CK_OBJECT_HANDLE)key->keyp,
420		wrapped_privkey, &wrapped_privkey_len);
421	if (ckrv != CKR_OK) {
422		(void) fprintf(stderr,
423			"Cannot wrap private key. error = %s\n",
424			pkcs11_strerror(ckrv));
425		rv = KMF_ERR_INTERNAL;
426		goto out;
427	}
428	/*
429	 * Create a label for the wrapped session key so we can find
430	 * it easier later.
431	 */
432	snprintf(wrapkey_label, sizeof (wrapkey_label), "ksslprikey_%d",
433		getpid());
434
435	unwrap_tmpl[5].pValue = wrapkey_label;
436	unwrap_tmpl[5].ulValueLen = strlen(wrapkey_label);
437
438	/*
439	 * Unwrap the key into the template and create a temporary
440	 * session private key.
441	 */
442	ckrv = C_UnwrapKey(pk11session, &aes_cbc_pad_mech, aes_key_obj,
443		wrapped_privkey, wrapped_privkey_len,
444		unwrap_tmpl, 6, &sess_privkey_obj);
445	if (ckrv != CKR_OK) {
446		(void) fprintf(stderr,
447			"Cannot unwrap private key. error = %s\n",
448			pkcs11_strerror(ckrv));
449		rv = KMF_ERR_INTERNAL;
450		goto out;
451	}
452
453	/*
454	 * Use KMF to find the session key and return it as RAW data
455	 * so we can pass it along to KSSL.
456	 */
457	fkparams->kstype = KMF_KEYSTORE_PK11TOKEN;
458	fkparams->keyclass = KMF_ASYM_PRI;
459	fkparams->format = KMF_FORMAT_RAWKEY;
460	fkparams->findLabel = wrapkey_label;
461	fkparams->pkcs11parms.sensitive = FALSE;
462	fkparams->pkcs11parms.private = FALSE;
463	fkparams->pkcs11parms.token = FALSE; /* <-- very important! */
464
465	rv = KMF_FindKey(kmfh, fkparams, rawkey, &nkeys);
466	if (rv != KMF_OK) {
467		REPORT_KMF_ERROR(rv, "Error finding raw private key", err);
468		goto out;
469	}
470out:
471	if (wrapped_privkey)
472		free(wrapped_privkey);
473
474	if (aes_key_obj != CK_INVALID_HANDLE)
475		C_DestroyObject(pk11session, aes_key_obj);
476
477	if (sess_privkey_obj != CK_INVALID_HANDLE)
478		C_DestroyObject(pk11session, sess_privkey_obj);
479
480	return (rv);
481}
482
483static kssl_params_t *
484load_from_pkcs11(const char *token_label, const char *password_file,
485    const char *certname, int *bufsize)
486{
487	KMF_RETURN rv;
488	KMF_HANDLE_T kmfh;
489	KMF_X509_DER_CERT cert;
490	KMF_KEY_HANDLE key, rawkey;
491	KMF_CREDENTIAL creds;
492	KMF_FINDCERT_PARAMS fcparams;
493	KMF_FINDKEY_PARAMS fkparams;
494	KMF_CONFIG_PARAMS cfgparams;
495	KMF_DATA iddata = { NULL, 0 };
496	kssl_params_t *kssl_params = NULL;
497	uint32_t ncerts, nkeys;
498	char *err, *idstr = NULL;
499	char password_buf[1024];
500	int nxkey = 0;
501
502	rv = KMF_Initialize(&kmfh, NULL, NULL);
503	if (rv != KMF_OK) {
504		REPORT_KMF_ERROR(rv, "Error initializing KMF", err);
505		return (0);
506	}
507	if (get_passphrase(password_file, password_buf,
508		sizeof (password_buf)) <= 0) {
509		perror("Unable to read passphrase");
510		goto done;
511	}
512	creds.cred = password_buf;
513	creds.credlen = strlen(password_buf);
514
515	bzero(&cfgparams, sizeof (cfgparams));
516	bzero(&fcparams, sizeof (fcparams));
517	bzero(&fkparams, sizeof (fkparams));
518
519	cfgparams.kstype = KMF_KEYSTORE_PK11TOKEN;
520	cfgparams.pkcs11config.label = (char *)token_label;
521	cfgparams.pkcs11config.readonly = B_FALSE;
522
523	rv = KMF_ConfigureKeystore(kmfh, &cfgparams);
524	if (rv != KMF_OK) {
525		REPORT_KMF_ERROR(rv, "Error configuring KMF keystore", err);
526		goto done;
527	}
528
529	/*
530	 * Find the certificate matching the given label.
531	 */
532	fcparams.kstype = KMF_KEYSTORE_PK11TOKEN;
533	fcparams.certLabel = (char *)certname;
534	rv = KMF_FindCert(kmfh, &fcparams, &cert, &ncerts);
535	if (rv != KMF_OK || ncerts == 0)
536		goto done;
537
538	/*
539	 * Find the associated private key for this cert by
540	 * keying off of the label and the ASCII ID string.
541	 */
542	rv = KMF_GetCertIDString(&cert.certificate, &idstr);
543	if (rv != KMF_OK)
544		goto done;
545
546	fkparams.kstype = KMF_KEYSTORE_PK11TOKEN;
547	fkparams.keyclass = KMF_ASYM_PRI;
548	fkparams.cred = creds;
549	fkparams.format = KMF_FORMAT_RAWKEY;
550	fkparams.findLabel = (char *)certname;
551	fkparams.idstr = idstr;
552	fkparams.pkcs11parms.private = TRUE;
553	fkparams.pkcs11parms.token = TRUE;
554
555	rv = KMF_FindKey(kmfh, &fkparams, &key, &nkeys);
556	if (rv == KMF_ERR_SENSITIVE_KEY) {
557		KMF_FreeKMFKey(kmfh, &key);
558		/*
559		 * Get a normal key handle and then do a wrap/unwrap
560		 * in order to get the necessary raw data fields needed
561		 * to send to KSSL.
562		 */
563		fkparams.format = KMF_FORMAT_NATIVE;
564		rv = get_sensitive_key_data(kmfh, &fkparams, &key, &rawkey);
565		if (rv == KMF_OK) {
566			/* Swap "key" for "rawkey" */
567			KMF_FreeKMFKey(kmfh, &key);
568
569			key = rawkey;
570		} else {
571			KMF_FreeKMFKey(kmfh, &key);
572
573			/* Let kssl try to find the key. */
574			nxkey = 1;
575			rv = KMF_GetCertIDData(&cert.certificate, &iddata);
576		}
577	} else if (rv == KMF_ERR_UNEXTRACTABLE_KEY) {
578			KMF_FreeKMFKey(kmfh, &key);
579
580			/* Let kssl try to find the key. */
581			nxkey = 1;
582			rv = KMF_GetCertIDData(&cert.certificate, &iddata);
583	} else if (rv != KMF_OK || nkeys == 0)
584		goto done;
585
586	if (rv == KMF_OK)
587		kssl_params = kmf_to_kssl(nxkey, (KMF_RAW_KEY_DATA *)key.keyp,
588			1, &cert.certificate, bufsize,
589			(char *)token_label, &iddata, &creds);
590done:
591	if (ncerts != 0)
592		KMF_FreeKMFCert(kmfh, &cert);
593	if (nkeys != 0)
594		KMF_FreeKMFKey(kmfh, &key);
595	if (idstr)
596		free(idstr);
597
598	if (kmfh != NULL)
599		(void) KMF_Finalize(kmfh);
600
601	return (kssl_params);
602}
603
604/*
605 * add_cacerts
606 *
607 * Load a chain of certificates from a PEM file.
608 */
609static kssl_params_t *
610add_cacerts(kssl_params_t *old_params, const char *cacert_chain_file)
611{
612	int i, newlen;
613	uint32_t certlen = 0, ncerts;
614	char *buf;
615	KMF_RETURN rv;
616	KMF_X509_DER_CERT *certs = NULL;
617	KMF_FINDCERT_PARAMS fcparms;
618	kssl_params_t *kssl_params;
619	KMF_HANDLE_T kmfh;
620	char *err = NULL;
621
622	bzero(&fcparms, sizeof (fcparms));
623	fcparms.kstype = KMF_KEYSTORE_OPENSSL;
624	fcparms.sslparms.certfile = (char *)cacert_chain_file;
625
626	rv = KMF_Initialize(&kmfh, NULL, NULL);
627	if (rv != KMF_OK) {
628		REPORT_KMF_ERROR(rv, "Error initializing KMF", err);
629		return (0);
630	}
631	rv = KMF_FindCert(kmfh, &fcparms, NULL, &ncerts);
632	if (rv != KMF_OK) {
633		REPORT_KMF_ERROR(rv, "Error finding CA certificates", err);
634		(void) KMF_Finalize(kmfh);
635		return (0);
636	}
637	certs = (KMF_X509_DER_CERT *)malloc(ncerts *
638		sizeof (KMF_X509_DER_CERT));
639	if (certs == NULL) {
640		(void) fprintf(stderr, "memory allocation error.\n");
641		(void) KMF_Finalize(kmfh);
642		return (NULL);
643	}
644	bzero(certs, ncerts * sizeof (KMF_X509_DER_CERT));
645	rv = KMF_FindCert(kmfh, &fcparms, certs, &ncerts);
646
647	(void) KMF_Finalize(kmfh);
648
649	if (rv != KMF_OK || ncerts == 0) {
650		bzero(old_params, old_params->kssl_params_size);
651		free(old_params);
652		return (NULL);
653	}
654
655	if (verbose) {
656		(void) printf("%d certificates read successfully\n", ncerts);
657	}
658
659	newlen = old_params->kssl_params_size;
660	for (i = 0; i < ncerts; i++)
661		newlen += certs[i].certificate.Length;
662
663	/*
664	 * Get a bigger structure and update the
665	 * fields to account for the additional certs.
666	 */
667	kssl_params = realloc(old_params, newlen);
668
669	kssl_params->kssl_params_size = newlen;
670	kssl_params->kssl_certs.sc_count += ncerts;
671
672	/* Put the cert size info starting from sc_sizes[1] */
673	buf = (char *)kssl_params;
674	buf += kssl_params->kssl_certs.sc_sizes_offset;
675	bcopy(buf, &certlen, sizeof (uint32_t));
676	buf += sizeof (uint32_t);
677	for (i = 0; i < ncerts; i++) {
678		uint32_t size = (uint32_t)certs[i].certificate.Length;
679		bcopy(&size, buf, sizeof (uint32_t));
680		buf += sizeof (uint32_t);
681	}
682
683	/* Put the cert_bufs starting from sc_certs[1] */
684	buf = (char *)kssl_params;
685	buf += kssl_params->kssl_certs.sc_certs_offset;
686	buf += certlen;
687
688	/* now the certs values */
689	for (i = 0; i < ncerts; i++) {
690		bcopy(certs[i].certificate.Data, buf,
691			certs[i].certificate.Length);
692		buf += certs[i].certificate.Length;
693	}
694
695	for (i = 0; i < ncerts; i++)
696		KMF_FreeKMFCert(kmfh, &certs[i]);
697	free(certs);
698
699	return (kssl_params);
700}
701
702/*
703 * Find a key and certificate(s) from a single PEM file.
704 */
705static kssl_params_t *
706load_from_pem(const char *filename, const char *password_file, int *paramsize)
707{
708	int ncerts = 0, i;
709	kssl_params_t *kssl_params;
710	KMF_RAW_KEY_DATA *rsa = NULL;
711	KMF_DATA *certs = NULL;
712
713	ncerts = PEM_get_rsa_key_certs(filename, (char *)password_file,
714		&rsa, &certs);
715	if (rsa == NULL || certs == NULL || ncerts == 0) {
716		return (NULL);
717	}
718
719	if (verbose)
720		(void) printf("%d certificates read successfully\n", ncerts);
721
722	kssl_params = kmf_to_kssl(0, rsa, ncerts, certs, paramsize, NULL,
723		NULL, NULL);
724
725	for (i = 0; i < ncerts; i++)
726		KMF_FreeData(&certs[i]);
727	free(certs);
728	KMF_FreeRawKey(rsa);
729
730	return (kssl_params);
731}
732
733/*
734 * Load a raw key and certificate(s) from a PKCS#12 file.
735 */
736static kssl_params_t *
737load_from_pkcs12(const char *filename, const char *password_file,
738    int *paramsize)
739{
740	KMF_RAW_KEY_DATA *rsa = NULL;
741	kssl_params_t *kssl_params;
742	KMF_DATA *certs = NULL;
743	int ncerts = 0, i;
744
745	ncerts = PKCS12_get_rsa_key_certs(filename,
746		password_file, &rsa, &certs);
747
748	if (certs == NULL || ncerts == 0) {
749		(void) fprintf(stderr,
750		    "Unable to read cert and/or key from %s\n", filename);
751		return (NULL);
752	}
753
754	if (verbose)
755		(void) printf("%d certificates read successfully\n", ncerts);
756
757	kssl_params = kmf_to_kssl(0, rsa, ncerts, certs, paramsize, NULL,
758		NULL, NULL);
759
760	for (i = 0; i < ncerts; i++)
761		KMF_FreeData(&certs[i]);
762	free(certs);
763
764	KMF_FreeRawKey(rsa);
765	return (kssl_params);
766}
767
768int
769parse_and_set_addr(char *server_address, char *server_port,
770    struct sockaddr_in *addr)
771{
772	if (server_port == NULL) {
773		return (-1);
774	}
775
776	if (server_address == NULL) {
777		addr->sin_addr.s_addr = INADDR_ANY;
778	} else {
779		addr->sin_addr.s_addr = inet_addr(server_address);
780		if ((int)addr->sin_addr.s_addr == -1) {
781			struct hostent *hp;
782
783			if ((hp = gethostbyname(server_address)) == NULL) {
784				(void) fprintf(stderr,
785				    "Error: Unknown host: %s\n",
786				    server_address);
787				return (-1);
788			}
789
790			(void) memcpy(&addr->sin_addr.s_addr,
791			    hp->h_addr_list[0],
792			    sizeof (addr->sin_addr.s_addr));
793		}
794	}
795
796	errno = 0;
797	addr->sin_port = strtol(server_port, NULL, 10);
798	if (addr->sin_port == 0 || errno != 0) {
799		(void) fprintf(stderr, "Error: Invalid Port value: %s\n",
800		    server_port);
801		return (-1);
802	}
803
804	return (0);
805}
806
807/*
808 * The order of the ciphers is important. It is used as the
809 * default order (when -c is not specified).
810 */
811struct csuite {
812	const char *suite;
813	uint16_t val;
814	boolean_t seen;
815} cipher_suites[CIPHER_SUITE_COUNT - 1] = {
816	{"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA, B_FALSE},
817	{"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5, B_FALSE},
818	{"rsa_3des_ede_cbc_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA, B_FALSE},
819	{"rsa_des_cbc_sha", SSL_RSA_WITH_DES_CBC_SHA, B_FALSE},
820};
821
822static int
823check_suites(char *suites, uint16_t *sarray)
824{
825	int i;
826	int err = 0;
827	char *suite;
828	int sindx = 0;
829
830	if (suites != NULL) {
831		for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++)
832			sarray[i] = CIPHER_NOTSET;
833	} else {
834		for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++)
835			sarray[i] = cipher_suites[i].val;
836		return (err);
837	}
838
839	suite = strtok(suites, ",");
840	do {
841		for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++) {
842			if (strcasecmp(suite, cipher_suites[i].suite) == 0) {
843				if (!cipher_suites[i].seen) {
844					sarray[sindx++] = cipher_suites[i].val;
845					cipher_suites[i].seen = B_TRUE;
846				}
847				break;
848			}
849		}
850
851		if (i == (CIPHER_SUITE_COUNT - 1)) {
852			(void) fprintf(stderr,
853			    "Unknown Cipher suite name: %s\n", suite);
854			err++;
855		}
856	} while ((suite = strtok(NULL, ",")) != NULL);
857
858	return (err);
859}
860
861int
862do_create(int argc, char *argv[])
863{
864	const char *softtoken_dir = NULL;
865	const char *token_label = NULL;
866	const char *password_file = NULL;
867	const char *cert_key_file = NULL;
868	const char *cacert_chain_file = NULL;
869	const char *certname = NULL;
870	char *suites = NULL;
871	uint32_t timeout = DEFAULT_SID_TIMEOUT;
872	uint32_t scache_size = DEFAULT_SID_CACHE_NENTRIES;
873	uint16_t kssl_suites[CIPHER_SUITE_COUNT - 1];
874	int proxy_port = -1;
875	struct sockaddr_in server_addr;
876	char *format = NULL;
877	char *port, *addr;
878	char c;
879	int pcnt;
880	kssl_params_t *kssl_params;
881	int bufsize;
882
883	argc -= 1;
884	argv += 1;
885
886	while ((c = getopt(argc, argv, "vT:d:f:h:i:p:c:C:t:x:z:")) != -1) {
887		switch (c) {
888		case 'd':
889			softtoken_dir = optarg;
890			break;
891		case 'c':
892			suites = optarg;
893			break;
894		case 'C':
895			certname = optarg;
896			break;
897		case 'f':
898			format = optarg;
899			break;
900		case 'h':
901			cacert_chain_file = optarg;
902			break;
903		case 'i':
904			cert_key_file = optarg;
905			break;
906		case 'T':
907			token_label = optarg;
908			break;
909		case 'p':
910			password_file = optarg;
911			break;
912		case 't':
913			timeout = atoi(optarg);
914			break;
915		case 'x':
916			proxy_port = atoi(optarg);
917			break;
918		case 'v':
919			verbose = B_TRUE;
920			break;
921		case 'z':
922			scache_size = atoi(optarg);
923			break;
924		default:
925			goto err;
926		}
927	}
928
929	pcnt = argc - optind;
930	if (pcnt == 0) {
931		port = "443";	/* default SSL port */
932		addr = NULL;
933	} else if (pcnt == 1) {
934		port = argv[optind];
935		addr = NULL;
936	} else if (pcnt == 2) {
937		addr = argv[optind];
938		port = argv[optind + 1];
939	} else {
940		goto err;
941	}
942
943	if (parse_and_set_addr(addr, port, &server_addr) < 0) {
944		goto err;
945	}
946
947	if (verbose) {
948		(void) printf("addr=%s, port = %d\n",
949		    inet_ntoa(server_addr.sin_addr), server_addr.sin_port);
950	}
951
952	if (format == NULL || proxy_port == -1) {
953		goto err;
954	}
955
956	if (check_suites(suites, kssl_suites) != 0) {
957		goto err;
958	}
959
960	if (strcmp(format, "pkcs11") == 0) {
961		if (token_label == NULL || certname == NULL) {
962			goto err;
963		}
964		if (softtoken_dir != NULL) {
965			(void) setenv("SOFTTOKEN_DIR", softtoken_dir, 1);
966			if (verbose) {
967				(void) printf(
968				    "SOFTTOKEN_DIR=%s\n",
969				    getenv("SOFTTOKEN_DIR"));
970			}
971		}
972		kssl_params = load_from_pkcs11(
973		    token_label, password_file, certname, &bufsize);
974	} else if (strcmp(format, "pkcs12") == 0) {
975		if (cert_key_file == NULL) {
976			goto err;
977		}
978		kssl_params = load_from_pkcs12(
979		    cert_key_file, password_file, &bufsize);
980	} else if (strcmp(format, "pem") == 0) {
981		if (cert_key_file == NULL) {
982			goto err;
983		}
984		kssl_params = load_from_pem(
985		    cert_key_file, password_file, &bufsize);
986	} else {
987		(void) fprintf(stderr, "Unsupported cert format: %s\n", format);
988		goto err;
989	}
990
991	if (kssl_params == NULL) {
992		return (FAILURE);
993	}
994
995	/*
996	 * Add the list of supported ciphers to the buffer.
997	 */
998	bcopy(kssl_suites, kssl_params->kssl_suites,
999	    sizeof (kssl_params->kssl_suites));
1000	kssl_params->kssl_params_size = bufsize;
1001	kssl_params->kssl_addr = server_addr;
1002	kssl_params->kssl_session_cache_timeout = timeout;
1003	kssl_params->kssl_proxy_port = proxy_port;
1004	kssl_params->kssl_session_cache_size = scache_size;
1005
1006	if (cacert_chain_file != NULL) {
1007		kssl_params = add_cacerts(kssl_params, cacert_chain_file);
1008		if (kssl_params == NULL) {
1009			return (FAILURE);
1010		}
1011	}
1012
1013	if (kssl_send_command((char *)kssl_params, KSSL_ADD_ENTRY) < 0) {
1014		int err = CRYPTO_FAILED;
1015
1016		if (kssl_params->kssl_is_nxkey)
1017			err = kssl_params->kssl_token.ck_rv;
1018		(void) fprintf(stderr,
1019		    "Error loading cert and key: 0x%x\n", err);
1020		return (FAILURE);
1021	}
1022
1023	if (verbose)
1024		(void) printf("Successfully loaded cert and key\n");
1025
1026	bzero(kssl_params, bufsize);
1027	free(kssl_params);
1028	return (SUCCESS);
1029
1030err:
1031	usage_create(B_TRUE);
1032	return (SMF_EXIT_ERR_CONFIG);
1033}
1034