xref: /onnv-gate/usr/src/uts/common/inet/kssl/ksslapi.c (revision 4556:ac52c70ecbe9)
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 /*
22*4556Svk199839  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23898Skais  * Use is subject to license terms.
24898Skais  */
25898Skais 
26898Skais #pragma ident	"%Z%%M%	%I%	%E% SMI"
27898Skais 
28898Skais #include <sys/types.h>
29898Skais #include <sys/stream.h>
30898Skais #include <sys/strsun.h>
31898Skais #include <sys/cmn_err.h>
32898Skais #include <sys/kmem.h>
33898Skais #include <sys/cpuvar.h>
34898Skais #include <sys/atomic.h>
35898Skais #include <sys/sysmacros.h>
36898Skais 
37898Skais #include <inet/common.h>
38898Skais #include <inet/ip.h>
39898Skais #include <inet/ip6.h>
40898Skais 
41898Skais #include <sys/systm.h>
42898Skais #include <sys/param.h>
43898Skais #include <sys/tihdr.h>
44898Skais 
45898Skais #include "ksslimpl.h"
46898Skais #include "ksslproto.h"
47898Skais #include "ksslapi.h"
48898Skais 
49898Skais static kssl_cmd_t kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp,
50898Skais     mblk_t **decrmp, kssl_callback_t cbfn, void *arg);
51898Skais static boolean_t kssl_enqueue(kssl_chain_t **head, void *item);
52898Skais static void kssl_dequeue(kssl_chain_t **head, void *item);
53898Skais static kssl_status_t kssl_build_single_record(ssl_t *ssl, mblk_t *mp);
54898Skais 
55898Skais /*
56898Skais  * The socket T_bind_req message is intercepted and re-routed here
57898Skais  * to see is there is SSL relevant job to do, based on the kssl config
58898Skais  * in the kssl_entry_tab.
59898Skais  * Looks up the kernel SSL proxy table, to find an entry that matches the
60898Skais  * same serveraddr, and has one of the following two criteria:
61898Skais  * 1. in_port is an ssl_port. This endpoint can be used later as a fallback
62898Skais  *    to complete connections that cannot be handled by the SSL kernel proxy
63898Skais  *    (typically non supported ciphersuite). The cookie for the calling client
64898Skais  *    is saved with the kssl_entry to be retrieved for the fallback.
65898Skais  *    The function returns KSSL_HAS_PROXY.
66898Skais  *
67898Skais  * 2. in_port is a proxy port for another ssl port. The ssl port is then
68898Skais  *    substituted to the in_port in the bind_req TPI structure, so that
69898Skais  *    the bind falls through to the SSL port. At the end of this operation,
70898Skais  *    all the packets arriving to the SSL port will be delivered to an
71898Skais  *    accepted endpoint child of this bound socket.
72898Skais  *    The  kssl_entry_t is returned in *ksslent, for later use by the
73898Skais  *    lower modules' SSL hooks that handle the Handshake messages.
74898Skais  *    The function returns KSSL_IS_PROXY.
75898Skais  *
76898Skais  * The function returns KSSL_NO_PROXY otherwise. We do not suppport
77898Skais  * IPv6 addresses.
78898Skais  */
79898Skais 
80898Skais kssl_endpt_type_t
81898Skais kssl_check_proxy(mblk_t *bindmp, void *cookie, kssl_ent_t *ksslent)
82898Skais {
83898Skais 	int i;
84898Skais 	kssl_endpt_type_t ret;
85898Skais 	kssl_entry_t *ep;
86898Skais 	sin_t *sin;
87898Skais 	struct T_bind_req *tbr;
88898Skais 	ipaddr_t v4addr;
89898Skais 	in_port_t in_port;
90898Skais 
91898Skais 	if (kssl_enabled == 0) {
92898Skais 		return (KSSL_NO_PROXY);
93898Skais 	}
94898Skais 
95898Skais 	tbr = (struct T_bind_req *)bindmp->b_rptr;
96898Skais 
97898Skais 	ret = KSSL_NO_PROXY;
98898Skais 
99898Skais 
100898Skais 	switch (tbr->ADDR_length) {
101898Skais 	case sizeof (sin_t):
102898Skais 		sin = (sin_t *)(bindmp->b_rptr + tbr->ADDR_length);
103898Skais 		in_port = ntohs(sin->sin_port);
104898Skais 		v4addr = sin->sin_addr.s_addr;
105898Skais 		break;
106898Skais 
107898Skais 	case sizeof (sin6_t):
108898Skais 		/* Future support of IPv6 goes here */
109898Skais 	default:
110898Skais 		/* Should ASSERT() here? */
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 
120898Skais 		if ((ep->ke_laddr == v4addr) || (ep->ke_laddr == INADDR_ANY)) {
121898Skais 
122898Skais 			/* This is an SSL port to fallback to */
123898Skais 			if (ep->ke_ssl_port == in_port) {
124898Skais 
125898Skais 				/*
126898Skais 				 * Let's see first if there's at least
127898Skais 				 * an endpoint for a proxy server.
128898Skais 				 * If there's none, then we return as we have
129898Skais 				 * no proxy, so that the bind() to the
130898Skais 				 * transport layer goes through.
131898Skais 				 * The calling module will ask for this
132898Skais 				 * cookie if it wants to fall back to it,
133898Skais 				 * so add this one to the list of fallback
134898Skais 				 * clients.
135898Skais 				 */
136898Skais 				if (!kssl_enqueue((kssl_chain_t **)
137898Skais 				    &(ep->ke_fallback_head), cookie)) {
138898Skais 					break;
139898Skais 				}
140898Skais 
141898Skais 				/*
142898Skais 				 * Now transform the T_BIND_REQ into
143898Skais 				 * a T_BIND_ACK.
144898Skais 				 */
145898Skais 				tbr->PRIM_type = T_BIND_ACK;
146898Skais 				bindmp->b_datap->db_type = M_PCPROTO;
147898Skais 
148898Skais 				KSSL_ENTRY_REFHOLD(ep);
149898Skais 				*ksslent = (kssl_ent_t)ep;
150898Skais 
151898Skais 				ret = KSSL_HAS_PROXY;
152898Skais 				break;
153898Skais 			}
154898Skais 
155898Skais 			/* This is a proxy port. */
156898Skais 			if (ep->ke_proxy_port == in_port) {
157898Skais 				mblk_t *entmp;
158898Skais 
159898Skais 				/* Append this entry to the bind_req mblk */
160898Skais 
161898Skais 				entmp = allocb(sizeof (kssl_entry_t),
162898Skais 				    BPRI_MED);
163898Skais 				if (entmp == NULL)
164898Skais 					break;
165898Skais 				*((kssl_entry_t **)entmp->b_rptr) = ep;
166898Skais 
167898Skais 				entmp->b_wptr = entmp->b_rptr +
168898Skais 				    sizeof (kssl_entry_t);
169898Skais 
170898Skais 				bindmp->b_cont = entmp;
171898Skais 
172898Skais 				/* Add the caller's cookie to proxies list */
173898Skais 
174898Skais 				if (!kssl_enqueue((kssl_chain_t **)
175898Skais 				    &(ep->ke_proxy_head), cookie)) {
176898Skais 					freeb(bindmp->b_cont);
177898Skais 					bindmp->b_cont = NULL;
178898Skais 					break;
179898Skais 				}
180898Skais 
181898Skais 				/*
182898Skais 				 * Make this look  like the SSL port to the
183898Skais 				 * transport below
184898Skais 				 */
185898Skais 				sin->sin_port = htons(ep->ke_ssl_port);
186898Skais 
187898Skais 				tbr->PRIM_type = T_SSL_PROXY_BIND_REQ;
188898Skais 
189898Skais 				KSSL_ENTRY_REFHOLD(ep);
190898Skais 				*ksslent = (kssl_ent_t)ep;
191898Skais 
192898Skais 				ret = KSSL_IS_PROXY;
193898Skais 				break;
194898Skais 			}
195898Skais 		}
196898Skais 	}
197898Skais 
198898Skais 	mutex_exit(&kssl_tab_mutex);
199898Skais 	return (ret);
200898Skais }
201898Skais 
202898Skais /*
203898Skais  * Retrieved an endpoint "bound" to the SSL entry.
204898Skais  * Such endpoint has previously called kssl_check_proxy(), got itself
205898Skais  * linked to the kssl_entry's ke_fallback_head list.
206898Skais  * This routine returns the cookie from that SSL entry ke_fallback_head list.
207898Skais  */
208898Skais void *
209898Skais kssl_find_fallback(kssl_ent_t ksslent)
210898Skais {
211898Skais 	kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent;
212898Skais 
213898Skais 	if (kssl_entry->ke_fallback_head != NULL)
214898Skais 		return (kssl_entry->ke_fallback_head->fallback_bound);
215898Skais 
216898Skais 	KSSL_COUNTER(proxy_fallback_failed, 1);
217898Skais 
218898Skais 	return (NULL);
219898Skais }
220898Skais 
221898Skais /*
222898Skais  * Re-usable code for adding and removing an element to/from a chain that
223898Skais  * matches "item"
224898Skais  * The chain is simple-linked and NULL ended.
225898Skais  */
226898Skais 
227898Skais /*
228898Skais  * This routine returns TRUE if the item was either successfully added to
229898Skais  * the chain, or is already there. It returns FALSE otherwise.
230898Skais  */
231898Skais static boolean_t
232898Skais kssl_enqueue(kssl_chain_t **head, void *item)
233898Skais {
234898Skais 	kssl_chain_t *newchain, *cur;
235898Skais 
236898Skais 	/* Lookup the existing entries to avoid duplicates */
237898Skais 	cur = *head;
238898Skais 	while (cur != NULL) {
239898Skais 		if (cur->item == item) {
240898Skais 			return (B_TRUE);
241898Skais 		}
242898Skais 		cur = cur->next;
243898Skais 	}
244898Skais 
245898Skais 	newchain = kmem_alloc(sizeof (kssl_chain_t), KM_NOSLEEP);
246898Skais 	if (newchain == NULL) {
247898Skais 		return (B_FALSE);
248898Skais 	}
249898Skais 
250898Skais 	newchain->item = item;
251898Skais 	newchain->next = *head;
252898Skais 	*head = newchain;
253898Skais 	return (B_TRUE);
254898Skais }
255898Skais 
256898Skais static void
257898Skais kssl_dequeue(kssl_chain_t **head, void *item)
258898Skais {
259898Skais 	kssl_chain_t *prev, *cur;
260898Skais 
261898Skais 	prev = cur = *head;
262898Skais 	while (cur != NULL) {
263898Skais 		if (cur->item == item) {
264898Skais 			if (cur == *head)
265898Skais 				*head = (*head)->next;
266898Skais 			else
267898Skais 				prev->next = cur->next;
268898Skais 			kmem_free(cur, sizeof (kssl_chain_t));
269898Skais 			return;
270898Skais 		}
271898Skais 		prev = cur;
272898Skais 		cur = cur->next;
273898Skais 	}
274898Skais }
275898Skais 
276898Skais /*
277898Skais  * Holds the kssl_entry
278898Skais  */
279898Skais void
280898Skais kssl_hold_ent(kssl_ent_t ksslent)
281898Skais {
282898Skais 	KSSL_ENTRY_REFHOLD((kssl_entry_t *)ksslent);
283898Skais }
284898Skais 
285898Skais /*
286898Skais  * Releases the kssl_entry
287898Skais  * If the caller passes a cookie, then it should be removed from both
288898Skais  * proxies and fallbacks chains.
289898Skais  */
290898Skais void
291898Skais kssl_release_ent(kssl_ent_t ksslent, void *cookie, kssl_endpt_type_t endpt_type)
292898Skais {
293898Skais 	kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent;
294898Skais 
295898Skais 	if (cookie != NULL) {
296898Skais 		if (endpt_type == KSSL_IS_PROXY)
297898Skais 			ASSERT(kssl_entry->ke_proxy_head != NULL);
298898Skais 			kssl_dequeue(
299898Skais 			    (kssl_chain_t **)&kssl_entry->ke_proxy_head,
300898Skais 			    cookie);
301898Skais 		if (endpt_type == KSSL_HAS_PROXY)
302898Skais 			ASSERT(kssl_entry->ke_fallback_head != NULL);
303898Skais 			kssl_dequeue(
304898Skais 			    (kssl_chain_t **)&kssl_entry->ke_fallback_head,
305898Skais 			    cookie);
306898Skais 	}
307898Skais 	KSSL_ENTRY_REFRELE(kssl_entry);
308898Skais }
309898Skais 
310898Skais /*
311898Skais  * Holds the kssl context
312898Skais  */
313898Skais void
314898Skais kssl_hold_ctx(kssl_ctx_t ksslctx)
315898Skais {
316898Skais 	ssl_t *ssl = (ssl_t *)ksslctx;
317898Skais 
318898Skais 	KSSL_SSL_REFHOLD(ssl);
319898Skais }
320898Skais 
321898Skais /*
322898Skais  * Releases the kssl_context
323898Skais  */
324898Skais void
325898Skais kssl_release_ctx(kssl_ctx_t ksslctx)
326898Skais {
327898Skais 	KSSL_SSL_REFRELE((ssl_t *)ksslctx);
328898Skais }
329898Skais 
330898Skais /*
331898Skais  * Packets are accumulated here, if there are packets already queued,
332898Skais  * or if the context is active.
333898Skais  * The context is active when an incoming record processing function
334898Skais  * is already executing on a different thread.
335898Skais  * Queued packets are handled either when an mblk arrived and completes
336898Skais  * a record, or, when the active context processor finishes the task at
337898Skais  * hand.
338898Skais  * The caller has to keep calling this routine in a loop until it returns
339898Skais  * B_FALSE in *more. The reason for this is SSL3: The protocol
340898Skais  * allows the client to send its first application_data message right
341898Skais  * after it had sent its Finished message, and not wait for the server
342898Skais  * ChangeCipherSpec and Finished. This overlap means we can't batch up
343898Skais  * a returned Handshake message to be sent on the wire
344898Skais  * with a decrypted application_data to be delivered to the application.
345898Skais  */
346898Skais kssl_cmd_t
347898Skais kssl_input(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, boolean_t *more,
348898Skais     kssl_callback_t cbfn, void *arg)
349898Skais {
350898Skais 	mblk_t *recmp, *outmp = NULL;
351898Skais 	kssl_cmd_t kssl_cmd;
352898Skais 	ssl_t *ssl;
353898Skais 	uint8_t *rec_sz_p;
354898Skais 	int mplen;
355898Skais 	SSL3ContentType content_type;
356898Skais 	uint16_t rec_sz;
357898Skais 
358898Skais 	ASSERT(ctx != NULL);
359898Skais 
360898Skais 	if (mp != NULL) {
361898Skais 		ASSERT(mp->b_prev == NULL && mp->b_next == NULL);
362898Skais 	}
363898Skais 
364898Skais 	ssl = (ssl_t *)(ctx);
365898Skais 
366898Skais 	*decrmp = NULL;
367898Skais 	*more = B_FALSE;
368898Skais 
369898Skais 	mutex_enter(&ssl->kssl_lock);
370898Skais 
371898Skais 	if (ssl->close_notify == B_TRUE) {
372898Skais 		goto sendnewalert;
373898Skais 	}
374898Skais 
375898Skais 	/* Whomever is currently processing this connection will get to this */
376898Skais 	if (ssl->activeinput) {
377898Skais 		if (mp != NULL) {
378898Skais 			KSSL_ENQUEUE_MP(ssl, mp);
379898Skais 		}
380898Skais 		mutex_exit(&ssl->kssl_lock);
381898Skais 		return (KSSL_CMD_NONE);
382898Skais 	}
383898Skais 
384898Skais 	/*
385898Skais 	 * Fast path for complete incoming application_data records on an empty
386898Skais 	 * queue.
387898Skais 	 * This is by far the most frequently encountered case
388898Skais 	 */
389898Skais 
390898Skais 	if ((!ssl->activeinput) && (ssl->rec_ass_head == NULL) &&
391898Skais 	    ((mp != NULL) && (mplen = MBLKL(mp)) > SSL3_HDR_LEN)) {
392898Skais 
393898Skais 		content_type = (SSL3ContentType)mp->b_rptr[0];
394898Skais 
395898Skais 		if ((content_type == content_application_data) &&
396898Skais 		    (ssl->hs_waitstate == idle_handshake)) {
397898Skais 			rec_sz_p = SSL3_REC_SIZE(mp);
398898Skais 			rec_sz = BE16_TO_U16(rec_sz_p);
399898Skais 
400898Skais 			if ((mp->b_cont == NULL) && (mplen == rec_sz)) {
401898Skais 
402898Skais 				mp->b_flag &= ~DBLK_COOKED;
403898Skais 				*decrmp = mp;
404898Skais 				mutex_exit(&ssl->kssl_lock);
405898Skais 				return (KSSL_CMD_DELIVER_PROXY);
406898Skais 			}
407898Skais 		}
408898Skais 	}
409898Skais 
410898Skais 	ssl->activeinput = B_TRUE;
411898Skais 	/* Accumulate at least one record */
412898Skais 	if (mp != NULL) {
413898Skais 		KSSL_ENQUEUE_MP(ssl, mp);
414898Skais 		mp = NULL;
415898Skais 	}
416898Skais 	recmp = kssl_get_next_record(ssl);
417898Skais 
418898Skais 	if (recmp == NULL) {
419898Skais 		ssl->activeinput = B_FALSE;
420898Skais 		if (ssl->alert_sendbuf != NULL) {
421898Skais 			goto sendalert;
422898Skais 		}
423898Skais 		/* Not even a complete header yet. wait for the rest */
424898Skais 		mutex_exit(&ssl->kssl_lock);
425898Skais 		return (KSSL_CMD_NONE);
426898Skais 	}
427898Skais 
428898Skais 	do {
429*4556Svk199839 		content_type = (SSL3ContentType)recmp->b_rptr[0];
430*4556Svk199839 
431*4556Svk199839 		switch (content_type) {
432*4556Svk199839 		case content_application_data:
433898Skais 			/*
434898Skais 			 * application_data records are decrypted and
435898Skais 			 * MAC-verified by the stream head, and in the context
436898Skais 			 * a read()'ing thread. This avoids unfairly charging
437898Skais 			 * the cost of handling this record on the whole system,
438898Skais 			 * and prevents doing it while in the shared IP
439898Skais 			 * perimeter.
440898Skais 			 */
441898Skais 			ssl->activeinput = B_FALSE;
442898Skais 			if (ssl->hs_waitstate != idle_handshake) {
443898Skais 				goto sendnewalert;
444898Skais 			}
445898Skais 			outmp = recmp;
446898Skais 			kssl_cmd = KSSL_CMD_DELIVER_PROXY;
447*4556Svk199839 			break;
448*4556Svk199839 		case content_change_cipher_spec:
449*4556Svk199839 		case content_alert:
450*4556Svk199839 		case content_handshake:
451*4556Svk199839 		case content_handshake_v2:
452898Skais 			/*
453898Skais 			 * If we're past the initial handshake, start letting
454898Skais 			 * the stream head process all records, in particular
455898Skais 			 * the close_notify.
456898Skais 			 * This is needed to avoid processing them out of
457898Skais 			 * sequence when previous application data packets are
458898Skais 			 * waiting to be decrypted/MAC'ed and delivered.
459898Skais 			 */
460898Skais 			if (ssl->hs_waitstate == idle_handshake) {
461898Skais 				ssl->activeinput = B_FALSE;
462898Skais 				outmp = recmp;
463898Skais 				kssl_cmd = KSSL_CMD_DELIVER_PROXY;
464898Skais 			} else {
465898Skais 				kssl_cmd = kssl_handle_any_record(ssl, recmp,
466898Skais 				    &outmp, cbfn, arg);
467898Skais 			}
468*4556Svk199839 			break;
469*4556Svk199839 		default:
470*4556Svk199839 			ssl->activeinput = B_FALSE;
471*4556Svk199839 			goto sendnewalert;
472898Skais 		}
473898Skais 
474898Skais 		/* Priority to Alert messages */
475898Skais 		if (ssl->alert_sendbuf != NULL) {
476898Skais 			goto sendalert;
477898Skais 		}
478898Skais 
479898Skais 		/* Then handshake messages */
480898Skais 		if (ssl->handshake_sendbuf) {
481898Skais 			if (*decrmp != NULL) {
482898Skais 				linkb(*decrmp, ssl->handshake_sendbuf);
483898Skais 			} else {
484898Skais 				*decrmp = ssl->handshake_sendbuf;
485898Skais 			}
486898Skais 			ssl->handshake_sendbuf = NULL;
487898Skais 
488898Skais 			*more = ((ssl->rec_ass_head != NULL) &&
489898Skais 			    (!ssl->activeinput));
490898Skais 			mutex_exit(&ssl->kssl_lock);
491898Skais 			return (kssl_cmd);
492898Skais 		}
493898Skais 
494898Skais 		if (ssl->hs_waitstate == idle_handshake) {
495898Skais 			*more = ((ssl->rec_ass_head != NULL) &&
496898Skais 			    (!ssl->activeinput));
497898Skais 		}
498898Skais 
499898Skais 		if (outmp != NULL) {
500898Skais 			*decrmp = outmp;
501898Skais 			/*
502898Skais 			 * Don't process any packet after an application_data.
503898Skais 			 * We could well receive the close_notify which should
504898Skais 			 * be handled separately.
505898Skais 			 */
506898Skais 			mutex_exit(&ssl->kssl_lock);
507898Skais 			return (kssl_cmd);
508898Skais 		}
509898Skais 		/*
510898Skais 		 * The current record isn't done yet. Don't start the next one
511898Skais 		 */
512898Skais 		if (ssl->activeinput) {
513898Skais 			mutex_exit(&ssl->kssl_lock);
514898Skais 			return (kssl_cmd);
515898Skais 		}
516898Skais 	} while ((recmp = kssl_get_next_record(ssl)) != NULL);
517898Skais 
518898Skais 	mutex_exit(&ssl->kssl_lock);
519898Skais 	return (kssl_cmd);
520898Skais 
521898Skais sendnewalert:
522898Skais 	kssl_send_alert(ssl, alert_fatal, unexpected_message);
523898Skais 	if (mp != NULL) {
524898Skais 		freeb(mp);
525898Skais 	}
526898Skais 
527898Skais sendalert:
528898Skais 	*decrmp = ssl->alert_sendbuf;
529898Skais 	ssl->alert_sendbuf = NULL;
530898Skais 	mutex_exit(&ssl->kssl_lock);
531898Skais 	return (KSSL_CMD_SEND);
532898Skais }
533898Skais 
534898Skais /*
535898Skais  * Decrypt and verify the MAC of an incoming chain of application_data record.
536898Skais  * Each block has exactly one SSL record.
537898Skais  * This routine recycles its incoming mblk, and flags it as DBLK_COOKED
538898Skais  */
539898Skais kssl_cmd_t
540898Skais kssl_handle_record(kssl_ctx_t ctx, mblk_t **mpp, mblk_t **outmp)
541898Skais {
542898Skais 	uchar_t *recend, *rec_sz_p;
543898Skais 	uchar_t *real_recend;
5441139Skais 	mblk_t *prevmp = NULL, *nextmp, *firstmp, *mp, *copybp;
545898Skais 	int mac_sz;
546898Skais 	uchar_t version[2];
547898Skais 	uint16_t rec_sz;
548898Skais 	SSL3AlertDescription desc;
549898Skais 	SSL3ContentType content_type;
550898Skais 	ssl_t *ssl;
551898Skais 	KSSLCipherSpec *spec;
552898Skais 	int error = 0, ret;
553898Skais 	kssl_cmd_t kssl_cmd = KSSL_CMD_DELIVER_PROXY;
554898Skais 	boolean_t deliverit = B_FALSE;
555898Skais 	crypto_data_t cipher_data;
556898Skais 
557898Skais 	ASSERT(ctx != NULL);
558898Skais 
559898Skais 	ssl = (ssl_t *)(ctx);
560898Skais 
5611139Skais 	mp = firstmp = *mpp;
562898Skais 	*outmp = NULL;
563898Skais 
564898Skais more:
565898Skais 
566898Skais 	while (mp != NULL) {
567898Skais 
568898Skais 		if (DB_REF(mp) > 1) {
569898Skais 			/*
570898Skais 			 * Fortunately copyb() preserves the offset,
571898Skais 			 * tail space and alignement so the copy is
572898Skais 			 * ready to be made an SSL record.
573898Skais 			 */
574898Skais 			if ((copybp = copyb(mp)) == NULL)
575898Skais 				return (NULL);
576898Skais 
577898Skais 			copybp->b_cont = mp->b_cont;
5781139Skais 			if (mp == firstmp) {
579898Skais 				*mpp = copybp;
580*4556Svk199839 			} else if (prevmp != NULL) {
581898Skais 				prevmp->b_cont = copybp;
582898Skais 			}
583898Skais 			freeb(mp);
584898Skais 			mp = copybp;
585898Skais 		}
586898Skais 
587898Skais 		content_type = (SSL3ContentType)mp->b_rptr[0];
588898Skais 
589*4556Svk199839 		switch (content_type) {
590*4556Svk199839 		case content_application_data:
591*4556Svk199839 			break;
592*4556Svk199839 		case content_change_cipher_spec:
593*4556Svk199839 		case content_alert:
594*4556Svk199839 		case content_handshake:
595*4556Svk199839 		case content_handshake_v2:
596898Skais 			nextmp = mp->b_cont;
597898Skais 
598898Skais 			/* Remove this message */
599898Skais 			if (prevmp != NULL) {
600898Skais 				prevmp->b_cont = nextmp;
601898Skais 
602898Skais 				/*
603898Skais 				 * If we had processed blocks that need to
604898Skais 				 * be delivered, then remember that error code
605898Skais 				 */
606898Skais 				if (kssl_cmd == KSSL_CMD_DELIVER_PROXY)
607898Skais 					deliverit = B_TRUE;
608898Skais 			}
609898Skais 
610898Skais 			mutex_enter(&ssl->kssl_lock);
611*4556Svk199839 			/* NOTE: This routine could free mp. */
612898Skais 			kssl_cmd = kssl_handle_any_record(ssl, mp, outmp,
613898Skais 			    NULL, NULL);
614898Skais 
615898Skais 			if (ssl->alert_sendbuf != NULL) {
616*4556Svk199839 				mp = nextmp;
617898Skais 				goto sendalert;
618898Skais 			}
619898Skais 			mutex_exit(&ssl->kssl_lock);
620898Skais 
621898Skais 			if (deliverit) {
622898Skais 				kssl_cmd = KSSL_CMD_DELIVER_PROXY;
623898Skais 			}
624898Skais 
625898Skais 			mp = nextmp;
626*4556Svk199839 			continue;	/* to the while loop */
627*4556Svk199839 		default:
628*4556Svk199839 			desc = decode_error;
629*4556Svk199839 			KSSL_COUNTER(internal_errors, 1);
630*4556Svk199839 			goto makealert;
631898Skais 		}
632898Skais 
633898Skais 		version[0] = mp->b_rptr[1];
634898Skais 		version[1] = mp->b_rptr[2];
635898Skais 		rec_sz_p = SSL3_REC_SIZE(mp);
636898Skais 		rec_sz = BE16_TO_U16(rec_sz_p);
637898Skais 
638898Skais 		mp->b_rptr += SSL3_HDR_LEN;
639898Skais 		recend = mp->b_rptr + rec_sz;
640898Skais 		real_recend = recend;
641898Skais 
642*4556Svk199839 		/*
643*4556Svk199839 		 * Check the assumption that each mblk contains exactly
644*4556Svk199839 		 * one complete SSL record. We bail out if the check fails.
645*4556Svk199839 		 */
646*4556Svk199839 		ASSERT(recend == mp->b_wptr);
647*4556Svk199839 		if (recend != mp->b_wptr) {
648*4556Svk199839 			desc = decode_error;
649*4556Svk199839 			KSSL_COUNTER(internal_errors, 1);
650*4556Svk199839 			goto makealert;
651*4556Svk199839 		}
652*4556Svk199839 
653898Skais 		spec = &ssl->spec[KSSL_READ];
654898Skais 		mac_sz = spec->mac_hashsz;
655898Skais 		if (spec->cipher_ctx != 0) {
6561139Skais 
6571139Skais 			/*
6581139Skais 			 * The record length must be a multiple of the
6591139Skais 			 * block size for block ciphers.
6601139Skais 			 * The cipher_bsize is always a power of 2.
6611139Skais 			 */
6621139Skais 			if ((spec->cipher_type == type_block) &&
6631139Skais 			    ((rec_sz & (spec->cipher_bsize - 1)) != 0)) {
6641139Skais #ifdef	DEBUG
6651139Skais 				cmn_err(CE_WARN, "kssl_handle_record: "
6661139Skais 				    "bad record size");
6671139Skais #endif	/* DEBUG */
6681139Skais 				KSSL_COUNTER(record_decrypt_failure, 1);
6691139Skais 				mp->b_rptr = recend;
6701139Skais 				desc = decrypt_error;
6711139Skais 				goto makealert;
6721139Skais 			}
6731139Skais 
674898Skais 			cipher_data.cd_format = CRYPTO_DATA_RAW;
675898Skais 			cipher_data.cd_offset = 0;
676898Skais 			cipher_data.cd_length = rec_sz;
677898Skais 			cipher_data.cd_miscdata = NULL;
678898Skais 			cipher_data.cd_raw.iov_base = (char *)mp->b_rptr;
679898Skais 			cipher_data.cd_raw.iov_len = rec_sz;
680898Skais 			error = crypto_decrypt_update(spec->cipher_ctx,
681898Skais 			    &cipher_data, NULL, NULL);
682898Skais 			if (CRYPTO_ERR(error)) {
683898Skais #ifdef	DEBUG
684898Skais 				cmn_err(CE_WARN, "kssl_handle_record: "
685898Skais 				    "crypto_decrypt_update failed: 0x%02X",
686898Skais 				    error);
687898Skais #endif	/* DEBUG */
688898Skais 				KSSL_COUNTER(record_decrypt_failure, 1);
689898Skais 				mp->b_rptr = recend;
690898Skais 				desc = decrypt_error;
691898Skais 				goto makealert;
692898Skais 			}
693898Skais 		}
694898Skais 		if (spec->cipher_type == type_block) {
695898Skais 			uint_t pad_sz = recend[-1];
696898Skais 			pad_sz++;
697898Skais 			if (pad_sz + mac_sz > rec_sz) {
698898Skais 				mp->b_rptr = recend;
699898Skais 				desc = bad_record_mac;
700898Skais 				goto makealert;
701898Skais 			}
702898Skais 			rec_sz -= pad_sz;
703898Skais 			recend -= pad_sz;
704898Skais 		}
705898Skais 		if (mac_sz != 0) {
706898Skais 			uchar_t hash[MAX_HASH_LEN];
707898Skais 			if (rec_sz < mac_sz) {
708898Skais 				mp->b_rptr = real_recend;
709898Skais 				desc = bad_record_mac;
710898Skais 				goto makealert;
711898Skais 			}
712898Skais 			rec_sz -= mac_sz;
713898Skais 			recend -= mac_sz;
714898Skais 			ret = kssl_compute_record_mac(ssl, KSSL_READ,
715898Skais 				ssl->seq_num[KSSL_READ], content_type,
716898Skais 				version, mp->b_rptr, rec_sz, hash);
717898Skais 			if (ret != CRYPTO_SUCCESS ||
718898Skais 			    bcmp(hash, recend, mac_sz)) {
719898Skais 				mp->b_rptr = real_recend;
720898Skais 				desc = bad_record_mac;
721898Skais #ifdef	DEBUG
722898Skais 				cmn_err(CE_WARN, "kssl_handle_record: "
723898Skais 					"msg MAC mismatch");
724898Skais #endif	/* DEBUG */
725898Skais 				KSSL_COUNTER(verify_mac_failure, 1);
726898Skais 				goto makealert;
727898Skais 			}
728898Skais 			ssl->seq_num[KSSL_READ]++;
729898Skais 		}
730898Skais 
731898Skais 		if (ssl->hs_waitstate != idle_handshake) {
732898Skais 			mp->b_rptr = real_recend;
733898Skais 			desc = unexpected_message;
734898Skais 			goto makealert;
735898Skais 		}
736898Skais 		mp->b_wptr = recend;
737898Skais 
738*4556Svk199839 		DB_FLAGS(mp) |= DBLK_COOKED;
739*4556Svk199839 		KSSL_COUNTER(appdata_record_ins, 1);
740*4556Svk199839 
741898Skais 		prevmp = mp;
742898Skais 		mp = mp->b_cont;
743898Skais 	}
744898Skais 
745898Skais 	return (kssl_cmd);
746898Skais 
747898Skais makealert:
748898Skais 	nextmp = mp->b_cont;
749898Skais 	freeb(mp);
750898Skais 	mp = nextmp;
751898Skais 	mutex_enter(&ssl->kssl_lock);
752898Skais 	kssl_send_alert(ssl, alert_fatal, desc);
753898Skais 
754898Skais 	if (ssl->alert_sendbuf == NULL) {
755898Skais 		/* internal memory allocation failure. just return. */
756898Skais #ifdef	DEBUG
757898Skais 		cmn_err(CE_WARN, "kssl_handle_record: "
758898Skais 		    "alert message allocation failed");
759898Skais #endif	/* DEBUG */
760898Skais 		mutex_exit(&ssl->kssl_lock);
761898Skais 
762898Skais 		if (mp) {
763898Skais 			prevmp = NULL;
764898Skais 			goto more;
765898Skais 		}
766898Skais 
767898Skais 		return (KSSL_CMD_NONE);
768898Skais 	}
769898Skais 	kssl_cmd = KSSL_CMD_SEND;
770898Skais sendalert:
771898Skais 	if (*outmp == NULL) {
772898Skais 		*outmp = ssl->alert_sendbuf;
773898Skais 	} else {
774898Skais 		linkb(*outmp, ssl->alert_sendbuf);
775898Skais 	}
776898Skais 	ssl->alert_sendbuf = NULL;
777898Skais 	mutex_exit(&ssl->kssl_lock);
778898Skais 
779898Skais 	if (mp) {
780898Skais 		prevmp = NULL;
781898Skais 		goto more;
782898Skais 	}
783898Skais 
784898Skais 	return (kssl_cmd);
785898Skais }
786898Skais /*
787898Skais  * This is the routine that handles incoming SSL records.
788898Skais  * When called the first time, with a NULL context, this routine expects
789898Skais  * a ClientHello SSL Handshake packet and shall allocate a context
790898Skais  * of a new SSL connection.
791898Skais  * During the rest of the handshake packets, the routine adjusts the
792898Skais  * state of the context according to the record received.
793898Skais  * After the ChangeCipherSpec message is received, the routine first
794898Skais  * decrypts/authenticated the packet using the key materials in the
795898Skais  * connection's context.
796898Skais  * The return code tells the caller what to do with the returned packet.
797898Skais  */
798898Skais static kssl_cmd_t
799898Skais kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp,
800898Skais     kssl_callback_t cbfn, void *arg)
801898Skais {
802898Skais 	uchar_t *recend, *rec_sz_p;
803898Skais 	uchar_t version[2];
804898Skais 	uchar_t *real_recend, *save_rptr, *save_wptr;
805898Skais 	int rhsz = SSL3_HDR_LEN;
806898Skais 	uint16_t rec_sz;
807898Skais 	int sz;
808898Skais 	int mac_sz;
809898Skais 	SSL3AlertDescription desc;
810898Skais 	SSL3AlertLevel level;
811898Skais 	SSL3ContentType content_type;
812898Skais 	ssl_t *ssl;
813898Skais 	KSSLCipherSpec *spec;
814898Skais 	int error = 0, ret;
815898Skais 
816898Skais 	ASSERT(ctx != NULL);
817898Skais 
818898Skais 	ssl = (ssl_t *)(ctx);
819898Skais 
820898Skais 	*decrmp = NULL;
821898Skais 
822898Skais 	save_rptr = mp->b_rptr;
823898Skais 	save_wptr = mp->b_wptr;
824898Skais 
825898Skais 	ASSERT(MUTEX_HELD(&ssl->kssl_lock));
826898Skais 
827898Skais 	content_type = (SSL3ContentType)mp->b_rptr[0];
828898Skais 	if (content_type == content_handshake_v2) {
829898Skais 		if (ssl->hs_waitstate == wait_client_hello) {
830898Skais 			/* V2 compatible ClientHello */
831898Skais 			if (mp->b_rptr[3] == 0x03 &&
832898Skais 			    (mp->b_rptr[4] == 0x01 ||
833898Skais 				mp->b_rptr[4] == 0x00)) {
834898Skais 				ssl->major_version = version[0] = mp->b_rptr[3];
835898Skais 				ssl->minor_version = version[1] = mp->b_rptr[4];
836898Skais 			} else {
837898Skais 			/* We don't support "pure" SSLv2 */
838898Skais 				desc = protocol_version;
839898Skais 				goto sendalert;
840898Skais 			}
841898Skais 		}
842898Skais 		rec_sz = (uint16_t)mp->b_rptr[1];
843898Skais 		rhsz = 2;
844898Skais 	} else {
845898Skais 		ssl->major_version = version[0] = mp->b_rptr[1];
846898Skais 		ssl->minor_version = version[1] = mp->b_rptr[2];
847898Skais 		rec_sz_p = SSL3_REC_SIZE(mp);
848898Skais 		rec_sz = BE16_TO_U16(rec_sz_p);
849898Skais 	}
850898Skais 
851898Skais 	mp->b_rptr += rhsz;
852898Skais 	recend = mp->b_rptr + rec_sz;
853898Skais 	real_recend = recend;
854898Skais 
855*4556Svk199839 	/*
856*4556Svk199839 	 * Check the assumption that each mblk contains exactly
857*4556Svk199839 	 * one complete SSL record. We bail out if the check fails.
858*4556Svk199839 	 */
859*4556Svk199839 	ASSERT(recend == mp->b_wptr);
860*4556Svk199839 	if (recend != mp->b_wptr) {
861*4556Svk199839 		desc = decode_error;
862*4556Svk199839 		KSSL_COUNTER(internal_errors, 1);
863*4556Svk199839 		goto sendalert;
864*4556Svk199839 	}
865*4556Svk199839 
866898Skais 	spec = &ssl->spec[KSSL_READ];
867898Skais 	mac_sz = spec->mac_hashsz;
868898Skais 	if (spec->cipher_ctx != 0) {
8691139Skais 		/*
8701139Skais 		 * The record length must be a multiple of the
8711139Skais 		 * block size for block ciphers.
8721139Skais 		 */
8731139Skais 		if ((spec->cipher_type == type_block) &&
8741139Skais 		    ((rec_sz & (spec->cipher_bsize - 1)) != 0)) {
8751139Skais #ifdef	DEBUG
8761139Skais 			cmn_err(CE_WARN, "kssl_handle_any_record: "
8771139Skais 			    "bad record size");
8781139Skais #endif	/* DEBUG */
8791139Skais 			KSSL_COUNTER(record_decrypt_failure, 1);
8801139Skais 			mp->b_rptr = recend;
8811139Skais 			desc = decrypt_error;
8821139Skais 			goto sendalert;
8831139Skais 		}
8841139Skais 
885898Skais 		spec->cipher_data.cd_length = rec_sz;
886898Skais 		spec->cipher_data.cd_raw.iov_base = (char *)mp->b_rptr;
887898Skais 		spec->cipher_data.cd_raw.iov_len = rec_sz;
888898Skais 		error = crypto_decrypt_update(spec->cipher_ctx,
889898Skais 		    &spec->cipher_data, NULL, NULL);
890898Skais 		if (CRYPTO_ERR(error)) {
891898Skais #ifdef	DEBUG
892898Skais 			cmn_err(CE_WARN,
893898Skais 				"kssl_handle_any_record: crypto_decrypt_update "
894898Skais 				"failed: 0x%02X", error);
895898Skais #endif	/* DEBUG */
896898Skais 			KSSL_COUNTER(record_decrypt_failure, 1);
897898Skais 			mp->b_rptr = recend;
898898Skais 			desc = decrypt_error;
899898Skais 			goto sendalert;
900898Skais 		}
901898Skais 	}
902898Skais 	if (spec->cipher_type == type_block) {
903898Skais 		uint_t pad_sz = recend[-1];
904898Skais 		pad_sz++;
905898Skais 		if (pad_sz + mac_sz > rec_sz) {
906898Skais 			mp->b_rptr = recend;
907898Skais 			desc = bad_record_mac;
908898Skais 			goto sendalert;
909898Skais 		}
910898Skais 		rec_sz -= pad_sz;
911898Skais 		recend -= pad_sz;
912898Skais 	}
913898Skais 	if (mac_sz != 0) {
914898Skais 		uchar_t hash[MAX_HASH_LEN];
915898Skais 		if (rec_sz < mac_sz) {
916898Skais 			mp->b_rptr = real_recend;
917898Skais 			desc = bad_record_mac;
918898Skais 			goto sendalert;
919898Skais 		}
920898Skais 		rec_sz -= mac_sz;
921898Skais 		recend -= mac_sz;
922898Skais 		ret = kssl_compute_record_mac(ssl, KSSL_READ,
923898Skais 			ssl->seq_num[KSSL_READ], content_type,
924898Skais 			version, mp->b_rptr, rec_sz, hash);
925898Skais 		if (ret != CRYPTO_SUCCESS ||
926898Skais 		    bcmp(hash, recend, mac_sz)) {
927898Skais 			mp->b_rptr = real_recend;
928898Skais 			desc = bad_record_mac;
929898Skais #ifdef	DEBUG
930898Skais 			cmn_err(CE_WARN, "kssl_handle_any_record: "
931898Skais 				"msg MAC mismatch");
932898Skais #endif	/* DEBUG */
933898Skais 			KSSL_COUNTER(verify_mac_failure, 1);
934898Skais 			goto sendalert;
935898Skais 		}
936898Skais 		ssl->seq_num[KSSL_READ]++;
937898Skais 	}
938898Skais 
939898Skais 	switch (content_type) {
940898Skais 	case content_handshake:
941898Skais 		do {
942898Skais 			if (error != 0 ||
943898Skais 			    /* ignore client renegotiation for now */
944898Skais 			    ssl->hs_waitstate == idle_handshake) {
945898Skais 				mp->b_rptr = recend;
946898Skais 			}
947898Skais 			if (mp->b_rptr == recend) {
948898Skais 				mp->b_rptr = real_recend;
949898Skais 				if (error != 0) {
950898Skais 					goto error;
951898Skais 				}
952898Skais 				freeb(mp);
953898Skais 
954898Skais 				if (ssl->hs_waitstate == wait_client_key_done)
955898Skais 					return (KSSL_CMD_QUEUED);
956898Skais 
957898Skais 				return ((ssl->handshake_sendbuf != NULL) ?
958898Skais 				    KSSL_CMD_SEND : KSSL_CMD_NONE);
959898Skais 			}
960898Skais 			if (ssl->msg.state < MSG_BODY) {
961898Skais 				if (ssl->msg.state == MSG_INIT) {
962898Skais 					ssl->msg.type =
963898Skais 					    (SSL3HandshakeType)*mp->b_rptr++;
964898Skais 					ssl->msg.state = MSG_INIT_LEN;
965898Skais 				}
966898Skais 				if (ssl->msg.state == MSG_INIT_LEN) {
967898Skais 					int msglenb =
968898Skais 					    ssl->msg.msglen_bytes;
969898Skais 					int msglen = ssl->msg.msglen;
970898Skais 					while (mp->b_rptr < recend &&
971898Skais 					    msglenb < 3) {
972898Skais 						msglen = (msglen << 8) +
973898Skais 						    (uint_t)(*mp->b_rptr++);
974898Skais 						msglenb++;
975898Skais 					}
976898Skais 					ssl->msg.msglen_bytes = msglenb;
977898Skais 					ssl->msg.msglen = msglen;
978898Skais 					if (msglenb == 3) {
979898Skais 						ssl->msg.state = MSG_BODY;
980898Skais 					}
981898Skais 				}
982898Skais 				if (mp->b_rptr == recend) {
983898Skais 					mp->b_rptr = real_recend;
984898Skais 					freeb(mp);
985898Skais 					return (KSSL_CMD_NONE);
986898Skais 				}
987898Skais 			}
988898Skais 			ASSERT(ssl->msg.state == MSG_BODY);
989898Skais 
990898Skais 			sz = recend - mp->b_rptr;
991898Skais 
992898Skais 			if (ssl->msg.head == NULL &&
993898Skais 			    ssl->msg.msglen <= sz) {
994898Skais 				continue;
995898Skais 			}
996898Skais 			if (ssl->msg.head != NULL) {
997898Skais 				sz += msgdsize(ssl->msg.head);
998898Skais 				if (ssl->msg.msglen <= sz) {
999898Skais 					ssl->msg.tail->b_cont = mp;
1000898Skais 					mp = ssl->msg.head;
1001898Skais 					ssl->sslcnt = 100;
1002898Skais 					ssl->msg.head = NULL;
1003898Skais 					ssl->msg.tail = NULL;
1004898Skais 					if (pullupmsg(mp, -1)) {
1005898Skais 						recend = mp->b_rptr + sz;
1006898Skais 						ASSERT(recend <= mp->b_wptr);
1007898Skais 						continue;
1008898Skais 					}
1009898Skais 					mp->b_rptr = real_recend;
1010898Skais 					error = ENOMEM;
1011898Skais 					KSSL_COUNTER(alloc_fails, 1);
1012898Skais 					goto error;
1013898Skais 				}
1014898Skais 			}
1015898Skais 
1016898Skais 			mp->b_wptr = recend;
1017898Skais 
1018898Skais 			if (ssl->msg.head == NULL) {
1019898Skais 				ssl->msg.head = mp;
1020898Skais 				ssl->msg.tail = mp;
1021898Skais 				return (KSSL_CMD_NONE);
1022898Skais 			} else {
1023898Skais 				ssl->msg.tail->b_cont = mp;
1024898Skais 				ssl->msg.tail = mp;
1025898Skais 				return (KSSL_CMD_NONE);
1026898Skais 			}
1027898Skais 		} while (kssl_handle_handshake_message(ssl, mp, &error, cbfn,
1028898Skais 		    arg));
1029898Skais 		if (error == SSL_MISS) {
1030898Skais 			mp->b_rptr = save_rptr;
1031898Skais 			mp->b_wptr = save_wptr;
1032898Skais 			KSSL_COUNTER(fallback_connections, 1);
1033898Skais 			return (KSSL_CMD_NOT_SUPPORTED);
1034898Skais 		}
1035898Skais 		if (ssl->hs_waitstate == wait_client_key_done) {
1036898Skais 			return (KSSL_CMD_QUEUED);
1037898Skais 		} else {
1038898Skais 			return (KSSL_CMD_NONE);
1039898Skais 		}
1040898Skais 	case content_alert:
1041898Skais 		if (rec_sz != 2) {
1042898Skais 			mp->b_rptr = real_recend;
1043898Skais 			desc = illegal_parameter;
1044898Skais 			goto sendalert;
1045898Skais 		} else {
1046898Skais 			level = *mp->b_rptr++;
1047898Skais 			desc = *mp->b_rptr++;
1048898Skais 			mp->b_rptr = real_recend;
1049898Skais 			if (level != alert_warning || desc != close_notify) {
1050898Skais 				if (ssl->sid.cached == B_TRUE) {
1051898Skais 					kssl_uncache_sid(&ssl->sid,
1052898Skais 					    ssl->kssl_entry);
1053898Skais 					ssl->sid.cached = B_FALSE;
1054898Skais 				}
1055898Skais 				ssl->fatal_alert = B_TRUE;
1056898Skais 				error = EBADMSG;
1057898Skais 				goto error;
1058898Skais 			} else {
1059898Skais 				ssl->close_notify = B_TRUE;
1060898Skais 				ssl->activeinput = B_FALSE;
1061898Skais 				freeb(mp);
1062898Skais 				return (KSSL_CMD_NONE);
1063898Skais 			}
1064898Skais 		}
1065898Skais 	case content_change_cipher_spec:
1066898Skais 		if (ssl->hs_waitstate != wait_change_cipher) {
1067898Skais 			desc = unexpected_message;
1068898Skais 		} else if (rec_sz != 1 || *mp->b_rptr != 1) {
1069898Skais 			desc = illegal_parameter;
1070898Skais 		} else {
1071898Skais 			mp->b_rptr = real_recend;
1072898Skais 			ssl->hs_waitstate = wait_finished;
1073898Skais 			ssl->seq_num[KSSL_READ] = 0;
1074898Skais 			if ((error = kssl_spec_init(ssl, KSSL_READ)) != 0) {
1075898Skais #ifdef	DEBUG
1076898Skais 				cmn_err(CE_WARN,
1077898Skais 					"kssl_spec_init returned error "
1078898Skais 					"0x%02X", error);
1079898Skais #endif	/* DEBUG */
1080898Skais 				goto error;
1081898Skais 			}
1082898Skais 			ssl->activeinput = B_FALSE;
1083898Skais 			freeb(mp);
1084898Skais 			return (KSSL_CMD_NONE);
1085898Skais 		}
1086898Skais 		mp->b_rptr = real_recend;
1087898Skais 		goto sendalert;
1088898Skais 
1089898Skais 	case content_application_data:
1090898Skais 		if (ssl->hs_waitstate != idle_handshake) {
1091898Skais 			mp->b_rptr = real_recend;
1092898Skais 			desc = unexpected_message;
1093898Skais 			goto sendalert;
1094898Skais 		}
1095898Skais 		mp->b_wptr = recend;
1096898Skais 		*decrmp = mp;
1097898Skais 		ssl->activeinput = B_FALSE;
1098898Skais 		return (KSSL_CMD_DELIVER_PROXY);
1099898Skais 
1100898Skais 	case content_handshake_v2:
1101898Skais 		error = kssl_handle_v2client_hello(ssl, mp, rec_sz);
1102898Skais 		if (error == SSL_MISS) {
1103898Skais 			mp->b_rptr = save_rptr;
1104898Skais 			mp->b_wptr = save_wptr;
1105898Skais 			KSSL_COUNTER(fallback_connections, 1);
1106898Skais 			return (KSSL_CMD_NOT_SUPPORTED);
1107898Skais 		} else if (error != 0) {
1108898Skais 			goto error;
1109898Skais 		}
1110898Skais 		freeb(mp);
1111898Skais 		return (KSSL_CMD_SEND);
1112898Skais 	default:
1113898Skais 		mp->b_rptr = real_recend;
1114898Skais 		desc = unexpected_message;
1115898Skais 		break;
1116898Skais 	}
1117898Skais 
1118898Skais sendalert:
1119898Skais 	kssl_send_alert(ssl, alert_fatal, desc);
1120898Skais 	*decrmp = ssl->alert_sendbuf;
1121898Skais 	ssl->alert_sendbuf = NULL;
1122898Skais 	freeb(mp);
1123898Skais 	return ((*decrmp != NULL) ? KSSL_CMD_SEND : KSSL_CMD_NONE);
1124898Skais error:
1125898Skais 	freeb(mp);
1126898Skais 	return (KSSL_CMD_NONE);
1127898Skais }
1128898Skais 
1129898Skais /*
1130898Skais  * Initialize the context of an SSL connection, coming to the specified
1131898Skais  * address.
1132898Skais  * the ssl structure returned is held.
1133898Skais  */
1134898Skais kssl_status_t
1135898Skais kssl_init_context(kssl_ent_t kssl_ent, ipaddr_t faddr, int mss,
1136898Skais     kssl_ctx_t *kssl_ctxp)
1137898Skais {
1138898Skais 	ssl_t *ssl = kmem_cache_alloc(kssl_cache, KM_NOSLEEP);
1139898Skais 
1140898Skais 	if (ssl == NULL) {
1141898Skais 		return (KSSL_STS_ERR);
1142898Skais 	}
1143898Skais 
1144898Skais 	kssl_cache_count++;
1145898Skais 
1146898Skais 	bzero(ssl, sizeof (ssl_t));
1147898Skais 
1148898Skais 	ssl->kssl_entry = (kssl_entry_t *)kssl_ent;
1149898Skais 	KSSL_ENTRY_REFHOLD(ssl->kssl_entry);
1150898Skais 
1151898Skais 	ssl->faddr = faddr;
1152898Skais 	ssl->tcp_mss = mss;
1153898Skais 	ssl->sendalert_level = alert_warning;
1154898Skais 	ssl->sendalert_desc = close_notify;
1155898Skais 	ssl->sid.cached = B_FALSE;
1156898Skais 
1157898Skais 	*kssl_ctxp = (kssl_ctx_t)ssl;
1158898Skais 	KSSL_SSL_REFHOLD(ssl);
1159898Skais 	return (KSSL_STS_OK);
1160898Skais }
1161898Skais 
1162898Skais /*
1163898Skais  * Builds SSL records out of the chain of mblks, and returns it.
1164898Skais  * Taked a copy of the message before encypting it if it has another
1165898Skais  * reference.
1166898Skais  * In case of failure, NULL is returned, and the message will be
1167898Skais  * freed by the caller.
1168898Skais  * A NULL mp means a close_notify is requested.
1169898Skais  */
1170898Skais mblk_t *
1171898Skais kssl_build_record(kssl_ctx_t ctx, mblk_t *mp)
1172898Skais {
1173898Skais 	ssl_t *ssl = (ssl_t *)ctx;
1174898Skais 	mblk_t *retmp = mp, *bp = mp, *prevbp = mp, *copybp;
1175898Skais 
1176898Skais 	ASSERT(ssl != NULL);
1177898Skais 	ASSERT(mp != NULL);
1178898Skais 
1179898Skais 	do {
1180898Skais 		if (DB_REF(bp) > 1) {
1181898Skais 			/*
1182898Skais 			 * Fortunately copyb() preserves the offset,
1183898Skais 			 * tail space and alignement so the copy is
1184898Skais 			 * ready to be made an SSL record.
1185898Skais 			 */
1186898Skais 			if ((copybp = copyb(bp)) == NULL)
1187898Skais 				return (NULL);
1188898Skais 
1189898Skais 			copybp->b_cont = bp->b_cont;
1190898Skais 			if (bp == mp) {
1191898Skais 				retmp = copybp;
1192898Skais 			} else {
1193898Skais 				prevbp->b_cont = copybp;
1194898Skais 			}
1195898Skais 			freeb(bp);
1196898Skais 			bp = copybp;
1197898Skais 		}
1198898Skais 
1199898Skais 		if (kssl_build_single_record(ssl, bp) != KSSL_STS_OK)
1200898Skais 			return (NULL);
1201898Skais 
1202898Skais 		prevbp = bp;
1203898Skais 		bp = bp->b_cont;
1204898Skais 	} while (bp != NULL);
1205898Skais 
1206898Skais 	return (retmp);
1207898Skais }
1208898Skais 
1209898Skais /*
1210898Skais  * Builds a single SSL record
1211898Skais  * In-line encryption of the record.
1212898Skais  */
1213898Skais static kssl_status_t
1214898Skais kssl_build_single_record(ssl_t *ssl, mblk_t *mp)
1215898Skais {
1216898Skais 	int len;
1217898Skais 	int reclen = 0;
1218898Skais 	uchar_t *recstart, *versionp;
1219898Skais 	KSSLCipherSpec *spec;
1220898Skais 	int mac_sz;
1221898Skais 	int pad_sz = 0;
1222898Skais 
1223898Skais 
1224898Skais 	spec = &ssl->spec[KSSL_WRITE];
1225898Skais 	mac_sz = spec->mac_hashsz;
1226898Skais 
1227898Skais 
1228898Skais 	ASSERT(DB_REF(mp) == 1);
1229898Skais 	ASSERT((mp->b_rptr - mp->b_datap->db_base >= SSL3_HDR_LEN) &&
1230898Skais 	    (mp->b_datap->db_lim - mp->b_wptr >= mac_sz + spec->cipher_bsize));
1231898Skais 
1232898Skais 	len = MBLKL(mp);
1233898Skais 
1234898Skais 	ASSERT(len > 0);
1235898Skais 
1236898Skais 	mutex_enter(&ssl->kssl_lock);
1237898Skais 
1238898Skais 	recstart = mp->b_rptr = mp->b_rptr - SSL3_HDR_LEN;
1239898Skais 	recstart[0] = content_application_data;
1240898Skais 	recstart[1] = ssl->major_version;
1241898Skais 	recstart[2] = ssl->minor_version;
1242898Skais 	versionp = &recstart[1];
1243898Skais 
1244898Skais 	reclen = len + mac_sz;
1245898Skais 	if (spec->cipher_type == type_block) {
1246898Skais 		pad_sz = spec->cipher_bsize -
1247898Skais 		    (reclen & (spec->cipher_bsize - 1));
1248898Skais 		ASSERT(reclen + pad_sz <=
1249898Skais 		    SSL3_MAX_RECORD_LENGTH);
1250898Skais 		reclen += pad_sz;
1251898Skais 	}
1252898Skais 	recstart[3] = (reclen >> 8) & 0xff;
1253898Skais 	recstart[4] = reclen & 0xff;
1254898Skais 
1255898Skais 	if (kssl_mac_encrypt_record(ssl, content_application_data, versionp,
1256898Skais 	    recstart, mp) != 0) {
1257898Skais 		/* Do we need an internal_error Alert here? */
1258898Skais 		mutex_exit(&ssl->kssl_lock);
1259898Skais 		return (KSSL_STS_ERR);
1260898Skais 	}
1261898Skais 
1262898Skais 	KSSL_COUNTER(appdata_record_outs, 1);
1263898Skais 	mutex_exit(&ssl->kssl_lock);
1264898Skais 	return (KSSL_STS_OK);
1265898Skais }
1266