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