xref: /titanic_52/usr/src/uts/common/inet/kssl/ksslapi.c (revision 9b1bd49f83497d7b339a684a1a76de3aaccf5269)
1c28749e9Skais /*
2c28749e9Skais  * CDDL HEADER START
3c28749e9Skais  *
4c28749e9Skais  * The contents of this file are subject to the terms of the
539d67566Skais  * Common Development and Distribution License (the "License").
639d67566Skais  * You may not use this file except in compliance with the License.
7c28749e9Skais  *
8c28749e9Skais  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c28749e9Skais  * or http://www.opensolaris.org/os/licensing.
10c28749e9Skais  * See the License for the specific language governing permissions
11c28749e9Skais  * and limitations under the License.
12c28749e9Skais  *
13c28749e9Skais  * When distributing Covered Code, include this CDDL HEADER in each
14c28749e9Skais  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c28749e9Skais  * If applicable, add the following below this CDDL HEADER, with the
16c28749e9Skais  * fields enclosed by brackets "[]" replaced with your own identifying
17c28749e9Skais  * information: Portions Copyright [yyyy] [name of copyright owner]
18c28749e9Skais  *
19c28749e9Skais  * CDDL HEADER END
20c28749e9Skais  */
21c28749e9Skais /*
2211d0a659SVladimir Kotal  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23c28749e9Skais  */
24c28749e9Skais 
25c28749e9Skais #include <sys/types.h>
26c28749e9Skais #include <sys/stream.h>
27c28749e9Skais #include <sys/strsun.h>
28c28749e9Skais #include <sys/kmem.h>
29c28749e9Skais #include <sys/cpuvar.h>
30c28749e9Skais #include <sys/atomic.h>
31c28749e9Skais #include <sys/sysmacros.h>
32c28749e9Skais 
33c28749e9Skais #include <inet/common.h>
34c28749e9Skais #include <inet/ip.h>
35c28749e9Skais 
36c28749e9Skais #include <sys/systm.h>
37c28749e9Skais #include <sys/param.h>
38c28749e9Skais #include <sys/tihdr.h>
39c28749e9Skais 
40c28749e9Skais #include "ksslimpl.h"
41c28749e9Skais #include "ksslproto.h"
42c28749e9Skais #include "ksslapi.h"
43c28749e9Skais 
44c28749e9Skais static kssl_cmd_t kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp,
45c28749e9Skais     mblk_t **decrmp, kssl_callback_t cbfn, void *arg);
46c28749e9Skais static boolean_t kssl_enqueue(kssl_chain_t **head, void *item);
47c28749e9Skais static void kssl_dequeue(kssl_chain_t **head, void *item);
48c28749e9Skais static kssl_status_t kssl_build_single_record(ssl_t *ssl, mblk_t *mp);
49c28749e9Skais 
50c28749e9Skais /*
51dd49f125SAnders Persson  * The socket bind request is intercepted and re-routed here
52c28749e9Skais  * to see is there is SSL relevant job to do, based on the kssl config
53c28749e9Skais  * in the kssl_entry_tab.
54c28749e9Skais  * Looks up the kernel SSL proxy table, to find an entry that matches the
55c28749e9Skais  * same serveraddr, and has one of the following two criteria:
56c28749e9Skais  * 1. in_port is an ssl_port. This endpoint can be used later as a fallback
57c28749e9Skais  *    to complete connections that cannot be handled by the SSL kernel proxy
58c28749e9Skais  *    (typically non supported ciphersuite). The cookie for the calling client
59c28749e9Skais  *    is saved with the kssl_entry to be retrieved for the fallback.
60c28749e9Skais  *    The function returns KSSL_HAS_PROXY.
61c28749e9Skais  *
62c28749e9Skais  * 2. in_port is a proxy port for another ssl port. The ssl port is then
63c28749e9Skais  *    substituted to the in_port in the bind_req TPI structure, so that
64c28749e9Skais  *    the bind falls through to the SSL port. At the end of this operation,
65c28749e9Skais  *    all the packets arriving to the SSL port will be delivered to an
66c28749e9Skais  *    accepted endpoint child of this bound socket.
67c28749e9Skais  *    The  kssl_entry_t is returned in *ksslent, for later use by the
68c28749e9Skais  *    lower modules' SSL hooks that handle the Handshake messages.
69c28749e9Skais  *    The function returns KSSL_IS_PROXY.
70c28749e9Skais  *
712ec7cc7fSKrishna Yenduri  * The function returns KSSL_NO_PROXY otherwise.
72c28749e9Skais  */
73c28749e9Skais 
74c28749e9Skais kssl_endpt_type_t
75dd49f125SAnders Persson kssl_check_proxy(struct sockaddr *addr, socklen_t len, void *cookie,
76dd49f125SAnders Persson     kssl_ent_t *ksslent)
77c28749e9Skais {
78c28749e9Skais 	int i;
79c28749e9Skais 	kssl_endpt_type_t ret;
80c28749e9Skais 	kssl_entry_t *ep;
81c28749e9Skais 	sin_t *sin;
8252bf5e39SKrishna Yenduri 	sin6_t *sin6;
832ec7cc7fSKrishna Yenduri 	in6_addr_t mapped_v4addr;
842ec7cc7fSKrishna Yenduri 	in6_addr_t *v6addr;
85c28749e9Skais 	in_port_t in_port;
86c28749e9Skais 
872ec7cc7fSKrishna Yenduri 	if (kssl_entry_tab_nentries == 0) {
88c28749e9Skais 		return (KSSL_NO_PROXY);
89c28749e9Skais 	}
90c28749e9Skais 
91c28749e9Skais 	ret = KSSL_NO_PROXY;
92dd49f125SAnders Persson 	sin = (struct sockaddr_in *)addr;
93c28749e9Skais 
94dd49f125SAnders Persson 	switch (len) {
95c28749e9Skais 	case sizeof (sin_t):
96c28749e9Skais 		in_port = ntohs(sin->sin_port);
972ec7cc7fSKrishna Yenduri 		IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &mapped_v4addr);
982ec7cc7fSKrishna Yenduri 		v6addr = &mapped_v4addr;
99c28749e9Skais 		break;
100c28749e9Skais 
101c28749e9Skais 	case sizeof (sin6_t):
10252bf5e39SKrishna Yenduri 		sin6 = (sin6_t *)sin;
10352bf5e39SKrishna Yenduri 		in_port = ntohs(sin6->sin6_port);
1042ec7cc7fSKrishna Yenduri 		v6addr = &sin6->sin6_addr;
10552bf5e39SKrishna Yenduri 		break;
10652bf5e39SKrishna Yenduri 
107c28749e9Skais 	default:
108c28749e9Skais 		return (ret);
109c28749e9Skais 	}
110c28749e9Skais 
111c28749e9Skais 	mutex_enter(&kssl_tab_mutex);
112c28749e9Skais 
113c28749e9Skais 	for (i = 0; i < kssl_entry_tab_size; i++) {
114c28749e9Skais 		if ((ep = kssl_entry_tab[i]) == NULL)
115c28749e9Skais 			continue;
116c28749e9Skais 
1172ec7cc7fSKrishna Yenduri 		if (IN6_ARE_ADDR_EQUAL(&ep->ke_laddr, v6addr) ||
1182ec7cc7fSKrishna Yenduri 		    IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr)) {
119c28749e9Skais 
120c28749e9Skais 			/* This is an SSL port to fallback to */
121c28749e9Skais 			if (ep->ke_ssl_port == in_port) {
122c28749e9Skais 
123c28749e9Skais 				/*
124c28749e9Skais 				 * Let's see first if there's at least
125c28749e9Skais 				 * an endpoint for a proxy server.
126c28749e9Skais 				 * If there's none, then we return as we have
127c28749e9Skais 				 * no proxy, so that the bind() to the
128c28749e9Skais 				 * transport layer goes through.
129c28749e9Skais 				 * The calling module will ask for this
130c28749e9Skais 				 * cookie if it wants to fall back to it,
131c28749e9Skais 				 * so add this one to the list of fallback
132c28749e9Skais 				 * clients.
133c28749e9Skais 				 */
134c28749e9Skais 				if (!kssl_enqueue((kssl_chain_t **)
135c28749e9Skais 				    &(ep->ke_fallback_head), cookie)) {
136c28749e9Skais 					break;
137c28749e9Skais 				}
138c28749e9Skais 
139c28749e9Skais 				KSSL_ENTRY_REFHOLD(ep);
140c28749e9Skais 				*ksslent = (kssl_ent_t)ep;
141c28749e9Skais 
142c28749e9Skais 				ret = KSSL_HAS_PROXY;
143c28749e9Skais 				break;
144c28749e9Skais 			}
145c28749e9Skais 
146c28749e9Skais 			/* This is a proxy port. */
147c28749e9Skais 			if (ep->ke_proxy_port == in_port) {
148c28749e9Skais 				/* Add the caller's cookie to proxies list */
149c28749e9Skais 
150c28749e9Skais 				if (!kssl_enqueue((kssl_chain_t **)
151c28749e9Skais 				    &(ep->ke_proxy_head), cookie)) {
152c28749e9Skais 					break;
153c28749e9Skais 				}
154c28749e9Skais 
155c28749e9Skais 				/*
156c28749e9Skais 				 * Make this look  like the SSL port to the
157c28749e9Skais 				 * transport below
158c28749e9Skais 				 */
159c28749e9Skais 				sin->sin_port = htons(ep->ke_ssl_port);
160c28749e9Skais 
161c28749e9Skais 				KSSL_ENTRY_REFHOLD(ep);
162c28749e9Skais 				*ksslent = (kssl_ent_t)ep;
163c28749e9Skais 
164c28749e9Skais 				ret = KSSL_IS_PROXY;
165c28749e9Skais 				break;
166c28749e9Skais 			}
167c28749e9Skais 		}
168c28749e9Skais 	}
169c28749e9Skais 
170c28749e9Skais 	mutex_exit(&kssl_tab_mutex);
171c28749e9Skais 	return (ret);
172c28749e9Skais }
173c28749e9Skais 
174c28749e9Skais /*
175c28749e9Skais  * Retrieved an endpoint "bound" to the SSL entry.
176c28749e9Skais  * Such endpoint has previously called kssl_check_proxy(), got itself
177c28749e9Skais  * linked to the kssl_entry's ke_fallback_head list.
178c28749e9Skais  * This routine returns the cookie from that SSL entry ke_fallback_head list.
179c28749e9Skais  */
180c28749e9Skais void *
181c28749e9Skais kssl_find_fallback(kssl_ent_t ksslent)
182c28749e9Skais {
183c28749e9Skais 	kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent;
184c28749e9Skais 
185c28749e9Skais 	if (kssl_entry->ke_fallback_head != NULL)
186c28749e9Skais 		return (kssl_entry->ke_fallback_head->fallback_bound);
187c28749e9Skais 
188c28749e9Skais 	KSSL_COUNTER(proxy_fallback_failed, 1);
189c28749e9Skais 
190c28749e9Skais 	return (NULL);
191c28749e9Skais }
192c28749e9Skais 
193c28749e9Skais /*
194c28749e9Skais  * Re-usable code for adding and removing an element to/from a chain that
195c28749e9Skais  * matches "item"
196c28749e9Skais  * The chain is simple-linked and NULL ended.
197c28749e9Skais  */
198c28749e9Skais 
199c28749e9Skais /*
200c28749e9Skais  * This routine returns TRUE if the item was either successfully added to
201c28749e9Skais  * the chain, or is already there. It returns FALSE otherwise.
202c28749e9Skais  */
203c28749e9Skais static boolean_t
204c28749e9Skais kssl_enqueue(kssl_chain_t **head, void *item)
205c28749e9Skais {
206c28749e9Skais 	kssl_chain_t *newchain, *cur;
207c28749e9Skais 
208c28749e9Skais 	/* Lookup the existing entries to avoid duplicates */
209c28749e9Skais 	cur = *head;
210c28749e9Skais 	while (cur != NULL) {
211c28749e9Skais 		if (cur->item == item) {
212c28749e9Skais 			return (B_TRUE);
213c28749e9Skais 		}
214c28749e9Skais 		cur = cur->next;
215c28749e9Skais 	}
216c28749e9Skais 
217c28749e9Skais 	newchain = kmem_alloc(sizeof (kssl_chain_t), KM_NOSLEEP);
218c28749e9Skais 	if (newchain == NULL) {
219c28749e9Skais 		return (B_FALSE);
220c28749e9Skais 	}
221c28749e9Skais 
222c28749e9Skais 	newchain->item = item;
223c28749e9Skais 	newchain->next = *head;
224c28749e9Skais 	*head = newchain;
225c28749e9Skais 	return (B_TRUE);
226c28749e9Skais }
227c28749e9Skais 
228c28749e9Skais static void
229c28749e9Skais kssl_dequeue(kssl_chain_t **head, void *item)
230c28749e9Skais {
231c28749e9Skais 	kssl_chain_t *prev, *cur;
232c28749e9Skais 
233c28749e9Skais 	prev = cur = *head;
234c28749e9Skais 	while (cur != NULL) {
235c28749e9Skais 		if (cur->item == item) {
236c28749e9Skais 			if (cur == *head)
237c28749e9Skais 				*head = (*head)->next;
238c28749e9Skais 			else
239c28749e9Skais 				prev->next = cur->next;
240c28749e9Skais 			kmem_free(cur, sizeof (kssl_chain_t));
241c28749e9Skais 			return;
242c28749e9Skais 		}
243c28749e9Skais 		prev = cur;
244c28749e9Skais 		cur = cur->next;
245c28749e9Skais 	}
246c28749e9Skais }
247c28749e9Skais 
248c28749e9Skais /*
249c28749e9Skais  * Holds the kssl_entry
250c28749e9Skais  */
251c28749e9Skais void
252c28749e9Skais kssl_hold_ent(kssl_ent_t ksslent)
253c28749e9Skais {
254c28749e9Skais 	KSSL_ENTRY_REFHOLD((kssl_entry_t *)ksslent);
255c28749e9Skais }
256c28749e9Skais 
257c28749e9Skais /*
258c28749e9Skais  * Releases the kssl_entry
259c28749e9Skais  * If the caller passes a cookie, then it should be removed from both
260c28749e9Skais  * proxies and fallbacks chains.
261c28749e9Skais  */
262c28749e9Skais void
263c28749e9Skais kssl_release_ent(kssl_ent_t ksslent, void *cookie, kssl_endpt_type_t endpt_type)
264c28749e9Skais {
265c28749e9Skais 	kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent;
266c28749e9Skais 
267c28749e9Skais 	if (cookie != NULL) {
2682ec7cc7fSKrishna Yenduri 		if (endpt_type == KSSL_IS_PROXY) {
269c28749e9Skais 			ASSERT(kssl_entry->ke_proxy_head != NULL);
270c28749e9Skais 			kssl_dequeue(
271c28749e9Skais 			    (kssl_chain_t **)&kssl_entry->ke_proxy_head,
272c28749e9Skais 			    cookie);
2732ec7cc7fSKrishna Yenduri 		}
2742ec7cc7fSKrishna Yenduri 		if (endpt_type == KSSL_HAS_PROXY) {
275c28749e9Skais 			ASSERT(kssl_entry->ke_fallback_head != NULL);
276c28749e9Skais 			kssl_dequeue(
277c28749e9Skais 			    (kssl_chain_t **)&kssl_entry->ke_fallback_head,
278c28749e9Skais 			    cookie);
279c28749e9Skais 		}
2802ec7cc7fSKrishna Yenduri 	}
281c28749e9Skais 	KSSL_ENTRY_REFRELE(kssl_entry);
282c28749e9Skais }
283c28749e9Skais 
284c28749e9Skais /*
285c28749e9Skais  * Releases the kssl_context
286c28749e9Skais  */
287c28749e9Skais void
288c28749e9Skais kssl_release_ctx(kssl_ctx_t ksslctx)
289c28749e9Skais {
290dd49f125SAnders Persson 	kssl_free_context((ssl_t *)ksslctx);
291dd49f125SAnders Persson }
292dd49f125SAnders Persson 
293dd49f125SAnders Persson /*
294dd49f125SAnders Persson  * Done with asynchronous processing
295dd49f125SAnders Persson  */
296dd49f125SAnders Persson void
297dd49f125SAnders Persson kssl_async_done(kssl_ctx_t ksslctx)
298dd49f125SAnders Persson {
299dd49f125SAnders Persson 	ssl_t *ssl = (ssl_t *)ksslctx;
300dd49f125SAnders Persson 
301dd49f125SAnders Persson 	mutex_enter(&ssl->kssl_lock);
302dd49f125SAnders Persson 	if (--ssl->async_ops_pending == 0)
303dd49f125SAnders Persson 		cv_signal(&ssl->async_cv);
304dd49f125SAnders Persson 	mutex_exit(&ssl->kssl_lock);
305c28749e9Skais }
306c28749e9Skais 
307c28749e9Skais /*
308c28749e9Skais  * Packets are accumulated here, if there are packets already queued,
309c28749e9Skais  * or if the context is active.
310c28749e9Skais  * The context is active when an incoming record processing function
311c28749e9Skais  * is already executing on a different thread.
312c28749e9Skais  * Queued packets are handled either when an mblk arrived and completes
313c28749e9Skais  * a record, or, when the active context processor finishes the task at
314c28749e9Skais  * hand.
315c28749e9Skais  * The caller has to keep calling this routine in a loop until it returns
316c28749e9Skais  * B_FALSE in *more. The reason for this is SSL3: The protocol
317c28749e9Skais  * allows the client to send its first application_data message right
318c28749e9Skais  * after it had sent its Finished message, and not wait for the server
319c28749e9Skais  * ChangeCipherSpec and Finished. This overlap means we can't batch up
320c28749e9Skais  * a returned Handshake message to be sent on the wire
321c28749e9Skais  * with a decrypted application_data to be delivered to the application.
322c28749e9Skais  */
323c28749e9Skais kssl_cmd_t
324c28749e9Skais kssl_input(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, boolean_t *more,
325c28749e9Skais     kssl_callback_t cbfn, void *arg)
326c28749e9Skais {
327c28749e9Skais 	mblk_t *recmp, *outmp = NULL;
328c28749e9Skais 	kssl_cmd_t kssl_cmd;
329c28749e9Skais 	ssl_t *ssl;
330c28749e9Skais 	uint8_t *rec_sz_p;
331c28749e9Skais 	int mplen;
332c28749e9Skais 	SSL3ContentType content_type;
333c28749e9Skais 	uint16_t rec_sz;
334c28749e9Skais 
335c28749e9Skais 	ASSERT(ctx != NULL);
336c28749e9Skais 
337c28749e9Skais 	if (mp != NULL) {
338c28749e9Skais 		ASSERT(mp->b_prev == NULL && mp->b_next == NULL);
339c28749e9Skais 	}
340c28749e9Skais 
341c28749e9Skais 	ssl = (ssl_t *)(ctx);
342c28749e9Skais 
343c28749e9Skais 	*decrmp = NULL;
344c28749e9Skais 	*more = B_FALSE;
345c28749e9Skais 
346c28749e9Skais 	mutex_enter(&ssl->kssl_lock);
347c28749e9Skais 
348*9b1bd49fSVladimir Kotal 	if (ssl->close_notify_clnt == B_TRUE) {
34951dd2c77Svk199839 		DTRACE_PROBE(kssl_err__close_notify);
350c28749e9Skais 		goto sendnewalert;
351c28749e9Skais 	}
352c28749e9Skais 
353c28749e9Skais 	/* Whomever is currently processing this connection will get to this */
354c28749e9Skais 	if (ssl->activeinput) {
355c28749e9Skais 		if (mp != NULL) {
356c28749e9Skais 			KSSL_ENQUEUE_MP(ssl, mp);
357c28749e9Skais 		}
358c28749e9Skais 		mutex_exit(&ssl->kssl_lock);
359c28749e9Skais 		return (KSSL_CMD_NONE);
360c28749e9Skais 	}
361c28749e9Skais 
362c28749e9Skais 	/*
363c28749e9Skais 	 * Fast path for complete incoming application_data records on an empty
364c28749e9Skais 	 * queue.
365c28749e9Skais 	 * This is by far the most frequently encountered case
366c28749e9Skais 	 */
367c28749e9Skais 
368c28749e9Skais 	if ((!ssl->activeinput) && (ssl->rec_ass_head == NULL) &&
369c28749e9Skais 	    ((mp != NULL) && (mplen = MBLKL(mp)) > SSL3_HDR_LEN)) {
370c28749e9Skais 
37151dd2c77Svk199839 		DTRACE_PROBE1(kssl_mblk__fast_path, mblk_t *, mp);
372c28749e9Skais 		content_type = (SSL3ContentType)mp->b_rptr[0];
373c28749e9Skais 
374c28749e9Skais 		if ((content_type == content_application_data) &&
375c28749e9Skais 		    (ssl->hs_waitstate == idle_handshake)) {
376c28749e9Skais 			rec_sz_p = SSL3_REC_SIZE(mp);
377c28749e9Skais 			rec_sz = BE16_TO_U16(rec_sz_p);
378c28749e9Skais 
379c28749e9Skais 			if ((mp->b_cont == NULL) && (mplen == rec_sz)) {
380c28749e9Skais 
381c28749e9Skais 				*decrmp = mp;
382c28749e9Skais 				mutex_exit(&ssl->kssl_lock);
383c28749e9Skais 				return (KSSL_CMD_DELIVER_PROXY);
384c28749e9Skais 			}
385c28749e9Skais 		}
386c28749e9Skais 	}
387c28749e9Skais 
388c28749e9Skais 	ssl->activeinput = B_TRUE;
389c28749e9Skais 	/* Accumulate at least one record */
390c28749e9Skais 	if (mp != NULL) {
391c28749e9Skais 		KSSL_ENQUEUE_MP(ssl, mp);
392c28749e9Skais 		mp = NULL;
393c28749e9Skais 	}
394c28749e9Skais 	recmp = kssl_get_next_record(ssl);
395c28749e9Skais 
396c28749e9Skais 	if (recmp == NULL) {
397c28749e9Skais 		ssl->activeinput = B_FALSE;
398c28749e9Skais 		if (ssl->alert_sendbuf != NULL) {
39951dd2c77Svk199839 			DTRACE_PROBE(kssl_err__alert_to_send);
400c28749e9Skais 			goto sendalert;
401c28749e9Skais 		}
402c28749e9Skais 		/* Not even a complete header yet. wait for the rest */
403c28749e9Skais 		mutex_exit(&ssl->kssl_lock);
404c28749e9Skais 		return (KSSL_CMD_NONE);
405c28749e9Skais 	}
406c28749e9Skais 
407c28749e9Skais 	do {
40851dd2c77Svk199839 		DTRACE_PROBE1(kssl_mblk__kssl_input_cycle, mblk_t *, recmp);
40984706141Svk199839 		content_type = (SSL3ContentType)recmp->b_rptr[0];
41084706141Svk199839 
41184706141Svk199839 		switch (content_type) {
41284706141Svk199839 		case content_application_data:
413c28749e9Skais 			/*
414c28749e9Skais 			 * application_data records are decrypted and
415c28749e9Skais 			 * MAC-verified by the stream head, and in the context
416c28749e9Skais 			 * a read()'ing thread. This avoids unfairly charging
417c28749e9Skais 			 * the cost of handling this record on the whole system,
418c28749e9Skais 			 * and prevents doing it while in the shared IP
419c28749e9Skais 			 * perimeter.
420c28749e9Skais 			 */
421c28749e9Skais 			ssl->activeinput = B_FALSE;
422c28749e9Skais 			if (ssl->hs_waitstate != idle_handshake) {
42351dd2c77Svk199839 				DTRACE_PROBE(kssl_err__waitstate_not_idle);
424c28749e9Skais 				goto sendnewalert;
425c28749e9Skais 			}
426c28749e9Skais 			outmp = recmp;
427c28749e9Skais 			kssl_cmd = KSSL_CMD_DELIVER_PROXY;
42884706141Svk199839 			break;
42984706141Svk199839 		case content_change_cipher_spec:
43084706141Svk199839 		case content_alert:
43184706141Svk199839 		case content_handshake:
43284706141Svk199839 		case content_handshake_v2:
433c28749e9Skais 			/*
434c28749e9Skais 			 * If we're past the initial handshake, start letting
435c28749e9Skais 			 * the stream head process all records, in particular
436c28749e9Skais 			 * the close_notify.
437c28749e9Skais 			 * This is needed to avoid processing them out of
438c28749e9Skais 			 * sequence when previous application data packets are
439c28749e9Skais 			 * waiting to be decrypted/MAC'ed and delivered.
440c28749e9Skais 			 */
441c28749e9Skais 			if (ssl->hs_waitstate == idle_handshake) {
442c28749e9Skais 				ssl->activeinput = B_FALSE;
443c28749e9Skais 				outmp = recmp;
444c28749e9Skais 				kssl_cmd = KSSL_CMD_DELIVER_PROXY;
445c28749e9Skais 			} else {
446c28749e9Skais 				kssl_cmd = kssl_handle_any_record(ssl, recmp,
447c28749e9Skais 				    &outmp, cbfn, arg);
448c28749e9Skais 			}
44984706141Svk199839 			break;
45084706141Svk199839 		default:
45184706141Svk199839 			ssl->activeinput = B_FALSE;
45251dd2c77Svk199839 			DTRACE_PROBE(kssl_err__invalid_content_type);
45384706141Svk199839 			goto sendnewalert;
454c28749e9Skais 		}
455c28749e9Skais 
456c28749e9Skais 		/* Priority to Alert messages */
457c28749e9Skais 		if (ssl->alert_sendbuf != NULL) {
45851dd2c77Svk199839 			DTRACE_PROBE(kssl_err__alert_to_send_cycle);
459c28749e9Skais 			goto sendalert;
460c28749e9Skais 		}
461c28749e9Skais 
462c28749e9Skais 		/* Then handshake messages */
463c28749e9Skais 		if (ssl->handshake_sendbuf) {
464c28749e9Skais 			if (*decrmp != NULL) {
465c28749e9Skais 				linkb(*decrmp, ssl->handshake_sendbuf);
466c28749e9Skais 			} else {
467c28749e9Skais 				*decrmp = ssl->handshake_sendbuf;
468c28749e9Skais 			}
469c28749e9Skais 			ssl->handshake_sendbuf = NULL;
470c28749e9Skais 
471c28749e9Skais 			*more = ((ssl->rec_ass_head != NULL) &&
472c28749e9Skais 			    (!ssl->activeinput));
473c28749e9Skais 			mutex_exit(&ssl->kssl_lock);
474c28749e9Skais 			return (kssl_cmd);
475c28749e9Skais 		}
476c28749e9Skais 
477c28749e9Skais 		if (ssl->hs_waitstate == idle_handshake) {
478c28749e9Skais 			*more = ((ssl->rec_ass_head != NULL) &&
479c28749e9Skais 			    (!ssl->activeinput));
480c28749e9Skais 		}
481c28749e9Skais 
482c28749e9Skais 		if (outmp != NULL) {
483c28749e9Skais 			*decrmp = outmp;
484c28749e9Skais 			/*
485c28749e9Skais 			 * Don't process any packet after an application_data.
486c28749e9Skais 			 * We could well receive the close_notify which should
487c28749e9Skais 			 * be handled separately.
488c28749e9Skais 			 */
489c28749e9Skais 			mutex_exit(&ssl->kssl_lock);
490c28749e9Skais 			return (kssl_cmd);
491c28749e9Skais 		}
492c28749e9Skais 		/*
493c28749e9Skais 		 * The current record isn't done yet. Don't start the next one
494c28749e9Skais 		 */
495c28749e9Skais 		if (ssl->activeinput) {
496c28749e9Skais 			mutex_exit(&ssl->kssl_lock);
497c28749e9Skais 			return (kssl_cmd);
498c28749e9Skais 		}
499c28749e9Skais 	} while ((recmp = kssl_get_next_record(ssl)) != NULL);
500c28749e9Skais 
501c28749e9Skais 	mutex_exit(&ssl->kssl_lock);
502c28749e9Skais 	return (kssl_cmd);
503c28749e9Skais 
504c28749e9Skais sendnewalert:
505c28749e9Skais 	kssl_send_alert(ssl, alert_fatal, unexpected_message);
506c28749e9Skais 	if (mp != NULL) {
507c28749e9Skais 		freeb(mp);
508c28749e9Skais 	}
509c28749e9Skais 
510c28749e9Skais sendalert:
511c28749e9Skais 	*decrmp = ssl->alert_sendbuf;
512c28749e9Skais 	ssl->alert_sendbuf = NULL;
513c28749e9Skais 	mutex_exit(&ssl->kssl_lock);
514c28749e9Skais 	return (KSSL_CMD_SEND);
515c28749e9Skais }
516c28749e9Skais 
517c28749e9Skais /*
518dd49f125SAnders Persson  * Decrypt and verify the MAC of an incoming chain of application_data record.
519dd49f125SAnders Persson  * Each block has exactly one SSL record.
520c28749e9Skais  */
521c28749e9Skais kssl_cmd_t
52251dd2c77Svk199839 kssl_handle_mblk(kssl_ctx_t ctx, mblk_t **mpp, mblk_t **outmp)
523c28749e9Skais {
524c28749e9Skais 	uchar_t *recend, *rec_sz_p;
525c28749e9Skais 	uchar_t *real_recend;
52639d67566Skais 	mblk_t *prevmp = NULL, *nextmp, *firstmp, *mp, *copybp;
527c28749e9Skais 	int mac_sz;
528c28749e9Skais 	uchar_t version[2];
529c28749e9Skais 	uint16_t rec_sz;
530c28749e9Skais 	SSL3AlertDescription desc;
531c28749e9Skais 	SSL3ContentType content_type;
532c28749e9Skais 	ssl_t *ssl;
533c28749e9Skais 	KSSLCipherSpec *spec;
5342ec7cc7fSKrishna Yenduri 	int error, ret;
535c28749e9Skais 	kssl_cmd_t kssl_cmd = KSSL_CMD_DELIVER_PROXY;
536c28749e9Skais 	boolean_t deliverit = B_FALSE;
537c28749e9Skais 	crypto_data_t cipher_data;
538c28749e9Skais 
539c28749e9Skais 	ASSERT(ctx != NULL);
540c28749e9Skais 
541c28749e9Skais 	ssl = (ssl_t *)(ctx);
542c28749e9Skais 
54339d67566Skais 	mp = firstmp = *mpp;
544c28749e9Skais 	*outmp = NULL;
545c28749e9Skais more:
546c28749e9Skais 
547c28749e9Skais 	while (mp != NULL) {
54851dd2c77Svk199839 		ASSERT(DB_TYPE(mp) == M_DATA);
549c28749e9Skais 
550c28749e9Skais 		if (DB_REF(mp) > 1) {
551c28749e9Skais 			/*
552c28749e9Skais 			 * Fortunately copyb() preserves the offset,
5532ec7cc7fSKrishna Yenduri 			 * tail space and alignment so the copy is
554c28749e9Skais 			 * ready to be made an SSL record.
555c28749e9Skais 			 */
556c28749e9Skais 			if ((copybp = copyb(mp)) == NULL)
557c28749e9Skais 				return (NULL);
558c28749e9Skais 
559c28749e9Skais 			copybp->b_cont = mp->b_cont;
56039d67566Skais 			if (mp == firstmp) {
561c28749e9Skais 				*mpp = copybp;
56284706141Svk199839 			} else if (prevmp != NULL) {
563c28749e9Skais 				prevmp->b_cont = copybp;
564c28749e9Skais 			}
565c28749e9Skais 			freeb(mp);
566c28749e9Skais 			mp = copybp;
567c28749e9Skais 		}
568c28749e9Skais 
56951dd2c77Svk199839 		DTRACE_PROBE1(kssl_mblk__handle_record_cycle, mblk_t *, mp);
570c28749e9Skais 		content_type = (SSL3ContentType)mp->b_rptr[0];
571c28749e9Skais 
57284706141Svk199839 		switch (content_type) {
57384706141Svk199839 		case content_application_data:
57484706141Svk199839 			break;
57584706141Svk199839 		case content_change_cipher_spec:
57684706141Svk199839 		case content_alert:
57784706141Svk199839 		case content_handshake:
57884706141Svk199839 		case content_handshake_v2:
579c28749e9Skais 			nextmp = mp->b_cont;
580c28749e9Skais 
581c28749e9Skais 			/* Remove this message */
582c28749e9Skais 			if (prevmp != NULL) {
583c28749e9Skais 				prevmp->b_cont = nextmp;
584c28749e9Skais 
585c28749e9Skais 				/*
586c28749e9Skais 				 * If we had processed blocks that need to
587c28749e9Skais 				 * be delivered, then remember that error code
588c28749e9Skais 				 */
589c28749e9Skais 				if (kssl_cmd == KSSL_CMD_DELIVER_PROXY)
590c28749e9Skais 					deliverit = B_TRUE;
591c28749e9Skais 			}
592c28749e9Skais 
593c28749e9Skais 			mutex_enter(&ssl->kssl_lock);
59484706141Svk199839 			/* NOTE: This routine could free mp. */
595c28749e9Skais 			kssl_cmd = kssl_handle_any_record(ssl, mp, outmp,
596c28749e9Skais 			    NULL, NULL);
597c28749e9Skais 
598c28749e9Skais 			if (ssl->alert_sendbuf != NULL) {
59984706141Svk199839 				mp = nextmp;
60051dd2c77Svk199839 				DTRACE_PROBE(kssl_err__alert_after_handle_any);
601c28749e9Skais 				goto sendalert;
602c28749e9Skais 			}
603c28749e9Skais 			mutex_exit(&ssl->kssl_lock);
604c28749e9Skais 
605c28749e9Skais 			if (deliverit) {
606c28749e9Skais 				kssl_cmd = KSSL_CMD_DELIVER_PROXY;
607c28749e9Skais 			}
608c28749e9Skais 
609c28749e9Skais 			mp = nextmp;
61084706141Svk199839 			continue;	/* to the while loop */
61184706141Svk199839 		default:
61284706141Svk199839 			desc = decode_error;
61384706141Svk199839 			KSSL_COUNTER(internal_errors, 1);
61451dd2c77Svk199839 			DTRACE_PROBE(kssl_err__decode_error);
61584706141Svk199839 			goto makealert;
616c28749e9Skais 		}
617c28749e9Skais 
618c28749e9Skais 		version[0] = mp->b_rptr[1];
619c28749e9Skais 		version[1] = mp->b_rptr[2];
620c28749e9Skais 		rec_sz_p = SSL3_REC_SIZE(mp);
621c28749e9Skais 		rec_sz = BE16_TO_U16(rec_sz_p);
622c28749e9Skais 
623c28749e9Skais 		mp->b_rptr += SSL3_HDR_LEN;
624c28749e9Skais 		recend = mp->b_rptr + rec_sz;
625c28749e9Skais 		real_recend = recend;
626c28749e9Skais 
62784706141Svk199839 		/*
62884706141Svk199839 		 * Check the assumption that each mblk contains exactly
62984706141Svk199839 		 * one complete SSL record. We bail out if the check fails.
63084706141Svk199839 		 */
63184706141Svk199839 		ASSERT(recend == mp->b_wptr);
63284706141Svk199839 		if (recend != mp->b_wptr) {
63384706141Svk199839 			desc = decode_error;
63484706141Svk199839 			KSSL_COUNTER(internal_errors, 1);
63551dd2c77Svk199839 			DTRACE_PROBE(kssl_err__not_complete_record);
63684706141Svk199839 			goto makealert;
63784706141Svk199839 		}
63884706141Svk199839 
639c28749e9Skais 		spec = &ssl->spec[KSSL_READ];
640c28749e9Skais 		mac_sz = spec->mac_hashsz;
641c28749e9Skais 		if (spec->cipher_ctx != 0) {
64239d67566Skais 
64339d67566Skais 			/*
64439d67566Skais 			 * The record length must be a multiple of the
64539d67566Skais 			 * block size for block ciphers.
64639d67566Skais 			 * The cipher_bsize is always a power of 2.
64739d67566Skais 			 */
64839d67566Skais 			if ((spec->cipher_type == type_block) &&
64939d67566Skais 			    ((rec_sz & (spec->cipher_bsize - 1)) != 0)) {
65051dd2c77Svk199839 				DTRACE_PROBE2(kssl_err__bad_record_size,
65151dd2c77Svk199839 				    uint16_t, rec_sz,
65251dd2c77Svk199839 				    int, spec->cipher_bsize);
65339d67566Skais 				KSSL_COUNTER(record_decrypt_failure, 1);
65439d67566Skais 				mp->b_rptr = recend;
65539d67566Skais 				desc = decrypt_error;
65639d67566Skais 				goto makealert;
65739d67566Skais 			}
65839d67566Skais 
659c28749e9Skais 			cipher_data.cd_format = CRYPTO_DATA_RAW;
660c28749e9Skais 			cipher_data.cd_offset = 0;
661c28749e9Skais 			cipher_data.cd_length = rec_sz;
662c28749e9Skais 			cipher_data.cd_miscdata = NULL;
663c28749e9Skais 			cipher_data.cd_raw.iov_base = (char *)mp->b_rptr;
664c28749e9Skais 			cipher_data.cd_raw.iov_len = rec_sz;
665c28749e9Skais 			error = crypto_decrypt_update(spec->cipher_ctx,
666c28749e9Skais 			    &cipher_data, NULL, NULL);
667c28749e9Skais 			if (CRYPTO_ERR(error)) {
66851dd2c77Svk199839 				DTRACE_PROBE1(
66951dd2c77Svk199839 				    kssl_err__crypto_decrypt_update_failed,
67051dd2c77Svk199839 				    int, error);
671c28749e9Skais 				KSSL_COUNTER(record_decrypt_failure, 1);
672c28749e9Skais 				mp->b_rptr = recend;
673c28749e9Skais 				desc = decrypt_error;
674c28749e9Skais 				goto makealert;
675c28749e9Skais 			}
676c28749e9Skais 		}
677c28749e9Skais 		if (spec->cipher_type == type_block) {
678c28749e9Skais 			uint_t pad_sz = recend[-1];
679c28749e9Skais 			pad_sz++;
680c28749e9Skais 			if (pad_sz + mac_sz > rec_sz) {
68151dd2c77Svk199839 				DTRACE_PROBE(kssl_err__pad_mac_bigger);
682c28749e9Skais 				mp->b_rptr = recend;
683c28749e9Skais 				desc = bad_record_mac;
684c28749e9Skais 				goto makealert;
685c28749e9Skais 			}
686c28749e9Skais 			rec_sz -= pad_sz;
687c28749e9Skais 			recend -= pad_sz;
688c28749e9Skais 		}
689c28749e9Skais 		if (mac_sz != 0) {
690c28749e9Skais 			uchar_t hash[MAX_HASH_LEN];
691c28749e9Skais 			if (rec_sz < mac_sz) {
69251dd2c77Svk199839 				DTRACE_PROBE(kssl_err__pad_smaller_mac);
693c28749e9Skais 				mp->b_rptr = real_recend;
694c28749e9Skais 				desc = bad_record_mac;
695c28749e9Skais 				goto makealert;
696c28749e9Skais 			}
697c28749e9Skais 			rec_sz -= mac_sz;
698c28749e9Skais 			recend -= mac_sz;
699c28749e9Skais 			ret = kssl_compute_record_mac(ssl, KSSL_READ,
700c28749e9Skais 			    ssl->seq_num[KSSL_READ], content_type,
701c28749e9Skais 			    version, mp->b_rptr, rec_sz, hash);
702c28749e9Skais 			if (ret != CRYPTO_SUCCESS ||
703c28749e9Skais 			    bcmp(hash, recend, mac_sz)) {
70451dd2c77Svk199839 				DTRACE_PROBE1(kssl_mblk__MACmismatch_handlerec,
70551dd2c77Svk199839 				    mblk_t *, mp);
706c28749e9Skais 				mp->b_rptr = real_recend;
707c28749e9Skais 				desc = bad_record_mac;
70851dd2c77Svk199839 				DTRACE_PROBE(kssl_err__msg_MAC_mismatch);
709c28749e9Skais 				KSSL_COUNTER(verify_mac_failure, 1);
710c28749e9Skais 				goto makealert;
711c28749e9Skais 			}
712c28749e9Skais 			ssl->seq_num[KSSL_READ]++;
713c28749e9Skais 		}
714c28749e9Skais 
715c28749e9Skais 		if (ssl->hs_waitstate != idle_handshake) {
71651dd2c77Svk199839 			DTRACE_PROBE1(kssl_err__unexpected_msg,
71751dd2c77Svk199839 			    SSL3WaitState, ssl->hs_waitstate);
718c28749e9Skais 			mp->b_rptr = real_recend;
719c28749e9Skais 			desc = unexpected_message;
720c28749e9Skais 			goto makealert;
721c28749e9Skais 		}
722c28749e9Skais 		mp->b_wptr = recend;
723c28749e9Skais 
72451dd2c77Svk199839 		DTRACE_PROBE1(kssl_mblk__dblk_cooked, mblk_t *, mp);
72584706141Svk199839 		KSSL_COUNTER(appdata_record_ins, 1);
72684706141Svk199839 
727c28749e9Skais 		prevmp = mp;
728c28749e9Skais 		mp = mp->b_cont;
729c28749e9Skais 	}
730c28749e9Skais 
731c28749e9Skais 	return (kssl_cmd);
732c28749e9Skais 
733c28749e9Skais makealert:
734c28749e9Skais 	nextmp = mp->b_cont;
735c28749e9Skais 	freeb(mp);
736c28749e9Skais 	mp = nextmp;
737c28749e9Skais 	mutex_enter(&ssl->kssl_lock);
738c28749e9Skais 	kssl_send_alert(ssl, alert_fatal, desc);
739c28749e9Skais 
740c28749e9Skais 	if (ssl->alert_sendbuf == NULL) {
741c28749e9Skais 		/* internal memory allocation failure. just return. */
74251dd2c77Svk199839 		DTRACE_PROBE(kssl_err__alert_msg_alloc_failed);
743c28749e9Skais 		mutex_exit(&ssl->kssl_lock);
744c28749e9Skais 
745c28749e9Skais 		if (mp) {
746c28749e9Skais 			prevmp = NULL;
747c28749e9Skais 			goto more;
748c28749e9Skais 		}
749c28749e9Skais 
750c28749e9Skais 		return (KSSL_CMD_NONE);
751c28749e9Skais 	}
752c28749e9Skais 	kssl_cmd = KSSL_CMD_SEND;
753c28749e9Skais sendalert:
754c28749e9Skais 	if (*outmp == NULL) {
755c28749e9Skais 		*outmp = ssl->alert_sendbuf;
756c28749e9Skais 	} else {
757c28749e9Skais 		linkb(*outmp, ssl->alert_sendbuf);
758c28749e9Skais 	}
759c28749e9Skais 	ssl->alert_sendbuf = NULL;
760c28749e9Skais 	mutex_exit(&ssl->kssl_lock);
761c28749e9Skais 
762c28749e9Skais 	if (mp) {
763c28749e9Skais 		prevmp = NULL;
764c28749e9Skais 		goto more;
765c28749e9Skais 	}
766c28749e9Skais 
767c28749e9Skais 	return (kssl_cmd);
768c28749e9Skais }
769c28749e9Skais /*
770c28749e9Skais  * This is the routine that handles incoming SSL records.
771c28749e9Skais  * When called the first time, with a NULL context, this routine expects
772c28749e9Skais  * a ClientHello SSL Handshake packet and shall allocate a context
773c28749e9Skais  * of a new SSL connection.
774c28749e9Skais  * During the rest of the handshake packets, the routine adjusts the
775c28749e9Skais  * state of the context according to the record received.
776c28749e9Skais  * After the ChangeCipherSpec message is received, the routine first
777c28749e9Skais  * decrypts/authenticated the packet using the key materials in the
778c28749e9Skais  * connection's context.
779c28749e9Skais  * The return code tells the caller what to do with the returned packet.
780c28749e9Skais  */
781c28749e9Skais static kssl_cmd_t
782c28749e9Skais kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp,
783c28749e9Skais     kssl_callback_t cbfn, void *arg)
784c28749e9Skais {
785c28749e9Skais 	uchar_t *recend, *rec_sz_p;
786c28749e9Skais 	uchar_t version[2];
787c28749e9Skais 	uchar_t *real_recend, *save_rptr, *save_wptr;
788c28749e9Skais 	int rhsz = SSL3_HDR_LEN;
789c28749e9Skais 	uint16_t rec_sz;
790c28749e9Skais 	int sz;
791c28749e9Skais 	int mac_sz;
792c28749e9Skais 	SSL3AlertDescription desc;
793c28749e9Skais 	SSL3AlertLevel level;
794c28749e9Skais 	SSL3ContentType content_type;
795c28749e9Skais 	ssl_t *ssl;
796c28749e9Skais 	KSSLCipherSpec *spec;
797c28749e9Skais 	int error = 0, ret;
798c28749e9Skais 
799c28749e9Skais 	ASSERT(ctx != NULL);
800c28749e9Skais 
801c28749e9Skais 	ssl = (ssl_t *)(ctx);
802c28749e9Skais 
803c28749e9Skais 	*decrmp = NULL;
804c28749e9Skais 
805c28749e9Skais 	save_rptr = mp->b_rptr;
806c28749e9Skais 	save_wptr = mp->b_wptr;
807c28749e9Skais 
808c28749e9Skais 	ASSERT(MUTEX_HELD(&ssl->kssl_lock));
809c28749e9Skais 
810c28749e9Skais 	content_type = (SSL3ContentType)mp->b_rptr[0];
811c28749e9Skais 	if (content_type == content_handshake_v2) {
812c28749e9Skais 		if (ssl->hs_waitstate == wait_client_hello) {
813c28749e9Skais 			/* V2 compatible ClientHello */
814c28749e9Skais 			if (mp->b_rptr[3] == 0x03 &&
815c28749e9Skais 			    (mp->b_rptr[4] == 0x01 ||
816c28749e9Skais 			    mp->b_rptr[4] == 0x00)) {
817c28749e9Skais 				ssl->major_version = version[0] = mp->b_rptr[3];
818c28749e9Skais 				ssl->minor_version = version[1] = mp->b_rptr[4];
819c28749e9Skais 			} else {
820c28749e9Skais 			/* We don't support "pure" SSLv2 */
82151dd2c77Svk199839 				DTRACE_PROBE(kssl_err__no_SSLv2);
8227dd0d8ffSVladimir Kotal 				ssl->major_version = mp->b_rptr[3];
8237dd0d8ffSVladimir Kotal 				ssl->minor_version = mp->b_rptr[4];
824c28749e9Skais 				desc = protocol_version;
825c28749e9Skais 				goto sendalert;
826c28749e9Skais 			}
827c28749e9Skais 		}
828c28749e9Skais 		rec_sz = (uint16_t)mp->b_rptr[1];
829c28749e9Skais 		rhsz = 2;
830c28749e9Skais 	} else {
831c28749e9Skais 		ssl->major_version = version[0] = mp->b_rptr[1];
832c28749e9Skais 		ssl->minor_version = version[1] = mp->b_rptr[2];
833c28749e9Skais 		rec_sz_p = SSL3_REC_SIZE(mp);
834c28749e9Skais 		rec_sz = BE16_TO_U16(rec_sz_p);
835c28749e9Skais 	}
836c28749e9Skais 
837c28749e9Skais 	mp->b_rptr += rhsz;
838c28749e9Skais 	recend = mp->b_rptr + rec_sz;
839c28749e9Skais 	real_recend = recend;
840c28749e9Skais 
84184706141Svk199839 	/*
84284706141Svk199839 	 * Check the assumption that each mblk contains exactly
84384706141Svk199839 	 * one complete SSL record. We bail out if the check fails.
84484706141Svk199839 	 */
84584706141Svk199839 	ASSERT(recend == mp->b_wptr);
84684706141Svk199839 	if (recend != mp->b_wptr) {
84751dd2c77Svk199839 		DTRACE_PROBE3(kssl_mblk__handle_any_record_recszerr,
84851dd2c77Svk199839 		    mblk_t *, mp, int, rhsz, int, rec_sz);
84951dd2c77Svk199839 		DTRACE_PROBE(kssl_err__record_size);
85084706141Svk199839 		desc = decode_error;
85184706141Svk199839 		KSSL_COUNTER(internal_errors, 1);
85284706141Svk199839 		goto sendalert;
85384706141Svk199839 	}
85484706141Svk199839 
855c28749e9Skais 	spec = &ssl->spec[KSSL_READ];
856c28749e9Skais 	mac_sz = spec->mac_hashsz;
857c28749e9Skais 	if (spec->cipher_ctx != 0) {
85839d67566Skais 		/*
85939d67566Skais 		 * The record length must be a multiple of the
86039d67566Skais 		 * block size for block ciphers.
86139d67566Skais 		 */
86239d67566Skais 		if ((spec->cipher_type == type_block) &&
86339d67566Skais 		    ((rec_sz & (spec->cipher_bsize - 1)) != 0)) {
86451dd2c77Svk199839 			DTRACE_PROBE2(kssl_err__bad_record_size,
86551dd2c77Svk199839 			    uint16_t, rec_sz, int, spec->cipher_bsize);
86639d67566Skais 			KSSL_COUNTER(record_decrypt_failure, 1);
86739d67566Skais 			mp->b_rptr = recend;
86839d67566Skais 			desc = decrypt_error;
86939d67566Skais 			goto sendalert;
87039d67566Skais 		}
87139d67566Skais 
872c28749e9Skais 		spec->cipher_data.cd_length = rec_sz;
873c28749e9Skais 		spec->cipher_data.cd_raw.iov_base = (char *)mp->b_rptr;
874c28749e9Skais 		spec->cipher_data.cd_raw.iov_len = rec_sz;
875c28749e9Skais 		error = crypto_decrypt_update(spec->cipher_ctx,
876c28749e9Skais 		    &spec->cipher_data, NULL, NULL);
877c28749e9Skais 		if (CRYPTO_ERR(error)) {
87851dd2c77Svk199839 			DTRACE_PROBE1(kssl_err__crypto_decrypt_update_failed,
87951dd2c77Svk199839 			    int, error);
880c28749e9Skais 			KSSL_COUNTER(record_decrypt_failure, 1);
881c28749e9Skais 			mp->b_rptr = recend;
882c28749e9Skais 			desc = decrypt_error;
883c28749e9Skais 			goto sendalert;
884c28749e9Skais 		}
885c28749e9Skais 	}
886c28749e9Skais 	if (spec->cipher_type == type_block) {
887c28749e9Skais 		uint_t pad_sz = recend[-1];
888c28749e9Skais 		pad_sz++;
889c28749e9Skais 		if (pad_sz + mac_sz > rec_sz) {
89051dd2c77Svk199839 			DTRACE_PROBE2(kssl_err__pad_mac_mismatch,
89151dd2c77Svk199839 			    int, pad_sz, int, mac_sz);
892c28749e9Skais 			mp->b_rptr = recend;
893c28749e9Skais 			desc = bad_record_mac;
894c28749e9Skais 			goto sendalert;
895c28749e9Skais 		}
896c28749e9Skais 		rec_sz -= pad_sz;
897c28749e9Skais 		recend -= pad_sz;
898c28749e9Skais 	}
899c28749e9Skais 	if (mac_sz != 0) {
900c28749e9Skais 		uchar_t hash[MAX_HASH_LEN];
901c28749e9Skais 		if (rec_sz < mac_sz) {
90251dd2c77Svk199839 			DTRACE_PROBE1(kssl_err__mac_size_too_big,
90351dd2c77Svk199839 			    int, mac_sz);
904c28749e9Skais 			mp->b_rptr = real_recend;
905c28749e9Skais 			desc = bad_record_mac;
906c28749e9Skais 			goto sendalert;
907c28749e9Skais 		}
908c28749e9Skais 		rec_sz -= mac_sz;
909c28749e9Skais 		recend -= mac_sz;
910c28749e9Skais 		ret = kssl_compute_record_mac(ssl, KSSL_READ,
911c28749e9Skais 		    ssl->seq_num[KSSL_READ], content_type,
912c28749e9Skais 		    version, mp->b_rptr, rec_sz, hash);
913c28749e9Skais 		if (ret != CRYPTO_SUCCESS ||
914c28749e9Skais 		    bcmp(hash, recend, mac_sz)) {
91551dd2c77Svk199839 			DTRACE_PROBE1(kssl_mblk__MACmismatch_anyrecord,
91651dd2c77Svk199839 			    mblk_t *, mp);
917c28749e9Skais 			mp->b_rptr = real_recend;
918c28749e9Skais 			desc = bad_record_mac;
91951dd2c77Svk199839 			DTRACE_PROBE(kssl_err__msg_MAC_mismatch);
920c28749e9Skais 			KSSL_COUNTER(verify_mac_failure, 1);
921c28749e9Skais 			goto sendalert;
922c28749e9Skais 		}
923c28749e9Skais 		ssl->seq_num[KSSL_READ]++;
92451dd2c77Svk199839 		DTRACE_PROBE1(kssl_mblk__after_compute_MAC,
92551dd2c77Svk199839 		    mblk_t *, mp);
926c28749e9Skais 	}
927c28749e9Skais 
928c28749e9Skais 	switch (content_type) {
929c28749e9Skais 	case content_handshake:
930c28749e9Skais 		do {
93151dd2c77Svk199839 			DTRACE_PROBE1(kssl_mblk__content_handshake_cycle,
93251dd2c77Svk199839 			    mblk_t *, mp);
933c28749e9Skais 			if (error != 0 ||
934c28749e9Skais 			    /* ignore client renegotiation for now */
935c28749e9Skais 			    ssl->hs_waitstate == idle_handshake) {
936c28749e9Skais 				mp->b_rptr = recend;
93711d0a659SVladimir Kotal 				DTRACE_PROBE(kssl_renegotiation_request);
938c28749e9Skais 			}
939c28749e9Skais 			if (mp->b_rptr == recend) {
940c28749e9Skais 				mp->b_rptr = real_recend;
941c28749e9Skais 				if (error != 0) {
942c28749e9Skais 					goto error;
943c28749e9Skais 				}
944c28749e9Skais 				freeb(mp);
945c28749e9Skais 
946c28749e9Skais 				if (ssl->hs_waitstate == wait_client_key_done)
947c28749e9Skais 					return (KSSL_CMD_QUEUED);
948c28749e9Skais 
949c28749e9Skais 				return ((ssl->handshake_sendbuf != NULL) ?
950c28749e9Skais 				    KSSL_CMD_SEND : KSSL_CMD_NONE);
951c28749e9Skais 			}
952c28749e9Skais 			if (ssl->msg.state < MSG_BODY) {
953c28749e9Skais 				if (ssl->msg.state == MSG_INIT) {
954c28749e9Skais 					ssl->msg.type =
955c28749e9Skais 					    (SSL3HandshakeType)*mp->b_rptr++;
956c28749e9Skais 					ssl->msg.state = MSG_INIT_LEN;
957c28749e9Skais 				}
958c28749e9Skais 				if (ssl->msg.state == MSG_INIT_LEN) {
959c28749e9Skais 					int msglenb =
960c28749e9Skais 					    ssl->msg.msglen_bytes;
961c28749e9Skais 					int msglen = ssl->msg.msglen;
962c28749e9Skais 					while (mp->b_rptr < recend &&
963c28749e9Skais 					    msglenb < 3) {
964c28749e9Skais 						msglen = (msglen << 8) +
965c28749e9Skais 						    (uint_t)(*mp->b_rptr++);
966c28749e9Skais 						msglenb++;
967c28749e9Skais 					}
968c28749e9Skais 					ssl->msg.msglen_bytes = msglenb;
969c28749e9Skais 					ssl->msg.msglen = msglen;
970c28749e9Skais 					if (msglenb == 3) {
971c28749e9Skais 						ssl->msg.state = MSG_BODY;
972c28749e9Skais 					}
973c28749e9Skais 				}
974c28749e9Skais 				if (mp->b_rptr == recend) {
975c28749e9Skais 					mp->b_rptr = real_recend;
976c28749e9Skais 					freeb(mp);
977c28749e9Skais 					return (KSSL_CMD_NONE);
978c28749e9Skais 				}
979c28749e9Skais 			}
980c28749e9Skais 			ASSERT(ssl->msg.state == MSG_BODY);
981c28749e9Skais 
982c28749e9Skais 			sz = recend - mp->b_rptr;
983c28749e9Skais 
984c28749e9Skais 			if (ssl->msg.head == NULL &&
985c28749e9Skais 			    ssl->msg.msglen <= sz) {
986c28749e9Skais 				continue;
987c28749e9Skais 			}
988c28749e9Skais 			if (ssl->msg.head != NULL) {
989c28749e9Skais 				sz += msgdsize(ssl->msg.head);
990c28749e9Skais 				if (ssl->msg.msglen <= sz) {
991c28749e9Skais 					ssl->msg.tail->b_cont = mp;
992c28749e9Skais 					mp = ssl->msg.head;
993c28749e9Skais 					ssl->sslcnt = 100;
994c28749e9Skais 					ssl->msg.head = NULL;
995c28749e9Skais 					ssl->msg.tail = NULL;
996c28749e9Skais 					if (pullupmsg(mp, -1)) {
997c28749e9Skais 						recend = mp->b_rptr + sz;
998c28749e9Skais 						ASSERT(recend <= mp->b_wptr);
999c28749e9Skais 						continue;
1000c28749e9Skais 					}
1001c28749e9Skais 					mp->b_rptr = real_recend;
1002c28749e9Skais 					error = ENOMEM;
1003c28749e9Skais 					KSSL_COUNTER(alloc_fails, 1);
1004c28749e9Skais 					goto error;
1005c28749e9Skais 				}
1006c28749e9Skais 			}
1007c28749e9Skais 
1008c28749e9Skais 			mp->b_wptr = recend;
1009c28749e9Skais 
1010c28749e9Skais 			if (ssl->msg.head == NULL) {
1011c28749e9Skais 				ssl->msg.head = mp;
1012c28749e9Skais 				ssl->msg.tail = mp;
1013c28749e9Skais 				return (KSSL_CMD_NONE);
1014c28749e9Skais 			} else {
1015c28749e9Skais 				ssl->msg.tail->b_cont = mp;
1016c28749e9Skais 				ssl->msg.tail = mp;
1017c28749e9Skais 				return (KSSL_CMD_NONE);
1018c28749e9Skais 			}
1019c28749e9Skais 		} while (kssl_handle_handshake_message(ssl, mp, &error, cbfn,
1020c28749e9Skais 		    arg));
1021c28749e9Skais 		if (error == SSL_MISS) {
1022c28749e9Skais 			mp->b_rptr = save_rptr;
1023c28749e9Skais 			mp->b_wptr = save_wptr;
1024c28749e9Skais 			KSSL_COUNTER(fallback_connections, 1);
1025c28749e9Skais 			return (KSSL_CMD_NOT_SUPPORTED);
1026c28749e9Skais 		}
1027c28749e9Skais 		if (ssl->hs_waitstate == wait_client_key_done) {
1028c28749e9Skais 			return (KSSL_CMD_QUEUED);
1029c28749e9Skais 		} else {
1030c28749e9Skais 			return (KSSL_CMD_NONE);
1031c28749e9Skais 		}
1032c28749e9Skais 	case content_alert:
103351dd2c77Svk199839 		DTRACE_PROBE1(kssl_mblk__content_alert, mblk_t *, mp);
1034c28749e9Skais 		if (rec_sz != 2) {
103551dd2c77Svk199839 			DTRACE_PROBE(kssl_err__illegal_param);
1036c28749e9Skais 			mp->b_rptr = real_recend;
1037c28749e9Skais 			desc = illegal_parameter;
1038c28749e9Skais 			goto sendalert;
1039c28749e9Skais 		} else {
1040c28749e9Skais 			level = *mp->b_rptr++;
1041c28749e9Skais 			desc = *mp->b_rptr++;
1042c28749e9Skais 			mp->b_rptr = real_recend;
1043c28749e9Skais 			if (level != alert_warning || desc != close_notify) {
1044c28749e9Skais 				if (ssl->sid.cached == B_TRUE) {
1045c28749e9Skais 					kssl_uncache_sid(&ssl->sid,
1046c28749e9Skais 					    ssl->kssl_entry);
1047c28749e9Skais 				}
104851dd2c77Svk199839 				DTRACE_PROBE2(kssl_err__bad_content_alert,
104951dd2c77Svk199839 				    SSL3AlertLevel, level,
105051dd2c77Svk199839 				    SSL3AlertDescription, desc);
1051c28749e9Skais 				ssl->fatal_alert = B_TRUE;
1052c28749e9Skais 				error = EBADMSG;
1053c28749e9Skais 				goto error;
1054c28749e9Skais 			} else {
1055*9b1bd49fSVladimir Kotal 				ssl->close_notify_clnt = B_TRUE;
1056c28749e9Skais 				ssl->activeinput = B_FALSE;
1057c28749e9Skais 				freeb(mp);
1058c28749e9Skais 				return (KSSL_CMD_NONE);
1059c28749e9Skais 			}
1060c28749e9Skais 		}
1061c28749e9Skais 	case content_change_cipher_spec:
106251dd2c77Svk199839 		DTRACE_PROBE1(kssl_mblk__change_cipher_spec,
106351dd2c77Svk199839 		    mblk_t *, mp);
1064c28749e9Skais 		if (ssl->hs_waitstate != wait_change_cipher) {
1065c28749e9Skais 			desc = unexpected_message;
1066c28749e9Skais 		} else if (rec_sz != 1 || *mp->b_rptr != 1) {
1067c28749e9Skais 			desc = illegal_parameter;
1068c28749e9Skais 		} else {
1069c28749e9Skais 			mp->b_rptr = real_recend;
1070c28749e9Skais 			ssl->hs_waitstate = wait_finished;
1071c28749e9Skais 			ssl->seq_num[KSSL_READ] = 0;
1072c28749e9Skais 			if ((error = kssl_spec_init(ssl, KSSL_READ)) != 0) {
107351dd2c77Svk199839 				DTRACE_PROBE1(kssl_err__kssl_spec_init_error,
107451dd2c77Svk199839 				    int, error);
1075c28749e9Skais 				goto error;
1076c28749e9Skais 			}
1077c28749e9Skais 			ssl->activeinput = B_FALSE;
1078c28749e9Skais 			freeb(mp);
1079c28749e9Skais 			return (KSSL_CMD_NONE);
1080c28749e9Skais 		}
1081c28749e9Skais 		mp->b_rptr = real_recend;
108251dd2c77Svk199839 		DTRACE_PROBE(kssl_err__change_cipher_spec);
1083c28749e9Skais 		goto sendalert;
1084c28749e9Skais 
1085c28749e9Skais 	case content_application_data:
108651dd2c77Svk199839 		DTRACE_PROBE1(kssl_mblk__content_app_data,
108751dd2c77Svk199839 		    mblk_t *, mp);
1088c28749e9Skais 		if (ssl->hs_waitstate != idle_handshake) {
108951dd2c77Svk199839 			DTRACE_PROBE(kssl_err__content_app_data);
1090c28749e9Skais 			mp->b_rptr = real_recend;
1091c28749e9Skais 			desc = unexpected_message;
1092c28749e9Skais 			goto sendalert;
1093c28749e9Skais 		}
1094c28749e9Skais 		mp->b_wptr = recend;
1095c28749e9Skais 		*decrmp = mp;
1096c28749e9Skais 		ssl->activeinput = B_FALSE;
1097c28749e9Skais 		return (KSSL_CMD_DELIVER_PROXY);
1098c28749e9Skais 
1099c28749e9Skais 	case content_handshake_v2:
110051dd2c77Svk199839 		DTRACE_PROBE1(kssl_mblk__content_handshake_v2,
110151dd2c77Svk199839 		    mblk_t *, mp);
1102c28749e9Skais 		error = kssl_handle_v2client_hello(ssl, mp, rec_sz);
1103c28749e9Skais 		if (error == SSL_MISS) {
1104c28749e9Skais 			mp->b_rptr = save_rptr;
1105c28749e9Skais 			mp->b_wptr = save_wptr;
1106c28749e9Skais 			KSSL_COUNTER(fallback_connections, 1);
1107c28749e9Skais 			return (KSSL_CMD_NOT_SUPPORTED);
1108c28749e9Skais 		} else if (error != 0) {
110951dd2c77Svk199839 			DTRACE_PROBE(kssl_err__v2client_hello_failed);
1110c28749e9Skais 			goto error;
1111c28749e9Skais 		}
1112c28749e9Skais 		freeb(mp);
1113c28749e9Skais 		return (KSSL_CMD_SEND);
1114c28749e9Skais 	default:
111551dd2c77Svk199839 		DTRACE_PROBE1(kssl_mblk__unexpected_msg,
111651dd2c77Svk199839 		    mblk_t *, mp);
1117c28749e9Skais 		mp->b_rptr = real_recend;
1118c28749e9Skais 		desc = unexpected_message;
1119c28749e9Skais 		break;
1120c28749e9Skais 	}
1121c28749e9Skais 
1122c28749e9Skais sendalert:
1123c28749e9Skais 	kssl_send_alert(ssl, alert_fatal, desc);
1124c28749e9Skais 	*decrmp = ssl->alert_sendbuf;
1125c28749e9Skais 	ssl->alert_sendbuf = NULL;
1126c28749e9Skais 	freeb(mp);
1127c28749e9Skais 	return ((*decrmp != NULL) ? KSSL_CMD_SEND : KSSL_CMD_NONE);
1128c28749e9Skais error:
1129c28749e9Skais 	freeb(mp);
1130c28749e9Skais 	return (KSSL_CMD_NONE);
1131c28749e9Skais }
1132c28749e9Skais 
1133c28749e9Skais /*
1134c28749e9Skais  * Initialize the context of an SSL connection, coming to the specified
11352ec7cc7fSKrishna Yenduri  * address. The ssl structure is returned held.
1136c28749e9Skais  */
1137c28749e9Skais kssl_status_t
1138dd49f125SAnders Persson kssl_init_context(kssl_ent_t kssl_ent, struct sockaddr *addr, int mss,
1139dd49f125SAnders Persson     kssl_ctx_t *kssl_ctxp)
1140c28749e9Skais {
1141c28749e9Skais 	ssl_t *ssl = kmem_cache_alloc(kssl_cache, KM_NOSLEEP);
1142dd49f125SAnders Persson 	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
1143c28749e9Skais 
1144c28749e9Skais 	if (ssl == NULL) {
1145c28749e9Skais 		return (KSSL_STS_ERR);
1146c28749e9Skais 	}
1147c28749e9Skais 
1148c28749e9Skais 	bzero(ssl, sizeof (ssl_t));
1149c28749e9Skais 
1150c28749e9Skais 	ssl->kssl_entry = (kssl_entry_t *)kssl_ent;
1151c28749e9Skais 	KSSL_ENTRY_REFHOLD(ssl->kssl_entry);
1152c28749e9Skais 
1153dd49f125SAnders Persson 	if (sin->sin_family == AF_INET) {
1154dd49f125SAnders Persson 		IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &ssl->faddr);
11552ec7cc7fSKrishna Yenduri 	} else {
1156dd49f125SAnders Persson 		/* struct assignment */
1157dd49f125SAnders Persson 		ssl->faddr = ((struct sockaddr_in6 *)addr)->sin6_addr;
11582ec7cc7fSKrishna Yenduri 	}
1159c28749e9Skais 	ssl->tcp_mss = mss;
1160c28749e9Skais 	ssl->sendalert_level = alert_warning;
1161c28749e9Skais 	ssl->sendalert_desc = close_notify;
1162c28749e9Skais 	ssl->sid.cached = B_FALSE;
1163c28749e9Skais 
1164c28749e9Skais 	*kssl_ctxp = (kssl_ctx_t)ssl;
1165c28749e9Skais 	return (KSSL_STS_OK);
1166c28749e9Skais }
1167c28749e9Skais 
1168dd49f125SAnders Persson void
1169dd49f125SAnders Persson kssl_set_mss(kssl_ctx_t ctx, uint32_t mss)
1170dd49f125SAnders Persson {
1171dd49f125SAnders Persson 	ssl_t *ssl = (ssl_t *)ctx;
1172dd49f125SAnders Persson 	ssl->tcp_mss = mss;
1173dd49f125SAnders Persson }
1174dd49f125SAnders Persson 
1175c28749e9Skais /*
1176c28749e9Skais  * Builds SSL records out of the chain of mblks, and returns it.
11772ec7cc7fSKrishna Yenduri  * Takes a copy of the message before encrypting it if it has another
1178c28749e9Skais  * reference.
1179c28749e9Skais  * In case of failure, NULL is returned, and the message will be
1180c28749e9Skais  * freed by the caller.
1181c28749e9Skais  * A NULL mp means a close_notify is requested.
1182c28749e9Skais  */
1183c28749e9Skais mblk_t *
1184c28749e9Skais kssl_build_record(kssl_ctx_t ctx, mblk_t *mp)
1185c28749e9Skais {
1186c28749e9Skais 	ssl_t *ssl = (ssl_t *)ctx;
1187c28749e9Skais 	mblk_t *retmp = mp, *bp = mp, *prevbp = mp, *copybp;
1188c28749e9Skais 
1189c28749e9Skais 	ASSERT(ssl != NULL);
1190*9b1bd49fSVladimir Kotal 
1191*9b1bd49fSVladimir Kotal 	/*
1192*9b1bd49fSVladimir Kotal 	 * Produce new close_notify message. This is necessary to perform
1193*9b1bd49fSVladimir Kotal 	 * proper cleanup w.r.t. SSL protocol spec by sending close_notify SSL
1194*9b1bd49fSVladimir Kotal 	 * alert record if running with KSSL proxy.
1195*9b1bd49fSVladimir Kotal 	 * This should be done prior to sending the FIN so the client side can
1196*9b1bd49fSVladimir Kotal 	 * attempt to do graceful cleanup. Ideally, we should wait for client's
1197*9b1bd49fSVladimir Kotal 	 * close_notify but not all clients send it which would hang the
1198*9b1bd49fSVladimir Kotal 	 * connection. This way of closing the SSL session (Incomplete Close)
1199*9b1bd49fSVladimir Kotal 	 * prevents truncation attacks for protocols without end-of-data
1200*9b1bd49fSVladimir Kotal 	 * markers (as opposed to the Premature Close).
1201*9b1bd49fSVladimir Kotal 	 * Checking the close_notify_srvr flag will prevent from sending the
1202*9b1bd49fSVladimir Kotal 	 * close_notify message twice in case of duplicate shutdown() calls.
1203*9b1bd49fSVladimir Kotal 	 */
1204*9b1bd49fSVladimir Kotal 	if (mp == NULL && !ssl->close_notify_srvr) {
1205*9b1bd49fSVladimir Kotal 		kssl_send_alert(ssl, alert_warning, close_notify);
1206*9b1bd49fSVladimir Kotal 		if (ssl->alert_sendbuf == NULL)
1207*9b1bd49fSVladimir Kotal 			return (NULL);
1208*9b1bd49fSVladimir Kotal 		mp = bp = retmp = prevbp = ssl->alert_sendbuf;
1209*9b1bd49fSVladimir Kotal 		ssl->alert_sendbuf = NULL;
1210*9b1bd49fSVladimir Kotal 		ssl->close_notify_srvr = B_TRUE;
1211*9b1bd49fSVladimir Kotal 	}
1212*9b1bd49fSVladimir Kotal 
1213c28749e9Skais 	ASSERT(mp != NULL);
1214*9b1bd49fSVladimir Kotal 	ASSERT(bp != NULL);
1215c28749e9Skais 
1216c28749e9Skais 	do {
1217c28749e9Skais 		if (DB_REF(bp) > 1) {
1218c28749e9Skais 			/*
1219c28749e9Skais 			 * Fortunately copyb() preserves the offset,
12202ec7cc7fSKrishna Yenduri 			 * tail space and alignment so the copy is
1221c28749e9Skais 			 * ready to be made an SSL record.
1222c28749e9Skais 			 */
1223c28749e9Skais 			if ((copybp = copyb(bp)) == NULL)
1224c28749e9Skais 				return (NULL);
1225c28749e9Skais 
1226c28749e9Skais 			copybp->b_cont = bp->b_cont;
1227c28749e9Skais 			if (bp == mp) {
1228c28749e9Skais 				retmp = copybp;
1229c28749e9Skais 			} else {
1230c28749e9Skais 				prevbp->b_cont = copybp;
1231c28749e9Skais 			}
1232c28749e9Skais 			freeb(bp);
1233c28749e9Skais 			bp = copybp;
1234c28749e9Skais 		}
1235c28749e9Skais 
1236c28749e9Skais 		if (kssl_build_single_record(ssl, bp) != KSSL_STS_OK)
1237c28749e9Skais 			return (NULL);
1238c28749e9Skais 
1239c28749e9Skais 		prevbp = bp;
1240c28749e9Skais 		bp = bp->b_cont;
1241c28749e9Skais 	} while (bp != NULL);
1242c28749e9Skais 
1243c28749e9Skais 	return (retmp);
1244c28749e9Skais }
1245c28749e9Skais 
1246c28749e9Skais /*
1247*9b1bd49fSVladimir Kotal  * Builds a single SSL record by prepending SSL header (optional) and performing
1248*9b1bd49fSVladimir Kotal  * encryption and MAC. The encryption of the record is done in-line.
1249*9b1bd49fSVladimir Kotal  * Expects an mblk with associated dblk's base to have space for the SSL header
1250*9b1bd49fSVladimir Kotal  * or an mblk which already has the header present. In both cases it presumes
1251*9b1bd49fSVladimir Kotal  * that the mblk's dblk limit has space for the MAC + padding.
1252*9b1bd49fSVladimir Kotal  * If the close_notify_srvr flag is set it is presumed that the mblk already
1253*9b1bd49fSVladimir Kotal  * contains SSL header in which case only the record length field will be
1254*9b1bd49fSVladimir Kotal  * adjusted with the MAC/padding size.
1255c28749e9Skais  */
1256c28749e9Skais static kssl_status_t
1257c28749e9Skais kssl_build_single_record(ssl_t *ssl, mblk_t *mp)
1258c28749e9Skais {
1259c28749e9Skais 	int len;
12602ec7cc7fSKrishna Yenduri 	int reclen;
1261c28749e9Skais 	uchar_t *recstart, *versionp;
1262c28749e9Skais 	KSSLCipherSpec *spec;
1263c28749e9Skais 	int mac_sz;
12642ec7cc7fSKrishna Yenduri 	int pad_sz;
1265c28749e9Skais 
1266c28749e9Skais 	spec = &ssl->spec[KSSL_WRITE];
1267c28749e9Skais 	mac_sz = spec->mac_hashsz;
1268c28749e9Skais 
1269c28749e9Skais 	ASSERT(DB_REF(mp) == 1);
1270*9b1bd49fSVladimir Kotal 	/* The dblk must always have space for the padding and MAC suffix. */
1271*9b1bd49fSVladimir Kotal 	ASSERT(mp->b_datap->db_lim - mp->b_wptr >= mac_sz + spec->cipher_bsize);
1272c28749e9Skais 
1273*9b1bd49fSVladimir Kotal 	/* kssl_send_alert() constructs the SSL header by itself. */
1274*9b1bd49fSVladimir Kotal 	if (!ssl->close_notify_srvr)
1275*9b1bd49fSVladimir Kotal 		len = MBLKL(mp) - SSL3_HDR_LEN;
1276*9b1bd49fSVladimir Kotal 	else
1277c28749e9Skais 		len = MBLKL(mp);
1278c28749e9Skais 
1279c28749e9Skais 	ASSERT(len > 0);
1280c28749e9Skais 
1281c28749e9Skais 	mutex_enter(&ssl->kssl_lock);
1282c28749e9Skais 
1283*9b1bd49fSVladimir Kotal 	recstart = mp->b_rptr;
1284*9b1bd49fSVladimir Kotal 	if (!ssl->close_notify_srvr) {
1285*9b1bd49fSVladimir Kotal 		/* The dblk must have space for the SSL header prefix. */
1286*9b1bd49fSVladimir Kotal 		ASSERT(mp->b_rptr - mp->b_datap->db_base >= SSL3_HDR_LEN);
1287c28749e9Skais 		recstart = mp->b_rptr = mp->b_rptr - SSL3_HDR_LEN;
1288c28749e9Skais 		recstart[0] = content_application_data;
1289c28749e9Skais 		recstart[1] = ssl->major_version;
1290c28749e9Skais 		recstart[2] = ssl->minor_version;
1291*9b1bd49fSVladimir Kotal 	}
1292c28749e9Skais 	versionp = &recstart[1];
1293c28749e9Skais 
1294c28749e9Skais 	reclen = len + mac_sz;
1295c28749e9Skais 	if (spec->cipher_type == type_block) {
1296c28749e9Skais 		pad_sz = spec->cipher_bsize -
1297c28749e9Skais 		    (reclen & (spec->cipher_bsize - 1));
1298c28749e9Skais 		ASSERT(reclen + pad_sz <=
1299c28749e9Skais 		    SSL3_MAX_RECORD_LENGTH);
1300c28749e9Skais 		reclen += pad_sz;
1301c28749e9Skais 	}
1302c28749e9Skais 	recstart[3] = (reclen >> 8) & 0xff;
1303c28749e9Skais 	recstart[4] = reclen & 0xff;
1304c28749e9Skais 
1305*9b1bd49fSVladimir Kotal 	if (kssl_mac_encrypt_record(ssl, recstart[0], versionp,
1306c28749e9Skais 	    recstart, mp) != 0) {
1307c28749e9Skais 		/* Do we need an internal_error Alert here? */
1308c28749e9Skais 		mutex_exit(&ssl->kssl_lock);
1309c28749e9Skais 		return (KSSL_STS_ERR);
1310c28749e9Skais 	}
1311c28749e9Skais 
1312*9b1bd49fSVladimir Kotal 	/* Alert messages are accounted in kssl_send_alert(). */
1313*9b1bd49fSVladimir Kotal 	if (recstart[0] == content_application_data)
1314c28749e9Skais 		KSSL_COUNTER(appdata_record_outs, 1);
1315c28749e9Skais 	mutex_exit(&ssl->kssl_lock);
1316c28749e9Skais 	return (KSSL_STS_OK);
1317c28749e9Skais }
1318