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
kssl_check_proxy(struct sockaddr * addr,socklen_t len,void * cookie,kssl_ent_t * ksslent)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 *
kssl_find_fallback(kssl_ent_t ksslent)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
kssl_enqueue(kssl_chain_t ** head,void * item)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
kssl_dequeue(kssl_chain_t ** head,void * item)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
kssl_hold_ent(kssl_ent_t ksslent)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
kssl_release_ent(kssl_ent_t ksslent,void * cookie,kssl_endpt_type_t endpt_type)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
kssl_release_ctx(kssl_ctx_t ksslctx)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
kssl_async_done(kssl_ctx_t ksslctx)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
kssl_input(kssl_ctx_t ctx,mblk_t * mp,mblk_t ** decrmp,boolean_t * more,kssl_callback_t cbfn,void * arg)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
kssl_handle_mblk(kssl_ctx_t ctx,mblk_t ** mpp,mblk_t ** outmp)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
kssl_handle_any_record(kssl_ctx_t ctx,mblk_t * mp,mblk_t ** decrmp,kssl_callback_t cbfn,void * arg)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
kssl_init_context(kssl_ent_t kssl_ent,struct sockaddr * addr,int mss,kssl_ctx_t * kssl_ctxp)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
kssl_set_mss(kssl_ctx_t ctx,uint32_t mss)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 *
kssl_build_record(kssl_ctx_t ctx,mblk_t * mp)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
kssl_build_single_record(ssl_t * ssl,mblk_t * mp)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