xref: /onnv-gate/usr/src/uts/common/inet/kssl/ksslioctl.c (revision 10520:1303da84e47a)
1898Skais /*
2898Skais  * CDDL HEADER START
3898Skais  *
4898Skais  * The contents of this file are subject to the terms of the
52800Skrishna  * Common Development and Distribution License (the "License").
62800Skrishna  * You may not use this file except in compliance with the License.
7898Skais  *
8898Skais  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9898Skais  * or http://www.opensolaris.org/os/licensing.
10898Skais  * See the License for the specific language governing permissions
11898Skais  * and limitations under the License.
12898Skais  *
13898Skais  * When distributing Covered Code, include this CDDL HEADER in each
14898Skais  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15898Skais  * If applicable, add the following below this CDDL HEADER, with the
16898Skais  * fields enclosed by brackets "[]" replaced with your own identifying
17898Skais  * information: Portions Copyright [yyyy] [name of copyright owner]
18898Skais  *
19898Skais  * CDDL HEADER END
20898Skais  */
21898Skais /*
22*10520SBhargava.Yenduri@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23898Skais  * Use is subject to license terms.
24898Skais  */
25898Skais 
26898Skais /*
27898Skais  * The kernel SSL module ioctls.
28898Skais  */
29898Skais 
30898Skais #include <sys/types.h>
31898Skais #include <sys/modctl.h>
32898Skais #include <sys/conf.h>
33898Skais #include <sys/ddi.h>
34898Skais #include <sys/sunddi.h>
35898Skais #include <sys/kmem.h>
36898Skais #include <sys/errno.h>
37898Skais #include <sys/file.h>
38898Skais #include <sys/cred.h>
39898Skais #include <sys/proc.h>
40898Skais #include <sys/task.h>
41898Skais #include <sys/model.h>
42898Skais #include <sys/sysmacros.h>
43898Skais #include <sys/policy.h>
44898Skais #include <sys/crypto/common.h>
45898Skais #include <sys/crypto/api.h>
46898Skais #include <inet/common.h>
47898Skais #include <inet/ip.h>
48898Skais 
49898Skais #include "ksslimpl.h"
50898Skais #include "kssl.h"
51898Skais #include "ksslproto.h"
52898Skais 
53898Skais kssl_entry_t **kssl_entry_tab;
54898Skais int kssl_entry_tab_size;
55898Skais int kssl_entry_tab_nentries;
56898Skais kmutex_t kssl_tab_mutex;
57898Skais 
58898Skais static void
59898Skais certificate_free(Certificate_t *cert)
60898Skais {
61898Skais 	kmem_free(cert->msg, cert->len);
62898Skais 	kmem_free(cert, sizeof (struct Certificate));
63898Skais }
64898Skais 
65898Skais static void
66898Skais privateKey_free(crypto_key_t *privkey)
67898Skais {
682800Skrishna 	int i;
692800Skrishna 	size_t attrs_size;
702800Skrishna 	crypto_object_attribute_t *attrs;
71898Skais 
722800Skrishna 	attrs = privkey->ck_attrs;
732800Skrishna 	attrs_size = privkey->ck_count * sizeof (crypto_object_attribute_t);
74898Skais 	for (i = 0; i < privkey->ck_count; i++) {
75898Skais 		bzero(attrs[i].oa_value, attrs[i].oa_value_len);
76898Skais 		kmem_free(attrs[i].oa_value, attrs[i].oa_value_len);
77898Skais 	}
78898Skais 	kmem_free(attrs, attrs_size);
79898Skais 	kmem_free(privkey, sizeof (crypto_key_t));
80898Skais }
81898Skais 
822800Skrishna static void
832800Skrishna sess_free(kssl_session_info_t *s)
842800Skrishna {
852800Skrishna 	if (s->is_valid_handle) {
862800Skrishna 		(void) crypto_session_logout(s->prov, s->sid, NULL);
872800Skrishna 		(void) crypto_session_close(s->prov, s->sid, NULL);
882800Skrishna 		crypto_release_provider(s->prov);
892800Skrishna 		s->is_valid_handle = B_FALSE;
902800Skrishna 	}
912800Skrishna 
922800Skrishna 	if (s->evnt_handle != NULL) {
932800Skrishna 		crypto_unnotify_events(s->evnt_handle);
942800Skrishna 		s->evnt_handle = NULL;
952800Skrishna 	}
962800Skrishna 
972800Skrishna 	bzero(s->tokpin, s->pinlen);
982800Skrishna 	kmem_free(s, sizeof (kssl_session_info_t) + s->pinlen);
992800Skrishna }
1002800Skrishna 
101898Skais /*
102898Skais  * Frees the space for the entry and the keys and certs
103898Skais  * it carries.
104898Skais  */
105898Skais void
106898Skais kssl_free_entry(kssl_entry_t *kssl_entry)
107898Skais {
108898Skais 	int i;
109898Skais 	Certificate_t *cert;
110898Skais 	crypto_key_t *privkey;
1112800Skrishna 	kssl_session_info_t *s;
112898Skais 
113898Skais 	if (kssl_entry->ke_no_freeall) {
114898Skais 		kmem_free(kssl_entry, sizeof (kssl_entry_t));
115898Skais 		return;
116898Skais 	}
117898Skais 
118898Skais 	if ((cert = kssl_entry->ke_server_certificate) != NULL) {
119898Skais 		certificate_free(cert);
120898Skais 	}
121898Skais 
122898Skais 	if ((privkey = kssl_entry->ke_private_key) != NULL) {
123898Skais 		privateKey_free(privkey);
1242800Skrishna 	}
125898Skais 
126898Skais 	for (i = 0; i < kssl_entry->sid_cache_nentries; i++)
127898Skais 		mutex_destroy(&(kssl_entry->sid_cache[i].se_lock));
128898Skais 
129898Skais 	kmem_free(kssl_entry->sid_cache,
130898Skais 	    kssl_entry->sid_cache_nentries * sizeof (kssl_sid_ent_t));
131898Skais 
132898Skais 	ASSERT(kssl_entry->ke_proxy_head == NULL);
133898Skais 	ASSERT(kssl_entry->ke_fallback_head == NULL);
134898Skais 
1352800Skrishna 	if ((s = kssl_entry->ke_sessinfo) != NULL) {
1362800Skrishna 		ASSERT(kssl_entry->ke_is_nxkey);
1372800Skrishna 		sess_free(s);
1382800Skrishna 	}
1392800Skrishna 
140898Skais 	kmem_free(kssl_entry, sizeof (kssl_entry_t));
141898Skais }
142898Skais 
143898Skais /*
144898Skais  * Returns the index of the entry in kssl_entry_tab[] that matches
145898Skais  * the address and port.  Returns -1 if no match is found.
146898Skais  */
147898Skais static int
148*10520SBhargava.Yenduri@Sun.COM kssl_find_entry(in6_addr_t laddr, in_port_t port, int type,
149898Skais     boolean_t wild_card_match)
150898Skais {
151898Skais 	int i;
152898Skais 	kssl_entry_t *ep;
153898Skais 
154898Skais 	ASSERT(MUTEX_HELD(&kssl_tab_mutex));
155898Skais 
156898Skais 	for (i = 0; i < kssl_entry_tab_size; i++) {
157898Skais 		ep = kssl_entry_tab[i];
158898Skais 		if (ep == NULL)
159898Skais 			continue;
160898Skais 
161898Skais 		if (!((type == IS_SSL_PORT && ep->ke_ssl_port == port) ||
162898Skais 		    (type == IS_PROXY_PORT && ep->ke_proxy_port == port)))
163898Skais 			continue;
164898Skais 
165*10520SBhargava.Yenduri@Sun.COM 		if (IN6_ARE_ADDR_EQUAL(&laddr, &ep->ke_laddr) ||
166*10520SBhargava.Yenduri@Sun.COM 		    (wild_card_match && (IN6_IS_ADDR_UNSPECIFIED(&laddr) ||
167*10520SBhargava.Yenduri@Sun.COM 		    IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr))))
168898Skais 			break;
169898Skais 	}
170898Skais 
171898Skais 	if (i == kssl_entry_tab_size)
172898Skais 		return (-1);
173898Skais 
174898Skais 	return (i);
175898Skais }
176898Skais 
177898Skais static void
178898Skais copy_int_to_bytearray(int x, uchar_t *buf)
179898Skais {
180898Skais 	buf[0] = (x >> 16) & 0xff;
181898Skais 	buf[1] = (x >> 8) & 0xff;
182898Skais 	buf[2] = (x) & 0xff;
183898Skais }
184898Skais 
185898Skais static int
186898Skais extract_certificate(kssl_params_t *kssl_params, Certificate_t **certpp)
187898Skais {
188898Skais 	int i, len;
189898Skais 	uint64_t in_size;
190898Skais 	uchar_t *end_pos;
191898Skais 	uint32_t ncert;
192898Skais 	uint32_t *cert_sizes;
193898Skais 	Certificate_t *cert;
194898Skais 	char *begin = (char *)kssl_params;
195898Skais 	uchar_t *cert_buf;
196898Skais 	int cert_buf_len;
197898Skais 	uchar_t *cert_from, *cert_to;
198898Skais 
199898Skais 	ASSERT(kssl_params);
200898Skais 
201898Skais 	in_size = kssl_params->kssl_params_size;
202898Skais 	end_pos = (uchar_t *)kssl_params + in_size;
203898Skais 
204898Skais 	/*
205898Skais 	 * Get the certs array. First the array of sizes, then the actual
206898Skais 	 * certs.
207898Skais 	 */
208898Skais 	ncert = kssl_params->kssl_certs.sc_count;
209898Skais 
210898Skais 	if (ncert == 0) {
211898Skais 		/* no certs in here! why did ya call? */
212898Skais 		return (EINVAL);
213898Skais 	}
214898Skais 	if (in_size < (sizeof (kssl_params_t) + ncert * sizeof (uint32_t))) {
215898Skais 		return (EINVAL);
216898Skais 	}
217898Skais 
2182800Skrishna 	/* Trusting that the system call preserved the 4-byte alignment */
219898Skais 	cert_sizes = (uint32_t *)(begin +
220898Skais 	    kssl_params->kssl_certs.sc_sizes_offset);
221898Skais 
222898Skais 	/* should this be an ASSERT()? */
223898Skais 	if (!IS_P2ALIGNED(cert_sizes, sizeof (uint32_t))) {
224898Skais 		return (EINVAL);
225898Skais 	}
226898Skais 
227898Skais 	len = 0;
228898Skais 	for (i = 0; i < ncert; i++) {
229898Skais 		if (cert_sizes[i] < 1) {
230898Skais 			return (EINVAL);
231898Skais 		}
232898Skais 		len += cert_sizes[i] + 3;
233898Skais 	}
234898Skais 
235898Skais 	len += 3;	/* length of certificate message without msg header */
236898Skais 
237898Skais 	cert_buf_len = len + 4 + 4;	/* add space for msg headers */
238898Skais 
239898Skais 	cert_buf = kmem_alloc(cert_buf_len, KM_SLEEP);
240898Skais 
241898Skais 	cert_buf[0] = (uchar_t)certificate;
242898Skais 	copy_int_to_bytearray(len, & cert_buf[1]);
243898Skais 	copy_int_to_bytearray(len - 3, & cert_buf[4]);
244898Skais 
245898Skais 	cert_from = (uchar_t *)(begin +
246898Skais 	    kssl_params->kssl_certs.sc_certs_offset);
247898Skais 	cert_to = &cert_buf[7];
248898Skais 
249898Skais 	for (i = 0; i < ncert; i++) {
250898Skais 		copy_int_to_bytearray(cert_sizes[i], cert_to);
251898Skais 		cert_to += 3;
252898Skais 
253898Skais 		if (cert_from + cert_sizes[i] > end_pos) {
254898Skais 			kmem_free(cert_buf, cert_buf_len);
255898Skais 			return (EINVAL);
256898Skais 		}
257898Skais 
258898Skais 		bcopy(cert_from, cert_to, cert_sizes[i]);
259898Skais 		cert_from += cert_sizes[i];
260898Skais 		cert_to += cert_sizes[i];
261898Skais 	}
262898Skais 
263898Skais 	len += 4;
264898Skais 	cert_buf[len] = (uchar_t)server_hello_done;
265898Skais 	copy_int_to_bytearray(0, & cert_buf[len + 1]);
266898Skais 
267898Skais 	cert = kmem_alloc(sizeof (Certificate_t), KM_SLEEP);
268898Skais 	cert->msg = cert_buf;
269898Skais 	cert->len = cert_buf_len;
270898Skais 
271898Skais 	*certpp = cert;
272898Skais 
273898Skais 	return (0);
274898Skais }
275898Skais 
276898Skais static int
277898Skais extract_private_key(kssl_params_t *kssl_params, crypto_key_t **privkey)
278898Skais {
279898Skais 	char *begin = (char *)kssl_params;
280898Skais 	char *end_pos;
281898Skais 	int i, j, rv;
282898Skais 	size_t attrs_size;
283*10520SBhargava.Yenduri@Sun.COM 	crypto_object_attribute_t *newattrs;
284898Skais 	char *mp_attrs;
285898Skais 	kssl_object_attribute_t att;
286898Skais 	char *attval;
287898Skais 	uint32_t attlen;
288898Skais 	crypto_key_t *kssl_privkey;
289898Skais 
290898Skais 	end_pos = (char *)kssl_params + kssl_params->kssl_params_size;
291898Skais 
292898Skais 	kssl_privkey = kmem_alloc(sizeof (crypto_key_t), KM_SLEEP);
293898Skais 
294898Skais 	kssl_privkey->ck_format = kssl_params->kssl_privkey.ks_format;
295898Skais 	kssl_privkey->ck_count = kssl_params->kssl_privkey.ks_count;
296898Skais 
297898Skais 	switch (kssl_privkey->ck_format) {
298898Skais 		case CRYPTO_KEY_ATTR_LIST:
299898Skais 			break;
300898Skais 		case CRYPTO_KEY_RAW:
301898Skais 		case CRYPTO_KEY_REFERENCE:
302898Skais 		default:
303898Skais 			rv = EINVAL;
304898Skais 			goto err1;
305898Skais 	}
306898Skais 
307898Skais 	/* allocate the attributes */
308898Skais 	attrs_size = kssl_privkey->ck_count *
309898Skais 	    sizeof (crypto_object_attribute_t);
310898Skais 
311898Skais 	mp_attrs = begin + kssl_params->kssl_privkey.ks_attrs_offset;
312898Skais 	if (mp_attrs + attrs_size > end_pos) {
313898Skais 		rv = EINVAL;
314898Skais 		goto err1;
315898Skais 	}
316898Skais 
3172800Skrishna 	newattrs = kmem_alloc(attrs_size, KM_SLEEP);
3182800Skrishna 
319898Skais 	/* Now the individual attributes */
320898Skais 	for (i = 0; i < kssl_privkey->ck_count; i++) {
321898Skais 		bcopy(mp_attrs, &att, sizeof (kssl_object_attribute_t));
322898Skais 
323898Skais 		mp_attrs += sizeof (kssl_object_attribute_t);
324898Skais 
325898Skais 		attval = begin + att.ka_value_offset;
326898Skais 		attlen = att.ka_value_len;
327898Skais 
328898Skais 		if (attval + attlen > end_pos) {
329898Skais 			rv = EINVAL;
330898Skais 			goto err2;
331898Skais 		}
332898Skais 
333898Skais 		newattrs[i].oa_type = att.ka_type;
334898Skais 		newattrs[i].oa_value_len = attlen;
3352800Skrishna 		newattrs[i].oa_value = kmem_alloc(attlen, KM_SLEEP);
336898Skais 
337898Skais 		bcopy(attval, newattrs[i].oa_value, attlen);
338898Skais 	}
339898Skais 
340898Skais 	kssl_privkey->ck_attrs = newattrs;
341898Skais 
342898Skais 	*privkey = kssl_privkey;
343898Skais 
344898Skais 	return (0);
345898Skais 
346898Skais err2:
347898Skais 	for (j = 0; j < i; j++) {
3482800Skrishna 		bzero(newattrs[j].oa_value, newattrs[j].oa_value_len);
349898Skais 		kmem_free(newattrs[j].oa_value, newattrs[j].oa_value_len);
350898Skais 	}
351898Skais 	kmem_free(newattrs, attrs_size);
352898Skais err1:
353898Skais 	kmem_free(kssl_privkey, sizeof (crypto_key_t));
354898Skais 	return (rv);
355898Skais }
356898Skais 
3572800Skrishna static int
3582800Skrishna create_sessinfo(kssl_params_t *kssl_params, kssl_entry_t *kssl_entry)
3592800Skrishna {
3602800Skrishna 	int rv;
3612800Skrishna 	char *p;
3622800Skrishna 	kssl_session_info_t *s;
3632800Skrishna 	kssl_tokinfo_t *t;
3642800Skrishna 
3652800Skrishna 	t =  &kssl_params->kssl_token;
3662800Skrishna 	/* Do a sanity check */
3672800Skrishna 	if (t->pinlen > MAX_PIN_LENGTH) {
3682800Skrishna 		return (EINVAL);
3692800Skrishna 	}
3702800Skrishna 
3712800Skrishna 	s = kmem_zalloc(sizeof (kssl_session_info_t) + t->pinlen, KM_SLEEP);
3722800Skrishna 	s->pinlen = t->pinlen;
3732800Skrishna 	bcopy(t->toklabel, s->toklabel, CRYPTO_EXT_SIZE_LABEL);
3742800Skrishna 	p = (char *)kssl_params + t->tokpin_offset;
3752800Skrishna 	bcopy(p, s->tokpin, s->pinlen);
3762800Skrishna 	ASSERT(kssl_entry->ke_sessinfo == NULL);
3772800Skrishna 	kssl_entry->ke_sessinfo = s;
3782800Skrishna 
3792800Skrishna 	/* Get the handle to the non extractable key */
3802800Skrishna 	rv = kssl_get_obj_handle(kssl_entry);
3812800Skrishna 	kssl_params->kssl_token.ck_rv = rv;
3822800Skrishna 	if (rv != CRYPTO_SUCCESS) {
3832800Skrishna 		sess_free(s);
3842800Skrishna 		kssl_entry->ke_sessinfo = NULL;
3852800Skrishna 		return (EINVAL);
3862800Skrishna 	}
3872800Skrishna 
3882800Skrishna 	kssl_entry->ke_sessinfo->is_valid_handle = B_TRUE;
3892800Skrishna 	kssl_entry->ke_sessinfo->do_reauth = B_FALSE;
3902800Skrishna 	kssl_entry->ke_sessinfo->evnt_handle =
3912800Skrishna 	    crypto_notify_events(kssl_prov_evnt,
3926788Skrishna 	    CRYPTO_EVENT_PROVIDER_REGISTERED |
3936788Skrishna 	    CRYPTO_EVENT_PROVIDER_UNREGISTERED);
3942800Skrishna 
3952800Skrishna 	return (0);
3962800Skrishna }
3972800Skrishna 
398898Skais static kssl_entry_t *
399898Skais create_kssl_entry(kssl_params_t *kssl_params, Certificate_t *cert,
400898Skais     crypto_key_t *privkey)
401898Skais {
402898Skais 	int i;
403898Skais 	uint16_t s;
4046788Skrishna 	kssl_entry_t *kssl_entry, *ep;
405898Skais 	uint_t cnt, mech_count;
406898Skais 	crypto_mech_name_t *mechs;
407898Skais 	boolean_t got_rsa, got_md5, got_sha1, got_rc4, got_des, got_3des;
4086788Skrishna 	boolean_t got_aes;
409898Skais 
410898Skais 	kssl_entry = kmem_zalloc(sizeof (kssl_entry_t), KM_SLEEP);
411898Skais 
412*10520SBhargava.Yenduri@Sun.COM 	kssl_entry->ke_laddr = kssl_params->kssl_addr.sin6_addr;
413*10520SBhargava.Yenduri@Sun.COM 	kssl_entry->ke_ssl_port = kssl_params->kssl_addr.sin6_port;
414898Skais 	kssl_entry->ke_proxy_port = kssl_params->kssl_proxy_port;
415898Skais 	if (kssl_params->kssl_session_cache_timeout == 0)
416898Skais 		kssl_entry->sid_cache_timeout = DEFAULT_SID_TIMEOUT;
417898Skais 	else
418898Skais 		kssl_entry->sid_cache_timeout =
419898Skais 		    kssl_params->kssl_session_cache_timeout;
420898Skais 	if (kssl_params->kssl_session_cache_size == 0)
421898Skais 		kssl_entry->sid_cache_nentries = DEFAULT_SID_CACHE_NENTRIES;
422898Skais 	else
423898Skais 		kssl_entry->sid_cache_nentries =
424898Skais 		    kssl_params->kssl_session_cache_size;
425898Skais 	kssl_entry->ke_private_key = privkey;
426898Skais 	kssl_entry->ke_server_certificate = cert;
427898Skais 
4282800Skrishna 	kssl_entry->ke_is_nxkey = kssl_params->kssl_is_nxkey;
4292800Skrishna 	if (kssl_entry->ke_is_nxkey) {
4302800Skrishna 		if (create_sessinfo(kssl_params, kssl_entry) != 0) {
4312800Skrishna 			kmem_free(kssl_entry, sizeof (kssl_entry_t));
4322800Skrishna 			return (NULL);
4332800Skrishna 		}
4342800Skrishna 	}
4352800Skrishna 
436898Skais 	mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
437898Skais 	if (mechs != NULL) {
438898Skais 		got_rsa = got_md5 = got_sha1 = got_rc4 =
4396788Skrishna 		    got_des = got_3des = got_aes = B_FALSE;
440898Skais 		for (i = 0; i < mech_count; i++) {
441898Skais 			if (strncmp(SUN_CKM_RSA_X_509, mechs[i],
442898Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
443898Skais 				got_rsa = B_TRUE;
444898Skais 			else if (strncmp(SUN_CKM_MD5_HMAC, mechs[i],
445898Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
446898Skais 				got_md5 = B_TRUE;
447898Skais 			else if (strncmp(SUN_CKM_SHA1_HMAC, mechs[i],
448898Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
449898Skais 				got_sha1 = B_TRUE;
450898Skais 			else if (strncmp(SUN_CKM_RC4, mechs[i],
451898Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
452898Skais 				got_rc4 = B_TRUE;
453898Skais 			else if (strncmp(SUN_CKM_DES_CBC, mechs[i],
454898Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
455898Skais 				got_des = B_TRUE;
456898Skais 			else if (strncmp(SUN_CKM_DES3_CBC, mechs[i],
457898Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
458898Skais 				got_3des = B_TRUE;
4596788Skrishna 			else if (strncmp(SUN_CKM_AES_CBC, mechs[i],
4606788Skrishna 			    CRYPTO_MAX_MECH_NAME) == 0)
4616788Skrishna 				got_aes = B_TRUE;
462898Skais 		}
463898Skais 
464898Skais 		cnt = 0;
4656788Skrishna 		ep = kssl_entry;
466898Skais 		for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++) {
467898Skais 			switch (s = kssl_params->kssl_suites[i]) {
468898Skais 			case SSL_RSA_WITH_RC4_128_MD5:
469898Skais 				if (got_rsa && got_rc4 && got_md5)
4706788Skrishna 					ep->kssl_cipherSuites[cnt++] = s;
471898Skais 				break;
472898Skais 			case SSL_RSA_WITH_RC4_128_SHA:
473898Skais 				if (got_rsa && got_rc4 && got_sha1)
4746788Skrishna 					ep->kssl_cipherSuites[cnt++] = s;
475898Skais 				break;
476898Skais 			case SSL_RSA_WITH_DES_CBC_SHA:
477898Skais 				if (got_rsa && got_des && got_sha1)
4786788Skrishna 					ep->kssl_cipherSuites[cnt++] = s;
479898Skais 				break;
480898Skais 			case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
481898Skais 				if (got_rsa && got_3des && got_sha1)
4826788Skrishna 					ep->kssl_cipherSuites[cnt++] = s;
4836788Skrishna 				break;
4846788Skrishna 			case TLS_RSA_WITH_AES_128_CBC_SHA:
4856788Skrishna 				if (got_rsa && got_aes && got_sha1)
4866788Skrishna 					ep->kssl_cipherSuites[cnt++] = s;
4876788Skrishna 				break;
4886788Skrishna 			case TLS_RSA_WITH_AES_256_CBC_SHA:
4896788Skrishna 				if (got_rsa && got_aes && got_sha1)
4906788Skrishna 					ep->kssl_cipherSuites[cnt++] = s;
491898Skais 				break;
492898Skais 			case CIPHER_NOTSET:
493898Skais 			default:
494898Skais 				break;
495898Skais 			}
496898Skais 		}
497898Skais 
498898Skais 		crypto_free_mech_list(mechs, mech_count);
499898Skais 	}
500898Skais 
501898Skais 	/* Add the no encryption suite to the end */
502898Skais 	kssl_entry->kssl_cipherSuites[cnt++] = SSL_RSA_WITH_NULL_SHA;
503898Skais 	kssl_entry->kssl_cipherSuites_nentries = cnt;
504898Skais 	for (i = 0; i < cnt; i++)
505898Skais 		kssl_entry->kssl_saved_Suites[i] =
506898Skais 		    kssl_entry->kssl_cipherSuites[i];
507898Skais 
508898Skais 	kssl_entry->sid_cache = kmem_alloc(
509898Skais 	    kssl_entry->sid_cache_nentries * sizeof (kssl_sid_ent_t), KM_SLEEP);
510898Skais 
511898Skais 	for (i = 0; i < kssl_entry->sid_cache_nentries; i++) {
512898Skais 		mutex_init(&(kssl_entry->sid_cache[i].se_lock), NULL,
513898Skais 		    MUTEX_DEFAULT, NULL);
514898Skais 		kssl_entry->sid_cache[i].se_used = 0;
515898Skais 		kssl_entry->sid_cache[i].se_sid.cached = B_FALSE;
516898Skais 	}
517898Skais 
518898Skais 	KSSL_ENTRY_REFHOLD(kssl_entry);
519898Skais 
520898Skais 	return (kssl_entry);
521898Skais }
522898Skais 
523898Skais int
524898Skais kssl_add_entry(kssl_params_t *kssl_params)
525898Skais {
526898Skais 	int rv, index, i;
527898Skais 	Certificate_t *cert;
528898Skais 	crypto_key_t *privkey;
529898Skais 	kssl_entry_t *kssl_entry;
530*10520SBhargava.Yenduri@Sun.COM 	in6_addr_t laddr;
531898Skais 
532898Skais 	if ((rv = extract_certificate(kssl_params, &cert)) != 0) {
533898Skais 		return (rv);
534898Skais 	}
535898Skais 
536898Skais 	if ((rv = extract_private_key(kssl_params, &privkey)) != 0) {
537898Skais 		certificate_free(cert);
538898Skais 		return (rv);
539898Skais 	}
540898Skais 
541898Skais 	kssl_entry = create_kssl_entry(kssl_params, cert, privkey);
5422800Skrishna 	if (kssl_entry == NULL) {
5432800Skrishna 		certificate_free(cert);
5442800Skrishna 		privateKey_free(privkey);
5452800Skrishna 		return (EINVAL);
5462800Skrishna 	}
547898Skais 
548*10520SBhargava.Yenduri@Sun.COM 	laddr = kssl_params->kssl_addr.sin6_addr;
549898Skais 
550898Skais retry:
551898Skais 	mutex_enter(&kssl_tab_mutex);
552898Skais 	/* Allocate the array first time here */
553898Skais 	if (kssl_entry_tab == NULL) {
554898Skais 		size_t allocsize;
555898Skais 		kssl_entry_t **tmp_tab;
556898Skais 		int tmp_size;
557898Skais 
558898Skais 		tmp_size = KSSL_TAB_INITSIZE;
559898Skais 		allocsize = tmp_size * sizeof (kssl_entry_t *);
560898Skais 		mutex_exit(&kssl_tab_mutex);
561898Skais 		tmp_tab = kmem_zalloc(allocsize, KM_SLEEP);
562898Skais 		mutex_enter(&kssl_tab_mutex);
563898Skais 		if (kssl_entry_tab != NULL) {
564898Skais 			mutex_exit(&kssl_tab_mutex);
565898Skais 			kmem_free(tmp_tab, allocsize);
566898Skais 			goto retry;
567898Skais 		}
568898Skais 		kssl_entry_tab_size = tmp_size;
569898Skais 		kssl_entry_tab = tmp_tab;
570898Skais 		index = 0;
571898Skais 	} else {
572898Skais 		/* Check if a matching entry exists already */
573898Skais 		index = kssl_find_entry(laddr,
574*10520SBhargava.Yenduri@Sun.COM 		    kssl_params->kssl_addr.sin6_port, IS_SSL_PORT, B_TRUE);
575898Skais 
576898Skais 		if (index == -1) {
577898Skais 			/* Check if an entry with the same proxy port exists */
578898Skais 			if (kssl_find_entry(laddr, kssl_params->kssl_proxy_port,
579898Skais 			    IS_PROXY_PORT, B_TRUE) != -1) {
580898Skais 				mutex_exit(&kssl_tab_mutex);
581898Skais 				kssl_free_entry(kssl_entry);
582898Skais 				return (EADDRINUSE);
583898Skais 			}
584898Skais 
585898Skais 			/* No matching entry, find an empty spot */
586898Skais 			for (i = 0; i < kssl_entry_tab_size; i++) {
587898Skais 				if (kssl_entry_tab[i] == NULL)
588898Skais 					break;
589898Skais 			}
590898Skais 			/* Table full. Gotta grow it */
591898Skais 			if (i == kssl_entry_tab_size) {
592898Skais 				kssl_entry_t **new_tab, **old_tab;
593898Skais 				size_t allocsize;
594898Skais 				size_t oldtabsize = kssl_entry_tab_size *
595898Skais 				    sizeof (kssl_entry_t *);
596898Skais 				int tmp_size, old_size;
597898Skais 
598898Skais 				tmp_size = old_size = kssl_entry_tab_size;
599898Skais 				tmp_size += KSSL_TAB_INITSIZE;
600898Skais 				allocsize = tmp_size * sizeof (kssl_entry_t *);
601898Skais 				mutex_exit(&kssl_tab_mutex);
602898Skais 				new_tab = kmem_zalloc(allocsize, KM_SLEEP);
603898Skais 				mutex_enter(&kssl_tab_mutex);
604898Skais 				if (kssl_entry_tab_size > old_size) {
605898Skais 					mutex_exit(&kssl_tab_mutex);
606898Skais 					kmem_free(new_tab, allocsize);
607898Skais 					goto retry;
608898Skais 				}
609898Skais 
610898Skais 				kssl_entry_tab_size = tmp_size;
611898Skais 				bcopy(kssl_entry_tab, new_tab, oldtabsize);
612898Skais 
613898Skais 				old_tab = kssl_entry_tab;
614898Skais 				kssl_entry_tab = new_tab;
615898Skais 
616898Skais 				kmem_free(old_tab, oldtabsize);
617898Skais 			}
618898Skais 			index = i;
619898Skais 		} else {
620*10520SBhargava.Yenduri@Sun.COM 			kssl_entry_t *ep;
621*10520SBhargava.Yenduri@Sun.COM 
622898Skais 			/*
623898Skais 			 * We do not want an entry with a specific address and
624898Skais 			 * an entry with IN_ADDR_ANY to coexist. We could
625898Skais 			 * replace the existing entry. But, most likely this
626898Skais 			 * is misconfiguration. Better bail out with an error.
627898Skais 			 */
628*10520SBhargava.Yenduri@Sun.COM 			ep = kssl_entry_tab[index];
629*10520SBhargava.Yenduri@Sun.COM 
630*10520SBhargava.Yenduri@Sun.COM 			if ((IN6_IS_ADDR_UNSPECIFIED(&laddr) &&
631*10520SBhargava.Yenduri@Sun.COM 			    !IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr)) ||
632*10520SBhargava.Yenduri@Sun.COM 			    (!IN6_IS_ADDR_UNSPECIFIED(&laddr) &&
633*10520SBhargava.Yenduri@Sun.COM 			    IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr))) {
634898Skais 				mutex_exit(&kssl_tab_mutex);
635898Skais 				kssl_free_entry(kssl_entry);
636898Skais 				return (EEXIST);
637898Skais 			}
638898Skais 
639898Skais 			/* Replace the existing entry */
640898Skais 			KSSL_ENTRY_REFRELE(kssl_entry_tab[index]);
641898Skais 			kssl_entry_tab[index] = NULL;
642898Skais 			kssl_entry_tab_nentries--;
643898Skais 		}
644898Skais 	}
645898Skais 
646898Skais 	kssl_entry_tab[index] = kssl_entry;
647898Skais 	kssl_entry_tab_nentries++;
648898Skais 	mutex_exit(&kssl_tab_mutex);
649898Skais 
650898Skais 	return (0);
651898Skais }
652898Skais 
653898Skais int
654*10520SBhargava.Yenduri@Sun.COM kssl_delete_entry(struct sockaddr_in6 *kssl_addr)
655898Skais {
656*10520SBhargava.Yenduri@Sun.COM 	in6_addr_t laddr;
657898Skais 	int index;
658898Skais 
659*10520SBhargava.Yenduri@Sun.COM 	laddr = kssl_addr->sin6_addr;
660898Skais 
661898Skais 	mutex_enter(&kssl_tab_mutex);
662*10520SBhargava.Yenduri@Sun.COM 	index = kssl_find_entry(laddr, kssl_addr->sin6_port,
663898Skais 	    IS_SSL_PORT, B_FALSE);
664898Skais 
665898Skais 	if (index == -1) {
666898Skais 		mutex_exit(&kssl_tab_mutex);
667898Skais 		return (ENOENT);
668898Skais 	}
669898Skais 
670898Skais 	KSSL_ENTRY_REFRELE(kssl_entry_tab[index]);
671898Skais 	kssl_entry_tab[index] = NULL;
672898Skais 	kssl_entry_tab_nentries--;
673898Skais 
674898Skais 	mutex_exit(&kssl_tab_mutex);
675898Skais 
676898Skais 	return (0);
677898Skais }
6782800Skrishna 
6792800Skrishna /*
6802800Skrishna  * We care about only one private key object.
6812800Skrishna  * So, set the max count to only 1.
6822800Skrishna  */
6832800Skrishna #define	MAX_OBJECT_COUNT	1
6842800Skrishna 
6852800Skrishna /*
6862800Skrishna  * Open a session to the provider specified by the label and
6872800Skrishna  * authenticate to it. Find the private key object with the
6882800Skrishna  * specified  attributes and save the handle. The userland component
6892800Skrishna  * must set all the attributes in the template so as to uniquely
6902800Skrishna  * identify the object.
6912800Skrishna  *
6922800Skrishna  * Note that the handle will be invalid if we logout or close
6932800Skrishna  * the session to the provider.
6942800Skrishna  */
6952800Skrishna int
6962800Skrishna kssl_get_obj_handle(kssl_entry_t *kp)
6972800Skrishna {
6982800Skrishna 	int rv;
6992800Skrishna 	unsigned int count;
7002800Skrishna 	void *cookie = NULL;
7012800Skrishna 	crypto_provider_t prov;
7022800Skrishna 	kssl_session_info_t *s;
7032800Skrishna 	crypto_session_id_t sid;
7042800Skrishna 	crypto_object_attribute_t *attrs;
7052800Skrishna 	crypto_object_id_t ohndl[MAX_OBJECT_COUNT];
7062800Skrishna 	char label[CRYPTO_EXT_SIZE_LABEL + 1];
7072800Skrishna 
7082800Skrishna 	ASSERT(kp->ke_is_nxkey);
7092800Skrishna 	s = kp->ke_sessinfo;
7102800Skrishna 
7112800Skrishna 	bcopy(s->toklabel, label, CRYPTO_EXT_SIZE_LABEL);
7122800Skrishna 	label[CRYPTO_EXT_SIZE_LABEL] = '\0';
7132800Skrishna 	prov = crypto_get_provider(label, NULL, NULL);
7142800Skrishna 	if (prov == NULL)
7152800Skrishna 		return (CRYPTO_UNKNOWN_PROVIDER);
7162800Skrishna 
7172800Skrishna 	rv = crypto_session_open(prov, &sid, NULL);
7182800Skrishna 	if (rv != CRYPTO_SUCCESS) {
7192800Skrishna 		goto err1;
7202800Skrishna 	}
7212800Skrishna 
7222800Skrishna 	rv = crypto_session_login(prov, sid, CRYPTO_USER,
7232800Skrishna 	    s->tokpin, s->pinlen, NULL);
7242800Skrishna 	if (rv != CRYPTO_SUCCESS) {
7252800Skrishna 		goto err2;
7262800Skrishna 	}
7272800Skrishna 
7282800Skrishna 	count = kp->ke_private_key->ck_count;
7292800Skrishna 	attrs = kp->ke_private_key->ck_attrs;
7302800Skrishna 
7312800Skrishna 	rv = crypto_object_find_init(prov, sid, attrs, count, &cookie, NULL);
7322800Skrishna 	if (rv != CRYPTO_SUCCESS) {
7332800Skrishna 		goto err3;
7342800Skrishna 	}
7352800Skrishna 
7362800Skrishna 	rv = crypto_object_find(prov, cookie, ohndl, &count,
7372800Skrishna 	    MAX_OBJECT_COUNT, NULL);
7382800Skrishna 	if (rv != CRYPTO_SUCCESS || count == 0) {
7392800Skrishna 		if (count == 0)
7402800Skrishna 			rv = CRYPTO_FAILED;
7412800Skrishna 		goto err3;
7422800Skrishna 	}
7432800Skrishna 
7442800Skrishna 	(void) crypto_object_find_final(prov, cookie, NULL);
7452800Skrishna 
7462800Skrishna 	s->sid = sid;
7472800Skrishna 	s->prov = prov;
7482800Skrishna 	s->key.ck_format = CRYPTO_KEY_REFERENCE;
7492800Skrishna 	/* Keep the handle around for later use */
7502800Skrishna 	s->key.ck_obj_id = ohndl[0];
7512800Skrishna 
7522800Skrishna 	return (CRYPTO_SUCCESS);
7532800Skrishna 
7542800Skrishna err3:
7552800Skrishna 	(void) crypto_session_logout(prov, sid, NULL);
7562800Skrishna err2:
7572800Skrishna 	(void) crypto_session_close(prov, sid, NULL);
7582800Skrishna err1:
7592800Skrishna 	crypto_release_provider(prov);
7602800Skrishna 	return (rv);
7612800Skrishna }
762