xref: /titanic_52/usr/src/uts/common/inet/kssl/ksslioctl.c (revision 65d184575ba5adcc532b970fc99d2f67e2df7af6)
1c28749e9Skais /*
2c28749e9Skais  * CDDL HEADER START
3c28749e9Skais  *
4c28749e9Skais  * The contents of this file are subject to the terms of the
5c892ebf1Skrishna  * Common Development and Distribution License (the "License").
6c892ebf1Skrishna  * You may not use this file except in compliance with the License.
7c28749e9Skais  *
8c28749e9Skais  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c28749e9Skais  * or http://www.opensolaris.org/os/licensing.
10c28749e9Skais  * See the License for the specific language governing permissions
11c28749e9Skais  * and limitations under the License.
12c28749e9Skais  *
13c28749e9Skais  * When distributing Covered Code, include this CDDL HEADER in each
14c28749e9Skais  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c28749e9Skais  * If applicable, add the following below this CDDL HEADER, with the
16c28749e9Skais  * fields enclosed by brackets "[]" replaced with your own identifying
17c28749e9Skais  * information: Portions Copyright [yyyy] [name of copyright owner]
18c28749e9Skais  *
19c28749e9Skais  * CDDL HEADER END
20c28749e9Skais  */
21c28749e9Skais /*
22*65d18457SVladimir Kotal  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23c28749e9Skais  * Use is subject to license terms.
24c28749e9Skais  */
25c28749e9Skais 
26c28749e9Skais /*
27c28749e9Skais  * The kernel SSL module ioctls.
28c28749e9Skais  */
29c28749e9Skais 
30c28749e9Skais #include <sys/types.h>
31c28749e9Skais #include <sys/modctl.h>
32c28749e9Skais #include <sys/conf.h>
33c28749e9Skais #include <sys/ddi.h>
34c28749e9Skais #include <sys/sunddi.h>
35c28749e9Skais #include <sys/kmem.h>
36c28749e9Skais #include <sys/errno.h>
37c28749e9Skais #include <sys/file.h>
38c28749e9Skais #include <sys/cred.h>
39c28749e9Skais #include <sys/proc.h>
40c28749e9Skais #include <sys/task.h>
41c28749e9Skais #include <sys/model.h>
42c28749e9Skais #include <sys/sysmacros.h>
43c28749e9Skais #include <sys/policy.h>
44c28749e9Skais #include <sys/crypto/common.h>
45c28749e9Skais #include <sys/crypto/api.h>
46c28749e9Skais #include <inet/common.h>
47c28749e9Skais #include <inet/ip.h>
48c28749e9Skais 
49c28749e9Skais #include "ksslimpl.h"
50c28749e9Skais #include "kssl.h"
51c28749e9Skais #include "ksslproto.h"
52c28749e9Skais 
53c28749e9Skais kssl_entry_t **kssl_entry_tab;
54c28749e9Skais int kssl_entry_tab_size;
55c28749e9Skais int kssl_entry_tab_nentries;
56*65d18457SVladimir Kotal uint_t null_cipher_suite;	/* setable in /etc/system */
57c28749e9Skais kmutex_t kssl_tab_mutex;
58c28749e9Skais 
59c28749e9Skais static void
60c28749e9Skais certificate_free(Certificate_t *cert)
61c28749e9Skais {
62c28749e9Skais 	kmem_free(cert->msg, cert->len);
63c28749e9Skais 	kmem_free(cert, sizeof (struct Certificate));
64c28749e9Skais }
65c28749e9Skais 
66c28749e9Skais static void
67c28749e9Skais privateKey_free(crypto_key_t *privkey)
68c28749e9Skais {
69c28749e9Skais 	int i;
70c892ebf1Skrishna 	size_t attrs_size;
71c892ebf1Skrishna 	crypto_object_attribute_t *attrs;
72c28749e9Skais 
73c892ebf1Skrishna 	attrs = privkey->ck_attrs;
74c892ebf1Skrishna 	attrs_size = privkey->ck_count * sizeof (crypto_object_attribute_t);
75c28749e9Skais 	for (i = 0; i < privkey->ck_count; i++) {
76c28749e9Skais 		bzero(attrs[i].oa_value, attrs[i].oa_value_len);
77c28749e9Skais 		kmem_free(attrs[i].oa_value, attrs[i].oa_value_len);
78c28749e9Skais 	}
79c28749e9Skais 	kmem_free(attrs, attrs_size);
80c28749e9Skais 	kmem_free(privkey, sizeof (crypto_key_t));
81c28749e9Skais }
82c28749e9Skais 
83c892ebf1Skrishna static void
84c892ebf1Skrishna sess_free(kssl_session_info_t *s)
85c892ebf1Skrishna {
86c892ebf1Skrishna 	if (s->is_valid_handle) {
87c892ebf1Skrishna 		(void) crypto_session_logout(s->prov, s->sid, NULL);
88c892ebf1Skrishna 		(void) crypto_session_close(s->prov, s->sid, NULL);
89c892ebf1Skrishna 		crypto_release_provider(s->prov);
90c892ebf1Skrishna 		s->is_valid_handle = B_FALSE;
91c892ebf1Skrishna 	}
92c892ebf1Skrishna 
93c892ebf1Skrishna 	if (s->evnt_handle != NULL) {
94c892ebf1Skrishna 		crypto_unnotify_events(s->evnt_handle);
95c892ebf1Skrishna 		s->evnt_handle = NULL;
96c892ebf1Skrishna 	}
97c892ebf1Skrishna 
98c892ebf1Skrishna 	bzero(s->tokpin, s->pinlen);
99c892ebf1Skrishna 	kmem_free(s, sizeof (kssl_session_info_t) + s->pinlen);
100c892ebf1Skrishna }
101c892ebf1Skrishna 
102c28749e9Skais /*
103c28749e9Skais  * Frees the space for the entry and the keys and certs
104c28749e9Skais  * it carries.
105c28749e9Skais  */
106c28749e9Skais void
107c28749e9Skais kssl_free_entry(kssl_entry_t *kssl_entry)
108c28749e9Skais {
109c28749e9Skais 	int i;
110c28749e9Skais 	Certificate_t *cert;
111c28749e9Skais 	crypto_key_t *privkey;
112c892ebf1Skrishna 	kssl_session_info_t *s;
113c28749e9Skais 
114c28749e9Skais 	if (kssl_entry->ke_no_freeall) {
115c28749e9Skais 		kmem_free(kssl_entry, sizeof (kssl_entry_t));
116c28749e9Skais 		return;
117c28749e9Skais 	}
118c28749e9Skais 
119c28749e9Skais 	if ((cert = kssl_entry->ke_server_certificate) != NULL) {
120c28749e9Skais 		certificate_free(cert);
121c28749e9Skais 	}
122c28749e9Skais 
123c28749e9Skais 	if ((privkey = kssl_entry->ke_private_key) != NULL) {
124c28749e9Skais 		privateKey_free(privkey);
125c892ebf1Skrishna 	}
126c28749e9Skais 
127c28749e9Skais 	for (i = 0; i < kssl_entry->sid_cache_nentries; i++)
128c28749e9Skais 		mutex_destroy(&(kssl_entry->sid_cache[i].se_lock));
129c28749e9Skais 
130c28749e9Skais 	kmem_free(kssl_entry->sid_cache,
131c28749e9Skais 	    kssl_entry->sid_cache_nentries * sizeof (kssl_sid_ent_t));
132c28749e9Skais 
133c28749e9Skais 	ASSERT(kssl_entry->ke_proxy_head == NULL);
134c28749e9Skais 	ASSERT(kssl_entry->ke_fallback_head == NULL);
135c28749e9Skais 
136c892ebf1Skrishna 	if ((s = kssl_entry->ke_sessinfo) != NULL) {
137c892ebf1Skrishna 		ASSERT(kssl_entry->ke_is_nxkey);
138c892ebf1Skrishna 		sess_free(s);
139c892ebf1Skrishna 	}
140c892ebf1Skrishna 
141c28749e9Skais 	kmem_free(kssl_entry, sizeof (kssl_entry_t));
142c28749e9Skais }
143c28749e9Skais 
144c28749e9Skais /*
145c28749e9Skais  * Returns the index of the entry in kssl_entry_tab[] that matches
146c28749e9Skais  * the address and port.  Returns -1 if no match is found.
147c28749e9Skais  */
148c28749e9Skais static int
1492ec7cc7fSKrishna Yenduri kssl_find_entry(in6_addr_t laddr, in_port_t port, int type,
150c28749e9Skais     boolean_t wild_card_match)
151c28749e9Skais {
152c28749e9Skais 	int i;
153c28749e9Skais 	kssl_entry_t *ep;
154c28749e9Skais 
155c28749e9Skais 	ASSERT(MUTEX_HELD(&kssl_tab_mutex));
156c28749e9Skais 
157c28749e9Skais 	for (i = 0; i < kssl_entry_tab_size; i++) {
158c28749e9Skais 		ep = kssl_entry_tab[i];
159c28749e9Skais 		if (ep == NULL)
160c28749e9Skais 			continue;
161c28749e9Skais 
162c28749e9Skais 		if (!((type == IS_SSL_PORT && ep->ke_ssl_port == port) ||
163c28749e9Skais 		    (type == IS_PROXY_PORT && ep->ke_proxy_port == port)))
164c28749e9Skais 			continue;
165c28749e9Skais 
1662ec7cc7fSKrishna Yenduri 		if (IN6_ARE_ADDR_EQUAL(&laddr, &ep->ke_laddr) ||
1672ec7cc7fSKrishna Yenduri 		    (wild_card_match && (IN6_IS_ADDR_UNSPECIFIED(&laddr) ||
1682ec7cc7fSKrishna Yenduri 		    IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr))))
169c28749e9Skais 			break;
170c28749e9Skais 	}
171c28749e9Skais 
172c28749e9Skais 	if (i == kssl_entry_tab_size)
173c28749e9Skais 		return (-1);
174c28749e9Skais 
175c28749e9Skais 	return (i);
176c28749e9Skais }
177c28749e9Skais 
178c28749e9Skais static void
179c28749e9Skais copy_int_to_bytearray(int x, uchar_t *buf)
180c28749e9Skais {
181c28749e9Skais 	buf[0] = (x >> 16) & 0xff;
182c28749e9Skais 	buf[1] = (x >> 8) & 0xff;
183c28749e9Skais 	buf[2] = (x) & 0xff;
184c28749e9Skais }
185c28749e9Skais 
186c28749e9Skais static int
187c28749e9Skais extract_certificate(kssl_params_t *kssl_params, Certificate_t **certpp)
188c28749e9Skais {
189c28749e9Skais 	int i, len;
190c28749e9Skais 	uint64_t in_size;
191c28749e9Skais 	uchar_t *end_pos;
192c28749e9Skais 	uint32_t ncert;
193c28749e9Skais 	uint32_t *cert_sizes;
194c28749e9Skais 	Certificate_t *cert;
195c28749e9Skais 	char *begin = (char *)kssl_params;
196c28749e9Skais 	uchar_t *cert_buf;
197c28749e9Skais 	int cert_buf_len;
198c28749e9Skais 	uchar_t *cert_from, *cert_to;
199c28749e9Skais 
200c28749e9Skais 	ASSERT(kssl_params);
201c28749e9Skais 
202c28749e9Skais 	in_size = kssl_params->kssl_params_size;
203c28749e9Skais 	end_pos = (uchar_t *)kssl_params + in_size;
204c28749e9Skais 
205c28749e9Skais 	/*
206c28749e9Skais 	 * Get the certs array. First the array of sizes, then the actual
207c28749e9Skais 	 * certs.
208c28749e9Skais 	 */
209c28749e9Skais 	ncert = kssl_params->kssl_certs.sc_count;
210c28749e9Skais 
211c28749e9Skais 	if (ncert == 0) {
212c28749e9Skais 		/* no certs in here! why did ya call? */
213c28749e9Skais 		return (EINVAL);
214c28749e9Skais 	}
215c28749e9Skais 	if (in_size < (sizeof (kssl_params_t) + ncert * sizeof (uint32_t))) {
216c28749e9Skais 		return (EINVAL);
217c28749e9Skais 	}
218c28749e9Skais 
219c892ebf1Skrishna 	/* Trusting that the system call preserved the 4-byte alignment */
220c28749e9Skais 	cert_sizes = (uint32_t *)(begin +
221c28749e9Skais 	    kssl_params->kssl_certs.sc_sizes_offset);
222c28749e9Skais 
223c28749e9Skais 	/* should this be an ASSERT()? */
224c28749e9Skais 	if (!IS_P2ALIGNED(cert_sizes, sizeof (uint32_t))) {
225c28749e9Skais 		return (EINVAL);
226c28749e9Skais 	}
227c28749e9Skais 
228c28749e9Skais 	len = 0;
229c28749e9Skais 	for (i = 0; i < ncert; i++) {
230c28749e9Skais 		if (cert_sizes[i] < 1) {
231c28749e9Skais 			return (EINVAL);
232c28749e9Skais 		}
233c28749e9Skais 		len += cert_sizes[i] + 3;
234c28749e9Skais 	}
235c28749e9Skais 
236c28749e9Skais 	len += 3;	/* length of certificate message without msg header */
237c28749e9Skais 
238c28749e9Skais 	cert_buf_len = len + 4 + 4;	/* add space for msg headers */
239c28749e9Skais 
240c28749e9Skais 	cert_buf = kmem_alloc(cert_buf_len, KM_SLEEP);
241c28749e9Skais 
242c28749e9Skais 	cert_buf[0] = (uchar_t)certificate;
243c28749e9Skais 	copy_int_to_bytearray(len, & cert_buf[1]);
244c28749e9Skais 	copy_int_to_bytearray(len - 3, & cert_buf[4]);
245c28749e9Skais 
246c28749e9Skais 	cert_from = (uchar_t *)(begin +
247c28749e9Skais 	    kssl_params->kssl_certs.sc_certs_offset);
248c28749e9Skais 	cert_to = &cert_buf[7];
249c28749e9Skais 
250c28749e9Skais 	for (i = 0; i < ncert; i++) {
251c28749e9Skais 		copy_int_to_bytearray(cert_sizes[i], cert_to);
252c28749e9Skais 		cert_to += 3;
253c28749e9Skais 
254c28749e9Skais 		if (cert_from + cert_sizes[i] > end_pos) {
255c28749e9Skais 			kmem_free(cert_buf, cert_buf_len);
256c28749e9Skais 			return (EINVAL);
257c28749e9Skais 		}
258c28749e9Skais 
259c28749e9Skais 		bcopy(cert_from, cert_to, cert_sizes[i]);
260c28749e9Skais 		cert_from += cert_sizes[i];
261c28749e9Skais 		cert_to += cert_sizes[i];
262c28749e9Skais 	}
263c28749e9Skais 
264c28749e9Skais 	len += 4;
265c28749e9Skais 	cert_buf[len] = (uchar_t)server_hello_done;
266c28749e9Skais 	copy_int_to_bytearray(0, & cert_buf[len + 1]);
267c28749e9Skais 
268c28749e9Skais 	cert = kmem_alloc(sizeof (Certificate_t), KM_SLEEP);
269c28749e9Skais 	cert->msg = cert_buf;
270c28749e9Skais 	cert->len = cert_buf_len;
271c28749e9Skais 
272c28749e9Skais 	*certpp = cert;
273c28749e9Skais 
274c28749e9Skais 	return (0);
275c28749e9Skais }
276c28749e9Skais 
277c28749e9Skais static int
278c28749e9Skais extract_private_key(kssl_params_t *kssl_params, crypto_key_t **privkey)
279c28749e9Skais {
280c28749e9Skais 	char *begin = (char *)kssl_params;
281c28749e9Skais 	char *end_pos;
282c28749e9Skais 	int i, j, rv;
283c28749e9Skais 	size_t attrs_size;
2842ec7cc7fSKrishna Yenduri 	crypto_object_attribute_t *newattrs;
285c28749e9Skais 	char *mp_attrs;
286c28749e9Skais 	kssl_object_attribute_t att;
287c28749e9Skais 	char *attval;
288c28749e9Skais 	uint32_t attlen;
289c28749e9Skais 	crypto_key_t *kssl_privkey;
290c28749e9Skais 
291c28749e9Skais 	end_pos = (char *)kssl_params + kssl_params->kssl_params_size;
292c28749e9Skais 
293c28749e9Skais 	kssl_privkey = kmem_alloc(sizeof (crypto_key_t), KM_SLEEP);
294c28749e9Skais 
295c28749e9Skais 	kssl_privkey->ck_format = kssl_params->kssl_privkey.ks_format;
296c28749e9Skais 	kssl_privkey->ck_count = kssl_params->kssl_privkey.ks_count;
297c28749e9Skais 
298c28749e9Skais 	switch (kssl_privkey->ck_format) {
299c28749e9Skais 		case CRYPTO_KEY_ATTR_LIST:
300c28749e9Skais 			break;
301c28749e9Skais 		case CRYPTO_KEY_RAW:
302c28749e9Skais 		case CRYPTO_KEY_REFERENCE:
303c28749e9Skais 		default:
304c28749e9Skais 			rv = EINVAL;
305c28749e9Skais 			goto err1;
306c28749e9Skais 	}
307c28749e9Skais 
308c28749e9Skais 	/* allocate the attributes */
309c28749e9Skais 	attrs_size = kssl_privkey->ck_count *
310c28749e9Skais 	    sizeof (crypto_object_attribute_t);
311c28749e9Skais 
312c28749e9Skais 	mp_attrs = begin + kssl_params->kssl_privkey.ks_attrs_offset;
313c28749e9Skais 	if (mp_attrs + attrs_size > end_pos) {
314c28749e9Skais 		rv = EINVAL;
315c28749e9Skais 		goto err1;
316c28749e9Skais 	}
317c28749e9Skais 
318c892ebf1Skrishna 	newattrs = kmem_alloc(attrs_size, KM_SLEEP);
319c892ebf1Skrishna 
320c28749e9Skais 	/* Now the individual attributes */
321c28749e9Skais 	for (i = 0; i < kssl_privkey->ck_count; i++) {
322c28749e9Skais 		bcopy(mp_attrs, &att, sizeof (kssl_object_attribute_t));
323c28749e9Skais 
324c28749e9Skais 		mp_attrs += sizeof (kssl_object_attribute_t);
325c28749e9Skais 
326c28749e9Skais 		attval = begin + att.ka_value_offset;
327c28749e9Skais 		attlen = att.ka_value_len;
328c28749e9Skais 
329c28749e9Skais 		if (attval + attlen > end_pos) {
330c28749e9Skais 			rv = EINVAL;
331c28749e9Skais 			goto err2;
332c28749e9Skais 		}
333c28749e9Skais 
334c28749e9Skais 		newattrs[i].oa_type = att.ka_type;
335c28749e9Skais 		newattrs[i].oa_value_len = attlen;
336c892ebf1Skrishna 		newattrs[i].oa_value = kmem_alloc(attlen, KM_SLEEP);
337c28749e9Skais 
338c28749e9Skais 		bcopy(attval, newattrs[i].oa_value, attlen);
339c28749e9Skais 	}
340c28749e9Skais 
341c28749e9Skais 	kssl_privkey->ck_attrs = newattrs;
342c28749e9Skais 
343c28749e9Skais 	*privkey = kssl_privkey;
344c28749e9Skais 
345c28749e9Skais 	return (0);
346c28749e9Skais 
347c28749e9Skais err2:
348c28749e9Skais 	for (j = 0; j < i; j++) {
349c892ebf1Skrishna 		bzero(newattrs[j].oa_value, newattrs[j].oa_value_len);
350c28749e9Skais 		kmem_free(newattrs[j].oa_value, newattrs[j].oa_value_len);
351c28749e9Skais 	}
352c28749e9Skais 	kmem_free(newattrs, attrs_size);
353c28749e9Skais err1:
354c28749e9Skais 	kmem_free(kssl_privkey, sizeof (crypto_key_t));
355c28749e9Skais 	return (rv);
356c28749e9Skais }
357c28749e9Skais 
358c892ebf1Skrishna static int
359c892ebf1Skrishna create_sessinfo(kssl_params_t *kssl_params, kssl_entry_t *kssl_entry)
360c892ebf1Skrishna {
361c892ebf1Skrishna 	int rv;
362c892ebf1Skrishna 	char *p;
363c892ebf1Skrishna 	kssl_session_info_t *s;
364c892ebf1Skrishna 	kssl_tokinfo_t *t;
365c892ebf1Skrishna 
366c892ebf1Skrishna 	t =  &kssl_params->kssl_token;
367c892ebf1Skrishna 	/* Do a sanity check */
368c892ebf1Skrishna 	if (t->pinlen > MAX_PIN_LENGTH) {
369c892ebf1Skrishna 		return (EINVAL);
370c892ebf1Skrishna 	}
371c892ebf1Skrishna 
372c892ebf1Skrishna 	s = kmem_zalloc(sizeof (kssl_session_info_t) + t->pinlen, KM_SLEEP);
373c892ebf1Skrishna 	s->pinlen = t->pinlen;
374c892ebf1Skrishna 	bcopy(t->toklabel, s->toklabel, CRYPTO_EXT_SIZE_LABEL);
375c892ebf1Skrishna 	p = (char *)kssl_params + t->tokpin_offset;
376c892ebf1Skrishna 	bcopy(p, s->tokpin, s->pinlen);
377c892ebf1Skrishna 	ASSERT(kssl_entry->ke_sessinfo == NULL);
378c892ebf1Skrishna 	kssl_entry->ke_sessinfo = s;
379c892ebf1Skrishna 
380c892ebf1Skrishna 	/* Get the handle to the non extractable key */
381c892ebf1Skrishna 	rv = kssl_get_obj_handle(kssl_entry);
382c892ebf1Skrishna 	kssl_params->kssl_token.ck_rv = rv;
383c892ebf1Skrishna 	if (rv != CRYPTO_SUCCESS) {
384c892ebf1Skrishna 		sess_free(s);
385c892ebf1Skrishna 		kssl_entry->ke_sessinfo = NULL;
386c892ebf1Skrishna 		return (EINVAL);
387c892ebf1Skrishna 	}
388c892ebf1Skrishna 
389c892ebf1Skrishna 	kssl_entry->ke_sessinfo->is_valid_handle = B_TRUE;
390c892ebf1Skrishna 	kssl_entry->ke_sessinfo->do_reauth = B_FALSE;
391c892ebf1Skrishna 	kssl_entry->ke_sessinfo->evnt_handle =
392c892ebf1Skrishna 	    crypto_notify_events(kssl_prov_evnt,
393c892ebf1Skrishna 	    CRYPTO_EVENT_PROVIDER_REGISTERED |
394c892ebf1Skrishna 	    CRYPTO_EVENT_PROVIDER_UNREGISTERED);
395c892ebf1Skrishna 
396c892ebf1Skrishna 	return (0);
397c892ebf1Skrishna }
398c892ebf1Skrishna 
399c28749e9Skais static kssl_entry_t *
400c28749e9Skais create_kssl_entry(kssl_params_t *kssl_params, Certificate_t *cert,
401c28749e9Skais     crypto_key_t *privkey)
402c28749e9Skais {
403c28749e9Skais 	int i;
404c28749e9Skais 	uint16_t s;
4052bd70d4bSkrishna 	kssl_entry_t *kssl_entry, *ep;
406c28749e9Skais 	uint_t cnt, mech_count;
407c28749e9Skais 	crypto_mech_name_t *mechs;
408c28749e9Skais 	boolean_t got_rsa, got_md5, got_sha1, got_rc4, got_des, got_3des;
4092bd70d4bSkrishna 	boolean_t got_aes;
410c28749e9Skais 
411c28749e9Skais 	kssl_entry = kmem_zalloc(sizeof (kssl_entry_t), KM_SLEEP);
412c28749e9Skais 
4132ec7cc7fSKrishna Yenduri 	kssl_entry->ke_laddr = kssl_params->kssl_addr.sin6_addr;
4142ec7cc7fSKrishna Yenduri 	kssl_entry->ke_ssl_port = kssl_params->kssl_addr.sin6_port;
415c28749e9Skais 	kssl_entry->ke_proxy_port = kssl_params->kssl_proxy_port;
416c28749e9Skais 	if (kssl_params->kssl_session_cache_timeout == 0)
417c28749e9Skais 		kssl_entry->sid_cache_timeout = DEFAULT_SID_TIMEOUT;
418c28749e9Skais 	else
419c28749e9Skais 		kssl_entry->sid_cache_timeout =
420c28749e9Skais 		    kssl_params->kssl_session_cache_timeout;
421c28749e9Skais 	if (kssl_params->kssl_session_cache_size == 0)
422c28749e9Skais 		kssl_entry->sid_cache_nentries = DEFAULT_SID_CACHE_NENTRIES;
423c28749e9Skais 	else
424c28749e9Skais 		kssl_entry->sid_cache_nentries =
425c28749e9Skais 		    kssl_params->kssl_session_cache_size;
426c28749e9Skais 	kssl_entry->ke_private_key = privkey;
427c28749e9Skais 	kssl_entry->ke_server_certificate = cert;
428c28749e9Skais 
429c892ebf1Skrishna 	kssl_entry->ke_is_nxkey = kssl_params->kssl_is_nxkey;
430c892ebf1Skrishna 	if (kssl_entry->ke_is_nxkey) {
431c892ebf1Skrishna 		if (create_sessinfo(kssl_params, kssl_entry) != 0) {
432c892ebf1Skrishna 			kmem_free(kssl_entry, sizeof (kssl_entry_t));
433c892ebf1Skrishna 			return (NULL);
434c892ebf1Skrishna 		}
435c892ebf1Skrishna 	}
436c892ebf1Skrishna 
437c28749e9Skais 	mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
438c28749e9Skais 	if (mechs != NULL) {
439c28749e9Skais 		got_rsa = got_md5 = got_sha1 = got_rc4 =
4402bd70d4bSkrishna 		    got_des = got_3des = got_aes = B_FALSE;
441c28749e9Skais 		for (i = 0; i < mech_count; i++) {
442c28749e9Skais 			if (strncmp(SUN_CKM_RSA_X_509, mechs[i],
443c28749e9Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
444c28749e9Skais 				got_rsa = B_TRUE;
445c28749e9Skais 			else if (strncmp(SUN_CKM_MD5_HMAC, mechs[i],
446c28749e9Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
447c28749e9Skais 				got_md5 = B_TRUE;
448c28749e9Skais 			else if (strncmp(SUN_CKM_SHA1_HMAC, mechs[i],
449c28749e9Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
450c28749e9Skais 				got_sha1 = B_TRUE;
451c28749e9Skais 			else if (strncmp(SUN_CKM_RC4, mechs[i],
452c28749e9Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
453c28749e9Skais 				got_rc4 = B_TRUE;
454c28749e9Skais 			else if (strncmp(SUN_CKM_DES_CBC, mechs[i],
455c28749e9Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
456c28749e9Skais 				got_des = B_TRUE;
457c28749e9Skais 			else if (strncmp(SUN_CKM_DES3_CBC, mechs[i],
458c28749e9Skais 			    CRYPTO_MAX_MECH_NAME) == 0)
459c28749e9Skais 				got_3des = B_TRUE;
4602bd70d4bSkrishna 			else if (strncmp(SUN_CKM_AES_CBC, mechs[i],
4612bd70d4bSkrishna 			    CRYPTO_MAX_MECH_NAME) == 0)
4622bd70d4bSkrishna 				got_aes = B_TRUE;
463c28749e9Skais 		}
464c28749e9Skais 
465c28749e9Skais 		cnt = 0;
4662bd70d4bSkrishna 		ep = kssl_entry;
467c28749e9Skais 		for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++) {
468c28749e9Skais 			switch (s = kssl_params->kssl_suites[i]) {
469c28749e9Skais 			case SSL_RSA_WITH_RC4_128_MD5:
470c28749e9Skais 				if (got_rsa && got_rc4 && got_md5)
4712bd70d4bSkrishna 					ep->kssl_cipherSuites[cnt++] = s;
472c28749e9Skais 				break;
473c28749e9Skais 			case SSL_RSA_WITH_RC4_128_SHA:
474c28749e9Skais 				if (got_rsa && got_rc4 && got_sha1)
4752bd70d4bSkrishna 					ep->kssl_cipherSuites[cnt++] = s;
476c28749e9Skais 				break;
477c28749e9Skais 			case SSL_RSA_WITH_DES_CBC_SHA:
478c28749e9Skais 				if (got_rsa && got_des && got_sha1)
4792bd70d4bSkrishna 					ep->kssl_cipherSuites[cnt++] = s;
480c28749e9Skais 				break;
481c28749e9Skais 			case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
482c28749e9Skais 				if (got_rsa && got_3des && got_sha1)
4832bd70d4bSkrishna 					ep->kssl_cipherSuites[cnt++] = s;
4842bd70d4bSkrishna 				break;
4852bd70d4bSkrishna 			case TLS_RSA_WITH_AES_128_CBC_SHA:
4862bd70d4bSkrishna 				if (got_rsa && got_aes && got_sha1)
4872bd70d4bSkrishna 					ep->kssl_cipherSuites[cnt++] = s;
4882bd70d4bSkrishna 				break;
4892bd70d4bSkrishna 			case TLS_RSA_WITH_AES_256_CBC_SHA:
4902bd70d4bSkrishna 				if (got_rsa && got_aes && got_sha1)
4912bd70d4bSkrishna 					ep->kssl_cipherSuites[cnt++] = s;
492c28749e9Skais 				break;
493c28749e9Skais 			case CIPHER_NOTSET:
494c28749e9Skais 			default:
495c28749e9Skais 				break;
496c28749e9Skais 			}
497c28749e9Skais 		}
498c28749e9Skais 
499c28749e9Skais 		crypto_free_mech_list(mechs, mech_count);
500c28749e9Skais 	}
501c28749e9Skais 
502*65d18457SVladimir Kotal 	/*
503*65d18457SVladimir Kotal 	 * Add the no encryption suite to the end if requested by the
504*65d18457SVladimir Kotal 	 * kssl:null_cipher_suite /etc/system tunable since we do not want
505*65d18457SVladimir Kotal 	 * to be running with it by default.
506*65d18457SVladimir Kotal 	 */
507*65d18457SVladimir Kotal 	if (null_cipher_suite && got_rsa && got_sha1)
508c28749e9Skais 		kssl_entry->kssl_cipherSuites[cnt++] = SSL_RSA_WITH_NULL_SHA;
509c28749e9Skais 	kssl_entry->kssl_cipherSuites_nentries = cnt;
510c28749e9Skais 	for (i = 0; i < cnt; i++)
511c28749e9Skais 		kssl_entry->kssl_saved_Suites[i] =
512c28749e9Skais 		    kssl_entry->kssl_cipherSuites[i];
513c28749e9Skais 
514c28749e9Skais 	kssl_entry->sid_cache = kmem_alloc(
515c28749e9Skais 	    kssl_entry->sid_cache_nentries * sizeof (kssl_sid_ent_t), KM_SLEEP);
516c28749e9Skais 
517c28749e9Skais 	for (i = 0; i < kssl_entry->sid_cache_nentries; i++) {
518c28749e9Skais 		mutex_init(&(kssl_entry->sid_cache[i].se_lock), NULL,
519c28749e9Skais 		    MUTEX_DEFAULT, NULL);
520c28749e9Skais 		kssl_entry->sid_cache[i].se_used = 0;
521c28749e9Skais 		kssl_entry->sid_cache[i].se_sid.cached = B_FALSE;
522c28749e9Skais 	}
523c28749e9Skais 
524c28749e9Skais 	KSSL_ENTRY_REFHOLD(kssl_entry);
525c28749e9Skais 
526c28749e9Skais 	return (kssl_entry);
527c28749e9Skais }
528c28749e9Skais 
529c28749e9Skais int
530c28749e9Skais kssl_add_entry(kssl_params_t *kssl_params)
531c28749e9Skais {
532c28749e9Skais 	int rv, index, i;
533c28749e9Skais 	Certificate_t *cert;
534c28749e9Skais 	crypto_key_t *privkey;
535c28749e9Skais 	kssl_entry_t *kssl_entry;
5362ec7cc7fSKrishna Yenduri 	in6_addr_t laddr;
537c28749e9Skais 
538c28749e9Skais 	if ((rv = extract_certificate(kssl_params, &cert)) != 0) {
539c28749e9Skais 		return (rv);
540c28749e9Skais 	}
541c28749e9Skais 
542c28749e9Skais 	if ((rv = extract_private_key(kssl_params, &privkey)) != 0) {
543c28749e9Skais 		certificate_free(cert);
544c28749e9Skais 		return (rv);
545c28749e9Skais 	}
546c28749e9Skais 
547c28749e9Skais 	kssl_entry = create_kssl_entry(kssl_params, cert, privkey);
548c892ebf1Skrishna 	if (kssl_entry == NULL) {
549c892ebf1Skrishna 		certificate_free(cert);
550c892ebf1Skrishna 		privateKey_free(privkey);
551c892ebf1Skrishna 		return (EINVAL);
552c892ebf1Skrishna 	}
553c28749e9Skais 
5542ec7cc7fSKrishna Yenduri 	laddr = kssl_params->kssl_addr.sin6_addr;
555c28749e9Skais 
556c28749e9Skais retry:
557c28749e9Skais 	mutex_enter(&kssl_tab_mutex);
558c28749e9Skais 	/* Allocate the array first time here */
559c28749e9Skais 	if (kssl_entry_tab == NULL) {
560c28749e9Skais 		size_t allocsize;
561c28749e9Skais 		kssl_entry_t **tmp_tab;
562c28749e9Skais 		int tmp_size;
563c28749e9Skais 
564c28749e9Skais 		tmp_size = KSSL_TAB_INITSIZE;
565c28749e9Skais 		allocsize = tmp_size * sizeof (kssl_entry_t *);
566c28749e9Skais 		mutex_exit(&kssl_tab_mutex);
567c28749e9Skais 		tmp_tab = kmem_zalloc(allocsize, KM_SLEEP);
568c28749e9Skais 		mutex_enter(&kssl_tab_mutex);
569c28749e9Skais 		if (kssl_entry_tab != NULL) {
570c28749e9Skais 			mutex_exit(&kssl_tab_mutex);
571c28749e9Skais 			kmem_free(tmp_tab, allocsize);
572c28749e9Skais 			goto retry;
573c28749e9Skais 		}
574c28749e9Skais 		kssl_entry_tab_size = tmp_size;
575c28749e9Skais 		kssl_entry_tab = tmp_tab;
576c28749e9Skais 		index = 0;
577c28749e9Skais 	} else {
578c28749e9Skais 		/* Check if a matching entry exists already */
579c28749e9Skais 		index = kssl_find_entry(laddr,
5802ec7cc7fSKrishna Yenduri 		    kssl_params->kssl_addr.sin6_port, IS_SSL_PORT, B_TRUE);
581c28749e9Skais 
582c28749e9Skais 		if (index == -1) {
583c28749e9Skais 			/* Check if an entry with the same proxy port exists */
584c28749e9Skais 			if (kssl_find_entry(laddr, kssl_params->kssl_proxy_port,
585c28749e9Skais 			    IS_PROXY_PORT, B_TRUE) != -1) {
586c28749e9Skais 				mutex_exit(&kssl_tab_mutex);
587c28749e9Skais 				kssl_free_entry(kssl_entry);
588c28749e9Skais 				return (EADDRINUSE);
589c28749e9Skais 			}
590c28749e9Skais 
591c28749e9Skais 			/* No matching entry, find an empty spot */
592c28749e9Skais 			for (i = 0; i < kssl_entry_tab_size; i++) {
593c28749e9Skais 				if (kssl_entry_tab[i] == NULL)
594c28749e9Skais 					break;
595c28749e9Skais 			}
596c28749e9Skais 			/* Table full. Gotta grow it */
597c28749e9Skais 			if (i == kssl_entry_tab_size) {
598c28749e9Skais 				kssl_entry_t **new_tab, **old_tab;
599c28749e9Skais 				size_t allocsize;
600c28749e9Skais 				size_t oldtabsize = kssl_entry_tab_size *
601c28749e9Skais 				    sizeof (kssl_entry_t *);
602c28749e9Skais 				int tmp_size, old_size;
603c28749e9Skais 
604c28749e9Skais 				tmp_size = old_size = kssl_entry_tab_size;
605c28749e9Skais 				tmp_size += KSSL_TAB_INITSIZE;
606c28749e9Skais 				allocsize = tmp_size * sizeof (kssl_entry_t *);
607c28749e9Skais 				mutex_exit(&kssl_tab_mutex);
608c28749e9Skais 				new_tab = kmem_zalloc(allocsize, KM_SLEEP);
609c28749e9Skais 				mutex_enter(&kssl_tab_mutex);
610c28749e9Skais 				if (kssl_entry_tab_size > old_size) {
611c28749e9Skais 					mutex_exit(&kssl_tab_mutex);
612c28749e9Skais 					kmem_free(new_tab, allocsize);
613c28749e9Skais 					goto retry;
614c28749e9Skais 				}
615c28749e9Skais 
616c28749e9Skais 				kssl_entry_tab_size = tmp_size;
617c28749e9Skais 				bcopy(kssl_entry_tab, new_tab, oldtabsize);
618c28749e9Skais 
619c28749e9Skais 				old_tab = kssl_entry_tab;
620c28749e9Skais 				kssl_entry_tab = new_tab;
621c28749e9Skais 
622c28749e9Skais 				kmem_free(old_tab, oldtabsize);
623c28749e9Skais 			}
624c28749e9Skais 			index = i;
625c28749e9Skais 		} else {
6262ec7cc7fSKrishna Yenduri 			kssl_entry_t *ep;
6272ec7cc7fSKrishna Yenduri 
628c28749e9Skais 			/*
629c28749e9Skais 			 * We do not want an entry with a specific address and
630c28749e9Skais 			 * an entry with IN_ADDR_ANY to coexist. We could
631c28749e9Skais 			 * replace the existing entry. But, most likely this
632c28749e9Skais 			 * is misconfiguration. Better bail out with an error.
633c28749e9Skais 			 */
6342ec7cc7fSKrishna Yenduri 			ep = kssl_entry_tab[index];
6352ec7cc7fSKrishna Yenduri 
6362ec7cc7fSKrishna Yenduri 			if ((IN6_IS_ADDR_UNSPECIFIED(&laddr) &&
6372ec7cc7fSKrishna Yenduri 			    !IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr)) ||
6382ec7cc7fSKrishna Yenduri 			    (!IN6_IS_ADDR_UNSPECIFIED(&laddr) &&
6392ec7cc7fSKrishna Yenduri 			    IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr))) {
640c28749e9Skais 				mutex_exit(&kssl_tab_mutex);
641c28749e9Skais 				kssl_free_entry(kssl_entry);
642c28749e9Skais 				return (EEXIST);
643c28749e9Skais 			}
644c28749e9Skais 
645c28749e9Skais 			/* Replace the existing entry */
646c28749e9Skais 			KSSL_ENTRY_REFRELE(kssl_entry_tab[index]);
647c28749e9Skais 			kssl_entry_tab[index] = NULL;
648c28749e9Skais 			kssl_entry_tab_nentries--;
649c28749e9Skais 		}
650c28749e9Skais 	}
651c28749e9Skais 
652c28749e9Skais 	kssl_entry_tab[index] = kssl_entry;
653c28749e9Skais 	kssl_entry_tab_nentries++;
654c28749e9Skais 	mutex_exit(&kssl_tab_mutex);
655c28749e9Skais 
656c28749e9Skais 	return (0);
657c28749e9Skais }
658c28749e9Skais 
659c28749e9Skais int
6602ec7cc7fSKrishna Yenduri kssl_delete_entry(struct sockaddr_in6 *kssl_addr)
661c28749e9Skais {
6622ec7cc7fSKrishna Yenduri 	in6_addr_t laddr;
663c28749e9Skais 	int index;
664c28749e9Skais 
6652ec7cc7fSKrishna Yenduri 	laddr = kssl_addr->sin6_addr;
666c28749e9Skais 
667c28749e9Skais 	mutex_enter(&kssl_tab_mutex);
6682ec7cc7fSKrishna Yenduri 	index = kssl_find_entry(laddr, kssl_addr->sin6_port,
669c28749e9Skais 	    IS_SSL_PORT, B_FALSE);
670c28749e9Skais 
671c28749e9Skais 	if (index == -1) {
672c28749e9Skais 		mutex_exit(&kssl_tab_mutex);
673c28749e9Skais 		return (ENOENT);
674c28749e9Skais 	}
675c28749e9Skais 
676c28749e9Skais 	KSSL_ENTRY_REFRELE(kssl_entry_tab[index]);
677c28749e9Skais 	kssl_entry_tab[index] = NULL;
678c28749e9Skais 	kssl_entry_tab_nentries--;
679c28749e9Skais 
680c28749e9Skais 	mutex_exit(&kssl_tab_mutex);
681c28749e9Skais 
682c28749e9Skais 	return (0);
683c28749e9Skais }
684c892ebf1Skrishna 
685c892ebf1Skrishna /*
686c892ebf1Skrishna  * We care about only one private key object.
687c892ebf1Skrishna  * So, set the max count to only 1.
688c892ebf1Skrishna  */
689c892ebf1Skrishna #define	MAX_OBJECT_COUNT	1
690c892ebf1Skrishna 
691c892ebf1Skrishna /*
692c892ebf1Skrishna  * Open a session to the provider specified by the label and
693c892ebf1Skrishna  * authenticate to it. Find the private key object with the
694c892ebf1Skrishna  * specified  attributes and save the handle. The userland component
695c892ebf1Skrishna  * must set all the attributes in the template so as to uniquely
696c892ebf1Skrishna  * identify the object.
697c892ebf1Skrishna  *
698c892ebf1Skrishna  * Note that the handle will be invalid if we logout or close
699c892ebf1Skrishna  * the session to the provider.
700c892ebf1Skrishna  */
701c892ebf1Skrishna int
702c892ebf1Skrishna kssl_get_obj_handle(kssl_entry_t *kp)
703c892ebf1Skrishna {
704c892ebf1Skrishna 	int rv;
705c892ebf1Skrishna 	unsigned int count;
706c892ebf1Skrishna 	void *cookie = NULL;
707c892ebf1Skrishna 	crypto_provider_t prov;
708c892ebf1Skrishna 	kssl_session_info_t *s;
709c892ebf1Skrishna 	crypto_session_id_t sid;
710c892ebf1Skrishna 	crypto_object_attribute_t *attrs;
711c892ebf1Skrishna 	crypto_object_id_t ohndl[MAX_OBJECT_COUNT];
712c892ebf1Skrishna 	char label[CRYPTO_EXT_SIZE_LABEL + 1];
713c892ebf1Skrishna 
714c892ebf1Skrishna 	ASSERT(kp->ke_is_nxkey);
715c892ebf1Skrishna 	s = kp->ke_sessinfo;
716c892ebf1Skrishna 
717c892ebf1Skrishna 	bcopy(s->toklabel, label, CRYPTO_EXT_SIZE_LABEL);
718c892ebf1Skrishna 	label[CRYPTO_EXT_SIZE_LABEL] = '\0';
719c892ebf1Skrishna 	prov = crypto_get_provider(label, NULL, NULL);
720c892ebf1Skrishna 	if (prov == NULL)
721c892ebf1Skrishna 		return (CRYPTO_UNKNOWN_PROVIDER);
722c892ebf1Skrishna 
723c892ebf1Skrishna 	rv = crypto_session_open(prov, &sid, NULL);
724c892ebf1Skrishna 	if (rv != CRYPTO_SUCCESS) {
725c892ebf1Skrishna 		goto err1;
726c892ebf1Skrishna 	}
727c892ebf1Skrishna 
728c892ebf1Skrishna 	rv = crypto_session_login(prov, sid, CRYPTO_USER,
729c892ebf1Skrishna 	    s->tokpin, s->pinlen, NULL);
730c892ebf1Skrishna 	if (rv != CRYPTO_SUCCESS) {
731c892ebf1Skrishna 		goto err2;
732c892ebf1Skrishna 	}
733c892ebf1Skrishna 
734c892ebf1Skrishna 	count = kp->ke_private_key->ck_count;
735c892ebf1Skrishna 	attrs = kp->ke_private_key->ck_attrs;
736c892ebf1Skrishna 
737c892ebf1Skrishna 	rv = crypto_object_find_init(prov, sid, attrs, count, &cookie, NULL);
738c892ebf1Skrishna 	if (rv != CRYPTO_SUCCESS) {
739c892ebf1Skrishna 		goto err3;
740c892ebf1Skrishna 	}
741c892ebf1Skrishna 
742c892ebf1Skrishna 	rv = crypto_object_find(prov, cookie, ohndl, &count,
743c892ebf1Skrishna 	    MAX_OBJECT_COUNT, NULL);
744c892ebf1Skrishna 	if (rv != CRYPTO_SUCCESS || count == 0) {
745c892ebf1Skrishna 		if (count == 0)
746c892ebf1Skrishna 			rv = CRYPTO_FAILED;
747c892ebf1Skrishna 		goto err3;
748c892ebf1Skrishna 	}
749c892ebf1Skrishna 
750c892ebf1Skrishna 	(void) crypto_object_find_final(prov, cookie, NULL);
751c892ebf1Skrishna 
752c892ebf1Skrishna 	s->sid = sid;
753c892ebf1Skrishna 	s->prov = prov;
754c892ebf1Skrishna 	s->key.ck_format = CRYPTO_KEY_REFERENCE;
755c892ebf1Skrishna 	/* Keep the handle around for later use */
756c892ebf1Skrishna 	s->key.ck_obj_id = ohndl[0];
757c892ebf1Skrishna 
758c892ebf1Skrishna 	return (CRYPTO_SUCCESS);
759c892ebf1Skrishna 
760c892ebf1Skrishna err3:
761c892ebf1Skrishna 	(void) crypto_session_logout(prov, sid, NULL);
762c892ebf1Skrishna err2:
763c892ebf1Skrishna 	(void) crypto_session_close(prov, sid, NULL);
764c892ebf1Skrishna err1:
765c892ebf1Skrishna 	crypto_release_provider(prov);
766c892ebf1Skrishna 	return (rv);
767c892ebf1Skrishna }
768