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*11984SVladimir.Kotal@Sun.COM * Copyright 2010 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;
56*11984SVladimir.Kotal@Sun.COM uint_t null_cipher_suite; /* setable in /etc/system */
57898Skais kmutex_t kssl_tab_mutex;
58898Skais
59898Skais static void
certificate_free(Certificate_t * cert)60898Skais certificate_free(Certificate_t *cert)
61898Skais {
62898Skais kmem_free(cert->msg, cert->len);
63898Skais kmem_free(cert, sizeof (struct Certificate));
64898Skais }
65898Skais
66898Skais static void
privateKey_free(crypto_key_t * privkey)67898Skais privateKey_free(crypto_key_t *privkey)
68898Skais {
692800Skrishna int i;
702800Skrishna size_t attrs_size;
712800Skrishna crypto_object_attribute_t *attrs;
72898Skais
732800Skrishna attrs = privkey->ck_attrs;
742800Skrishna attrs_size = privkey->ck_count * sizeof (crypto_object_attribute_t);
75898Skais for (i = 0; i < privkey->ck_count; i++) {
76898Skais bzero(attrs[i].oa_value, attrs[i].oa_value_len);
77898Skais kmem_free(attrs[i].oa_value, attrs[i].oa_value_len);
78898Skais }
79898Skais kmem_free(attrs, attrs_size);
80898Skais kmem_free(privkey, sizeof (crypto_key_t));
81898Skais }
82898Skais
832800Skrishna static void
sess_free(kssl_session_info_t * s)842800Skrishna sess_free(kssl_session_info_t *s)
852800Skrishna {
862800Skrishna if (s->is_valid_handle) {
872800Skrishna (void) crypto_session_logout(s->prov, s->sid, NULL);
882800Skrishna (void) crypto_session_close(s->prov, s->sid, NULL);
892800Skrishna crypto_release_provider(s->prov);
902800Skrishna s->is_valid_handle = B_FALSE;
912800Skrishna }
922800Skrishna
932800Skrishna if (s->evnt_handle != NULL) {
942800Skrishna crypto_unnotify_events(s->evnt_handle);
952800Skrishna s->evnt_handle = NULL;
962800Skrishna }
972800Skrishna
982800Skrishna bzero(s->tokpin, s->pinlen);
992800Skrishna kmem_free(s, sizeof (kssl_session_info_t) + s->pinlen);
1002800Skrishna }
1012800Skrishna
102898Skais /*
103898Skais * Frees the space for the entry and the keys and certs
104898Skais * it carries.
105898Skais */
106898Skais void
kssl_free_entry(kssl_entry_t * kssl_entry)107898Skais kssl_free_entry(kssl_entry_t *kssl_entry)
108898Skais {
109898Skais int i;
110898Skais Certificate_t *cert;
111898Skais crypto_key_t *privkey;
1122800Skrishna kssl_session_info_t *s;
113898Skais
114898Skais if (kssl_entry->ke_no_freeall) {
115898Skais kmem_free(kssl_entry, sizeof (kssl_entry_t));
116898Skais return;
117898Skais }
118898Skais
119898Skais if ((cert = kssl_entry->ke_server_certificate) != NULL) {
120898Skais certificate_free(cert);
121898Skais }
122898Skais
123898Skais if ((privkey = kssl_entry->ke_private_key) != NULL) {
124898Skais privateKey_free(privkey);
1252800Skrishna }
126898Skais
127898Skais for (i = 0; i < kssl_entry->sid_cache_nentries; i++)
128898Skais mutex_destroy(&(kssl_entry->sid_cache[i].se_lock));
129898Skais
130898Skais kmem_free(kssl_entry->sid_cache,
131898Skais kssl_entry->sid_cache_nentries * sizeof (kssl_sid_ent_t));
132898Skais
133898Skais ASSERT(kssl_entry->ke_proxy_head == NULL);
134898Skais ASSERT(kssl_entry->ke_fallback_head == NULL);
135898Skais
1362800Skrishna if ((s = kssl_entry->ke_sessinfo) != NULL) {
1372800Skrishna ASSERT(kssl_entry->ke_is_nxkey);
1382800Skrishna sess_free(s);
1392800Skrishna }
1402800Skrishna
141898Skais kmem_free(kssl_entry, sizeof (kssl_entry_t));
142898Skais }
143898Skais
144898Skais /*
145898Skais * Returns the index of the entry in kssl_entry_tab[] that matches
146898Skais * the address and port. Returns -1 if no match is found.
147898Skais */
148898Skais static int
kssl_find_entry(in6_addr_t laddr,in_port_t port,int type,boolean_t wild_card_match)14910520SBhargava.Yenduri@Sun.COM kssl_find_entry(in6_addr_t laddr, in_port_t port, int type,
150898Skais boolean_t wild_card_match)
151898Skais {
152898Skais int i;
153898Skais kssl_entry_t *ep;
154898Skais
155898Skais ASSERT(MUTEX_HELD(&kssl_tab_mutex));
156898Skais
157898Skais for (i = 0; i < kssl_entry_tab_size; i++) {
158898Skais ep = kssl_entry_tab[i];
159898Skais if (ep == NULL)
160898Skais continue;
161898Skais
162898Skais if (!((type == IS_SSL_PORT && ep->ke_ssl_port == port) ||
163898Skais (type == IS_PROXY_PORT && ep->ke_proxy_port == port)))
164898Skais continue;
165898Skais
16610520SBhargava.Yenduri@Sun.COM if (IN6_ARE_ADDR_EQUAL(&laddr, &ep->ke_laddr) ||
16710520SBhargava.Yenduri@Sun.COM (wild_card_match && (IN6_IS_ADDR_UNSPECIFIED(&laddr) ||
16810520SBhargava.Yenduri@Sun.COM IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr))))
169898Skais break;
170898Skais }
171898Skais
172898Skais if (i == kssl_entry_tab_size)
173898Skais return (-1);
174898Skais
175898Skais return (i);
176898Skais }
177898Skais
178898Skais static void
copy_int_to_bytearray(int x,uchar_t * buf)179898Skais copy_int_to_bytearray(int x, uchar_t *buf)
180898Skais {
181898Skais buf[0] = (x >> 16) & 0xff;
182898Skais buf[1] = (x >> 8) & 0xff;
183898Skais buf[2] = (x) & 0xff;
184898Skais }
185898Skais
186898Skais static int
extract_certificate(kssl_params_t * kssl_params,Certificate_t ** certpp)187898Skais extract_certificate(kssl_params_t *kssl_params, Certificate_t **certpp)
188898Skais {
189898Skais int i, len;
190898Skais uint64_t in_size;
191898Skais uchar_t *end_pos;
192898Skais uint32_t ncert;
193898Skais uint32_t *cert_sizes;
194898Skais Certificate_t *cert;
195898Skais char *begin = (char *)kssl_params;
196898Skais uchar_t *cert_buf;
197898Skais int cert_buf_len;
198898Skais uchar_t *cert_from, *cert_to;
199898Skais
200898Skais ASSERT(kssl_params);
201898Skais
202898Skais in_size = kssl_params->kssl_params_size;
203898Skais end_pos = (uchar_t *)kssl_params + in_size;
204898Skais
205898Skais /*
206898Skais * Get the certs array. First the array of sizes, then the actual
207898Skais * certs.
208898Skais */
209898Skais ncert = kssl_params->kssl_certs.sc_count;
210898Skais
211898Skais if (ncert == 0) {
212898Skais /* no certs in here! why did ya call? */
213898Skais return (EINVAL);
214898Skais }
215898Skais if (in_size < (sizeof (kssl_params_t) + ncert * sizeof (uint32_t))) {
216898Skais return (EINVAL);
217898Skais }
218898Skais
2192800Skrishna /* Trusting that the system call preserved the 4-byte alignment */
220898Skais cert_sizes = (uint32_t *)(begin +
221898Skais kssl_params->kssl_certs.sc_sizes_offset);
222898Skais
223898Skais /* should this be an ASSERT()? */
224898Skais if (!IS_P2ALIGNED(cert_sizes, sizeof (uint32_t))) {
225898Skais return (EINVAL);
226898Skais }
227898Skais
228898Skais len = 0;
229898Skais for (i = 0; i < ncert; i++) {
230898Skais if (cert_sizes[i] < 1) {
231898Skais return (EINVAL);
232898Skais }
233898Skais len += cert_sizes[i] + 3;
234898Skais }
235898Skais
236898Skais len += 3; /* length of certificate message without msg header */
237898Skais
238898Skais cert_buf_len = len + 4 + 4; /* add space for msg headers */
239898Skais
240898Skais cert_buf = kmem_alloc(cert_buf_len, KM_SLEEP);
241898Skais
242898Skais cert_buf[0] = (uchar_t)certificate;
243898Skais copy_int_to_bytearray(len, & cert_buf[1]);
244898Skais copy_int_to_bytearray(len - 3, & cert_buf[4]);
245898Skais
246898Skais cert_from = (uchar_t *)(begin +
247898Skais kssl_params->kssl_certs.sc_certs_offset);
248898Skais cert_to = &cert_buf[7];
249898Skais
250898Skais for (i = 0; i < ncert; i++) {
251898Skais copy_int_to_bytearray(cert_sizes[i], cert_to);
252898Skais cert_to += 3;
253898Skais
254898Skais if (cert_from + cert_sizes[i] > end_pos) {
255898Skais kmem_free(cert_buf, cert_buf_len);
256898Skais return (EINVAL);
257898Skais }
258898Skais
259898Skais bcopy(cert_from, cert_to, cert_sizes[i]);
260898Skais cert_from += cert_sizes[i];
261898Skais cert_to += cert_sizes[i];
262898Skais }
263898Skais
264898Skais len += 4;
265898Skais cert_buf[len] = (uchar_t)server_hello_done;
266898Skais copy_int_to_bytearray(0, & cert_buf[len + 1]);
267898Skais
268898Skais cert = kmem_alloc(sizeof (Certificate_t), KM_SLEEP);
269898Skais cert->msg = cert_buf;
270898Skais cert->len = cert_buf_len;
271898Skais
272898Skais *certpp = cert;
273898Skais
274898Skais return (0);
275898Skais }
276898Skais
277898Skais static int
extract_private_key(kssl_params_t * kssl_params,crypto_key_t ** privkey)278898Skais extract_private_key(kssl_params_t *kssl_params, crypto_key_t **privkey)
279898Skais {
280898Skais char *begin = (char *)kssl_params;
281898Skais char *end_pos;
282898Skais int i, j, rv;
283898Skais size_t attrs_size;
28410520SBhargava.Yenduri@Sun.COM crypto_object_attribute_t *newattrs;
285898Skais char *mp_attrs;
286898Skais kssl_object_attribute_t att;
287898Skais char *attval;
288898Skais uint32_t attlen;
289898Skais crypto_key_t *kssl_privkey;
290898Skais
291898Skais end_pos = (char *)kssl_params + kssl_params->kssl_params_size;
292898Skais
293898Skais kssl_privkey = kmem_alloc(sizeof (crypto_key_t), KM_SLEEP);
294898Skais
295898Skais kssl_privkey->ck_format = kssl_params->kssl_privkey.ks_format;
296898Skais kssl_privkey->ck_count = kssl_params->kssl_privkey.ks_count;
297898Skais
298898Skais switch (kssl_privkey->ck_format) {
299898Skais case CRYPTO_KEY_ATTR_LIST:
300898Skais break;
301898Skais case CRYPTO_KEY_RAW:
302898Skais case CRYPTO_KEY_REFERENCE:
303898Skais default:
304898Skais rv = EINVAL;
305898Skais goto err1;
306898Skais }
307898Skais
308898Skais /* allocate the attributes */
309898Skais attrs_size = kssl_privkey->ck_count *
310898Skais sizeof (crypto_object_attribute_t);
311898Skais
312898Skais mp_attrs = begin + kssl_params->kssl_privkey.ks_attrs_offset;
313898Skais if (mp_attrs + attrs_size > end_pos) {
314898Skais rv = EINVAL;
315898Skais goto err1;
316898Skais }
317898Skais
3182800Skrishna newattrs = kmem_alloc(attrs_size, KM_SLEEP);
3192800Skrishna
320898Skais /* Now the individual attributes */
321898Skais for (i = 0; i < kssl_privkey->ck_count; i++) {
322898Skais bcopy(mp_attrs, &att, sizeof (kssl_object_attribute_t));
323898Skais
324898Skais mp_attrs += sizeof (kssl_object_attribute_t);
325898Skais
326898Skais attval = begin + att.ka_value_offset;
327898Skais attlen = att.ka_value_len;
328898Skais
329898Skais if (attval + attlen > end_pos) {
330898Skais rv = EINVAL;
331898Skais goto err2;
332898Skais }
333898Skais
334898Skais newattrs[i].oa_type = att.ka_type;
335898Skais newattrs[i].oa_value_len = attlen;
3362800Skrishna newattrs[i].oa_value = kmem_alloc(attlen, KM_SLEEP);
337898Skais
338898Skais bcopy(attval, newattrs[i].oa_value, attlen);
339898Skais }
340898Skais
341898Skais kssl_privkey->ck_attrs = newattrs;
342898Skais
343898Skais *privkey = kssl_privkey;
344898Skais
345898Skais return (0);
346898Skais
347898Skais err2:
348898Skais for (j = 0; j < i; j++) {
3492800Skrishna bzero(newattrs[j].oa_value, newattrs[j].oa_value_len);
350898Skais kmem_free(newattrs[j].oa_value, newattrs[j].oa_value_len);
351898Skais }
352898Skais kmem_free(newattrs, attrs_size);
353898Skais err1:
354898Skais kmem_free(kssl_privkey, sizeof (crypto_key_t));
355898Skais return (rv);
356898Skais }
357898Skais
3582800Skrishna static int
create_sessinfo(kssl_params_t * kssl_params,kssl_entry_t * kssl_entry)3592800Skrishna create_sessinfo(kssl_params_t *kssl_params, kssl_entry_t *kssl_entry)
3602800Skrishna {
3612800Skrishna int rv;
3622800Skrishna char *p;
3632800Skrishna kssl_session_info_t *s;
3642800Skrishna kssl_tokinfo_t *t;
3652800Skrishna
3662800Skrishna t = &kssl_params->kssl_token;
3672800Skrishna /* Do a sanity check */
3682800Skrishna if (t->pinlen > MAX_PIN_LENGTH) {
3692800Skrishna return (EINVAL);
3702800Skrishna }
3712800Skrishna
3722800Skrishna s = kmem_zalloc(sizeof (kssl_session_info_t) + t->pinlen, KM_SLEEP);
3732800Skrishna s->pinlen = t->pinlen;
3742800Skrishna bcopy(t->toklabel, s->toklabel, CRYPTO_EXT_SIZE_LABEL);
3752800Skrishna p = (char *)kssl_params + t->tokpin_offset;
3762800Skrishna bcopy(p, s->tokpin, s->pinlen);
3772800Skrishna ASSERT(kssl_entry->ke_sessinfo == NULL);
3782800Skrishna kssl_entry->ke_sessinfo = s;
3792800Skrishna
3802800Skrishna /* Get the handle to the non extractable key */
3812800Skrishna rv = kssl_get_obj_handle(kssl_entry);
3822800Skrishna kssl_params->kssl_token.ck_rv = rv;
3832800Skrishna if (rv != CRYPTO_SUCCESS) {
3842800Skrishna sess_free(s);
3852800Skrishna kssl_entry->ke_sessinfo = NULL;
3862800Skrishna return (EINVAL);
3872800Skrishna }
3882800Skrishna
3892800Skrishna kssl_entry->ke_sessinfo->is_valid_handle = B_TRUE;
3902800Skrishna kssl_entry->ke_sessinfo->do_reauth = B_FALSE;
3912800Skrishna kssl_entry->ke_sessinfo->evnt_handle =
3922800Skrishna crypto_notify_events(kssl_prov_evnt,
3936788Skrishna CRYPTO_EVENT_PROVIDER_REGISTERED |
3946788Skrishna CRYPTO_EVENT_PROVIDER_UNREGISTERED);
3952800Skrishna
3962800Skrishna return (0);
3972800Skrishna }
3982800Skrishna
399898Skais static kssl_entry_t *
create_kssl_entry(kssl_params_t * kssl_params,Certificate_t * cert,crypto_key_t * privkey)400898Skais create_kssl_entry(kssl_params_t *kssl_params, Certificate_t *cert,
401898Skais crypto_key_t *privkey)
402898Skais {
403898Skais int i;
404898Skais uint16_t s;
4056788Skrishna kssl_entry_t *kssl_entry, *ep;
406898Skais uint_t cnt, mech_count;
407898Skais crypto_mech_name_t *mechs;
408898Skais boolean_t got_rsa, got_md5, got_sha1, got_rc4, got_des, got_3des;
4096788Skrishna boolean_t got_aes;
410898Skais
411898Skais kssl_entry = kmem_zalloc(sizeof (kssl_entry_t), KM_SLEEP);
412898Skais
41310520SBhargava.Yenduri@Sun.COM kssl_entry->ke_laddr = kssl_params->kssl_addr.sin6_addr;
41410520SBhargava.Yenduri@Sun.COM kssl_entry->ke_ssl_port = kssl_params->kssl_addr.sin6_port;
415898Skais kssl_entry->ke_proxy_port = kssl_params->kssl_proxy_port;
416898Skais if (kssl_params->kssl_session_cache_timeout == 0)
417898Skais kssl_entry->sid_cache_timeout = DEFAULT_SID_TIMEOUT;
418898Skais else
419898Skais kssl_entry->sid_cache_timeout =
420898Skais kssl_params->kssl_session_cache_timeout;
421898Skais if (kssl_params->kssl_session_cache_size == 0)
422898Skais kssl_entry->sid_cache_nentries = DEFAULT_SID_CACHE_NENTRIES;
423898Skais else
424898Skais kssl_entry->sid_cache_nentries =
425898Skais kssl_params->kssl_session_cache_size;
426898Skais kssl_entry->ke_private_key = privkey;
427898Skais kssl_entry->ke_server_certificate = cert;
428898Skais
4292800Skrishna kssl_entry->ke_is_nxkey = kssl_params->kssl_is_nxkey;
4302800Skrishna if (kssl_entry->ke_is_nxkey) {
4312800Skrishna if (create_sessinfo(kssl_params, kssl_entry) != 0) {
4322800Skrishna kmem_free(kssl_entry, sizeof (kssl_entry_t));
4332800Skrishna return (NULL);
4342800Skrishna }
4352800Skrishna }
4362800Skrishna
437898Skais mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
438898Skais if (mechs != NULL) {
439898Skais got_rsa = got_md5 = got_sha1 = got_rc4 =
4406788Skrishna got_des = got_3des = got_aes = B_FALSE;
441898Skais for (i = 0; i < mech_count; i++) {
442898Skais if (strncmp(SUN_CKM_RSA_X_509, mechs[i],
443898Skais CRYPTO_MAX_MECH_NAME) == 0)
444898Skais got_rsa = B_TRUE;
445898Skais else if (strncmp(SUN_CKM_MD5_HMAC, mechs[i],
446898Skais CRYPTO_MAX_MECH_NAME) == 0)
447898Skais got_md5 = B_TRUE;
448898Skais else if (strncmp(SUN_CKM_SHA1_HMAC, mechs[i],
449898Skais CRYPTO_MAX_MECH_NAME) == 0)
450898Skais got_sha1 = B_TRUE;
451898Skais else if (strncmp(SUN_CKM_RC4, mechs[i],
452898Skais CRYPTO_MAX_MECH_NAME) == 0)
453898Skais got_rc4 = B_TRUE;
454898Skais else if (strncmp(SUN_CKM_DES_CBC, mechs[i],
455898Skais CRYPTO_MAX_MECH_NAME) == 0)
456898Skais got_des = B_TRUE;
457898Skais else if (strncmp(SUN_CKM_DES3_CBC, mechs[i],
458898Skais CRYPTO_MAX_MECH_NAME) == 0)
459898Skais got_3des = B_TRUE;
4606788Skrishna else if (strncmp(SUN_CKM_AES_CBC, mechs[i],
4616788Skrishna CRYPTO_MAX_MECH_NAME) == 0)
4626788Skrishna got_aes = B_TRUE;
463898Skais }
464898Skais
465898Skais cnt = 0;
4666788Skrishna ep = kssl_entry;
467898Skais for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++) {
468898Skais switch (s = kssl_params->kssl_suites[i]) {
469898Skais case SSL_RSA_WITH_RC4_128_MD5:
470898Skais if (got_rsa && got_rc4 && got_md5)
4716788Skrishna ep->kssl_cipherSuites[cnt++] = s;
472898Skais break;
473898Skais case SSL_RSA_WITH_RC4_128_SHA:
474898Skais if (got_rsa && got_rc4 && got_sha1)
4756788Skrishna ep->kssl_cipherSuites[cnt++] = s;
476898Skais break;
477898Skais case SSL_RSA_WITH_DES_CBC_SHA:
478898Skais if (got_rsa && got_des && got_sha1)
4796788Skrishna ep->kssl_cipherSuites[cnt++] = s;
480898Skais break;
481898Skais case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
482898Skais if (got_rsa && got_3des && got_sha1)
4836788Skrishna ep->kssl_cipherSuites[cnt++] = s;
4846788Skrishna break;
4856788Skrishna case TLS_RSA_WITH_AES_128_CBC_SHA:
4866788Skrishna if (got_rsa && got_aes && got_sha1)
4876788Skrishna ep->kssl_cipherSuites[cnt++] = s;
4886788Skrishna break;
4896788Skrishna case TLS_RSA_WITH_AES_256_CBC_SHA:
4906788Skrishna if (got_rsa && got_aes && got_sha1)
4916788Skrishna ep->kssl_cipherSuites[cnt++] = s;
492898Skais break;
493898Skais case CIPHER_NOTSET:
494898Skais default:
495898Skais break;
496898Skais }
497898Skais }
498898Skais
499898Skais crypto_free_mech_list(mechs, mech_count);
500898Skais }
501898Skais
502*11984SVladimir.Kotal@Sun.COM /*
503*11984SVladimir.Kotal@Sun.COM * Add the no encryption suite to the end if requested by the
504*11984SVladimir.Kotal@Sun.COM * kssl:null_cipher_suite /etc/system tunable since we do not want
505*11984SVladimir.Kotal@Sun.COM * to be running with it by default.
506*11984SVladimir.Kotal@Sun.COM */
507*11984SVladimir.Kotal@Sun.COM if (null_cipher_suite && got_rsa && got_sha1)
508*11984SVladimir.Kotal@Sun.COM kssl_entry->kssl_cipherSuites[cnt++] = SSL_RSA_WITH_NULL_SHA;
509898Skais kssl_entry->kssl_cipherSuites_nentries = cnt;
510898Skais for (i = 0; i < cnt; i++)
511898Skais kssl_entry->kssl_saved_Suites[i] =
512898Skais kssl_entry->kssl_cipherSuites[i];
513898Skais
514898Skais kssl_entry->sid_cache = kmem_alloc(
515898Skais kssl_entry->sid_cache_nentries * sizeof (kssl_sid_ent_t), KM_SLEEP);
516898Skais
517898Skais for (i = 0; i < kssl_entry->sid_cache_nentries; i++) {
518898Skais mutex_init(&(kssl_entry->sid_cache[i].se_lock), NULL,
519898Skais MUTEX_DEFAULT, NULL);
520898Skais kssl_entry->sid_cache[i].se_used = 0;
521898Skais kssl_entry->sid_cache[i].se_sid.cached = B_FALSE;
522898Skais }
523898Skais
524898Skais KSSL_ENTRY_REFHOLD(kssl_entry);
525898Skais
526898Skais return (kssl_entry);
527898Skais }
528898Skais
529898Skais int
kssl_add_entry(kssl_params_t * kssl_params)530898Skais kssl_add_entry(kssl_params_t *kssl_params)
531898Skais {
532898Skais int rv, index, i;
533898Skais Certificate_t *cert;
534898Skais crypto_key_t *privkey;
535898Skais kssl_entry_t *kssl_entry;
53610520SBhargava.Yenduri@Sun.COM in6_addr_t laddr;
537898Skais
538898Skais if ((rv = extract_certificate(kssl_params, &cert)) != 0) {
539898Skais return (rv);
540898Skais }
541898Skais
542898Skais if ((rv = extract_private_key(kssl_params, &privkey)) != 0) {
543898Skais certificate_free(cert);
544898Skais return (rv);
545898Skais }
546898Skais
547898Skais kssl_entry = create_kssl_entry(kssl_params, cert, privkey);
5482800Skrishna if (kssl_entry == NULL) {
5492800Skrishna certificate_free(cert);
5502800Skrishna privateKey_free(privkey);
5512800Skrishna return (EINVAL);
5522800Skrishna }
553898Skais
55410520SBhargava.Yenduri@Sun.COM laddr = kssl_params->kssl_addr.sin6_addr;
555898Skais
556898Skais retry:
557898Skais mutex_enter(&kssl_tab_mutex);
558898Skais /* Allocate the array first time here */
559898Skais if (kssl_entry_tab == NULL) {
560898Skais size_t allocsize;
561898Skais kssl_entry_t **tmp_tab;
562898Skais int tmp_size;
563898Skais
564898Skais tmp_size = KSSL_TAB_INITSIZE;
565898Skais allocsize = tmp_size * sizeof (kssl_entry_t *);
566898Skais mutex_exit(&kssl_tab_mutex);
567898Skais tmp_tab = kmem_zalloc(allocsize, KM_SLEEP);
568898Skais mutex_enter(&kssl_tab_mutex);
569898Skais if (kssl_entry_tab != NULL) {
570898Skais mutex_exit(&kssl_tab_mutex);
571898Skais kmem_free(tmp_tab, allocsize);
572898Skais goto retry;
573898Skais }
574898Skais kssl_entry_tab_size = tmp_size;
575898Skais kssl_entry_tab = tmp_tab;
576898Skais index = 0;
577898Skais } else {
578898Skais /* Check if a matching entry exists already */
579898Skais index = kssl_find_entry(laddr,
58010520SBhargava.Yenduri@Sun.COM kssl_params->kssl_addr.sin6_port, IS_SSL_PORT, B_TRUE);
581898Skais
582898Skais if (index == -1) {
583898Skais /* Check if an entry with the same proxy port exists */
584898Skais if (kssl_find_entry(laddr, kssl_params->kssl_proxy_port,
585898Skais IS_PROXY_PORT, B_TRUE) != -1) {
586898Skais mutex_exit(&kssl_tab_mutex);
587898Skais kssl_free_entry(kssl_entry);
588898Skais return (EADDRINUSE);
589898Skais }
590898Skais
591898Skais /* No matching entry, find an empty spot */
592898Skais for (i = 0; i < kssl_entry_tab_size; i++) {
593898Skais if (kssl_entry_tab[i] == NULL)
594898Skais break;
595898Skais }
596898Skais /* Table full. Gotta grow it */
597898Skais if (i == kssl_entry_tab_size) {
598898Skais kssl_entry_t **new_tab, **old_tab;
599898Skais size_t allocsize;
600898Skais size_t oldtabsize = kssl_entry_tab_size *
601898Skais sizeof (kssl_entry_t *);
602898Skais int tmp_size, old_size;
603898Skais
604898Skais tmp_size = old_size = kssl_entry_tab_size;
605898Skais tmp_size += KSSL_TAB_INITSIZE;
606898Skais allocsize = tmp_size * sizeof (kssl_entry_t *);
607898Skais mutex_exit(&kssl_tab_mutex);
608898Skais new_tab = kmem_zalloc(allocsize, KM_SLEEP);
609898Skais mutex_enter(&kssl_tab_mutex);
610898Skais if (kssl_entry_tab_size > old_size) {
611898Skais mutex_exit(&kssl_tab_mutex);
612898Skais kmem_free(new_tab, allocsize);
613898Skais goto retry;
614898Skais }
615898Skais
616898Skais kssl_entry_tab_size = tmp_size;
617898Skais bcopy(kssl_entry_tab, new_tab, oldtabsize);
618898Skais
619898Skais old_tab = kssl_entry_tab;
620898Skais kssl_entry_tab = new_tab;
621898Skais
622898Skais kmem_free(old_tab, oldtabsize);
623898Skais }
624898Skais index = i;
625898Skais } else {
62610520SBhargava.Yenduri@Sun.COM kssl_entry_t *ep;
62710520SBhargava.Yenduri@Sun.COM
628898Skais /*
629898Skais * We do not want an entry with a specific address and
630898Skais * an entry with IN_ADDR_ANY to coexist. We could
631898Skais * replace the existing entry. But, most likely this
632898Skais * is misconfiguration. Better bail out with an error.
633898Skais */
63410520SBhargava.Yenduri@Sun.COM ep = kssl_entry_tab[index];
63510520SBhargava.Yenduri@Sun.COM
63610520SBhargava.Yenduri@Sun.COM if ((IN6_IS_ADDR_UNSPECIFIED(&laddr) &&
63710520SBhargava.Yenduri@Sun.COM !IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr)) ||
63810520SBhargava.Yenduri@Sun.COM (!IN6_IS_ADDR_UNSPECIFIED(&laddr) &&
63910520SBhargava.Yenduri@Sun.COM IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr))) {
640898Skais mutex_exit(&kssl_tab_mutex);
641898Skais kssl_free_entry(kssl_entry);
642898Skais return (EEXIST);
643898Skais }
644898Skais
645898Skais /* Replace the existing entry */
646898Skais KSSL_ENTRY_REFRELE(kssl_entry_tab[index]);
647898Skais kssl_entry_tab[index] = NULL;
648898Skais kssl_entry_tab_nentries--;
649898Skais }
650898Skais }
651898Skais
652898Skais kssl_entry_tab[index] = kssl_entry;
653898Skais kssl_entry_tab_nentries++;
654898Skais mutex_exit(&kssl_tab_mutex);
655898Skais
656898Skais return (0);
657898Skais }
658898Skais
659898Skais int
kssl_delete_entry(struct sockaddr_in6 * kssl_addr)66010520SBhargava.Yenduri@Sun.COM kssl_delete_entry(struct sockaddr_in6 *kssl_addr)
661898Skais {
66210520SBhargava.Yenduri@Sun.COM in6_addr_t laddr;
663898Skais int index;
664898Skais
66510520SBhargava.Yenduri@Sun.COM laddr = kssl_addr->sin6_addr;
666898Skais
667898Skais mutex_enter(&kssl_tab_mutex);
66810520SBhargava.Yenduri@Sun.COM index = kssl_find_entry(laddr, kssl_addr->sin6_port,
669898Skais IS_SSL_PORT, B_FALSE);
670898Skais
671898Skais if (index == -1) {
672898Skais mutex_exit(&kssl_tab_mutex);
673898Skais return (ENOENT);
674898Skais }
675898Skais
676898Skais KSSL_ENTRY_REFRELE(kssl_entry_tab[index]);
677898Skais kssl_entry_tab[index] = NULL;
678898Skais kssl_entry_tab_nentries--;
679898Skais
680898Skais mutex_exit(&kssl_tab_mutex);
681898Skais
682898Skais return (0);
683898Skais }
6842800Skrishna
6852800Skrishna /*
6862800Skrishna * We care about only one private key object.
6872800Skrishna * So, set the max count to only 1.
6882800Skrishna */
6892800Skrishna #define MAX_OBJECT_COUNT 1
6902800Skrishna
6912800Skrishna /*
6922800Skrishna * Open a session to the provider specified by the label and
6932800Skrishna * authenticate to it. Find the private key object with the
6942800Skrishna * specified attributes and save the handle. The userland component
6952800Skrishna * must set all the attributes in the template so as to uniquely
6962800Skrishna * identify the object.
6972800Skrishna *
6982800Skrishna * Note that the handle will be invalid if we logout or close
6992800Skrishna * the session to the provider.
7002800Skrishna */
7012800Skrishna int
kssl_get_obj_handle(kssl_entry_t * kp)7022800Skrishna kssl_get_obj_handle(kssl_entry_t *kp)
7032800Skrishna {
7042800Skrishna int rv;
7052800Skrishna unsigned int count;
7062800Skrishna void *cookie = NULL;
7072800Skrishna crypto_provider_t prov;
7082800Skrishna kssl_session_info_t *s;
7092800Skrishna crypto_session_id_t sid;
7102800Skrishna crypto_object_attribute_t *attrs;
7112800Skrishna crypto_object_id_t ohndl[MAX_OBJECT_COUNT];
7122800Skrishna char label[CRYPTO_EXT_SIZE_LABEL + 1];
7132800Skrishna
7142800Skrishna ASSERT(kp->ke_is_nxkey);
7152800Skrishna s = kp->ke_sessinfo;
7162800Skrishna
7172800Skrishna bcopy(s->toklabel, label, CRYPTO_EXT_SIZE_LABEL);
7182800Skrishna label[CRYPTO_EXT_SIZE_LABEL] = '\0';
7192800Skrishna prov = crypto_get_provider(label, NULL, NULL);
7202800Skrishna if (prov == NULL)
7212800Skrishna return (CRYPTO_UNKNOWN_PROVIDER);
7222800Skrishna
7232800Skrishna rv = crypto_session_open(prov, &sid, NULL);
7242800Skrishna if (rv != CRYPTO_SUCCESS) {
7252800Skrishna goto err1;
7262800Skrishna }
7272800Skrishna
7282800Skrishna rv = crypto_session_login(prov, sid, CRYPTO_USER,
7292800Skrishna s->tokpin, s->pinlen, NULL);
7302800Skrishna if (rv != CRYPTO_SUCCESS) {
7312800Skrishna goto err2;
7322800Skrishna }
7332800Skrishna
7342800Skrishna count = kp->ke_private_key->ck_count;
7352800Skrishna attrs = kp->ke_private_key->ck_attrs;
7362800Skrishna
7372800Skrishna rv = crypto_object_find_init(prov, sid, attrs, count, &cookie, NULL);
7382800Skrishna if (rv != CRYPTO_SUCCESS) {
7392800Skrishna goto err3;
7402800Skrishna }
7412800Skrishna
7422800Skrishna rv = crypto_object_find(prov, cookie, ohndl, &count,
7432800Skrishna MAX_OBJECT_COUNT, NULL);
7442800Skrishna if (rv != CRYPTO_SUCCESS || count == 0) {
7452800Skrishna if (count == 0)
7462800Skrishna rv = CRYPTO_FAILED;
7472800Skrishna goto err3;
7482800Skrishna }
7492800Skrishna
7502800Skrishna (void) crypto_object_find_final(prov, cookie, NULL);
7512800Skrishna
7522800Skrishna s->sid = sid;
7532800Skrishna s->prov = prov;
7542800Skrishna s->key.ck_format = CRYPTO_KEY_REFERENCE;
7552800Skrishna /* Keep the handle around for later use */
7562800Skrishna s->key.ck_obj_id = ohndl[0];
7572800Skrishna
7582800Skrishna return (CRYPTO_SUCCESS);
7592800Skrishna
7602800Skrishna err3:
7612800Skrishna (void) crypto_session_logout(prov, sid, NULL);
7622800Skrishna err2:
7632800Skrishna (void) crypto_session_close(prov, sid, NULL);
7642800Skrishna err1:
7652800Skrishna crypto_release_provider(prov);
7662800Skrishna return (rv);
7672800Skrishna }
768