xref: /onnv-gate/usr/src/uts/common/inet/kssl/ksslapi.c (revision 10520:1303da84e47a)
1898Skais /*
2898Skais  * CDDL HEADER START
3898Skais  *
4898Skais  * The contents of this file are subject to the terms of the
51139Skais  * Common Development and Distribution License (the "License").
61139Skais  * 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 /*
229624SBhargava.Yenduri@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23898Skais  * Use is subject to license terms.
24898Skais  */
25898Skais 
26898Skais #include <sys/types.h>
27898Skais #include <sys/stream.h>
28898Skais #include <sys/strsun.h>
29898Skais #include <sys/kmem.h>
30898Skais #include <sys/cpuvar.h>
31898Skais #include <sys/atomic.h>
32898Skais #include <sys/sysmacros.h>
33898Skais 
34898Skais #include <inet/common.h>
35898Skais #include <inet/ip.h>
36898Skais 
37898Skais #include <sys/systm.h>
38898Skais #include <sys/param.h>
39898Skais #include <sys/tihdr.h>
40898Skais 
41898Skais #include "ksslimpl.h"
42898Skais #include "ksslproto.h"
43898Skais #include "ksslapi.h"
44898Skais 
45898Skais static kssl_cmd_t kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp,
46898Skais     mblk_t **decrmp, kssl_callback_t cbfn, void *arg);
47898Skais static boolean_t kssl_enqueue(kssl_chain_t **head, void *item);
48898Skais static void kssl_dequeue(kssl_chain_t **head, void *item);
49898Skais static kssl_status_t kssl_build_single_record(ssl_t *ssl, mblk_t *mp);
50898Skais 
51898Skais /*
52898Skais  * The socket T_bind_req message is intercepted and re-routed here
53898Skais  * to see is there is SSL relevant job to do, based on the kssl config
54898Skais  * in the kssl_entry_tab.
55898Skais  * Looks up the kernel SSL proxy table, to find an entry that matches the
56898Skais  * same serveraddr, and has one of the following two criteria:
57898Skais  * 1. in_port is an ssl_port. This endpoint can be used later as a fallback
58898Skais  *    to complete connections that cannot be handled by the SSL kernel proxy
59898Skais  *    (typically non supported ciphersuite). The cookie for the calling client
60898Skais  *    is saved with the kssl_entry to be retrieved for the fallback.
61898Skais  *    The function returns KSSL_HAS_PROXY.
62898Skais  *
63898Skais  * 2. in_port is a proxy port for another ssl port. The ssl port is then
64898Skais  *    substituted to the in_port in the bind_req TPI structure, so that
65898Skais  *    the bind falls through to the SSL port. At the end of this operation,
66898Skais  *    all the packets arriving to the SSL port will be delivered to an
67898Skais  *    accepted endpoint child of this bound socket.
68898Skais  *    The  kssl_entry_t is returned in *ksslent, for later use by the
69898Skais  *    lower modules' SSL hooks that handle the Handshake messages.
70898Skais  *    The function returns KSSL_IS_PROXY.
71898Skais  *
72*10520SBhargava.Yenduri@Sun.COM  * The function returns KSSL_NO_PROXY otherwise.
73898Skais  */
74898Skais 
75898Skais kssl_endpt_type_t
76898Skais kssl_check_proxy(mblk_t *bindmp, void *cookie, kssl_ent_t *ksslent)
77898Skais {
78898Skais 	int i;
79898Skais 	kssl_endpt_type_t ret;
80898Skais 	kssl_entry_t *ep;
81898Skais 	sin_t *sin;
829624SBhargava.Yenduri@Sun.COM 	sin6_t *sin6;
83898Skais 	struct T_bind_req *tbr;
84*10520SBhargava.Yenduri@Sun.COM 	in6_addr_t mapped_v4addr;
85*10520SBhargava.Yenduri@Sun.COM 	in6_addr_t *v6addr;
86898Skais 	in_port_t in_port;
87898Skais 
88*10520SBhargava.Yenduri@Sun.COM 	if (kssl_entry_tab_nentries == 0) {
89898Skais 		return (KSSL_NO_PROXY);
90898Skais 	}
91898Skais 
92898Skais 	ret = KSSL_NO_PROXY;
93898Skais 
94*10520SBhargava.Yenduri@Sun.COM 	tbr = (struct T_bind_req *)bindmp->b_rptr;
959624SBhargava.Yenduri@Sun.COM 	sin = (sin_t *)(bindmp->b_rptr + tbr->ADDR_offset);
96898Skais 
97898Skais 	switch (tbr->ADDR_length) {
98898Skais 	case sizeof (sin_t):
99898Skais 		in_port = ntohs(sin->sin_port);
100*10520SBhargava.Yenduri@Sun.COM 		IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &mapped_v4addr);
101*10520SBhargava.Yenduri@Sun.COM 		v6addr = &mapped_v4addr;
102898Skais 		break;
103898Skais 
104898Skais 	case sizeof (sin6_t):
1059624SBhargava.Yenduri@Sun.COM 		sin6 = (sin6_t *)sin;
106*10520SBhargava.Yenduri@Sun.COM 		in_port = ntohs(sin6->sin6_port);
107*10520SBhargava.Yenduri@Sun.COM 		v6addr = &sin6->sin6_addr;
108*10520SBhargava.Yenduri@Sun.COM 		break;
1099624SBhargava.Yenduri@Sun.COM 
110898Skais 	default:
111898Skais 		return (ret);
112898Skais 	}
113898Skais 
114898Skais 	mutex_enter(&kssl_tab_mutex);
115898Skais 
116898Skais 	for (i = 0; i < kssl_entry_tab_size; i++) {
117898Skais 		if ((ep = kssl_entry_tab[i]) == NULL)
118898Skais 			continue;
119898Skais 
120*10520SBhargava.Yenduri@Sun.COM 		if (IN6_ARE_ADDR_EQUAL(&ep->ke_laddr, v6addr) ||
121*10520SBhargava.Yenduri@Sun.COM 		    IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr)) {
122898Skais 
123898Skais 			/* This is an SSL port to fallback to */
124898Skais 			if (ep->ke_ssl_port == in_port) {
125898Skais 
126898Skais 				/*
127898Skais 				 * Let's see first if there's at least
128898Skais 				 * an endpoint for a proxy server.
129898Skais 				 * If there's none, then we return as we have
130898Skais 				 * no proxy, so that the bind() to the
131898Skais 				 * transport layer goes through.
132898Skais 				 * The calling module will ask for this
133898Skais 				 * cookie if it wants to fall back to it,
134898Skais 				 * so add this one to the list of fallback
135898Skais 				 * clients.
136898Skais 				 */
137898Skais 				if (!kssl_enqueue((kssl_chain_t **)
138898Skais 				    &(ep->ke_fallback_head), cookie)) {
139898Skais 					break;
140898Skais 				}
141898Skais 
142898Skais 				/*
143898Skais 				 * Now transform the T_BIND_REQ into
144898Skais 				 * a T_BIND_ACK.
145898Skais 				 */
146898Skais 				tbr->PRIM_type = T_BIND_ACK;
147898Skais 				bindmp->b_datap->db_type = M_PCPROTO;
148898Skais 
149898Skais 				KSSL_ENTRY_REFHOLD(ep);
150898Skais 				*ksslent = (kssl_ent_t)ep;
151898Skais 
152898Skais 				ret = KSSL_HAS_PROXY;
153898Skais 				break;
154898Skais 			}
155898Skais 
156898Skais 			/* This is a proxy port. */
157898Skais 			if (ep->ke_proxy_port == in_port) {
158898Skais 				mblk_t *entmp;
159898Skais 
160898Skais 				/* Append this entry to the bind_req mblk */
161898Skais 
162898Skais 				entmp = allocb(sizeof (kssl_entry_t),
163898Skais 				    BPRI_MED);
164898Skais 				if (entmp == NULL)
165898Skais 					break;
166898Skais 				*((kssl_entry_t **)entmp->b_rptr) = ep;
167898Skais 
168898Skais 				entmp->b_wptr = entmp->b_rptr +
169898Skais 				    sizeof (kssl_entry_t);
170898Skais 
171898Skais 				bindmp->b_cont = entmp;
172898Skais 
173898Skais 				/* Add the caller's cookie to proxies list */
174898Skais 
175898Skais 				if (!kssl_enqueue((kssl_chain_t **)
176898Skais 				    &(ep->ke_proxy_head), cookie)) {
177898Skais 					freeb(bindmp->b_cont);
178898Skais 					bindmp->b_cont = NULL;
179898Skais 					break;
180898Skais 				}
181898Skais 
182898Skais 				/*
183898Skais 				 * Make this look  like the SSL port to the
184898Skais 				 * transport below
185898Skais 				 */
186898Skais 				sin->sin_port = htons(ep->ke_ssl_port);
187898Skais 
188898Skais 				tbr->PRIM_type = T_SSL_PROXY_BIND_REQ;
189898Skais 
190898Skais 				KSSL_ENTRY_REFHOLD(ep);
191898Skais 				*ksslent = (kssl_ent_t)ep;
192898Skais 
193898Skais 				ret = KSSL_IS_PROXY;
194898Skais 				break;
195898Skais 			}
196898Skais 		}
197898Skais 	}
198898Skais 
199898Skais 	mutex_exit(&kssl_tab_mutex);
200898Skais 	return (ret);
201898Skais }
202898Skais 
203898Skais /*
204898Skais  * Retrieved an endpoint "bound" to the SSL entry.
205898Skais  * Such endpoint has previously called kssl_check_proxy(), got itself
206898Skais  * linked to the kssl_entry's ke_fallback_head list.
207898Skais  * This routine returns the cookie from that SSL entry ke_fallback_head list.
208898Skais  */
209898Skais void *
210898Skais kssl_find_fallback(kssl_ent_t ksslent)
211898Skais {
212898Skais 	kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent;
213898Skais 
214898Skais 	if (kssl_entry->ke_fallback_head != NULL)
215898Skais 		return (kssl_entry->ke_fallback_head->fallback_bound);
216898Skais 
217898Skais 	KSSL_COUNTER(proxy_fallback_failed, 1);
218898Skais 
219898Skais 	return (NULL);
220898Skais }
221898Skais 
222898Skais /*
223898Skais  * Re-usable code for adding and removing an element to/from a chain that
224898Skais  * matches "item"
225898Skais  * The chain is simple-linked and NULL ended.
226898Skais  */
227898Skais 
228898Skais /*
229898Skais  * This routine returns TRUE if the item was either successfully added to
230898Skais  * the chain, or is already there. It returns FALSE otherwise.
231898Skais  */
232898Skais static boolean_t
233898Skais kssl_enqueue(kssl_chain_t **head, void *item)
234898Skais {
235898Skais 	kssl_chain_t *newchain, *cur;
236898Skais 
237898Skais 	/* Lookup the existing entries to avoid duplicates */
238898Skais 	cur = *head;
239898Skais 	while (cur != NULL) {
240898Skais 		if (cur->item == item) {
241898Skais 			return (B_TRUE);
242898Skais 		}
243898Skais 		cur = cur->next;
244898Skais 	}
245898Skais 
246898Skais 	newchain = kmem_alloc(sizeof (kssl_chain_t), KM_NOSLEEP);
247898Skais 	if (newchain == NULL) {
248898Skais 		return (B_FALSE);
249898Skais 	}
250898Skais 
251898Skais 	newchain->item = item;
252898Skais 	newchain->next = *head;
253898Skais 	*head = newchain;
254898Skais 	return (B_TRUE);
255898Skais }
256898Skais 
257898Skais static void
258898Skais kssl_dequeue(kssl_chain_t **head, void *item)
259898Skais {
260898Skais 	kssl_chain_t *prev, *cur;
261898Skais 
262898Skais 	prev = cur = *head;
263898Skais 	while (cur != NULL) {
264898Skais 		if (cur->item == item) {
265898Skais 			if (cur == *head)
266898Skais 				*head = (*head)->next;
267898Skais 			else
268898Skais 				prev->next = cur->next;
269898Skais 			kmem_free(cur, sizeof (kssl_chain_t));
270898Skais 			return;
271898Skais 		}
272898Skais 		prev = cur;
273898Skais 		cur = cur->next;
274898Skais 	}
275898Skais }
276898Skais 
277898Skais /*
278898Skais  * Holds the kssl_entry
279898Skais  */
280898Skais void
281898Skais kssl_hold_ent(kssl_ent_t ksslent)
282898Skais {
283898Skais 	KSSL_ENTRY_REFHOLD((kssl_entry_t *)ksslent);
284898Skais }
285898Skais 
286898Skais /*
287898Skais  * Releases the kssl_entry
288898Skais  * If the caller passes a cookie, then it should be removed from both
289898Skais  * proxies and fallbacks chains.
290898Skais  */
291898Skais void
292898Skais kssl_release_ent(kssl_ent_t ksslent, void *cookie, kssl_endpt_type_t endpt_type)
293898Skais {
294898Skais 	kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent;
295898Skais 
296898Skais 	if (cookie != NULL) {
297*10520SBhargava.Yenduri@Sun.COM 		if (endpt_type == KSSL_IS_PROXY) {
298898Skais 			ASSERT(kssl_entry->ke_proxy_head != NULL);
299898Skais 			kssl_dequeue(
300898Skais 			    (kssl_chain_t **)&kssl_entry->ke_proxy_head,
301898Skais 			    cookie);
302*10520SBhargava.Yenduri@Sun.COM 		}
303*10520SBhargava.Yenduri@Sun.COM 		if (endpt_type == KSSL_HAS_PROXY) {
304898Skais 			ASSERT(kssl_entry->ke_fallback_head != NULL);
305898Skais 			kssl_dequeue(
306898Skais 			    (kssl_chain_t **)&kssl_entry->ke_fallback_head,
307898Skais 			    cookie);
308*10520SBhargava.Yenduri@Sun.COM 		}
309898Skais 	}
310898Skais 	KSSL_ENTRY_REFRELE(kssl_entry);
311898Skais }
312898Skais 
313898Skais /*
314898Skais  * Holds the kssl context
315898Skais  */
316898Skais void
317898Skais kssl_hold_ctx(kssl_ctx_t ksslctx)
318898Skais {
319898Skais 	ssl_t *ssl = (ssl_t *)ksslctx;
320898Skais 
321898Skais 	KSSL_SSL_REFHOLD(ssl);
322898Skais }
323898Skais 
324898Skais /*
325898Skais  * Releases the kssl_context
326898Skais  */
327898Skais void
328898Skais kssl_release_ctx(kssl_ctx_t ksslctx)
329898Skais {
330898Skais 	KSSL_SSL_REFRELE((ssl_t *)ksslctx);
331898Skais }
332898Skais 
333898Skais /*
334898Skais  * Packets are accumulated here, if there are packets already queued,
335898Skais  * or if the context is active.
336898Skais  * The context is active when an incoming record processing function
337898Skais  * is already executing on a different thread.
338898Skais  * Queued packets are handled either when an mblk arrived and completes
339898Skais  * a record, or, when the active context processor finishes the task at
340898Skais  * hand.
341898Skais  * The caller has to keep calling this routine in a loop until it returns
342898Skais  * B_FALSE in *more. The reason for this is SSL3: The protocol
343898Skais  * allows the client to send its first application_data message right
344898Skais  * after it had sent its Finished message, and not wait for the server
345898Skais  * ChangeCipherSpec and Finished. This overlap means we can't batch up
346898Skais  * a returned Handshake message to be sent on the wire
347898Skais  * with a decrypted application_data to be delivered to the application.
348898Skais  */
349898Skais kssl_cmd_t
350898Skais kssl_input(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, boolean_t *more,
351898Skais     kssl_callback_t cbfn, void *arg)
352898Skais {
353898Skais 	mblk_t *recmp, *outmp = NULL;
354898Skais 	kssl_cmd_t kssl_cmd;
355898Skais 	ssl_t *ssl;
356898Skais 	uint8_t *rec_sz_p;
357898Skais 	int mplen;
358898Skais 	SSL3ContentType content_type;
359898Skais 	uint16_t rec_sz;
360898Skais 
361898Skais 	ASSERT(ctx != NULL);
362898Skais 
363898Skais 	if (mp != NULL) {
364898Skais 		ASSERT(mp->b_prev == NULL && mp->b_next == NULL);
365898Skais 	}
366898Skais 
367898Skais 	ssl = (ssl_t *)(ctx);
368898Skais 
369898Skais 	*decrmp = NULL;
370898Skais 	*more = B_FALSE;
371898Skais 
372898Skais 	mutex_enter(&ssl->kssl_lock);
373898Skais 
374898Skais 	if (ssl->close_notify == B_TRUE) {
3755850Svk199839 		DTRACE_PROBE(kssl_err__close_notify);
376898Skais 		goto sendnewalert;
377898Skais 	}
378898Skais 
379898Skais 	/* Whomever is currently processing this connection will get to this */
380898Skais 	if (ssl->activeinput) {
381898Skais 		if (mp != NULL) {
382898Skais 			KSSL_ENQUEUE_MP(ssl, mp);
383898Skais 		}
384898Skais 		mutex_exit(&ssl->kssl_lock);
385898Skais 		return (KSSL_CMD_NONE);
386898Skais 	}
387898Skais 
388898Skais 	/*
389898Skais 	 * Fast path for complete incoming application_data records on an empty
390898Skais 	 * queue.
391898Skais 	 * This is by far the most frequently encountered case
392898Skais 	 */
393898Skais 
394898Skais 	if ((!ssl->activeinput) && (ssl->rec_ass_head == NULL) &&
395898Skais 	    ((mp != NULL) && (mplen = MBLKL(mp)) > SSL3_HDR_LEN)) {
396898Skais 
3975850Svk199839 		DTRACE_PROBE1(kssl_mblk__fast_path, mblk_t *, mp);
398898Skais 		content_type = (SSL3ContentType)mp->b_rptr[0];
399898Skais 
400898Skais 		if ((content_type == content_application_data) &&
401898Skais 		    (ssl->hs_waitstate == idle_handshake)) {
402898Skais 			rec_sz_p = SSL3_REC_SIZE(mp);
403898Skais 			rec_sz = BE16_TO_U16(rec_sz_p);
404898Skais 
405898Skais 			if ((mp->b_cont == NULL) && (mplen == rec_sz)) {
406898Skais 
4074859Skrishna 				DB_FLAGS(mp) &= ~DBLK_COOKED;
408898Skais 				*decrmp = mp;
409898Skais 				mutex_exit(&ssl->kssl_lock);
410898Skais 				return (KSSL_CMD_DELIVER_PROXY);
411898Skais 			}
412898Skais 		}
413898Skais 	}
414898Skais 
415898Skais 	ssl->activeinput = B_TRUE;
416898Skais 	/* Accumulate at least one record */
417898Skais 	if (mp != NULL) {
418898Skais 		KSSL_ENQUEUE_MP(ssl, mp);
419898Skais 		mp = NULL;
420898Skais 	}
421898Skais 	recmp = kssl_get_next_record(ssl);
422898Skais 
423898Skais 	if (recmp == NULL) {
424898Skais 		ssl->activeinput = B_FALSE;
425898Skais 		if (ssl->alert_sendbuf != NULL) {
4265850Svk199839 			DTRACE_PROBE(kssl_err__alert_to_send);
427898Skais 			goto sendalert;
428898Skais 		}
429898Skais 		/* Not even a complete header yet. wait for the rest */
430898Skais 		mutex_exit(&ssl->kssl_lock);
431898Skais 		return (KSSL_CMD_NONE);
432898Skais 	}
433898Skais 
434898Skais 	do {
4355850Svk199839 		DTRACE_PROBE1(kssl_mblk__kssl_input_cycle, mblk_t *, recmp);
4364556Svk199839 		content_type = (SSL3ContentType)recmp->b_rptr[0];
4374556Svk199839 
4384556Svk199839 		switch (content_type) {
4394556Svk199839 		case content_application_data:
440898Skais 			/*
441898Skais 			 * application_data records are decrypted and
442898Skais 			 * MAC-verified by the stream head, and in the context
443898Skais 			 * a read()'ing thread. This avoids unfairly charging
444898Skais 			 * the cost of handling this record on the whole system,
445898Skais 			 * and prevents doing it while in the shared IP
446898Skais 			 * perimeter.
447898Skais 			 */
448898Skais 			ssl->activeinput = B_FALSE;
449898Skais 			if (ssl->hs_waitstate != idle_handshake) {
4505850Svk199839 				DTRACE_PROBE(kssl_err__waitstate_not_idle);
451898Skais 				goto sendnewalert;
452898Skais 			}
453898Skais 			outmp = recmp;
454898Skais 			kssl_cmd = KSSL_CMD_DELIVER_PROXY;
4554556Svk199839 			break;
4564556Svk199839 		case content_change_cipher_spec:
4574556Svk199839 		case content_alert:
4584556Svk199839 		case content_handshake:
4594556Svk199839 		case content_handshake_v2:
460898Skais 			/*
461898Skais 			 * If we're past the initial handshake, start letting
462898Skais 			 * the stream head process all records, in particular
463898Skais 			 * the close_notify.
464898Skais 			 * This is needed to avoid processing them out of
465898Skais 			 * sequence when previous application data packets are
466898Skais 			 * waiting to be decrypted/MAC'ed and delivered.
467898Skais 			 */
468898Skais 			if (ssl->hs_waitstate == idle_handshake) {
469898Skais 				ssl->activeinput = B_FALSE;
470898Skais 				outmp = recmp;
471898Skais 				kssl_cmd = KSSL_CMD_DELIVER_PROXY;
472898Skais 			} else {
473898Skais 				kssl_cmd = kssl_handle_any_record(ssl, recmp,
474898Skais 				    &outmp, cbfn, arg);
475898Skais 			}
4764556Svk199839 			break;
4774556Svk199839 		default:
4784556Svk199839 			ssl->activeinput = B_FALSE;
4795850Svk199839 			DTRACE_PROBE(kssl_err__invalid_content_type);
4804556Svk199839 			goto sendnewalert;
481898Skais 		}
482898Skais 
483898Skais 		/* Priority to Alert messages */
484898Skais 		if (ssl->alert_sendbuf != NULL) {
4855850Svk199839 			DTRACE_PROBE(kssl_err__alert_to_send_cycle);
486898Skais 			goto sendalert;
487898Skais 		}
488898Skais 
489898Skais 		/* Then handshake messages */
490898Skais 		if (ssl->handshake_sendbuf) {
491898Skais 			if (*decrmp != NULL) {
492898Skais 				linkb(*decrmp, ssl->handshake_sendbuf);
493898Skais 			} else {
494898Skais 				*decrmp = ssl->handshake_sendbuf;
495898Skais 			}
496898Skais 			ssl->handshake_sendbuf = NULL;
497898Skais 
498898Skais 			*more = ((ssl->rec_ass_head != NULL) &&
499898Skais 			    (!ssl->activeinput));
500898Skais 			mutex_exit(&ssl->kssl_lock);
501898Skais 			return (kssl_cmd);
502898Skais 		}
503898Skais 
504898Skais 		if (ssl->hs_waitstate == idle_handshake) {
505898Skais 			*more = ((ssl->rec_ass_head != NULL) &&
506898Skais 			    (!ssl->activeinput));
507898Skais 		}
508898Skais 
509898Skais 		if (outmp != NULL) {
510898Skais 			*decrmp = outmp;
511898Skais 			/*
512898Skais 			 * Don't process any packet after an application_data.
513898Skais 			 * We could well receive the close_notify which should
514898Skais 			 * be handled separately.
515898Skais 			 */
516898Skais 			mutex_exit(&ssl->kssl_lock);
517898Skais 			return (kssl_cmd);
518898Skais 		}
519898Skais 		/*
520898Skais 		 * The current record isn't done yet. Don't start the next one
521898Skais 		 */
522898Skais 		if (ssl->activeinput) {
523898Skais 			mutex_exit(&ssl->kssl_lock);
524898Skais 			return (kssl_cmd);
525898Skais 		}
526898Skais 	} while ((recmp = kssl_get_next_record(ssl)) != NULL);
527898Skais 
528898Skais 	mutex_exit(&ssl->kssl_lock);
529898Skais 	return (kssl_cmd);
530898Skais 
531898Skais sendnewalert:
532898Skais 	kssl_send_alert(ssl, alert_fatal, unexpected_message);
533898Skais 	if (mp != NULL) {
534898Skais 		freeb(mp);
535898Skais 	}
536898Skais 
537898Skais sendalert:
538898Skais 	*decrmp = ssl->alert_sendbuf;
539898Skais 	ssl->alert_sendbuf = NULL;
540898Skais 	mutex_exit(&ssl->kssl_lock);
541898Skais 	return (KSSL_CMD_SEND);
542898Skais }
543898Skais 
544898Skais /*
5455850Svk199839  * Process mblk b_cont chain returned from stream head. The chain could
5465850Svk199839  * contain a mixture (albeit continuous) of processed and unprocessed
5475850Svk199839  * mblks. This situation could happen when more data was available in
5485850Svk199839  * stream head queue than requested. In such case the rest of processed
5495850Svk199839  * data would be putback().
5505850Svk199839  *
5515850Svk199839  * Processed mblks in this function contain either a full or partial portion
5525850Svk199839  * of a decrypted and verified SSL record. The former case is produced
5535850Svk199839  * by the function itself, the latter case is explained above.
5545850Svk199839  *
5555850Svk199839  * In case of unprocessed mblks, decrypt and verify the MAC of an incoming
5565850Svk199839  * chain of application_data record. Each block has exactly one SSL record.
5575850Svk199839  * This routine recycles incoming mblks, and flags them as DBLK_COOKED.
558898Skais  */
559898Skais kssl_cmd_t
5605850Svk199839 kssl_handle_mblk(kssl_ctx_t ctx, mblk_t **mpp, mblk_t **outmp)
561898Skais {
562898Skais 	uchar_t *recend, *rec_sz_p;
563898Skais 	uchar_t *real_recend;
5641139Skais 	mblk_t *prevmp = NULL, *nextmp, *firstmp, *mp, *copybp;
565898Skais 	int mac_sz;
566898Skais 	uchar_t version[2];
567898Skais 	uint16_t rec_sz;
568898Skais 	SSL3AlertDescription desc;
569898Skais 	SSL3ContentType content_type;
570898Skais 	ssl_t *ssl;
571898Skais 	KSSLCipherSpec *spec;
572*10520SBhargava.Yenduri@Sun.COM 	int error, ret;
573898Skais 	kssl_cmd_t kssl_cmd = KSSL_CMD_DELIVER_PROXY;
574898Skais 	boolean_t deliverit = B_FALSE;
575898Skais 	crypto_data_t cipher_data;
576898Skais 
577898Skais 	ASSERT(ctx != NULL);
578898Skais 
579898Skais 	ssl = (ssl_t *)(ctx);
580898Skais 
5811139Skais 	mp = firstmp = *mpp;
582898Skais 	*outmp = NULL;
583898Skais 
5845850Svk199839 	/*
5855850Svk199839 	 * Skip over already processed mblks. This prevents a case where
5865850Svk199839 	 * struiocopyout() copies unprocessed data to userland.
5875850Svk199839 	 */
5885850Svk199839 	while ((mp != NULL) && (DB_FLAGS(mp) & DBLK_COOKED)) {
5895850Svk199839 		ASSERT(DB_TYPE(mp) == M_DATA);
5905850Svk199839 		DTRACE_PROBE1(kssl_mblk__already_processed_mblk, mblk_t *, mp);
5915850Svk199839 		mp = mp->b_cont;
5925850Svk199839 	}
5935850Svk199839 
594898Skais more:
595898Skais 
596898Skais 	while (mp != NULL) {
5975850Svk199839 		/* only unprocessed mblks should reach us */
5985850Svk199839 		ASSERT(DB_TYPE(mp) == M_DATA);
5995850Svk199839 		ASSERT(!(DB_FLAGS(mp) & DBLK_COOKED));
600898Skais 
601898Skais 		if (DB_REF(mp) > 1) {
602898Skais 			/*
603898Skais 			 * Fortunately copyb() preserves the offset,
604*10520SBhargava.Yenduri@Sun.COM 			 * tail space and alignment so the copy is
605898Skais 			 * ready to be made an SSL record.
606898Skais 			 */
607898Skais 			if ((copybp = copyb(mp)) == NULL)
608898Skais 				return (NULL);
609898Skais 
610898Skais 			copybp->b_cont = mp->b_cont;
6111139Skais 			if (mp == firstmp) {
612898Skais 				*mpp = copybp;
6134556Svk199839 			} else if (prevmp != NULL) {
614898Skais 				prevmp->b_cont = copybp;
615898Skais 			}
616898Skais 			freeb(mp);
617898Skais 			mp = copybp;
618898Skais 		}
619898Skais 
6205850Svk199839 		DTRACE_PROBE1(kssl_mblk__handle_record_cycle, mblk_t *, mp);
621898Skais 		content_type = (SSL3ContentType)mp->b_rptr[0];
622898Skais 
6234556Svk199839 		switch (content_type) {
6244556Svk199839 		case content_application_data:
6254556Svk199839 			break;
6264556Svk199839 		case content_change_cipher_spec:
6274556Svk199839 		case content_alert:
6284556Svk199839 		case content_handshake:
6294556Svk199839 		case content_handshake_v2:
630898Skais 			nextmp = mp->b_cont;
631898Skais 
632898Skais 			/* Remove this message */
633898Skais 			if (prevmp != NULL) {
634898Skais 				prevmp->b_cont = nextmp;
635898Skais 
636898Skais 				/*
637898Skais 				 * If we had processed blocks that need to
638898Skais 				 * be delivered, then remember that error code
639898Skais 				 */
640898Skais 				if (kssl_cmd == KSSL_CMD_DELIVER_PROXY)
641898Skais 					deliverit = B_TRUE;
642898Skais 			}
643898Skais 
644898Skais 			mutex_enter(&ssl->kssl_lock);
6454556Svk199839 			/* NOTE: This routine could free mp. */
646898Skais 			kssl_cmd = kssl_handle_any_record(ssl, mp, outmp,
647898Skais 			    NULL, NULL);
648898Skais 
649898Skais 			if (ssl->alert_sendbuf != NULL) {
6504556Svk199839 				mp = nextmp;
6515850Svk199839 				DTRACE_PROBE(kssl_err__alert_after_handle_any);
652898Skais 				goto sendalert;
653898Skais 			}
654898Skais 			mutex_exit(&ssl->kssl_lock);
655898Skais 
656898Skais 			if (deliverit) {
657898Skais 				kssl_cmd = KSSL_CMD_DELIVER_PROXY;
658898Skais 			}
659898Skais 
660898Skais 			mp = nextmp;
6614556Svk199839 			continue;	/* to the while loop */
6624556Svk199839 		default:
6634556Svk199839 			desc = decode_error;
6644556Svk199839 			KSSL_COUNTER(internal_errors, 1);
6655850Svk199839 			DTRACE_PROBE(kssl_err__decode_error);
6664556Svk199839 			goto makealert;
667898Skais 		}
668898Skais 
669898Skais 		version[0] = mp->b_rptr[1];
670898Skais 		version[1] = mp->b_rptr[2];
671898Skais 		rec_sz_p = SSL3_REC_SIZE(mp);
672898Skais 		rec_sz = BE16_TO_U16(rec_sz_p);
673898Skais 
674898Skais 		mp->b_rptr += SSL3_HDR_LEN;
675898Skais 		recend = mp->b_rptr + rec_sz;
676898Skais 		real_recend = recend;
677898Skais 
6784556Svk199839 		/*
6794556Svk199839 		 * Check the assumption that each mblk contains exactly
6804556Svk199839 		 * one complete SSL record. We bail out if the check fails.
6814556Svk199839 		 */
6824556Svk199839 		ASSERT(recend == mp->b_wptr);
6834556Svk199839 		if (recend != mp->b_wptr) {
6844556Svk199839 			desc = decode_error;
6854556Svk199839 			KSSL_COUNTER(internal_errors, 1);
6865850Svk199839 			DTRACE_PROBE(kssl_err__not_complete_record);
6874556Svk199839 			goto makealert;
6884556Svk199839 		}
6894556Svk199839 
690898Skais 		spec = &ssl->spec[KSSL_READ];
691898Skais 		mac_sz = spec->mac_hashsz;
692898Skais 		if (spec->cipher_ctx != 0) {
6931139Skais 
6941139Skais 			/*
6951139Skais 			 * The record length must be a multiple of the
6961139Skais 			 * block size for block ciphers.
6971139Skais 			 * The cipher_bsize is always a power of 2.
6981139Skais 			 */
6991139Skais 			if ((spec->cipher_type == type_block) &&
7001139Skais 			    ((rec_sz & (spec->cipher_bsize - 1)) != 0)) {
7015850Svk199839 				DTRACE_PROBE2(kssl_err__bad_record_size,
7025850Svk199839 				    uint16_t, rec_sz,
7035850Svk199839 				    int, spec->cipher_bsize);
7041139Skais 				KSSL_COUNTER(record_decrypt_failure, 1);
7051139Skais 				mp->b_rptr = recend;
7061139Skais 				desc = decrypt_error;
7071139Skais 				goto makealert;
7081139Skais 			}
7091139Skais 
710898Skais 			cipher_data.cd_format = CRYPTO_DATA_RAW;
711898Skais 			cipher_data.cd_offset = 0;
712898Skais 			cipher_data.cd_length = rec_sz;
713898Skais 			cipher_data.cd_miscdata = NULL;
714898Skais 			cipher_data.cd_raw.iov_base = (char *)mp->b_rptr;
715898Skais 			cipher_data.cd_raw.iov_len = rec_sz;
716898Skais 			error = crypto_decrypt_update(spec->cipher_ctx,
717898Skais 			    &cipher_data, NULL, NULL);
718898Skais 			if (CRYPTO_ERR(error)) {
7195850Svk199839 				DTRACE_PROBE1(
7205850Svk199839 				    kssl_err__crypto_decrypt_update_failed,
7215850Svk199839 				    int, error);
722898Skais 				KSSL_COUNTER(record_decrypt_failure, 1);
723898Skais 				mp->b_rptr = recend;
724898Skais 				desc = decrypt_error;
725898Skais 				goto makealert;
726898Skais 			}
727898Skais 		}
728898Skais 		if (spec->cipher_type == type_block) {
729898Skais 			uint_t pad_sz = recend[-1];
730898Skais 			pad_sz++;
731898Skais 			if (pad_sz + mac_sz > rec_sz) {
7325850Svk199839 				DTRACE_PROBE(kssl_err__pad_mac_bigger);
733898Skais 				mp->b_rptr = recend;
734898Skais 				desc = bad_record_mac;
735898Skais 				goto makealert;
736898Skais 			}
737898Skais 			rec_sz -= pad_sz;
738898Skais 			recend -= pad_sz;
739898Skais 		}
740898Skais 		if (mac_sz != 0) {
741898Skais 			uchar_t hash[MAX_HASH_LEN];
742898Skais 			if (rec_sz < mac_sz) {
7435850Svk199839 				DTRACE_PROBE(kssl_err__pad_smaller_mac);
744898Skais 				mp->b_rptr = real_recend;
745898Skais 				desc = bad_record_mac;
746898Skais 				goto makealert;
747898Skais 			}
748898Skais 			rec_sz -= mac_sz;
749898Skais 			recend -= mac_sz;
750898Skais 			ret = kssl_compute_record_mac(ssl, KSSL_READ,
7515850Svk199839 			    ssl->seq_num[KSSL_READ], content_type,
7525850Svk199839 			    version, mp->b_rptr, rec_sz, hash);
753898Skais 			if (ret != CRYPTO_SUCCESS ||
754898Skais 			    bcmp(hash, recend, mac_sz)) {
7555850Svk199839 				DTRACE_PROBE1(kssl_mblk__MACmismatch_handlerec,
7565850Svk199839 				    mblk_t *, mp);
757898Skais 				mp->b_rptr = real_recend;
758898Skais 				desc = bad_record_mac;
7595850Svk199839 				DTRACE_PROBE(kssl_err__msg_MAC_mismatch);
760898Skais 				KSSL_COUNTER(verify_mac_failure, 1);
761898Skais 				goto makealert;
762898Skais 			}
763898Skais 			ssl->seq_num[KSSL_READ]++;
764898Skais 		}
765898Skais 
766898Skais 		if (ssl->hs_waitstate != idle_handshake) {
7675850Svk199839 			DTRACE_PROBE1(kssl_err__unexpected_msg,
7685850Svk199839 			    SSL3WaitState, ssl->hs_waitstate);
769898Skais 			mp->b_rptr = real_recend;
770898Skais 			desc = unexpected_message;
771898Skais 			goto makealert;
772898Skais 		}
773898Skais 		mp->b_wptr = recend;
774898Skais 
7754556Svk199839 		DB_FLAGS(mp) |= DBLK_COOKED;
7765850Svk199839 		DTRACE_PROBE1(kssl_mblk__dblk_cooked, mblk_t *, mp);
7774556Svk199839 		KSSL_COUNTER(appdata_record_ins, 1);
7784556Svk199839 
779898Skais 		prevmp = mp;
780898Skais 		mp = mp->b_cont;
781898Skais 	}
782898Skais 
783898Skais 	return (kssl_cmd);
784898Skais 
785898Skais makealert:
786898Skais 	nextmp = mp->b_cont;
787898Skais 	freeb(mp);
788898Skais 	mp = nextmp;
789898Skais 	mutex_enter(&ssl->kssl_lock);
790898Skais 	kssl_send_alert(ssl, alert_fatal, desc);
791898Skais 
792898Skais 	if (ssl->alert_sendbuf == NULL) {
793898Skais 		/* internal memory allocation failure. just return. */
7945850Svk199839 		DTRACE_PROBE(kssl_err__alert_msg_alloc_failed);
795898Skais 		mutex_exit(&ssl->kssl_lock);
796898Skais 
797898Skais 		if (mp) {
798898Skais 			prevmp = NULL;
799898Skais 			goto more;
800898Skais 		}
801898Skais 
802898Skais 		return (KSSL_CMD_NONE);
803898Skais 	}
804898Skais 	kssl_cmd = KSSL_CMD_SEND;
805898Skais sendalert:
806898Skais 	if (*outmp == NULL) {
807898Skais 		*outmp = ssl->alert_sendbuf;
808898Skais 	} else {
809898Skais 		linkb(*outmp, ssl->alert_sendbuf);
810898Skais 	}
811898Skais 	ssl->alert_sendbuf = NULL;
812898Skais 	mutex_exit(&ssl->kssl_lock);
813898Skais 
814898Skais 	if (mp) {
815898Skais 		prevmp = NULL;
816898Skais 		goto more;
817898Skais 	}
818898Skais 
819898Skais 	return (kssl_cmd);
820898Skais }
821898Skais /*
822898Skais  * This is the routine that handles incoming SSL records.
823898Skais  * When called the first time, with a NULL context, this routine expects
824898Skais  * a ClientHello SSL Handshake packet and shall allocate a context
825898Skais  * of a new SSL connection.
826898Skais  * During the rest of the handshake packets, the routine adjusts the
827898Skais  * state of the context according to the record received.
828898Skais  * After the ChangeCipherSpec message is received, the routine first
829898Skais  * decrypts/authenticated the packet using the key materials in the
830898Skais  * connection's context.
831898Skais  * The return code tells the caller what to do with the returned packet.
832898Skais  */
833898Skais static kssl_cmd_t
834898Skais kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp,
835898Skais     kssl_callback_t cbfn, void *arg)
836898Skais {
837898Skais 	uchar_t *recend, *rec_sz_p;
838898Skais 	uchar_t version[2];
839898Skais 	uchar_t *real_recend, *save_rptr, *save_wptr;
840898Skais 	int rhsz = SSL3_HDR_LEN;
841898Skais 	uint16_t rec_sz;
842898Skais 	int sz;
843898Skais 	int mac_sz;
844898Skais 	SSL3AlertDescription desc;
845898Skais 	SSL3AlertLevel level;
846898Skais 	SSL3ContentType content_type;
847898Skais 	ssl_t *ssl;
848898Skais 	KSSLCipherSpec *spec;
849898Skais 	int error = 0, ret;
850898Skais 
851898Skais 	ASSERT(ctx != NULL);
852898Skais 
853898Skais 	ssl = (ssl_t *)(ctx);
854898Skais 
855898Skais 	*decrmp = NULL;
856898Skais 
857898Skais 	save_rptr = mp->b_rptr;
858898Skais 	save_wptr = mp->b_wptr;
859898Skais 
860898Skais 	ASSERT(MUTEX_HELD(&ssl->kssl_lock));
861898Skais 
862898Skais 	content_type = (SSL3ContentType)mp->b_rptr[0];
863898Skais 	if (content_type == content_handshake_v2) {
864898Skais 		if (ssl->hs_waitstate == wait_client_hello) {
865898Skais 			/* V2 compatible ClientHello */
866898Skais 			if (mp->b_rptr[3] == 0x03 &&
867898Skais 			    (mp->b_rptr[4] == 0x01 ||
8685850Svk199839 			    mp->b_rptr[4] == 0x00)) {
869898Skais 				ssl->major_version = version[0] = mp->b_rptr[3];
870898Skais 				ssl->minor_version = version[1] = mp->b_rptr[4];
871898Skais 			} else {
872898Skais 			/* We don't support "pure" SSLv2 */
8735850Svk199839 				DTRACE_PROBE(kssl_err__no_SSLv2);
874898Skais 				desc = protocol_version;
875898Skais 				goto sendalert;
876898Skais 			}
877898Skais 		}
878898Skais 		rec_sz = (uint16_t)mp->b_rptr[1];
879898Skais 		rhsz = 2;
880898Skais 	} else {
881898Skais 		ssl->major_version = version[0] = mp->b_rptr[1];
882898Skais 		ssl->minor_version = version[1] = mp->b_rptr[2];
883898Skais 		rec_sz_p = SSL3_REC_SIZE(mp);
884898Skais 		rec_sz = BE16_TO_U16(rec_sz_p);
885898Skais 	}
886898Skais 
887898Skais 	mp->b_rptr += rhsz;
888898Skais 	recend = mp->b_rptr + rec_sz;
889898Skais 	real_recend = recend;
890898Skais 
8914556Svk199839 	/*
8924556Svk199839 	 * Check the assumption that each mblk contains exactly
8934556Svk199839 	 * one complete SSL record. We bail out if the check fails.
8944556Svk199839 	 */
8954556Svk199839 	ASSERT(recend == mp->b_wptr);
8964556Svk199839 	if (recend != mp->b_wptr) {
8975850Svk199839 		DTRACE_PROBE3(kssl_mblk__handle_any_record_recszerr,
8985850Svk199839 		    mblk_t *, mp, int, rhsz, int, rec_sz);
8995850Svk199839 		DTRACE_PROBE(kssl_err__record_size);
9004556Svk199839 		desc = decode_error;
9014556Svk199839 		KSSL_COUNTER(internal_errors, 1);
9024556Svk199839 		goto sendalert;
9034556Svk199839 	}
9044556Svk199839 
905898Skais 	spec = &ssl->spec[KSSL_READ];
906898Skais 	mac_sz = spec->mac_hashsz;
907898Skais 	if (spec->cipher_ctx != 0) {
9081139Skais 		/*
9091139Skais 		 * The record length must be a multiple of the
9101139Skais 		 * block size for block ciphers.
9111139Skais 		 */
9121139Skais 		if ((spec->cipher_type == type_block) &&
9131139Skais 		    ((rec_sz & (spec->cipher_bsize - 1)) != 0)) {
9145850Svk199839 			DTRACE_PROBE2(kssl_err__bad_record_size,
9155850Svk199839 			    uint16_t, rec_sz, int, spec->cipher_bsize);
9161139Skais 			KSSL_COUNTER(record_decrypt_failure, 1);
9171139Skais 			mp->b_rptr = recend;
9181139Skais 			desc = decrypt_error;
9191139Skais 			goto sendalert;
9201139Skais 		}
9211139Skais 
922898Skais 		spec->cipher_data.cd_length = rec_sz;
923898Skais 		spec->cipher_data.cd_raw.iov_base = (char *)mp->b_rptr;
924898Skais 		spec->cipher_data.cd_raw.iov_len = rec_sz;
925898Skais 		error = crypto_decrypt_update(spec->cipher_ctx,
926898Skais 		    &spec->cipher_data, NULL, NULL);
927898Skais 		if (CRYPTO_ERR(error)) {
9285850Svk199839 			DTRACE_PROBE1(kssl_err__crypto_decrypt_update_failed,
9295850Svk199839 			    int, error);
930898Skais 			KSSL_COUNTER(record_decrypt_failure, 1);
931898Skais 			mp->b_rptr = recend;
932898Skais 			desc = decrypt_error;
933898Skais 			goto sendalert;
934898Skais 		}
935898Skais 	}
936898Skais 	if (spec->cipher_type == type_block) {
937898Skais 		uint_t pad_sz = recend[-1];
938898Skais 		pad_sz++;
939898Skais 		if (pad_sz + mac_sz > rec_sz) {
9405850Svk199839 			DTRACE_PROBE2(kssl_err__pad_mac_mismatch,
9415850Svk199839 			    int, pad_sz, int, mac_sz);
942898Skais 			mp->b_rptr = recend;
943898Skais 			desc = bad_record_mac;
944898Skais 			goto sendalert;
945898Skais 		}
946898Skais 		rec_sz -= pad_sz;
947898Skais 		recend -= pad_sz;
948898Skais 	}
949898Skais 	if (mac_sz != 0) {
950898Skais 		uchar_t hash[MAX_HASH_LEN];
951898Skais 		if (rec_sz < mac_sz) {
9525850Svk199839 			DTRACE_PROBE1(kssl_err__mac_size_too_big,
9535850Svk199839 			    int, mac_sz);
954898Skais 			mp->b_rptr = real_recend;
955898Skais 			desc = bad_record_mac;
956898Skais 			goto sendalert;
957898Skais 		}
958898Skais 		rec_sz -= mac_sz;
959898Skais 		recend -= mac_sz;
960898Skais 		ret = kssl_compute_record_mac(ssl, KSSL_READ,
9615850Svk199839 		    ssl->seq_num[KSSL_READ], content_type,
9625850Svk199839 		    version, mp->b_rptr, rec_sz, hash);
963898Skais 		if (ret != CRYPTO_SUCCESS ||
964898Skais 		    bcmp(hash, recend, mac_sz)) {
9655850Svk199839 			DTRACE_PROBE1(kssl_mblk__MACmismatch_anyrecord,
9665850Svk199839 			    mblk_t *, mp);
967898Skais 			mp->b_rptr = real_recend;
968898Skais 			desc = bad_record_mac;
9695850Svk199839 			DTRACE_PROBE(kssl_err__msg_MAC_mismatch);
970898Skais 			KSSL_COUNTER(verify_mac_failure, 1);
971898Skais 			goto sendalert;
972898Skais 		}
973898Skais 		ssl->seq_num[KSSL_READ]++;
9745850Svk199839 		DTRACE_PROBE1(kssl_mblk__after_compute_MAC,
9755850Svk199839 		    mblk_t *, mp);
976898Skais 	}
977898Skais 
978898Skais 	switch (content_type) {
979898Skais 	case content_handshake:
980898Skais 		do {
9815850Svk199839 			DTRACE_PROBE1(kssl_mblk__content_handshake_cycle,
9825850Svk199839 			    mblk_t *, mp);
983898Skais 			if (error != 0 ||
984898Skais 			    /* ignore client renegotiation for now */
985898Skais 			    ssl->hs_waitstate == idle_handshake) {
986898Skais 				mp->b_rptr = recend;
987898Skais 			}
988898Skais 			if (mp->b_rptr == recend) {
989898Skais 				mp->b_rptr = real_recend;
990898Skais 				if (error != 0) {
991898Skais 					goto error;
992898Skais 				}
993898Skais 				freeb(mp);
994898Skais 
995898Skais 				if (ssl->hs_waitstate == wait_client_key_done)
996898Skais 					return (KSSL_CMD_QUEUED);
997898Skais 
998898Skais 				return ((ssl->handshake_sendbuf != NULL) ?
999898Skais 				    KSSL_CMD_SEND : KSSL_CMD_NONE);
1000898Skais 			}
1001898Skais 			if (ssl->msg.state < MSG_BODY) {
1002898Skais 				if (ssl->msg.state == MSG_INIT) {
1003898Skais 					ssl->msg.type =
1004898Skais 					    (SSL3HandshakeType)*mp->b_rptr++;
1005898Skais 					ssl->msg.state = MSG_INIT_LEN;
1006898Skais 				}
1007898Skais 				if (ssl->msg.state == MSG_INIT_LEN) {
1008898Skais 					int msglenb =
1009898Skais 					    ssl->msg.msglen_bytes;
1010898Skais 					int msglen = ssl->msg.msglen;
1011898Skais 					while (mp->b_rptr < recend &&
1012898Skais 					    msglenb < 3) {
1013898Skais 						msglen = (msglen << 8) +
1014898Skais 						    (uint_t)(*mp->b_rptr++);
1015898Skais 						msglenb++;
1016898Skais 					}
1017898Skais 					ssl->msg.msglen_bytes = msglenb;
1018898Skais 					ssl->msg.msglen = msglen;
1019898Skais 					if (msglenb == 3) {
1020898Skais 						ssl->msg.state = MSG_BODY;
1021898Skais 					}
1022898Skais 				}
1023898Skais 				if (mp->b_rptr == recend) {
1024898Skais 					mp->b_rptr = real_recend;
1025898Skais 					freeb(mp);
1026898Skais 					return (KSSL_CMD_NONE);
1027898Skais 				}
1028898Skais 			}
1029898Skais 			ASSERT(ssl->msg.state == MSG_BODY);
1030898Skais 
1031898Skais 			sz = recend - mp->b_rptr;
1032898Skais 
1033898Skais 			if (ssl->msg.head == NULL &&
1034898Skais 			    ssl->msg.msglen <= sz) {
1035898Skais 				continue;
1036898Skais 			}
1037898Skais 			if (ssl->msg.head != NULL) {
1038898Skais 				sz += msgdsize(ssl->msg.head);
1039898Skais 				if (ssl->msg.msglen <= sz) {
1040898Skais 					ssl->msg.tail->b_cont = mp;
1041898Skais 					mp = ssl->msg.head;
1042898Skais 					ssl->sslcnt = 100;
1043898Skais 					ssl->msg.head = NULL;
1044898Skais 					ssl->msg.tail = NULL;
1045898Skais 					if (pullupmsg(mp, -1)) {
1046898Skais 						recend = mp->b_rptr + sz;
1047898Skais 						ASSERT(recend <= mp->b_wptr);
1048898Skais 						continue;
1049898Skais 					}
1050898Skais 					mp->b_rptr = real_recend;
1051898Skais 					error = ENOMEM;
1052898Skais 					KSSL_COUNTER(alloc_fails, 1);
1053898Skais 					goto error;
1054898Skais 				}
1055898Skais 			}
1056898Skais 
1057898Skais 			mp->b_wptr = recend;
1058898Skais 
1059898Skais 			if (ssl->msg.head == NULL) {
1060898Skais 				ssl->msg.head = mp;
1061898Skais 				ssl->msg.tail = mp;
1062898Skais 				return (KSSL_CMD_NONE);
1063898Skais 			} else {
1064898Skais 				ssl->msg.tail->b_cont = mp;
1065898Skais 				ssl->msg.tail = mp;
1066898Skais 				return (KSSL_CMD_NONE);
1067898Skais 			}
1068898Skais 		} while (kssl_handle_handshake_message(ssl, mp, &error, cbfn,
1069898Skais 		    arg));
1070898Skais 		if (error == SSL_MISS) {
1071898Skais 			mp->b_rptr = save_rptr;
1072898Skais 			mp->b_wptr = save_wptr;
1073898Skais 			KSSL_COUNTER(fallback_connections, 1);
1074898Skais 			return (KSSL_CMD_NOT_SUPPORTED);
1075898Skais 		}
1076898Skais 		if (ssl->hs_waitstate == wait_client_key_done) {
1077898Skais 			return (KSSL_CMD_QUEUED);
1078898Skais 		} else {
1079898Skais 			return (KSSL_CMD_NONE);
1080898Skais 		}
1081898Skais 	case content_alert:
10825850Svk199839 		DTRACE_PROBE1(kssl_mblk__content_alert, mblk_t *, mp);
1083898Skais 		if (rec_sz != 2) {
10845850Svk199839 			DTRACE_PROBE(kssl_err__illegal_param);
1085898Skais 			mp->b_rptr = real_recend;
1086898Skais 			desc = illegal_parameter;
1087898Skais 			goto sendalert;
1088898Skais 		} else {
1089898Skais 			level = *mp->b_rptr++;
1090898Skais 			desc = *mp->b_rptr++;
1091898Skais 			mp->b_rptr = real_recend;
1092898Skais 			if (level != alert_warning || desc != close_notify) {
1093898Skais 				if (ssl->sid.cached == B_TRUE) {
1094898Skais 					kssl_uncache_sid(&ssl->sid,
1095898Skais 					    ssl->kssl_entry);
1096898Skais 				}
10975850Svk199839 				DTRACE_PROBE2(kssl_err__bad_content_alert,
10985850Svk199839 				    SSL3AlertLevel, level,
10995850Svk199839 				    SSL3AlertDescription, desc);
1100898Skais 				ssl->fatal_alert = B_TRUE;
1101898Skais 				error = EBADMSG;
1102898Skais 				goto error;
1103898Skais 			} else {
1104898Skais 				ssl->close_notify = B_TRUE;
1105898Skais 				ssl->activeinput = B_FALSE;
1106898Skais 				freeb(mp);
1107898Skais 				return (KSSL_CMD_NONE);
1108898Skais 			}
1109898Skais 		}
1110898Skais 	case content_change_cipher_spec:
11115850Svk199839 		DTRACE_PROBE1(kssl_mblk__change_cipher_spec,
11125850Svk199839 		    mblk_t *, mp);
1113898Skais 		if (ssl->hs_waitstate != wait_change_cipher) {
1114898Skais 			desc = unexpected_message;
1115898Skais 		} else if (rec_sz != 1 || *mp->b_rptr != 1) {
1116898Skais 			desc = illegal_parameter;
1117898Skais 		} else {
1118898Skais 			mp->b_rptr = real_recend;
1119898Skais 			ssl->hs_waitstate = wait_finished;
1120898Skais 			ssl->seq_num[KSSL_READ] = 0;
1121898Skais 			if ((error = kssl_spec_init(ssl, KSSL_READ)) != 0) {
11225850Svk199839 				DTRACE_PROBE1(kssl_err__kssl_spec_init_error,
11235850Svk199839 				    int, error);
1124898Skais 				goto error;
1125898Skais 			}
1126898Skais 			ssl->activeinput = B_FALSE;
1127898Skais 			freeb(mp);
1128898Skais 			return (KSSL_CMD_NONE);
1129898Skais 		}
1130898Skais 		mp->b_rptr = real_recend;
11315850Svk199839 		DTRACE_PROBE(kssl_err__change_cipher_spec);
1132898Skais 		goto sendalert;
1133898Skais 
1134898Skais 	case content_application_data:
11355850Svk199839 		DTRACE_PROBE1(kssl_mblk__content_app_data,
11365850Svk199839 		    mblk_t *, mp);
1137898Skais 		if (ssl->hs_waitstate != idle_handshake) {
11385850Svk199839 			DTRACE_PROBE(kssl_err__content_app_data);
1139898Skais 			mp->b_rptr = real_recend;
1140898Skais 			desc = unexpected_message;
1141898Skais 			goto sendalert;
1142898Skais 		}
1143898Skais 		mp->b_wptr = recend;
1144898Skais 		*decrmp = mp;
1145898Skais 		ssl->activeinput = B_FALSE;
1146898Skais 		return (KSSL_CMD_DELIVER_PROXY);
1147898Skais 
1148898Skais 	case content_handshake_v2:
11495850Svk199839 		DTRACE_PROBE1(kssl_mblk__content_handshake_v2,
11505850Svk199839 		    mblk_t *, mp);
1151898Skais 		error = kssl_handle_v2client_hello(ssl, mp, rec_sz);
1152898Skais 		if (error == SSL_MISS) {
1153898Skais 			mp->b_rptr = save_rptr;
1154898Skais 			mp->b_wptr = save_wptr;
1155898Skais 			KSSL_COUNTER(fallback_connections, 1);
1156898Skais 			return (KSSL_CMD_NOT_SUPPORTED);
1157898Skais 		} else if (error != 0) {
11585850Svk199839 			DTRACE_PROBE(kssl_err__v2client_hello_failed);
1159898Skais 			goto error;
1160898Skais 		}
1161898Skais 		freeb(mp);
1162898Skais 		return (KSSL_CMD_SEND);
1163898Skais 	default:
11645850Svk199839 		DTRACE_PROBE1(kssl_mblk__unexpected_msg,
11655850Svk199839 		    mblk_t *, mp);
1166898Skais 		mp->b_rptr = real_recend;
1167898Skais 		desc = unexpected_message;
1168898Skais 		break;
1169898Skais 	}
1170898Skais 
1171898Skais sendalert:
1172898Skais 	kssl_send_alert(ssl, alert_fatal, desc);
1173898Skais 	*decrmp = ssl->alert_sendbuf;
1174898Skais 	ssl->alert_sendbuf = NULL;
1175898Skais 	freeb(mp);
1176898Skais 	return ((*decrmp != NULL) ? KSSL_CMD_SEND : KSSL_CMD_NONE);
1177898Skais error:
1178898Skais 	freeb(mp);
1179898Skais 	return (KSSL_CMD_NONE);
1180898Skais }
1181898Skais 
1182898Skais /*
1183898Skais  * Initialize the context of an SSL connection, coming to the specified
1184*10520SBhargava.Yenduri@Sun.COM  * address. The ssl structure is returned held.
1185898Skais  */
1186898Skais kssl_status_t
1187*10520SBhargava.Yenduri@Sun.COM kssl_init_context(kssl_ent_t kssl_ent, void *addr, boolean_t is_v4,
1188*10520SBhargava.Yenduri@Sun.COM     int mss, kssl_ctx_t *kssl_ctxp)
1189898Skais {
1190898Skais 	ssl_t *ssl = kmem_cache_alloc(kssl_cache, KM_NOSLEEP);
1191898Skais 
1192898Skais 	if (ssl == NULL) {
1193898Skais 		return (KSSL_STS_ERR);
1194898Skais 	}
1195898Skais 
1196898Skais 	kssl_cache_count++;
1197898Skais 
1198898Skais 	bzero(ssl, sizeof (ssl_t));
1199898Skais 
1200898Skais 	ssl->kssl_entry = (kssl_entry_t *)kssl_ent;
1201898Skais 	KSSL_ENTRY_REFHOLD(ssl->kssl_entry);
1202898Skais 
1203*10520SBhargava.Yenduri@Sun.COM 	if (is_v4) {
1204*10520SBhargava.Yenduri@Sun.COM 		IN6_IPADDR_TO_V4MAPPED(*((ipaddr_t *)addr), &ssl->faddr);
1205*10520SBhargava.Yenduri@Sun.COM 	} else {
1206*10520SBhargava.Yenduri@Sun.COM 		ssl->faddr = *((in6_addr_t *)addr);	/* struct assignment */
1207*10520SBhargava.Yenduri@Sun.COM 	}
1208898Skais 	ssl->tcp_mss = mss;
1209898Skais 	ssl->sendalert_level = alert_warning;
1210898Skais 	ssl->sendalert_desc = close_notify;
1211898Skais 	ssl->sid.cached = B_FALSE;
1212898Skais 
1213898Skais 	*kssl_ctxp = (kssl_ctx_t)ssl;
1214898Skais 	KSSL_SSL_REFHOLD(ssl);
1215898Skais 	return (KSSL_STS_OK);
1216898Skais }
1217898Skais 
1218898Skais /*
1219898Skais  * Builds SSL records out of the chain of mblks, and returns it.
1220*10520SBhargava.Yenduri@Sun.COM  * Takes a copy of the message before encrypting it if it has another
1221898Skais  * reference.
1222898Skais  * In case of failure, NULL is returned, and the message will be
1223898Skais  * freed by the caller.
1224898Skais  * A NULL mp means a close_notify is requested.
1225898Skais  */
1226898Skais mblk_t *
1227898Skais kssl_build_record(kssl_ctx_t ctx, mblk_t *mp)
1228898Skais {
1229898Skais 	ssl_t *ssl = (ssl_t *)ctx;
1230898Skais 	mblk_t *retmp = mp, *bp = mp, *prevbp = mp, *copybp;
1231898Skais 
1232898Skais 	ASSERT(ssl != NULL);
1233898Skais 	ASSERT(mp != NULL);
1234898Skais 
1235898Skais 	do {
1236898Skais 		if (DB_REF(bp) > 1) {
1237898Skais 			/*
1238898Skais 			 * Fortunately copyb() preserves the offset,
1239*10520SBhargava.Yenduri@Sun.COM 			 * tail space and alignment so the copy is
1240898Skais 			 * ready to be made an SSL record.
1241898Skais 			 */
1242898Skais 			if ((copybp = copyb(bp)) == NULL)
1243898Skais 				return (NULL);
1244898Skais 
1245898Skais 			copybp->b_cont = bp->b_cont;
1246898Skais 			if (bp == mp) {
1247898Skais 				retmp = copybp;
1248898Skais 			} else {
1249898Skais 				prevbp->b_cont = copybp;
1250898Skais 			}
1251898Skais 			freeb(bp);
1252898Skais 			bp = copybp;
1253898Skais 		}
1254898Skais 
1255898Skais 		if (kssl_build_single_record(ssl, bp) != KSSL_STS_OK)
1256898Skais 			return (NULL);
1257898Skais 
1258898Skais 		prevbp = bp;
1259898Skais 		bp = bp->b_cont;
1260898Skais 	} while (bp != NULL);
1261898Skais 
1262898Skais 	return (retmp);
1263898Skais }
1264898Skais 
1265898Skais /*
1266*10520SBhargava.Yenduri@Sun.COM  * Builds a single SSL record.
1267898Skais  * In-line encryption of the record.
1268898Skais  */
1269898Skais static kssl_status_t
1270898Skais kssl_build_single_record(ssl_t *ssl, mblk_t *mp)
1271898Skais {
1272898Skais 	int len;
1273*10520SBhargava.Yenduri@Sun.COM 	int reclen;
1274898Skais 	uchar_t *recstart, *versionp;
1275898Skais 	KSSLCipherSpec *spec;
1276898Skais 	int mac_sz;
1277*10520SBhargava.Yenduri@Sun.COM 	int pad_sz;
1278898Skais 
1279898Skais 	spec = &ssl->spec[KSSL_WRITE];
1280898Skais 	mac_sz = spec->mac_hashsz;
1281898Skais 
1282898Skais 	ASSERT(DB_REF(mp) == 1);
1283898Skais 	ASSERT((mp->b_rptr - mp->b_datap->db_base >= SSL3_HDR_LEN) &&
1284898Skais 	    (mp->b_datap->db_lim - mp->b_wptr >= mac_sz + spec->cipher_bsize));
1285898Skais 
1286898Skais 	len = MBLKL(mp);
1287898Skais 
1288898Skais 	ASSERT(len > 0);
1289898Skais 
1290898Skais 	mutex_enter(&ssl->kssl_lock);
1291898Skais 
1292898Skais 	recstart = mp->b_rptr = mp->b_rptr - SSL3_HDR_LEN;
1293898Skais 	recstart[0] = content_application_data;
1294898Skais 	recstart[1] = ssl->major_version;
1295898Skais 	recstart[2] = ssl->minor_version;
1296898Skais 	versionp = &recstart[1];
1297898Skais 
1298898Skais 	reclen = len + mac_sz;
1299898Skais 	if (spec->cipher_type == type_block) {
1300898Skais 		pad_sz = spec->cipher_bsize -
1301898Skais 		    (reclen & (spec->cipher_bsize - 1));
1302898Skais 		ASSERT(reclen + pad_sz <=
1303898Skais 		    SSL3_MAX_RECORD_LENGTH);
1304898Skais 		reclen += pad_sz;
1305898Skais 	}
1306898Skais 	recstart[3] = (reclen >> 8) & 0xff;
1307898Skais 	recstart[4] = reclen & 0xff;
1308898Skais 
1309898Skais 	if (kssl_mac_encrypt_record(ssl, content_application_data, versionp,
1310898Skais 	    recstart, mp) != 0) {
1311898Skais 		/* Do we need an internal_error Alert here? */
1312898Skais 		mutex_exit(&ssl->kssl_lock);
1313898Skais 		return (KSSL_STS_ERR);
1314898Skais 	}
1315898Skais 
1316898Skais 	KSSL_COUNTER(appdata_record_outs, 1);
1317898Skais 	mutex_exit(&ssl->kssl_lock);
1318898Skais 	return (KSSL_STS_OK);
1319898Skais }
1320