|
1 /* |
|
2 * CDDL HEADER START |
|
3 * |
|
4 * The contents of this file are subject to the terms of the |
|
5 * Common Development and Distribution License, Version 1.0 only |
|
6 * (the "License"). You may not use this file except in compliance |
|
7 * with the License. |
|
8 * |
|
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
10 * or http://www.opensolaris.org/os/licensing. |
|
11 * See the License for the specific language governing permissions |
|
12 * and limitations under the License. |
|
13 * |
|
14 * When distributing Covered Code, include this CDDL HEADER in each |
|
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
16 * If applicable, add the following below this CDDL HEADER, with the |
|
17 * fields enclosed by brackets "[]" replaced with your own identifying |
|
18 * information: Portions Copyright [yyyy] [name of copyright owner] |
|
19 * |
|
20 * CDDL HEADER END |
|
21 */ |
|
22 /* |
|
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. |
|
24 * Use is subject to license terms. |
|
25 */ |
|
26 |
|
27 #pragma ident "%Z%%M% %I% %E% SMI" |
|
28 |
|
29 #include <sys/types.h> |
|
30 #include <sys/stream.h> |
|
31 #include <sys/strsun.h> |
|
32 #include <sys/cmn_err.h> |
|
33 #include <sys/kmem.h> |
|
34 #include <sys/cpuvar.h> |
|
35 #include <sys/atomic.h> |
|
36 #include <sys/sysmacros.h> |
|
37 |
|
38 #include <inet/common.h> |
|
39 #include <inet/ip.h> |
|
40 #include <inet/ip6.h> |
|
41 |
|
42 #include <sys/systm.h> |
|
43 #include <sys/param.h> |
|
44 #include <sys/tihdr.h> |
|
45 |
|
46 #include "ksslimpl.h" |
|
47 #include "ksslproto.h" |
|
48 #include "ksslapi.h" |
|
49 |
|
50 static kssl_cmd_t kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, |
|
51 mblk_t **decrmp, kssl_callback_t cbfn, void *arg); |
|
52 static boolean_t kssl_enqueue(kssl_chain_t **head, void *item); |
|
53 static void kssl_dequeue(kssl_chain_t **head, void *item); |
|
54 static kssl_status_t kssl_build_single_record(ssl_t *ssl, mblk_t *mp); |
|
55 |
|
56 /* |
|
57 * The socket T_bind_req message is intercepted and re-routed here |
|
58 * to see is there is SSL relevant job to do, based on the kssl config |
|
59 * in the kssl_entry_tab. |
|
60 * Looks up the kernel SSL proxy table, to find an entry that matches the |
|
61 * same serveraddr, and has one of the following two criteria: |
|
62 * 1. in_port is an ssl_port. This endpoint can be used later as a fallback |
|
63 * to complete connections that cannot be handled by the SSL kernel proxy |
|
64 * (typically non supported ciphersuite). The cookie for the calling client |
|
65 * is saved with the kssl_entry to be retrieved for the fallback. |
|
66 * The function returns KSSL_HAS_PROXY. |
|
67 * |
|
68 * 2. in_port is a proxy port for another ssl port. The ssl port is then |
|
69 * substituted to the in_port in the bind_req TPI structure, so that |
|
70 * the bind falls through to the SSL port. At the end of this operation, |
|
71 * all the packets arriving to the SSL port will be delivered to an |
|
72 * accepted endpoint child of this bound socket. |
|
73 * The kssl_entry_t is returned in *ksslent, for later use by the |
|
74 * lower modules' SSL hooks that handle the Handshake messages. |
|
75 * The function returns KSSL_IS_PROXY. |
|
76 * |
|
77 * The function returns KSSL_NO_PROXY otherwise. We do not suppport |
|
78 * IPv6 addresses. |
|
79 */ |
|
80 |
|
81 kssl_endpt_type_t |
|
82 kssl_check_proxy(mblk_t *bindmp, void *cookie, kssl_ent_t *ksslent) |
|
83 { |
|
84 int i; |
|
85 kssl_endpt_type_t ret; |
|
86 kssl_entry_t *ep; |
|
87 sin_t *sin; |
|
88 struct T_bind_req *tbr; |
|
89 ipaddr_t v4addr; |
|
90 in_port_t in_port; |
|
91 |
|
92 if (kssl_enabled == 0) { |
|
93 return (KSSL_NO_PROXY); |
|
94 } |
|
95 |
|
96 tbr = (struct T_bind_req *)bindmp->b_rptr; |
|
97 |
|
98 ret = KSSL_NO_PROXY; |
|
99 |
|
100 |
|
101 switch (tbr->ADDR_length) { |
|
102 case sizeof (sin_t): |
|
103 sin = (sin_t *)(bindmp->b_rptr + tbr->ADDR_length); |
|
104 in_port = ntohs(sin->sin_port); |
|
105 v4addr = sin->sin_addr.s_addr; |
|
106 break; |
|
107 |
|
108 case sizeof (sin6_t): |
|
109 /* Future support of IPv6 goes here */ |
|
110 default: |
|
111 /* Should ASSERT() here? */ |
|
112 return (ret); |
|
113 } |
|
114 |
|
115 mutex_enter(&kssl_tab_mutex); |
|
116 |
|
117 for (i = 0; i < kssl_entry_tab_size; i++) { |
|
118 if ((ep = kssl_entry_tab[i]) == NULL) |
|
119 continue; |
|
120 |
|
121 if ((ep->ke_laddr == v4addr) || (ep->ke_laddr == INADDR_ANY)) { |
|
122 |
|
123 /* This is an SSL port to fallback to */ |
|
124 if (ep->ke_ssl_port == in_port) { |
|
125 |
|
126 /* |
|
127 * Let's see first if there's at least |
|
128 * an endpoint for a proxy server. |
|
129 * If there's none, then we return as we have |
|
130 * no proxy, so that the bind() to the |
|
131 * transport layer goes through. |
|
132 * The calling module will ask for this |
|
133 * cookie if it wants to fall back to it, |
|
134 * so add this one to the list of fallback |
|
135 * clients. |
|
136 */ |
|
137 if (!kssl_enqueue((kssl_chain_t **) |
|
138 &(ep->ke_fallback_head), cookie)) { |
|
139 break; |
|
140 } |
|
141 |
|
142 /* |
|
143 * Now transform the T_BIND_REQ into |
|
144 * a T_BIND_ACK. |
|
145 */ |
|
146 tbr->PRIM_type = T_BIND_ACK; |
|
147 bindmp->b_datap->db_type = M_PCPROTO; |
|
148 |
|
149 KSSL_ENTRY_REFHOLD(ep); |
|
150 *ksslent = (kssl_ent_t)ep; |
|
151 |
|
152 ret = KSSL_HAS_PROXY; |
|
153 break; |
|
154 } |
|
155 |
|
156 /* This is a proxy port. */ |
|
157 if (ep->ke_proxy_port == in_port) { |
|
158 mblk_t *entmp; |
|
159 |
|
160 /* Append this entry to the bind_req mblk */ |
|
161 |
|
162 entmp = allocb(sizeof (kssl_entry_t), |
|
163 BPRI_MED); |
|
164 if (entmp == NULL) |
|
165 break; |
|
166 *((kssl_entry_t **)entmp->b_rptr) = ep; |
|
167 |
|
168 entmp->b_wptr = entmp->b_rptr + |
|
169 sizeof (kssl_entry_t); |
|
170 |
|
171 bindmp->b_cont = entmp; |
|
172 |
|
173 /* Add the caller's cookie to proxies list */ |
|
174 |
|
175 if (!kssl_enqueue((kssl_chain_t **) |
|
176 &(ep->ke_proxy_head), cookie)) { |
|
177 freeb(bindmp->b_cont); |
|
178 bindmp->b_cont = NULL; |
|
179 break; |
|
180 } |
|
181 |
|
182 /* |
|
183 * Make this look like the SSL port to the |
|
184 * transport below |
|
185 */ |
|
186 sin->sin_port = htons(ep->ke_ssl_port); |
|
187 |
|
188 tbr->PRIM_type = T_SSL_PROXY_BIND_REQ; |
|
189 |
|
190 KSSL_ENTRY_REFHOLD(ep); |
|
191 *ksslent = (kssl_ent_t)ep; |
|
192 |
|
193 ret = KSSL_IS_PROXY; |
|
194 break; |
|
195 } |
|
196 } |
|
197 } |
|
198 |
|
199 mutex_exit(&kssl_tab_mutex); |
|
200 return (ret); |
|
201 } |
|
202 |
|
203 /* |
|
204 * Retrieved an endpoint "bound" to the SSL entry. |
|
205 * Such endpoint has previously called kssl_check_proxy(), got itself |
|
206 * linked to the kssl_entry's ke_fallback_head list. |
|
207 * This routine returns the cookie from that SSL entry ke_fallback_head list. |
|
208 */ |
|
209 void * |
|
210 kssl_find_fallback(kssl_ent_t ksslent) |
|
211 { |
|
212 kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; |
|
213 |
|
214 if (kssl_entry->ke_fallback_head != NULL) |
|
215 return (kssl_entry->ke_fallback_head->fallback_bound); |
|
216 |
|
217 KSSL_COUNTER(proxy_fallback_failed, 1); |
|
218 |
|
219 return (NULL); |
|
220 } |
|
221 |
|
222 /* |
|
223 * Re-usable code for adding and removing an element to/from a chain that |
|
224 * matches "item" |
|
225 * The chain is simple-linked and NULL ended. |
|
226 */ |
|
227 |
|
228 /* |
|
229 * This routine returns TRUE if the item was either successfully added to |
|
230 * the chain, or is already there. It returns FALSE otherwise. |
|
231 */ |
|
232 static boolean_t |
|
233 kssl_enqueue(kssl_chain_t **head, void *item) |
|
234 { |
|
235 kssl_chain_t *newchain, *cur; |
|
236 |
|
237 /* Lookup the existing entries to avoid duplicates */ |
|
238 cur = *head; |
|
239 while (cur != NULL) { |
|
240 if (cur->item == item) { |
|
241 return (B_TRUE); |
|
242 } |
|
243 cur = cur->next; |
|
244 } |
|
245 |
|
246 newchain = kmem_alloc(sizeof (kssl_chain_t), KM_NOSLEEP); |
|
247 if (newchain == NULL) { |
|
248 return (B_FALSE); |
|
249 } |
|
250 |
|
251 newchain->item = item; |
|
252 newchain->next = *head; |
|
253 *head = newchain; |
|
254 return (B_TRUE); |
|
255 } |
|
256 |
|
257 static void |
|
258 kssl_dequeue(kssl_chain_t **head, void *item) |
|
259 { |
|
260 kssl_chain_t *prev, *cur; |
|
261 |
|
262 prev = cur = *head; |
|
263 while (cur != NULL) { |
|
264 if (cur->item == item) { |
|
265 if (cur == *head) |
|
266 *head = (*head)->next; |
|
267 else |
|
268 prev->next = cur->next; |
|
269 kmem_free(cur, sizeof (kssl_chain_t)); |
|
270 return; |
|
271 } |
|
272 prev = cur; |
|
273 cur = cur->next; |
|
274 } |
|
275 } |
|
276 |
|
277 /* |
|
278 * Holds the kssl_entry |
|
279 */ |
|
280 void |
|
281 kssl_hold_ent(kssl_ent_t ksslent) |
|
282 { |
|
283 KSSL_ENTRY_REFHOLD((kssl_entry_t *)ksslent); |
|
284 } |
|
285 |
|
286 /* |
|
287 * Releases the kssl_entry |
|
288 * If the caller passes a cookie, then it should be removed from both |
|
289 * proxies and fallbacks chains. |
|
290 */ |
|
291 void |
|
292 kssl_release_ent(kssl_ent_t ksslent, void *cookie, kssl_endpt_type_t endpt_type) |
|
293 { |
|
294 kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; |
|
295 |
|
296 if (cookie != NULL) { |
|
297 if (endpt_type == KSSL_IS_PROXY) |
|
298 ASSERT(kssl_entry->ke_proxy_head != NULL); |
|
299 kssl_dequeue( |
|
300 (kssl_chain_t **)&kssl_entry->ke_proxy_head, |
|
301 cookie); |
|
302 if (endpt_type == KSSL_HAS_PROXY) |
|
303 ASSERT(kssl_entry->ke_fallback_head != NULL); |
|
304 kssl_dequeue( |
|
305 (kssl_chain_t **)&kssl_entry->ke_fallback_head, |
|
306 cookie); |
|
307 } |
|
308 KSSL_ENTRY_REFRELE(kssl_entry); |
|
309 } |
|
310 |
|
311 /* |
|
312 * Holds the kssl context |
|
313 */ |
|
314 void |
|
315 kssl_hold_ctx(kssl_ctx_t ksslctx) |
|
316 { |
|
317 ssl_t *ssl = (ssl_t *)ksslctx; |
|
318 |
|
319 KSSL_SSL_REFHOLD(ssl); |
|
320 } |
|
321 |
|
322 /* |
|
323 * Releases the kssl_context |
|
324 */ |
|
325 void |
|
326 kssl_release_ctx(kssl_ctx_t ksslctx) |
|
327 { |
|
328 KSSL_SSL_REFRELE((ssl_t *)ksslctx); |
|
329 } |
|
330 |
|
331 /* |
|
332 * Packets are accumulated here, if there are packets already queued, |
|
333 * or if the context is active. |
|
334 * The context is active when an incoming record processing function |
|
335 * is already executing on a different thread. |
|
336 * Queued packets are handled either when an mblk arrived and completes |
|
337 * a record, or, when the active context processor finishes the task at |
|
338 * hand. |
|
339 * The caller has to keep calling this routine in a loop until it returns |
|
340 * B_FALSE in *more. The reason for this is SSL3: The protocol |
|
341 * allows the client to send its first application_data message right |
|
342 * after it had sent its Finished message, and not wait for the server |
|
343 * ChangeCipherSpec and Finished. This overlap means we can't batch up |
|
344 * a returned Handshake message to be sent on the wire |
|
345 * with a decrypted application_data to be delivered to the application. |
|
346 */ |
|
347 kssl_cmd_t |
|
348 kssl_input(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, boolean_t *more, |
|
349 kssl_callback_t cbfn, void *arg) |
|
350 { |
|
351 mblk_t *recmp, *outmp = NULL; |
|
352 kssl_cmd_t kssl_cmd; |
|
353 ssl_t *ssl; |
|
354 uint8_t *rec_sz_p; |
|
355 int mplen; |
|
356 SSL3ContentType content_type; |
|
357 uint16_t rec_sz; |
|
358 |
|
359 ASSERT(ctx != NULL); |
|
360 |
|
361 if (mp != NULL) { |
|
362 ASSERT(mp->b_prev == NULL && mp->b_next == NULL); |
|
363 } |
|
364 |
|
365 ssl = (ssl_t *)(ctx); |
|
366 |
|
367 *decrmp = NULL; |
|
368 *more = B_FALSE; |
|
369 |
|
370 mutex_enter(&ssl->kssl_lock); |
|
371 |
|
372 if (ssl->close_notify == B_TRUE) { |
|
373 goto sendnewalert; |
|
374 } |
|
375 |
|
376 /* Whomever is currently processing this connection will get to this */ |
|
377 if (ssl->activeinput) { |
|
378 if (mp != NULL) { |
|
379 KSSL_ENQUEUE_MP(ssl, mp); |
|
380 } |
|
381 mutex_exit(&ssl->kssl_lock); |
|
382 return (KSSL_CMD_NONE); |
|
383 } |
|
384 |
|
385 /* |
|
386 * Fast path for complete incoming application_data records on an empty |
|
387 * queue. |
|
388 * This is by far the most frequently encountered case |
|
389 */ |
|
390 |
|
391 if ((!ssl->activeinput) && (ssl->rec_ass_head == NULL) && |
|
392 ((mp != NULL) && (mplen = MBLKL(mp)) > SSL3_HDR_LEN)) { |
|
393 |
|
394 content_type = (SSL3ContentType)mp->b_rptr[0]; |
|
395 |
|
396 if ((content_type == content_application_data) && |
|
397 (ssl->hs_waitstate == idle_handshake)) { |
|
398 rec_sz_p = SSL3_REC_SIZE(mp); |
|
399 rec_sz = BE16_TO_U16(rec_sz_p); |
|
400 |
|
401 if ((mp->b_cont == NULL) && (mplen == rec_sz)) { |
|
402 |
|
403 mp->b_flag &= ~DBLK_COOKED; |
|
404 *decrmp = mp; |
|
405 mutex_exit(&ssl->kssl_lock); |
|
406 return (KSSL_CMD_DELIVER_PROXY); |
|
407 } |
|
408 } |
|
409 } |
|
410 |
|
411 ssl->activeinput = B_TRUE; |
|
412 /* Accumulate at least one record */ |
|
413 if (mp != NULL) { |
|
414 KSSL_ENQUEUE_MP(ssl, mp); |
|
415 mp = NULL; |
|
416 } |
|
417 recmp = kssl_get_next_record(ssl); |
|
418 |
|
419 if (recmp == NULL) { |
|
420 ssl->activeinput = B_FALSE; |
|
421 if (ssl->alert_sendbuf != NULL) { |
|
422 goto sendalert; |
|
423 } |
|
424 /* Not even a complete header yet. wait for the rest */ |
|
425 mutex_exit(&ssl->kssl_lock); |
|
426 return (KSSL_CMD_NONE); |
|
427 } |
|
428 |
|
429 do { |
|
430 if ((SSL3ContentType)recmp->b_rptr[0] == |
|
431 content_application_data) { |
|
432 /* |
|
433 * application_data records are decrypted and |
|
434 * MAC-verified by the stream head, and in the context |
|
435 * a read()'ing thread. This avoids unfairly charging |
|
436 * the cost of handling this record on the whole system, |
|
437 * and prevents doing it while in the shared IP |
|
438 * perimeter. |
|
439 */ |
|
440 ssl->activeinput = B_FALSE; |
|
441 if (ssl->hs_waitstate != idle_handshake) { |
|
442 goto sendnewalert; |
|
443 } |
|
444 outmp = recmp; |
|
445 kssl_cmd = KSSL_CMD_DELIVER_PROXY; |
|
446 } else { |
|
447 /* |
|
448 * If we're past the initial handshake, start letting |
|
449 * the stream head process all records, in particular |
|
450 * the close_notify. |
|
451 * This is needed to avoid processing them out of |
|
452 * sequence when previous application data packets are |
|
453 * waiting to be decrypted/MAC'ed and delivered. |
|
454 */ |
|
455 if (ssl->hs_waitstate == idle_handshake) { |
|
456 ssl->activeinput = B_FALSE; |
|
457 outmp = recmp; |
|
458 kssl_cmd = KSSL_CMD_DELIVER_PROXY; |
|
459 } else { |
|
460 kssl_cmd = kssl_handle_any_record(ssl, recmp, |
|
461 &outmp, cbfn, arg); |
|
462 } |
|
463 } |
|
464 |
|
465 /* Priority to Alert messages */ |
|
466 if (ssl->alert_sendbuf != NULL) { |
|
467 goto sendalert; |
|
468 } |
|
469 |
|
470 /* Then handshake messages */ |
|
471 if (ssl->handshake_sendbuf) { |
|
472 if (*decrmp != NULL) { |
|
473 linkb(*decrmp, ssl->handshake_sendbuf); |
|
474 } else { |
|
475 *decrmp = ssl->handshake_sendbuf; |
|
476 } |
|
477 ssl->handshake_sendbuf = NULL; |
|
478 |
|
479 *more = ((ssl->rec_ass_head != NULL) && |
|
480 (!ssl->activeinput)); |
|
481 mutex_exit(&ssl->kssl_lock); |
|
482 return (kssl_cmd); |
|
483 } |
|
484 |
|
485 if (ssl->hs_waitstate == idle_handshake) { |
|
486 *more = ((ssl->rec_ass_head != NULL) && |
|
487 (!ssl->activeinput)); |
|
488 } |
|
489 |
|
490 if (outmp != NULL) { |
|
491 *decrmp = outmp; |
|
492 /* |
|
493 * Don't process any packet after an application_data. |
|
494 * We could well receive the close_notify which should |
|
495 * be handled separately. |
|
496 */ |
|
497 mutex_exit(&ssl->kssl_lock); |
|
498 return (kssl_cmd); |
|
499 } |
|
500 /* |
|
501 * The current record isn't done yet. Don't start the next one |
|
502 */ |
|
503 if (ssl->activeinput) { |
|
504 mutex_exit(&ssl->kssl_lock); |
|
505 return (kssl_cmd); |
|
506 } |
|
507 } while ((recmp = kssl_get_next_record(ssl)) != NULL); |
|
508 |
|
509 mutex_exit(&ssl->kssl_lock); |
|
510 return (kssl_cmd); |
|
511 |
|
512 sendnewalert: |
|
513 kssl_send_alert(ssl, alert_fatal, unexpected_message); |
|
514 if (mp != NULL) { |
|
515 freeb(mp); |
|
516 } |
|
517 |
|
518 sendalert: |
|
519 *decrmp = ssl->alert_sendbuf; |
|
520 ssl->alert_sendbuf = NULL; |
|
521 mutex_exit(&ssl->kssl_lock); |
|
522 return (KSSL_CMD_SEND); |
|
523 } |
|
524 |
|
525 /* |
|
526 * Decrypt and verify the MAC of an incoming chain of application_data record. |
|
527 * Each block has exactly one SSL record. |
|
528 * This routine recycles its incoming mblk, and flags it as DBLK_COOKED |
|
529 */ |
|
530 kssl_cmd_t |
|
531 kssl_handle_record(kssl_ctx_t ctx, mblk_t **mpp, mblk_t **outmp) |
|
532 { |
|
533 uchar_t *recend, *rec_sz_p; |
|
534 uchar_t *real_recend; |
|
535 mblk_t *prevmp = NULL, *nextmp, *mp = *mpp, *copybp; |
|
536 int mac_sz; |
|
537 uchar_t version[2]; |
|
538 uint16_t rec_sz; |
|
539 SSL3AlertDescription desc; |
|
540 SSL3ContentType content_type; |
|
541 ssl_t *ssl; |
|
542 KSSLCipherSpec *spec; |
|
543 int error = 0, ret; |
|
544 kssl_cmd_t kssl_cmd = KSSL_CMD_DELIVER_PROXY; |
|
545 boolean_t deliverit = B_FALSE; |
|
546 crypto_data_t cipher_data; |
|
547 |
|
548 ASSERT(ctx != NULL); |
|
549 |
|
550 ssl = (ssl_t *)(ctx); |
|
551 |
|
552 *outmp = NULL; |
|
553 |
|
554 more: |
|
555 |
|
556 while (mp != NULL) { |
|
557 |
|
558 if (DB_REF(mp) > 1) { |
|
559 /* |
|
560 * Fortunately copyb() preserves the offset, |
|
561 * tail space and alignement so the copy is |
|
562 * ready to be made an SSL record. |
|
563 */ |
|
564 if ((copybp = copyb(mp)) == NULL) |
|
565 return (NULL); |
|
566 |
|
567 copybp->b_cont = mp->b_cont; |
|
568 if (mp == *mpp) { |
|
569 *mpp = copybp; |
|
570 } else { |
|
571 prevmp->b_cont = copybp; |
|
572 } |
|
573 freeb(mp); |
|
574 mp = copybp; |
|
575 } |
|
576 |
|
577 content_type = (SSL3ContentType)mp->b_rptr[0]; |
|
578 |
|
579 if (content_type != content_application_data) { |
|
580 nextmp = mp->b_cont; |
|
581 |
|
582 /* Remove this message */ |
|
583 if (prevmp != NULL) { |
|
584 prevmp->b_cont = nextmp; |
|
585 |
|
586 /* |
|
587 * If we had processed blocks that need to |
|
588 * be delivered, then remember that error code |
|
589 */ |
|
590 if (kssl_cmd == KSSL_CMD_DELIVER_PROXY) |
|
591 deliverit = B_TRUE; |
|
592 } |
|
593 |
|
594 mutex_enter(&ssl->kssl_lock); |
|
595 kssl_cmd = kssl_handle_any_record(ssl, mp, outmp, |
|
596 NULL, NULL); |
|
597 |
|
598 if (ssl->alert_sendbuf != NULL) { |
|
599 goto sendalert; |
|
600 } |
|
601 mutex_exit(&ssl->kssl_lock); |
|
602 |
|
603 if (deliverit) { |
|
604 kssl_cmd = KSSL_CMD_DELIVER_PROXY; |
|
605 } |
|
606 |
|
607 mp = nextmp; |
|
608 continue; |
|
609 } |
|
610 |
|
611 version[0] = mp->b_rptr[1]; |
|
612 version[1] = mp->b_rptr[2]; |
|
613 rec_sz_p = SSL3_REC_SIZE(mp); |
|
614 rec_sz = BE16_TO_U16(rec_sz_p); |
|
615 |
|
616 mp->b_rptr += SSL3_HDR_LEN; |
|
617 recend = mp->b_rptr + rec_sz; |
|
618 real_recend = recend; |
|
619 |
|
620 spec = &ssl->spec[KSSL_READ]; |
|
621 mac_sz = spec->mac_hashsz; |
|
622 if (spec->cipher_ctx != 0) { |
|
623 cipher_data.cd_format = CRYPTO_DATA_RAW; |
|
624 cipher_data.cd_offset = 0; |
|
625 cipher_data.cd_length = rec_sz; |
|
626 cipher_data.cd_miscdata = NULL; |
|
627 cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; |
|
628 cipher_data.cd_raw.iov_len = rec_sz; |
|
629 error = crypto_decrypt_update(spec->cipher_ctx, |
|
630 &cipher_data, NULL, NULL); |
|
631 if (CRYPTO_ERR(error)) { |
|
632 #ifdef DEBUG |
|
633 cmn_err(CE_WARN, "kssl_handle_record: " |
|
634 "crypto_decrypt_update failed: 0x%02X", |
|
635 error); |
|
636 #endif /* DEBUG */ |
|
637 KSSL_COUNTER(record_decrypt_failure, 1); |
|
638 mp->b_rptr = recend; |
|
639 desc = decrypt_error; |
|
640 goto makealert; |
|
641 } |
|
642 } |
|
643 if (spec->cipher_type == type_block) { |
|
644 uint_t pad_sz = recend[-1]; |
|
645 pad_sz++; |
|
646 if (pad_sz + mac_sz > rec_sz) { |
|
647 mp->b_rptr = recend; |
|
648 desc = bad_record_mac; |
|
649 goto makealert; |
|
650 } |
|
651 rec_sz -= pad_sz; |
|
652 recend -= pad_sz; |
|
653 } |
|
654 if (mac_sz != 0) { |
|
655 uchar_t hash[MAX_HASH_LEN]; |
|
656 if (rec_sz < mac_sz) { |
|
657 mp->b_rptr = real_recend; |
|
658 desc = bad_record_mac; |
|
659 goto makealert; |
|
660 } |
|
661 rec_sz -= mac_sz; |
|
662 recend -= mac_sz; |
|
663 ret = kssl_compute_record_mac(ssl, KSSL_READ, |
|
664 ssl->seq_num[KSSL_READ], content_type, |
|
665 version, mp->b_rptr, rec_sz, hash); |
|
666 if (ret != CRYPTO_SUCCESS || |
|
667 bcmp(hash, recend, mac_sz)) { |
|
668 mp->b_rptr = real_recend; |
|
669 desc = bad_record_mac; |
|
670 #ifdef DEBUG |
|
671 cmn_err(CE_WARN, "kssl_handle_record: " |
|
672 "msg MAC mismatch"); |
|
673 #endif /* DEBUG */ |
|
674 KSSL_COUNTER(verify_mac_failure, 1); |
|
675 goto makealert; |
|
676 } |
|
677 ssl->seq_num[KSSL_READ]++; |
|
678 } |
|
679 |
|
680 if (ssl->hs_waitstate != idle_handshake) { |
|
681 mp->b_rptr = real_recend; |
|
682 desc = unexpected_message; |
|
683 goto makealert; |
|
684 } |
|
685 mp->b_wptr = recend; |
|
686 |
|
687 prevmp = mp; |
|
688 mp = mp->b_cont; |
|
689 } |
|
690 |
|
691 KSSL_COUNTER(appdata_record_ins, 1); |
|
692 return (kssl_cmd); |
|
693 |
|
694 makealert: |
|
695 nextmp = mp->b_cont; |
|
696 freeb(mp); |
|
697 mp = nextmp; |
|
698 mutex_enter(&ssl->kssl_lock); |
|
699 kssl_send_alert(ssl, alert_fatal, desc); |
|
700 |
|
701 if (ssl->alert_sendbuf == NULL) { |
|
702 /* internal memory allocation failure. just return. */ |
|
703 #ifdef DEBUG |
|
704 cmn_err(CE_WARN, "kssl_handle_record: " |
|
705 "alert message allocation failed"); |
|
706 #endif /* DEBUG */ |
|
707 mutex_exit(&ssl->kssl_lock); |
|
708 |
|
709 if (mp) { |
|
710 prevmp = NULL; |
|
711 goto more; |
|
712 } |
|
713 |
|
714 return (KSSL_CMD_NONE); |
|
715 } |
|
716 kssl_cmd = KSSL_CMD_SEND; |
|
717 sendalert: |
|
718 if (*outmp == NULL) { |
|
719 *outmp = ssl->alert_sendbuf; |
|
720 } else { |
|
721 linkb(*outmp, ssl->alert_sendbuf); |
|
722 } |
|
723 ssl->alert_sendbuf = NULL; |
|
724 mutex_exit(&ssl->kssl_lock); |
|
725 |
|
726 if (mp) { |
|
727 prevmp = NULL; |
|
728 goto more; |
|
729 } |
|
730 |
|
731 return (kssl_cmd); |
|
732 } |
|
733 /* |
|
734 * This is the routine that handles incoming SSL records. |
|
735 * When called the first time, with a NULL context, this routine expects |
|
736 * a ClientHello SSL Handshake packet and shall allocate a context |
|
737 * of a new SSL connection. |
|
738 * During the rest of the handshake packets, the routine adjusts the |
|
739 * state of the context according to the record received. |
|
740 * After the ChangeCipherSpec message is received, the routine first |
|
741 * decrypts/authenticated the packet using the key materials in the |
|
742 * connection's context. |
|
743 * The return code tells the caller what to do with the returned packet. |
|
744 */ |
|
745 static kssl_cmd_t |
|
746 kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, |
|
747 kssl_callback_t cbfn, void *arg) |
|
748 { |
|
749 uchar_t *recend, *rec_sz_p; |
|
750 uchar_t version[2]; |
|
751 uchar_t *real_recend, *save_rptr, *save_wptr; |
|
752 int rhsz = SSL3_HDR_LEN; |
|
753 uint16_t rec_sz; |
|
754 int sz; |
|
755 int mac_sz; |
|
756 SSL3AlertDescription desc; |
|
757 SSL3AlertLevel level; |
|
758 SSL3ContentType content_type; |
|
759 ssl_t *ssl; |
|
760 KSSLCipherSpec *spec; |
|
761 int error = 0, ret; |
|
762 |
|
763 ASSERT(ctx != NULL); |
|
764 |
|
765 ssl = (ssl_t *)(ctx); |
|
766 |
|
767 *decrmp = NULL; |
|
768 |
|
769 save_rptr = mp->b_rptr; |
|
770 save_wptr = mp->b_wptr; |
|
771 |
|
772 ASSERT(MUTEX_HELD(&ssl->kssl_lock)); |
|
773 |
|
774 content_type = (SSL3ContentType)mp->b_rptr[0]; |
|
775 if (content_type == content_handshake_v2) { |
|
776 if (ssl->hs_waitstate == wait_client_hello) { |
|
777 /* V2 compatible ClientHello */ |
|
778 if (mp->b_rptr[3] == 0x03 && |
|
779 (mp->b_rptr[4] == 0x01 || |
|
780 mp->b_rptr[4] == 0x00)) { |
|
781 ssl->major_version = version[0] = mp->b_rptr[3]; |
|
782 ssl->minor_version = version[1] = mp->b_rptr[4]; |
|
783 } else { |
|
784 /* We don't support "pure" SSLv2 */ |
|
785 desc = protocol_version; |
|
786 goto sendalert; |
|
787 } |
|
788 } |
|
789 rec_sz = (uint16_t)mp->b_rptr[1]; |
|
790 rhsz = 2; |
|
791 } else { |
|
792 ssl->major_version = version[0] = mp->b_rptr[1]; |
|
793 ssl->minor_version = version[1] = mp->b_rptr[2]; |
|
794 rec_sz_p = SSL3_REC_SIZE(mp); |
|
795 rec_sz = BE16_TO_U16(rec_sz_p); |
|
796 } |
|
797 |
|
798 mp->b_rptr += rhsz; |
|
799 recend = mp->b_rptr + rec_sz; |
|
800 real_recend = recend; |
|
801 |
|
802 spec = &ssl->spec[KSSL_READ]; |
|
803 mac_sz = spec->mac_hashsz; |
|
804 if (spec->cipher_ctx != 0) { |
|
805 spec->cipher_data.cd_length = rec_sz; |
|
806 spec->cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; |
|
807 spec->cipher_data.cd_raw.iov_len = rec_sz; |
|
808 error = crypto_decrypt_update(spec->cipher_ctx, |
|
809 &spec->cipher_data, NULL, NULL); |
|
810 if (CRYPTO_ERR(error)) { |
|
811 #ifdef DEBUG |
|
812 cmn_err(CE_WARN, |
|
813 "kssl_handle_any_record: crypto_decrypt_update " |
|
814 "failed: 0x%02X", error); |
|
815 #endif /* DEBUG */ |
|
816 KSSL_COUNTER(record_decrypt_failure, 1); |
|
817 mp->b_rptr = recend; |
|
818 desc = decrypt_error; |
|
819 goto sendalert; |
|
820 } |
|
821 } |
|
822 if (spec->cipher_type == type_block) { |
|
823 uint_t pad_sz = recend[-1]; |
|
824 pad_sz++; |
|
825 if (pad_sz + mac_sz > rec_sz) { |
|
826 mp->b_rptr = recend; |
|
827 desc = bad_record_mac; |
|
828 goto sendalert; |
|
829 } |
|
830 rec_sz -= pad_sz; |
|
831 recend -= pad_sz; |
|
832 } |
|
833 if (mac_sz != 0) { |
|
834 uchar_t hash[MAX_HASH_LEN]; |
|
835 if (rec_sz < mac_sz) { |
|
836 mp->b_rptr = real_recend; |
|
837 desc = bad_record_mac; |
|
838 goto sendalert; |
|
839 } |
|
840 rec_sz -= mac_sz; |
|
841 recend -= mac_sz; |
|
842 ret = kssl_compute_record_mac(ssl, KSSL_READ, |
|
843 ssl->seq_num[KSSL_READ], content_type, |
|
844 version, mp->b_rptr, rec_sz, hash); |
|
845 if (ret != CRYPTO_SUCCESS || |
|
846 bcmp(hash, recend, mac_sz)) { |
|
847 mp->b_rptr = real_recend; |
|
848 desc = bad_record_mac; |
|
849 #ifdef DEBUG |
|
850 cmn_err(CE_WARN, "kssl_handle_any_record: " |
|
851 "msg MAC mismatch"); |
|
852 #endif /* DEBUG */ |
|
853 KSSL_COUNTER(verify_mac_failure, 1); |
|
854 goto sendalert; |
|
855 } |
|
856 ssl->seq_num[KSSL_READ]++; |
|
857 } |
|
858 |
|
859 switch (content_type) { |
|
860 case content_handshake: |
|
861 do { |
|
862 if (error != 0 || |
|
863 /* ignore client renegotiation for now */ |
|
864 ssl->hs_waitstate == idle_handshake) { |
|
865 mp->b_rptr = recend; |
|
866 } |
|
867 if (mp->b_rptr == recend) { |
|
868 mp->b_rptr = real_recend; |
|
869 if (error != 0) { |
|
870 goto error; |
|
871 } |
|
872 freeb(mp); |
|
873 |
|
874 if (ssl->hs_waitstate == wait_client_key_done) |
|
875 return (KSSL_CMD_QUEUED); |
|
876 |
|
877 return ((ssl->handshake_sendbuf != NULL) ? |
|
878 KSSL_CMD_SEND : KSSL_CMD_NONE); |
|
879 } |
|
880 if (ssl->msg.state < MSG_BODY) { |
|
881 if (ssl->msg.state == MSG_INIT) { |
|
882 ssl->msg.type = |
|
883 (SSL3HandshakeType)*mp->b_rptr++; |
|
884 ssl->msg.state = MSG_INIT_LEN; |
|
885 } |
|
886 if (ssl->msg.state == MSG_INIT_LEN) { |
|
887 int msglenb = |
|
888 ssl->msg.msglen_bytes; |
|
889 int msglen = ssl->msg.msglen; |
|
890 while (mp->b_rptr < recend && |
|
891 msglenb < 3) { |
|
892 msglen = (msglen << 8) + |
|
893 (uint_t)(*mp->b_rptr++); |
|
894 msglenb++; |
|
895 } |
|
896 ssl->msg.msglen_bytes = msglenb; |
|
897 ssl->msg.msglen = msglen; |
|
898 if (msglenb == 3) { |
|
899 ssl->msg.state = MSG_BODY; |
|
900 } |
|
901 } |
|
902 if (mp->b_rptr == recend) { |
|
903 mp->b_rptr = real_recend; |
|
904 freeb(mp); |
|
905 return (KSSL_CMD_NONE); |
|
906 } |
|
907 } |
|
908 ASSERT(ssl->msg.state == MSG_BODY); |
|
909 |
|
910 sz = recend - mp->b_rptr; |
|
911 |
|
912 if (ssl->msg.head == NULL && |
|
913 ssl->msg.msglen <= sz) { |
|
914 continue; |
|
915 } |
|
916 if (ssl->msg.head != NULL) { |
|
917 sz += msgdsize(ssl->msg.head); |
|
918 if (ssl->msg.msglen <= sz) { |
|
919 ssl->msg.tail->b_cont = mp; |
|
920 mp = ssl->msg.head; |
|
921 ssl->sslcnt = 100; |
|
922 ssl->msg.head = NULL; |
|
923 ssl->msg.tail = NULL; |
|
924 if (pullupmsg(mp, -1)) { |
|
925 recend = mp->b_rptr + sz; |
|
926 ASSERT(recend <= mp->b_wptr); |
|
927 continue; |
|
928 } |
|
929 mp->b_rptr = real_recend; |
|
930 error = ENOMEM; |
|
931 KSSL_COUNTER(alloc_fails, 1); |
|
932 goto error; |
|
933 } |
|
934 } |
|
935 |
|
936 mp->b_wptr = recend; |
|
937 |
|
938 if (ssl->msg.head == NULL) { |
|
939 ssl->msg.head = mp; |
|
940 ssl->msg.tail = mp; |
|
941 return (KSSL_CMD_NONE); |
|
942 } else { |
|
943 ssl->msg.tail->b_cont = mp; |
|
944 ssl->msg.tail = mp; |
|
945 return (KSSL_CMD_NONE); |
|
946 } |
|
947 } while (kssl_handle_handshake_message(ssl, mp, &error, cbfn, |
|
948 arg)); |
|
949 if (error == SSL_MISS) { |
|
950 mp->b_rptr = save_rptr; |
|
951 mp->b_wptr = save_wptr; |
|
952 KSSL_COUNTER(fallback_connections, 1); |
|
953 return (KSSL_CMD_NOT_SUPPORTED); |
|
954 } |
|
955 if (ssl->hs_waitstate == wait_client_key_done) { |
|
956 return (KSSL_CMD_QUEUED); |
|
957 } else { |
|
958 return (KSSL_CMD_NONE); |
|
959 } |
|
960 case content_alert: |
|
961 if (rec_sz != 2) { |
|
962 mp->b_rptr = real_recend; |
|
963 desc = illegal_parameter; |
|
964 goto sendalert; |
|
965 } else { |
|
966 level = *mp->b_rptr++; |
|
967 desc = *mp->b_rptr++; |
|
968 mp->b_rptr = real_recend; |
|
969 if (level != alert_warning || desc != close_notify) { |
|
970 if (ssl->sid.cached == B_TRUE) { |
|
971 kssl_uncache_sid(&ssl->sid, |
|
972 ssl->kssl_entry); |
|
973 ssl->sid.cached = B_FALSE; |
|
974 } |
|
975 ssl->fatal_alert = B_TRUE; |
|
976 error = EBADMSG; |
|
977 goto error; |
|
978 } else { |
|
979 ssl->close_notify = B_TRUE; |
|
980 ssl->activeinput = B_FALSE; |
|
981 freeb(mp); |
|
982 return (KSSL_CMD_NONE); |
|
983 } |
|
984 } |
|
985 case content_change_cipher_spec: |
|
986 if (ssl->hs_waitstate != wait_change_cipher) { |
|
987 desc = unexpected_message; |
|
988 } else if (rec_sz != 1 || *mp->b_rptr != 1) { |
|
989 desc = illegal_parameter; |
|
990 } else { |
|
991 mp->b_rptr = real_recend; |
|
992 ssl->hs_waitstate = wait_finished; |
|
993 ssl->seq_num[KSSL_READ] = 0; |
|
994 if ((error = kssl_spec_init(ssl, KSSL_READ)) != 0) { |
|
995 #ifdef DEBUG |
|
996 cmn_err(CE_WARN, |
|
997 "kssl_spec_init returned error " |
|
998 "0x%02X", error); |
|
999 #endif /* DEBUG */ |
|
1000 goto error; |
|
1001 } |
|
1002 ssl->activeinput = B_FALSE; |
|
1003 freeb(mp); |
|
1004 return (KSSL_CMD_NONE); |
|
1005 } |
|
1006 mp->b_rptr = real_recend; |
|
1007 goto sendalert; |
|
1008 |
|
1009 case content_application_data: |
|
1010 if (ssl->hs_waitstate != idle_handshake) { |
|
1011 mp->b_rptr = real_recend; |
|
1012 desc = unexpected_message; |
|
1013 goto sendalert; |
|
1014 } |
|
1015 mp->b_wptr = recend; |
|
1016 *decrmp = mp; |
|
1017 ssl->activeinput = B_FALSE; |
|
1018 return (KSSL_CMD_DELIVER_PROXY); |
|
1019 |
|
1020 case content_handshake_v2: |
|
1021 error = kssl_handle_v2client_hello(ssl, mp, rec_sz); |
|
1022 if (error == SSL_MISS) { |
|
1023 mp->b_rptr = save_rptr; |
|
1024 mp->b_wptr = save_wptr; |
|
1025 KSSL_COUNTER(fallback_connections, 1); |
|
1026 return (KSSL_CMD_NOT_SUPPORTED); |
|
1027 } else if (error != 0) { |
|
1028 goto error; |
|
1029 } |
|
1030 freeb(mp); |
|
1031 return (KSSL_CMD_SEND); |
|
1032 default: |
|
1033 mp->b_rptr = real_recend; |
|
1034 desc = unexpected_message; |
|
1035 break; |
|
1036 } |
|
1037 |
|
1038 sendalert: |
|
1039 kssl_send_alert(ssl, alert_fatal, desc); |
|
1040 *decrmp = ssl->alert_sendbuf; |
|
1041 ssl->alert_sendbuf = NULL; |
|
1042 freeb(mp); |
|
1043 return ((*decrmp != NULL) ? KSSL_CMD_SEND : KSSL_CMD_NONE); |
|
1044 error: |
|
1045 freeb(mp); |
|
1046 return (KSSL_CMD_NONE); |
|
1047 } |
|
1048 |
|
1049 /* |
|
1050 * Initialize the context of an SSL connection, coming to the specified |
|
1051 * address. |
|
1052 * the ssl structure returned is held. |
|
1053 */ |
|
1054 kssl_status_t |
|
1055 kssl_init_context(kssl_ent_t kssl_ent, ipaddr_t faddr, int mss, |
|
1056 kssl_ctx_t *kssl_ctxp) |
|
1057 { |
|
1058 ssl_t *ssl = kmem_cache_alloc(kssl_cache, KM_NOSLEEP); |
|
1059 |
|
1060 if (ssl == NULL) { |
|
1061 return (KSSL_STS_ERR); |
|
1062 } |
|
1063 |
|
1064 kssl_cache_count++; |
|
1065 |
|
1066 bzero(ssl, sizeof (ssl_t)); |
|
1067 |
|
1068 ssl->kssl_entry = (kssl_entry_t *)kssl_ent; |
|
1069 KSSL_ENTRY_REFHOLD(ssl->kssl_entry); |
|
1070 |
|
1071 ssl->faddr = faddr; |
|
1072 ssl->tcp_mss = mss; |
|
1073 ssl->sendalert_level = alert_warning; |
|
1074 ssl->sendalert_desc = close_notify; |
|
1075 ssl->sid.cached = B_FALSE; |
|
1076 |
|
1077 *kssl_ctxp = (kssl_ctx_t)ssl; |
|
1078 KSSL_SSL_REFHOLD(ssl); |
|
1079 return (KSSL_STS_OK); |
|
1080 } |
|
1081 |
|
1082 /* |
|
1083 * Builds SSL records out of the chain of mblks, and returns it. |
|
1084 * Taked a copy of the message before encypting it if it has another |
|
1085 * reference. |
|
1086 * In case of failure, NULL is returned, and the message will be |
|
1087 * freed by the caller. |
|
1088 * A NULL mp means a close_notify is requested. |
|
1089 */ |
|
1090 mblk_t * |
|
1091 kssl_build_record(kssl_ctx_t ctx, mblk_t *mp) |
|
1092 { |
|
1093 ssl_t *ssl = (ssl_t *)ctx; |
|
1094 mblk_t *retmp = mp, *bp = mp, *prevbp = mp, *copybp; |
|
1095 |
|
1096 ASSERT(ssl != NULL); |
|
1097 ASSERT(mp != NULL); |
|
1098 |
|
1099 do { |
|
1100 if (DB_REF(bp) > 1) { |
|
1101 /* |
|
1102 * Fortunately copyb() preserves the offset, |
|
1103 * tail space and alignement so the copy is |
|
1104 * ready to be made an SSL record. |
|
1105 */ |
|
1106 if ((copybp = copyb(bp)) == NULL) |
|
1107 return (NULL); |
|
1108 |
|
1109 copybp->b_cont = bp->b_cont; |
|
1110 if (bp == mp) { |
|
1111 retmp = copybp; |
|
1112 } else { |
|
1113 prevbp->b_cont = copybp; |
|
1114 } |
|
1115 freeb(bp); |
|
1116 bp = copybp; |
|
1117 } |
|
1118 |
|
1119 if (kssl_build_single_record(ssl, bp) != KSSL_STS_OK) |
|
1120 return (NULL); |
|
1121 |
|
1122 prevbp = bp; |
|
1123 bp = bp->b_cont; |
|
1124 } while (bp != NULL); |
|
1125 |
|
1126 return (retmp); |
|
1127 } |
|
1128 |
|
1129 /* |
|
1130 * Builds a single SSL record |
|
1131 * In-line encryption of the record. |
|
1132 */ |
|
1133 static kssl_status_t |
|
1134 kssl_build_single_record(ssl_t *ssl, mblk_t *mp) |
|
1135 { |
|
1136 int len; |
|
1137 int reclen = 0; |
|
1138 uchar_t *recstart, *versionp; |
|
1139 KSSLCipherSpec *spec; |
|
1140 int mac_sz; |
|
1141 int pad_sz = 0; |
|
1142 |
|
1143 |
|
1144 spec = &ssl->spec[KSSL_WRITE]; |
|
1145 mac_sz = spec->mac_hashsz; |
|
1146 |
|
1147 |
|
1148 ASSERT(DB_REF(mp) == 1); |
|
1149 ASSERT((mp->b_rptr - mp->b_datap->db_base >= SSL3_HDR_LEN) && |
|
1150 (mp->b_datap->db_lim - mp->b_wptr >= mac_sz + spec->cipher_bsize)); |
|
1151 |
|
1152 len = MBLKL(mp); |
|
1153 |
|
1154 ASSERT(len > 0); |
|
1155 |
|
1156 mutex_enter(&ssl->kssl_lock); |
|
1157 |
|
1158 recstart = mp->b_rptr = mp->b_rptr - SSL3_HDR_LEN; |
|
1159 recstart[0] = content_application_data; |
|
1160 recstart[1] = ssl->major_version; |
|
1161 recstart[2] = ssl->minor_version; |
|
1162 versionp = &recstart[1]; |
|
1163 |
|
1164 reclen = len + mac_sz; |
|
1165 if (spec->cipher_type == type_block) { |
|
1166 pad_sz = spec->cipher_bsize - |
|
1167 (reclen & (spec->cipher_bsize - 1)); |
|
1168 ASSERT(reclen + pad_sz <= |
|
1169 SSL3_MAX_RECORD_LENGTH); |
|
1170 reclen += pad_sz; |
|
1171 } |
|
1172 recstart[3] = (reclen >> 8) & 0xff; |
|
1173 recstart[4] = reclen & 0xff; |
|
1174 |
|
1175 if (kssl_mac_encrypt_record(ssl, content_application_data, versionp, |
|
1176 recstart, mp) != 0) { |
|
1177 /* Do we need an internal_error Alert here? */ |
|
1178 mutex_exit(&ssl->kssl_lock); |
|
1179 return (KSSL_STS_ERR); |
|
1180 } |
|
1181 |
|
1182 KSSL_COUNTER(appdata_record_outs, 1); |
|
1183 mutex_exit(&ssl->kssl_lock); |
|
1184 return (KSSL_STS_OK); |
|
1185 } |