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 /* 229624SBhargava.Yenduri@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23898Skais * Use is subject to license terms. 24898Skais */ 25898Skais 26898Skais #include <sys/types.h> 27898Skais #include <sys/stream.h> 28898Skais #include <sys/strsun.h> 29898Skais #include <sys/kmem.h> 30898Skais #include <sys/cpuvar.h> 31898Skais #include <sys/atomic.h> 32898Skais #include <sys/sysmacros.h> 33898Skais 34898Skais #include <inet/common.h> 35898Skais #include <inet/ip.h> 36898Skais 37898Skais #include <sys/systm.h> 38898Skais #include <sys/param.h> 39898Skais #include <sys/tihdr.h> 40898Skais 41898Skais #include "ksslimpl.h" 42898Skais #include "ksslproto.h" 43898Skais #include "ksslapi.h" 44898Skais 45898Skais static kssl_cmd_t kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, 46898Skais mblk_t **decrmp, kssl_callback_t cbfn, void *arg); 47898Skais static boolean_t kssl_enqueue(kssl_chain_t **head, void *item); 48898Skais static void kssl_dequeue(kssl_chain_t **head, void *item); 49898Skais static kssl_status_t kssl_build_single_record(ssl_t *ssl, mblk_t *mp); 50898Skais 51898Skais /* 52898Skais * The socket T_bind_req message is intercepted and re-routed here 53898Skais * to see is there is SSL relevant job to do, based on the kssl config 54898Skais * in the kssl_entry_tab. 55898Skais * Looks up the kernel SSL proxy table, to find an entry that matches the 56898Skais * same serveraddr, and has one of the following two criteria: 57898Skais * 1. in_port is an ssl_port. This endpoint can be used later as a fallback 58898Skais * to complete connections that cannot be handled by the SSL kernel proxy 59898Skais * (typically non supported ciphersuite). The cookie for the calling client 60898Skais * is saved with the kssl_entry to be retrieved for the fallback. 61898Skais * The function returns KSSL_HAS_PROXY. 62898Skais * 63898Skais * 2. in_port is a proxy port for another ssl port. The ssl port is then 64898Skais * substituted to the in_port in the bind_req TPI structure, so that 65898Skais * the bind falls through to the SSL port. At the end of this operation, 66898Skais * all the packets arriving to the SSL port will be delivered to an 67898Skais * accepted endpoint child of this bound socket. 68898Skais * The kssl_entry_t is returned in *ksslent, for later use by the 69898Skais * lower modules' SSL hooks that handle the Handshake messages. 70898Skais * The function returns KSSL_IS_PROXY. 71898Skais * 72*10520SBhargava.Yenduri@Sun.COM * The function returns KSSL_NO_PROXY otherwise. 73898Skais */ 74898Skais 75898Skais kssl_endpt_type_t 76898Skais kssl_check_proxy(mblk_t *bindmp, void *cookie, kssl_ent_t *ksslent) 77898Skais { 78898Skais int i; 79898Skais kssl_endpt_type_t ret; 80898Skais kssl_entry_t *ep; 81898Skais sin_t *sin; 829624SBhargava.Yenduri@Sun.COM sin6_t *sin6; 83898Skais struct T_bind_req *tbr; 84*10520SBhargava.Yenduri@Sun.COM in6_addr_t mapped_v4addr; 85*10520SBhargava.Yenduri@Sun.COM in6_addr_t *v6addr; 86898Skais in_port_t in_port; 87898Skais 88*10520SBhargava.Yenduri@Sun.COM if (kssl_entry_tab_nentries == 0) { 89898Skais return (KSSL_NO_PROXY); 90898Skais } 91898Skais 92898Skais ret = KSSL_NO_PROXY; 93898Skais 94*10520SBhargava.Yenduri@Sun.COM tbr = (struct T_bind_req *)bindmp->b_rptr; 959624SBhargava.Yenduri@Sun.COM sin = (sin_t *)(bindmp->b_rptr + tbr->ADDR_offset); 96898Skais 97898Skais switch (tbr->ADDR_length) { 98898Skais case sizeof (sin_t): 99898Skais in_port = ntohs(sin->sin_port); 100*10520SBhargava.Yenduri@Sun.COM IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &mapped_v4addr); 101*10520SBhargava.Yenduri@Sun.COM v6addr = &mapped_v4addr; 102898Skais break; 103898Skais 104898Skais case sizeof (sin6_t): 1059624SBhargava.Yenduri@Sun.COM sin6 = (sin6_t *)sin; 106*10520SBhargava.Yenduri@Sun.COM in_port = ntohs(sin6->sin6_port); 107*10520SBhargava.Yenduri@Sun.COM v6addr = &sin6->sin6_addr; 108*10520SBhargava.Yenduri@Sun.COM break; 1099624SBhargava.Yenduri@Sun.COM 110898Skais default: 111898Skais return (ret); 112898Skais } 113898Skais 114898Skais mutex_enter(&kssl_tab_mutex); 115898Skais 116898Skais for (i = 0; i < kssl_entry_tab_size; i++) { 117898Skais if ((ep = kssl_entry_tab[i]) == NULL) 118898Skais continue; 119898Skais 120*10520SBhargava.Yenduri@Sun.COM if (IN6_ARE_ADDR_EQUAL(&ep->ke_laddr, v6addr) || 121*10520SBhargava.Yenduri@Sun.COM IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr)) { 122898Skais 123898Skais /* This is an SSL port to fallback to */ 124898Skais if (ep->ke_ssl_port == in_port) { 125898Skais 126898Skais /* 127898Skais * Let's see first if there's at least 128898Skais * an endpoint for a proxy server. 129898Skais * If there's none, then we return as we have 130898Skais * no proxy, so that the bind() to the 131898Skais * transport layer goes through. 132898Skais * The calling module will ask for this 133898Skais * cookie if it wants to fall back to it, 134898Skais * so add this one to the list of fallback 135898Skais * clients. 136898Skais */ 137898Skais if (!kssl_enqueue((kssl_chain_t **) 138898Skais &(ep->ke_fallback_head), cookie)) { 139898Skais break; 140898Skais } 141898Skais 142898Skais /* 143898Skais * Now transform the T_BIND_REQ into 144898Skais * a T_BIND_ACK. 145898Skais */ 146898Skais tbr->PRIM_type = T_BIND_ACK; 147898Skais bindmp->b_datap->db_type = M_PCPROTO; 148898Skais 149898Skais KSSL_ENTRY_REFHOLD(ep); 150898Skais *ksslent = (kssl_ent_t)ep; 151898Skais 152898Skais ret = KSSL_HAS_PROXY; 153898Skais break; 154898Skais } 155898Skais 156898Skais /* This is a proxy port. */ 157898Skais if (ep->ke_proxy_port == in_port) { 158898Skais mblk_t *entmp; 159898Skais 160898Skais /* Append this entry to the bind_req mblk */ 161898Skais 162898Skais entmp = allocb(sizeof (kssl_entry_t), 163898Skais BPRI_MED); 164898Skais if (entmp == NULL) 165898Skais break; 166898Skais *((kssl_entry_t **)entmp->b_rptr) = ep; 167898Skais 168898Skais entmp->b_wptr = entmp->b_rptr + 169898Skais sizeof (kssl_entry_t); 170898Skais 171898Skais bindmp->b_cont = entmp; 172898Skais 173898Skais /* Add the caller's cookie to proxies list */ 174898Skais 175898Skais if (!kssl_enqueue((kssl_chain_t **) 176898Skais &(ep->ke_proxy_head), cookie)) { 177898Skais freeb(bindmp->b_cont); 178898Skais bindmp->b_cont = NULL; 179898Skais break; 180898Skais } 181898Skais 182898Skais /* 183898Skais * Make this look like the SSL port to the 184898Skais * transport below 185898Skais */ 186898Skais sin->sin_port = htons(ep->ke_ssl_port); 187898Skais 188898Skais tbr->PRIM_type = T_SSL_PROXY_BIND_REQ; 189898Skais 190898Skais KSSL_ENTRY_REFHOLD(ep); 191898Skais *ksslent = (kssl_ent_t)ep; 192898Skais 193898Skais ret = KSSL_IS_PROXY; 194898Skais break; 195898Skais } 196898Skais } 197898Skais } 198898Skais 199898Skais mutex_exit(&kssl_tab_mutex); 200898Skais return (ret); 201898Skais } 202898Skais 203898Skais /* 204898Skais * Retrieved an endpoint "bound" to the SSL entry. 205898Skais * Such endpoint has previously called kssl_check_proxy(), got itself 206898Skais * linked to the kssl_entry's ke_fallback_head list. 207898Skais * This routine returns the cookie from that SSL entry ke_fallback_head list. 208898Skais */ 209898Skais void * 210898Skais kssl_find_fallback(kssl_ent_t ksslent) 211898Skais { 212898Skais kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; 213898Skais 214898Skais if (kssl_entry->ke_fallback_head != NULL) 215898Skais return (kssl_entry->ke_fallback_head->fallback_bound); 216898Skais 217898Skais KSSL_COUNTER(proxy_fallback_failed, 1); 218898Skais 219898Skais return (NULL); 220898Skais } 221898Skais 222898Skais /* 223898Skais * Re-usable code for adding and removing an element to/from a chain that 224898Skais * matches "item" 225898Skais * The chain is simple-linked and NULL ended. 226898Skais */ 227898Skais 228898Skais /* 229898Skais * This routine returns TRUE if the item was either successfully added to 230898Skais * the chain, or is already there. It returns FALSE otherwise. 231898Skais */ 232898Skais static boolean_t 233898Skais kssl_enqueue(kssl_chain_t **head, void *item) 234898Skais { 235898Skais kssl_chain_t *newchain, *cur; 236898Skais 237898Skais /* Lookup the existing entries to avoid duplicates */ 238898Skais cur = *head; 239898Skais while (cur != NULL) { 240898Skais if (cur->item == item) { 241898Skais return (B_TRUE); 242898Skais } 243898Skais cur = cur->next; 244898Skais } 245898Skais 246898Skais newchain = kmem_alloc(sizeof (kssl_chain_t), KM_NOSLEEP); 247898Skais if (newchain == NULL) { 248898Skais return (B_FALSE); 249898Skais } 250898Skais 251898Skais newchain->item = item; 252898Skais newchain->next = *head; 253898Skais *head = newchain; 254898Skais return (B_TRUE); 255898Skais } 256898Skais 257898Skais static void 258898Skais kssl_dequeue(kssl_chain_t **head, void *item) 259898Skais { 260898Skais kssl_chain_t *prev, *cur; 261898Skais 262898Skais prev = cur = *head; 263898Skais while (cur != NULL) { 264898Skais if (cur->item == item) { 265898Skais if (cur == *head) 266898Skais *head = (*head)->next; 267898Skais else 268898Skais prev->next = cur->next; 269898Skais kmem_free(cur, sizeof (kssl_chain_t)); 270898Skais return; 271898Skais } 272898Skais prev = cur; 273898Skais cur = cur->next; 274898Skais } 275898Skais } 276898Skais 277898Skais /* 278898Skais * Holds the kssl_entry 279898Skais */ 280898Skais void 281898Skais kssl_hold_ent(kssl_ent_t ksslent) 282898Skais { 283898Skais KSSL_ENTRY_REFHOLD((kssl_entry_t *)ksslent); 284898Skais } 285898Skais 286898Skais /* 287898Skais * Releases the kssl_entry 288898Skais * If the caller passes a cookie, then it should be removed from both 289898Skais * proxies and fallbacks chains. 290898Skais */ 291898Skais void 292898Skais kssl_release_ent(kssl_ent_t ksslent, void *cookie, kssl_endpt_type_t endpt_type) 293898Skais { 294898Skais kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; 295898Skais 296898Skais if (cookie != NULL) { 297*10520SBhargava.Yenduri@Sun.COM if (endpt_type == KSSL_IS_PROXY) { 298898Skais ASSERT(kssl_entry->ke_proxy_head != NULL); 299898Skais kssl_dequeue( 300898Skais (kssl_chain_t **)&kssl_entry->ke_proxy_head, 301898Skais cookie); 302*10520SBhargava.Yenduri@Sun.COM } 303*10520SBhargava.Yenduri@Sun.COM if (endpt_type == KSSL_HAS_PROXY) { 304898Skais ASSERT(kssl_entry->ke_fallback_head != NULL); 305898Skais kssl_dequeue( 306898Skais (kssl_chain_t **)&kssl_entry->ke_fallback_head, 307898Skais cookie); 308*10520SBhargava.Yenduri@Sun.COM } 309898Skais } 310898Skais KSSL_ENTRY_REFRELE(kssl_entry); 311898Skais } 312898Skais 313898Skais /* 314898Skais * Holds the kssl context 315898Skais */ 316898Skais void 317898Skais kssl_hold_ctx(kssl_ctx_t ksslctx) 318898Skais { 319898Skais ssl_t *ssl = (ssl_t *)ksslctx; 320898Skais 321898Skais KSSL_SSL_REFHOLD(ssl); 322898Skais } 323898Skais 324898Skais /* 325898Skais * Releases the kssl_context 326898Skais */ 327898Skais void 328898Skais kssl_release_ctx(kssl_ctx_t ksslctx) 329898Skais { 330898Skais KSSL_SSL_REFRELE((ssl_t *)ksslctx); 331898Skais } 332898Skais 333898Skais /* 334898Skais * Packets are accumulated here, if there are packets already queued, 335898Skais * or if the context is active. 336898Skais * The context is active when an incoming record processing function 337898Skais * is already executing on a different thread. 338898Skais * Queued packets are handled either when an mblk arrived and completes 339898Skais * a record, or, when the active context processor finishes the task at 340898Skais * hand. 341898Skais * The caller has to keep calling this routine in a loop until it returns 342898Skais * B_FALSE in *more. The reason for this is SSL3: The protocol 343898Skais * allows the client to send its first application_data message right 344898Skais * after it had sent its Finished message, and not wait for the server 345898Skais * ChangeCipherSpec and Finished. This overlap means we can't batch up 346898Skais * a returned Handshake message to be sent on the wire 347898Skais * with a decrypted application_data to be delivered to the application. 348898Skais */ 349898Skais kssl_cmd_t 350898Skais kssl_input(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, boolean_t *more, 351898Skais kssl_callback_t cbfn, void *arg) 352898Skais { 353898Skais mblk_t *recmp, *outmp = NULL; 354898Skais kssl_cmd_t kssl_cmd; 355898Skais ssl_t *ssl; 356898Skais uint8_t *rec_sz_p; 357898Skais int mplen; 358898Skais SSL3ContentType content_type; 359898Skais uint16_t rec_sz; 360898Skais 361898Skais ASSERT(ctx != NULL); 362898Skais 363898Skais if (mp != NULL) { 364898Skais ASSERT(mp->b_prev == NULL && mp->b_next == NULL); 365898Skais } 366898Skais 367898Skais ssl = (ssl_t *)(ctx); 368898Skais 369898Skais *decrmp = NULL; 370898Skais *more = B_FALSE; 371898Skais 372898Skais mutex_enter(&ssl->kssl_lock); 373898Skais 374898Skais if (ssl->close_notify == B_TRUE) { 3755850Svk199839 DTRACE_PROBE(kssl_err__close_notify); 376898Skais goto sendnewalert; 377898Skais } 378898Skais 379898Skais /* Whomever is currently processing this connection will get to this */ 380898Skais if (ssl->activeinput) { 381898Skais if (mp != NULL) { 382898Skais KSSL_ENQUEUE_MP(ssl, mp); 383898Skais } 384898Skais mutex_exit(&ssl->kssl_lock); 385898Skais return (KSSL_CMD_NONE); 386898Skais } 387898Skais 388898Skais /* 389898Skais * Fast path for complete incoming application_data records on an empty 390898Skais * queue. 391898Skais * This is by far the most frequently encountered case 392898Skais */ 393898Skais 394898Skais if ((!ssl->activeinput) && (ssl->rec_ass_head == NULL) && 395898Skais ((mp != NULL) && (mplen = MBLKL(mp)) > SSL3_HDR_LEN)) { 396898Skais 3975850Svk199839 DTRACE_PROBE1(kssl_mblk__fast_path, mblk_t *, mp); 398898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 399898Skais 400898Skais if ((content_type == content_application_data) && 401898Skais (ssl->hs_waitstate == idle_handshake)) { 402898Skais rec_sz_p = SSL3_REC_SIZE(mp); 403898Skais rec_sz = BE16_TO_U16(rec_sz_p); 404898Skais 405898Skais if ((mp->b_cont == NULL) && (mplen == rec_sz)) { 406898Skais 4074859Skrishna DB_FLAGS(mp) &= ~DBLK_COOKED; 408898Skais *decrmp = mp; 409898Skais mutex_exit(&ssl->kssl_lock); 410898Skais return (KSSL_CMD_DELIVER_PROXY); 411898Skais } 412898Skais } 413898Skais } 414898Skais 415898Skais ssl->activeinput = B_TRUE; 416898Skais /* Accumulate at least one record */ 417898Skais if (mp != NULL) { 418898Skais KSSL_ENQUEUE_MP(ssl, mp); 419898Skais mp = NULL; 420898Skais } 421898Skais recmp = kssl_get_next_record(ssl); 422898Skais 423898Skais if (recmp == NULL) { 424898Skais ssl->activeinput = B_FALSE; 425898Skais if (ssl->alert_sendbuf != NULL) { 4265850Svk199839 DTRACE_PROBE(kssl_err__alert_to_send); 427898Skais goto sendalert; 428898Skais } 429898Skais /* Not even a complete header yet. wait for the rest */ 430898Skais mutex_exit(&ssl->kssl_lock); 431898Skais return (KSSL_CMD_NONE); 432898Skais } 433898Skais 434898Skais do { 4355850Svk199839 DTRACE_PROBE1(kssl_mblk__kssl_input_cycle, mblk_t *, recmp); 4364556Svk199839 content_type = (SSL3ContentType)recmp->b_rptr[0]; 4374556Svk199839 4384556Svk199839 switch (content_type) { 4394556Svk199839 case content_application_data: 440898Skais /* 441898Skais * application_data records are decrypted and 442898Skais * MAC-verified by the stream head, and in the context 443898Skais * a read()'ing thread. This avoids unfairly charging 444898Skais * the cost of handling this record on the whole system, 445898Skais * and prevents doing it while in the shared IP 446898Skais * perimeter. 447898Skais */ 448898Skais ssl->activeinput = B_FALSE; 449898Skais if (ssl->hs_waitstate != idle_handshake) { 4505850Svk199839 DTRACE_PROBE(kssl_err__waitstate_not_idle); 451898Skais goto sendnewalert; 452898Skais } 453898Skais outmp = recmp; 454898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 4554556Svk199839 break; 4564556Svk199839 case content_change_cipher_spec: 4574556Svk199839 case content_alert: 4584556Svk199839 case content_handshake: 4594556Svk199839 case content_handshake_v2: 460898Skais /* 461898Skais * If we're past the initial handshake, start letting 462898Skais * the stream head process all records, in particular 463898Skais * the close_notify. 464898Skais * This is needed to avoid processing them out of 465898Skais * sequence when previous application data packets are 466898Skais * waiting to be decrypted/MAC'ed and delivered. 467898Skais */ 468898Skais if (ssl->hs_waitstate == idle_handshake) { 469898Skais ssl->activeinput = B_FALSE; 470898Skais outmp = recmp; 471898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 472898Skais } else { 473898Skais kssl_cmd = kssl_handle_any_record(ssl, recmp, 474898Skais &outmp, cbfn, arg); 475898Skais } 4764556Svk199839 break; 4774556Svk199839 default: 4784556Svk199839 ssl->activeinput = B_FALSE; 4795850Svk199839 DTRACE_PROBE(kssl_err__invalid_content_type); 4804556Svk199839 goto sendnewalert; 481898Skais } 482898Skais 483898Skais /* Priority to Alert messages */ 484898Skais if (ssl->alert_sendbuf != NULL) { 4855850Svk199839 DTRACE_PROBE(kssl_err__alert_to_send_cycle); 486898Skais goto sendalert; 487898Skais } 488898Skais 489898Skais /* Then handshake messages */ 490898Skais if (ssl->handshake_sendbuf) { 491898Skais if (*decrmp != NULL) { 492898Skais linkb(*decrmp, ssl->handshake_sendbuf); 493898Skais } else { 494898Skais *decrmp = ssl->handshake_sendbuf; 495898Skais } 496898Skais ssl->handshake_sendbuf = NULL; 497898Skais 498898Skais *more = ((ssl->rec_ass_head != NULL) && 499898Skais (!ssl->activeinput)); 500898Skais mutex_exit(&ssl->kssl_lock); 501898Skais return (kssl_cmd); 502898Skais } 503898Skais 504898Skais if (ssl->hs_waitstate == idle_handshake) { 505898Skais *more = ((ssl->rec_ass_head != NULL) && 506898Skais (!ssl->activeinput)); 507898Skais } 508898Skais 509898Skais if (outmp != NULL) { 510898Skais *decrmp = outmp; 511898Skais /* 512898Skais * Don't process any packet after an application_data. 513898Skais * We could well receive the close_notify which should 514898Skais * be handled separately. 515898Skais */ 516898Skais mutex_exit(&ssl->kssl_lock); 517898Skais return (kssl_cmd); 518898Skais } 519898Skais /* 520898Skais * The current record isn't done yet. Don't start the next one 521898Skais */ 522898Skais if (ssl->activeinput) { 523898Skais mutex_exit(&ssl->kssl_lock); 524898Skais return (kssl_cmd); 525898Skais } 526898Skais } while ((recmp = kssl_get_next_record(ssl)) != NULL); 527898Skais 528898Skais mutex_exit(&ssl->kssl_lock); 529898Skais return (kssl_cmd); 530898Skais 531898Skais sendnewalert: 532898Skais kssl_send_alert(ssl, alert_fatal, unexpected_message); 533898Skais if (mp != NULL) { 534898Skais freeb(mp); 535898Skais } 536898Skais 537898Skais sendalert: 538898Skais *decrmp = ssl->alert_sendbuf; 539898Skais ssl->alert_sendbuf = NULL; 540898Skais mutex_exit(&ssl->kssl_lock); 541898Skais return (KSSL_CMD_SEND); 542898Skais } 543898Skais 544898Skais /* 5455850Svk199839 * Process mblk b_cont chain returned from stream head. The chain could 5465850Svk199839 * contain a mixture (albeit continuous) of processed and unprocessed 5475850Svk199839 * mblks. This situation could happen when more data was available in 5485850Svk199839 * stream head queue than requested. In such case the rest of processed 5495850Svk199839 * data would be putback(). 5505850Svk199839 * 5515850Svk199839 * Processed mblks in this function contain either a full or partial portion 5525850Svk199839 * of a decrypted and verified SSL record. The former case is produced 5535850Svk199839 * by the function itself, the latter case is explained above. 5545850Svk199839 * 5555850Svk199839 * In case of unprocessed mblks, decrypt and verify the MAC of an incoming 5565850Svk199839 * chain of application_data record. Each block has exactly one SSL record. 5575850Svk199839 * This routine recycles incoming mblks, and flags them as DBLK_COOKED. 558898Skais */ 559898Skais kssl_cmd_t 5605850Svk199839 kssl_handle_mblk(kssl_ctx_t ctx, mblk_t **mpp, mblk_t **outmp) 561898Skais { 562898Skais uchar_t *recend, *rec_sz_p; 563898Skais uchar_t *real_recend; 5641139Skais mblk_t *prevmp = NULL, *nextmp, *firstmp, *mp, *copybp; 565898Skais int mac_sz; 566898Skais uchar_t version[2]; 567898Skais uint16_t rec_sz; 568898Skais SSL3AlertDescription desc; 569898Skais SSL3ContentType content_type; 570898Skais ssl_t *ssl; 571898Skais KSSLCipherSpec *spec; 572*10520SBhargava.Yenduri@Sun.COM int error, ret; 573898Skais kssl_cmd_t kssl_cmd = KSSL_CMD_DELIVER_PROXY; 574898Skais boolean_t deliverit = B_FALSE; 575898Skais crypto_data_t cipher_data; 576898Skais 577898Skais ASSERT(ctx != NULL); 578898Skais 579898Skais ssl = (ssl_t *)(ctx); 580898Skais 5811139Skais mp = firstmp = *mpp; 582898Skais *outmp = NULL; 583898Skais 5845850Svk199839 /* 5855850Svk199839 * Skip over already processed mblks. This prevents a case where 5865850Svk199839 * struiocopyout() copies unprocessed data to userland. 5875850Svk199839 */ 5885850Svk199839 while ((mp != NULL) && (DB_FLAGS(mp) & DBLK_COOKED)) { 5895850Svk199839 ASSERT(DB_TYPE(mp) == M_DATA); 5905850Svk199839 DTRACE_PROBE1(kssl_mblk__already_processed_mblk, mblk_t *, mp); 5915850Svk199839 mp = mp->b_cont; 5925850Svk199839 } 5935850Svk199839 594898Skais more: 595898Skais 596898Skais while (mp != NULL) { 5975850Svk199839 /* only unprocessed mblks should reach us */ 5985850Svk199839 ASSERT(DB_TYPE(mp) == M_DATA); 5995850Svk199839 ASSERT(!(DB_FLAGS(mp) & DBLK_COOKED)); 600898Skais 601898Skais if (DB_REF(mp) > 1) { 602898Skais /* 603898Skais * Fortunately copyb() preserves the offset, 604*10520SBhargava.Yenduri@Sun.COM * tail space and alignment so the copy is 605898Skais * ready to be made an SSL record. 606898Skais */ 607898Skais if ((copybp = copyb(mp)) == NULL) 608898Skais return (NULL); 609898Skais 610898Skais copybp->b_cont = mp->b_cont; 6111139Skais if (mp == firstmp) { 612898Skais *mpp = copybp; 6134556Svk199839 } else if (prevmp != NULL) { 614898Skais prevmp->b_cont = copybp; 615898Skais } 616898Skais freeb(mp); 617898Skais mp = copybp; 618898Skais } 619898Skais 6205850Svk199839 DTRACE_PROBE1(kssl_mblk__handle_record_cycle, mblk_t *, mp); 621898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 622898Skais 6234556Svk199839 switch (content_type) { 6244556Svk199839 case content_application_data: 6254556Svk199839 break; 6264556Svk199839 case content_change_cipher_spec: 6274556Svk199839 case content_alert: 6284556Svk199839 case content_handshake: 6294556Svk199839 case content_handshake_v2: 630898Skais nextmp = mp->b_cont; 631898Skais 632898Skais /* Remove this message */ 633898Skais if (prevmp != NULL) { 634898Skais prevmp->b_cont = nextmp; 635898Skais 636898Skais /* 637898Skais * If we had processed blocks that need to 638898Skais * be delivered, then remember that error code 639898Skais */ 640898Skais if (kssl_cmd == KSSL_CMD_DELIVER_PROXY) 641898Skais deliverit = B_TRUE; 642898Skais } 643898Skais 644898Skais mutex_enter(&ssl->kssl_lock); 6454556Svk199839 /* NOTE: This routine could free mp. */ 646898Skais kssl_cmd = kssl_handle_any_record(ssl, mp, outmp, 647898Skais NULL, NULL); 648898Skais 649898Skais if (ssl->alert_sendbuf != NULL) { 6504556Svk199839 mp = nextmp; 6515850Svk199839 DTRACE_PROBE(kssl_err__alert_after_handle_any); 652898Skais goto sendalert; 653898Skais } 654898Skais mutex_exit(&ssl->kssl_lock); 655898Skais 656898Skais if (deliverit) { 657898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 658898Skais } 659898Skais 660898Skais mp = nextmp; 6614556Svk199839 continue; /* to the while loop */ 6624556Svk199839 default: 6634556Svk199839 desc = decode_error; 6644556Svk199839 KSSL_COUNTER(internal_errors, 1); 6655850Svk199839 DTRACE_PROBE(kssl_err__decode_error); 6664556Svk199839 goto makealert; 667898Skais } 668898Skais 669898Skais version[0] = mp->b_rptr[1]; 670898Skais version[1] = mp->b_rptr[2]; 671898Skais rec_sz_p = SSL3_REC_SIZE(mp); 672898Skais rec_sz = BE16_TO_U16(rec_sz_p); 673898Skais 674898Skais mp->b_rptr += SSL3_HDR_LEN; 675898Skais recend = mp->b_rptr + rec_sz; 676898Skais real_recend = recend; 677898Skais 6784556Svk199839 /* 6794556Svk199839 * Check the assumption that each mblk contains exactly 6804556Svk199839 * one complete SSL record. We bail out if the check fails. 6814556Svk199839 */ 6824556Svk199839 ASSERT(recend == mp->b_wptr); 6834556Svk199839 if (recend != mp->b_wptr) { 6844556Svk199839 desc = decode_error; 6854556Svk199839 KSSL_COUNTER(internal_errors, 1); 6865850Svk199839 DTRACE_PROBE(kssl_err__not_complete_record); 6874556Svk199839 goto makealert; 6884556Svk199839 } 6894556Svk199839 690898Skais spec = &ssl->spec[KSSL_READ]; 691898Skais mac_sz = spec->mac_hashsz; 692898Skais if (spec->cipher_ctx != 0) { 6931139Skais 6941139Skais /* 6951139Skais * The record length must be a multiple of the 6961139Skais * block size for block ciphers. 6971139Skais * The cipher_bsize is always a power of 2. 6981139Skais */ 6991139Skais if ((spec->cipher_type == type_block) && 7001139Skais ((rec_sz & (spec->cipher_bsize - 1)) != 0)) { 7015850Svk199839 DTRACE_PROBE2(kssl_err__bad_record_size, 7025850Svk199839 uint16_t, rec_sz, 7035850Svk199839 int, spec->cipher_bsize); 7041139Skais KSSL_COUNTER(record_decrypt_failure, 1); 7051139Skais mp->b_rptr = recend; 7061139Skais desc = decrypt_error; 7071139Skais goto makealert; 7081139Skais } 7091139Skais 710898Skais cipher_data.cd_format = CRYPTO_DATA_RAW; 711898Skais cipher_data.cd_offset = 0; 712898Skais cipher_data.cd_length = rec_sz; 713898Skais cipher_data.cd_miscdata = NULL; 714898Skais cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; 715898Skais cipher_data.cd_raw.iov_len = rec_sz; 716898Skais error = crypto_decrypt_update(spec->cipher_ctx, 717898Skais &cipher_data, NULL, NULL); 718898Skais if (CRYPTO_ERR(error)) { 7195850Svk199839 DTRACE_PROBE1( 7205850Svk199839 kssl_err__crypto_decrypt_update_failed, 7215850Svk199839 int, error); 722898Skais KSSL_COUNTER(record_decrypt_failure, 1); 723898Skais mp->b_rptr = recend; 724898Skais desc = decrypt_error; 725898Skais goto makealert; 726898Skais } 727898Skais } 728898Skais if (spec->cipher_type == type_block) { 729898Skais uint_t pad_sz = recend[-1]; 730898Skais pad_sz++; 731898Skais if (pad_sz + mac_sz > rec_sz) { 7325850Svk199839 DTRACE_PROBE(kssl_err__pad_mac_bigger); 733898Skais mp->b_rptr = recend; 734898Skais desc = bad_record_mac; 735898Skais goto makealert; 736898Skais } 737898Skais rec_sz -= pad_sz; 738898Skais recend -= pad_sz; 739898Skais } 740898Skais if (mac_sz != 0) { 741898Skais uchar_t hash[MAX_HASH_LEN]; 742898Skais if (rec_sz < mac_sz) { 7435850Svk199839 DTRACE_PROBE(kssl_err__pad_smaller_mac); 744898Skais mp->b_rptr = real_recend; 745898Skais desc = bad_record_mac; 746898Skais goto makealert; 747898Skais } 748898Skais rec_sz -= mac_sz; 749898Skais recend -= mac_sz; 750898Skais ret = kssl_compute_record_mac(ssl, KSSL_READ, 7515850Svk199839 ssl->seq_num[KSSL_READ], content_type, 7525850Svk199839 version, mp->b_rptr, rec_sz, hash); 753898Skais if (ret != CRYPTO_SUCCESS || 754898Skais bcmp(hash, recend, mac_sz)) { 7555850Svk199839 DTRACE_PROBE1(kssl_mblk__MACmismatch_handlerec, 7565850Svk199839 mblk_t *, mp); 757898Skais mp->b_rptr = real_recend; 758898Skais desc = bad_record_mac; 7595850Svk199839 DTRACE_PROBE(kssl_err__msg_MAC_mismatch); 760898Skais KSSL_COUNTER(verify_mac_failure, 1); 761898Skais goto makealert; 762898Skais } 763898Skais ssl->seq_num[KSSL_READ]++; 764898Skais } 765898Skais 766898Skais if (ssl->hs_waitstate != idle_handshake) { 7675850Svk199839 DTRACE_PROBE1(kssl_err__unexpected_msg, 7685850Svk199839 SSL3WaitState, ssl->hs_waitstate); 769898Skais mp->b_rptr = real_recend; 770898Skais desc = unexpected_message; 771898Skais goto makealert; 772898Skais } 773898Skais mp->b_wptr = recend; 774898Skais 7754556Svk199839 DB_FLAGS(mp) |= DBLK_COOKED; 7765850Svk199839 DTRACE_PROBE1(kssl_mblk__dblk_cooked, mblk_t *, mp); 7774556Svk199839 KSSL_COUNTER(appdata_record_ins, 1); 7784556Svk199839 779898Skais prevmp = mp; 780898Skais mp = mp->b_cont; 781898Skais } 782898Skais 783898Skais return (kssl_cmd); 784898Skais 785898Skais makealert: 786898Skais nextmp = mp->b_cont; 787898Skais freeb(mp); 788898Skais mp = nextmp; 789898Skais mutex_enter(&ssl->kssl_lock); 790898Skais kssl_send_alert(ssl, alert_fatal, desc); 791898Skais 792898Skais if (ssl->alert_sendbuf == NULL) { 793898Skais /* internal memory allocation failure. just return. */ 7945850Svk199839 DTRACE_PROBE(kssl_err__alert_msg_alloc_failed); 795898Skais mutex_exit(&ssl->kssl_lock); 796898Skais 797898Skais if (mp) { 798898Skais prevmp = NULL; 799898Skais goto more; 800898Skais } 801898Skais 802898Skais return (KSSL_CMD_NONE); 803898Skais } 804898Skais kssl_cmd = KSSL_CMD_SEND; 805898Skais sendalert: 806898Skais if (*outmp == NULL) { 807898Skais *outmp = ssl->alert_sendbuf; 808898Skais } else { 809898Skais linkb(*outmp, ssl->alert_sendbuf); 810898Skais } 811898Skais ssl->alert_sendbuf = NULL; 812898Skais mutex_exit(&ssl->kssl_lock); 813898Skais 814898Skais if (mp) { 815898Skais prevmp = NULL; 816898Skais goto more; 817898Skais } 818898Skais 819898Skais return (kssl_cmd); 820898Skais } 821898Skais /* 822898Skais * This is the routine that handles incoming SSL records. 823898Skais * When called the first time, with a NULL context, this routine expects 824898Skais * a ClientHello SSL Handshake packet and shall allocate a context 825898Skais * of a new SSL connection. 826898Skais * During the rest of the handshake packets, the routine adjusts the 827898Skais * state of the context according to the record received. 828898Skais * After the ChangeCipherSpec message is received, the routine first 829898Skais * decrypts/authenticated the packet using the key materials in the 830898Skais * connection's context. 831898Skais * The return code tells the caller what to do with the returned packet. 832898Skais */ 833898Skais static kssl_cmd_t 834898Skais kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, 835898Skais kssl_callback_t cbfn, void *arg) 836898Skais { 837898Skais uchar_t *recend, *rec_sz_p; 838898Skais uchar_t version[2]; 839898Skais uchar_t *real_recend, *save_rptr, *save_wptr; 840898Skais int rhsz = SSL3_HDR_LEN; 841898Skais uint16_t rec_sz; 842898Skais int sz; 843898Skais int mac_sz; 844898Skais SSL3AlertDescription desc; 845898Skais SSL3AlertLevel level; 846898Skais SSL3ContentType content_type; 847898Skais ssl_t *ssl; 848898Skais KSSLCipherSpec *spec; 849898Skais int error = 0, ret; 850898Skais 851898Skais ASSERT(ctx != NULL); 852898Skais 853898Skais ssl = (ssl_t *)(ctx); 854898Skais 855898Skais *decrmp = NULL; 856898Skais 857898Skais save_rptr = mp->b_rptr; 858898Skais save_wptr = mp->b_wptr; 859898Skais 860898Skais ASSERT(MUTEX_HELD(&ssl->kssl_lock)); 861898Skais 862898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 863898Skais if (content_type == content_handshake_v2) { 864898Skais if (ssl->hs_waitstate == wait_client_hello) { 865898Skais /* V2 compatible ClientHello */ 866898Skais if (mp->b_rptr[3] == 0x03 && 867898Skais (mp->b_rptr[4] == 0x01 || 8685850Svk199839 mp->b_rptr[4] == 0x00)) { 869898Skais ssl->major_version = version[0] = mp->b_rptr[3]; 870898Skais ssl->minor_version = version[1] = mp->b_rptr[4]; 871898Skais } else { 872898Skais /* We don't support "pure" SSLv2 */ 8735850Svk199839 DTRACE_PROBE(kssl_err__no_SSLv2); 874898Skais desc = protocol_version; 875898Skais goto sendalert; 876898Skais } 877898Skais } 878898Skais rec_sz = (uint16_t)mp->b_rptr[1]; 879898Skais rhsz = 2; 880898Skais } else { 881898Skais ssl->major_version = version[0] = mp->b_rptr[1]; 882898Skais ssl->minor_version = version[1] = mp->b_rptr[2]; 883898Skais rec_sz_p = SSL3_REC_SIZE(mp); 884898Skais rec_sz = BE16_TO_U16(rec_sz_p); 885898Skais } 886898Skais 887898Skais mp->b_rptr += rhsz; 888898Skais recend = mp->b_rptr + rec_sz; 889898Skais real_recend = recend; 890898Skais 8914556Svk199839 /* 8924556Svk199839 * Check the assumption that each mblk contains exactly 8934556Svk199839 * one complete SSL record. We bail out if the check fails. 8944556Svk199839 */ 8954556Svk199839 ASSERT(recend == mp->b_wptr); 8964556Svk199839 if (recend != mp->b_wptr) { 8975850Svk199839 DTRACE_PROBE3(kssl_mblk__handle_any_record_recszerr, 8985850Svk199839 mblk_t *, mp, int, rhsz, int, rec_sz); 8995850Svk199839 DTRACE_PROBE(kssl_err__record_size); 9004556Svk199839 desc = decode_error; 9014556Svk199839 KSSL_COUNTER(internal_errors, 1); 9024556Svk199839 goto sendalert; 9034556Svk199839 } 9044556Svk199839 905898Skais spec = &ssl->spec[KSSL_READ]; 906898Skais mac_sz = spec->mac_hashsz; 907898Skais if (spec->cipher_ctx != 0) { 9081139Skais /* 9091139Skais * The record length must be a multiple of the 9101139Skais * block size for block ciphers. 9111139Skais */ 9121139Skais if ((spec->cipher_type == type_block) && 9131139Skais ((rec_sz & (spec->cipher_bsize - 1)) != 0)) { 9145850Svk199839 DTRACE_PROBE2(kssl_err__bad_record_size, 9155850Svk199839 uint16_t, rec_sz, int, spec->cipher_bsize); 9161139Skais KSSL_COUNTER(record_decrypt_failure, 1); 9171139Skais mp->b_rptr = recend; 9181139Skais desc = decrypt_error; 9191139Skais goto sendalert; 9201139Skais } 9211139Skais 922898Skais spec->cipher_data.cd_length = rec_sz; 923898Skais spec->cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; 924898Skais spec->cipher_data.cd_raw.iov_len = rec_sz; 925898Skais error = crypto_decrypt_update(spec->cipher_ctx, 926898Skais &spec->cipher_data, NULL, NULL); 927898Skais if (CRYPTO_ERR(error)) { 9285850Svk199839 DTRACE_PROBE1(kssl_err__crypto_decrypt_update_failed, 9295850Svk199839 int, error); 930898Skais KSSL_COUNTER(record_decrypt_failure, 1); 931898Skais mp->b_rptr = recend; 932898Skais desc = decrypt_error; 933898Skais goto sendalert; 934898Skais } 935898Skais } 936898Skais if (spec->cipher_type == type_block) { 937898Skais uint_t pad_sz = recend[-1]; 938898Skais pad_sz++; 939898Skais if (pad_sz + mac_sz > rec_sz) { 9405850Svk199839 DTRACE_PROBE2(kssl_err__pad_mac_mismatch, 9415850Svk199839 int, pad_sz, int, mac_sz); 942898Skais mp->b_rptr = recend; 943898Skais desc = bad_record_mac; 944898Skais goto sendalert; 945898Skais } 946898Skais rec_sz -= pad_sz; 947898Skais recend -= pad_sz; 948898Skais } 949898Skais if (mac_sz != 0) { 950898Skais uchar_t hash[MAX_HASH_LEN]; 951898Skais if (rec_sz < mac_sz) { 9525850Svk199839 DTRACE_PROBE1(kssl_err__mac_size_too_big, 9535850Svk199839 int, mac_sz); 954898Skais mp->b_rptr = real_recend; 955898Skais desc = bad_record_mac; 956898Skais goto sendalert; 957898Skais } 958898Skais rec_sz -= mac_sz; 959898Skais recend -= mac_sz; 960898Skais ret = kssl_compute_record_mac(ssl, KSSL_READ, 9615850Svk199839 ssl->seq_num[KSSL_READ], content_type, 9625850Svk199839 version, mp->b_rptr, rec_sz, hash); 963898Skais if (ret != CRYPTO_SUCCESS || 964898Skais bcmp(hash, recend, mac_sz)) { 9655850Svk199839 DTRACE_PROBE1(kssl_mblk__MACmismatch_anyrecord, 9665850Svk199839 mblk_t *, mp); 967898Skais mp->b_rptr = real_recend; 968898Skais desc = bad_record_mac; 9695850Svk199839 DTRACE_PROBE(kssl_err__msg_MAC_mismatch); 970898Skais KSSL_COUNTER(verify_mac_failure, 1); 971898Skais goto sendalert; 972898Skais } 973898Skais ssl->seq_num[KSSL_READ]++; 9745850Svk199839 DTRACE_PROBE1(kssl_mblk__after_compute_MAC, 9755850Svk199839 mblk_t *, mp); 976898Skais } 977898Skais 978898Skais switch (content_type) { 979898Skais case content_handshake: 980898Skais do { 9815850Svk199839 DTRACE_PROBE1(kssl_mblk__content_handshake_cycle, 9825850Svk199839 mblk_t *, mp); 983898Skais if (error != 0 || 984898Skais /* ignore client renegotiation for now */ 985898Skais ssl->hs_waitstate == idle_handshake) { 986898Skais mp->b_rptr = recend; 987898Skais } 988898Skais if (mp->b_rptr == recend) { 989898Skais mp->b_rptr = real_recend; 990898Skais if (error != 0) { 991898Skais goto error; 992898Skais } 993898Skais freeb(mp); 994898Skais 995898Skais if (ssl->hs_waitstate == wait_client_key_done) 996898Skais return (KSSL_CMD_QUEUED); 997898Skais 998898Skais return ((ssl->handshake_sendbuf != NULL) ? 999898Skais KSSL_CMD_SEND : KSSL_CMD_NONE); 1000898Skais } 1001898Skais if (ssl->msg.state < MSG_BODY) { 1002898Skais if (ssl->msg.state == MSG_INIT) { 1003898Skais ssl->msg.type = 1004898Skais (SSL3HandshakeType)*mp->b_rptr++; 1005898Skais ssl->msg.state = MSG_INIT_LEN; 1006898Skais } 1007898Skais if (ssl->msg.state == MSG_INIT_LEN) { 1008898Skais int msglenb = 1009898Skais ssl->msg.msglen_bytes; 1010898Skais int msglen = ssl->msg.msglen; 1011898Skais while (mp->b_rptr < recend && 1012898Skais msglenb < 3) { 1013898Skais msglen = (msglen << 8) + 1014898Skais (uint_t)(*mp->b_rptr++); 1015898Skais msglenb++; 1016898Skais } 1017898Skais ssl->msg.msglen_bytes = msglenb; 1018898Skais ssl->msg.msglen = msglen; 1019898Skais if (msglenb == 3) { 1020898Skais ssl->msg.state = MSG_BODY; 1021898Skais } 1022898Skais } 1023898Skais if (mp->b_rptr == recend) { 1024898Skais mp->b_rptr = real_recend; 1025898Skais freeb(mp); 1026898Skais return (KSSL_CMD_NONE); 1027898Skais } 1028898Skais } 1029898Skais ASSERT(ssl->msg.state == MSG_BODY); 1030898Skais 1031898Skais sz = recend - mp->b_rptr; 1032898Skais 1033898Skais if (ssl->msg.head == NULL && 1034898Skais ssl->msg.msglen <= sz) { 1035898Skais continue; 1036898Skais } 1037898Skais if (ssl->msg.head != NULL) { 1038898Skais sz += msgdsize(ssl->msg.head); 1039898Skais if (ssl->msg.msglen <= sz) { 1040898Skais ssl->msg.tail->b_cont = mp; 1041898Skais mp = ssl->msg.head; 1042898Skais ssl->sslcnt = 100; 1043898Skais ssl->msg.head = NULL; 1044898Skais ssl->msg.tail = NULL; 1045898Skais if (pullupmsg(mp, -1)) { 1046898Skais recend = mp->b_rptr + sz; 1047898Skais ASSERT(recend <= mp->b_wptr); 1048898Skais continue; 1049898Skais } 1050898Skais mp->b_rptr = real_recend; 1051898Skais error = ENOMEM; 1052898Skais KSSL_COUNTER(alloc_fails, 1); 1053898Skais goto error; 1054898Skais } 1055898Skais } 1056898Skais 1057898Skais mp->b_wptr = recend; 1058898Skais 1059898Skais if (ssl->msg.head == NULL) { 1060898Skais ssl->msg.head = mp; 1061898Skais ssl->msg.tail = mp; 1062898Skais return (KSSL_CMD_NONE); 1063898Skais } else { 1064898Skais ssl->msg.tail->b_cont = mp; 1065898Skais ssl->msg.tail = mp; 1066898Skais return (KSSL_CMD_NONE); 1067898Skais } 1068898Skais } while (kssl_handle_handshake_message(ssl, mp, &error, cbfn, 1069898Skais arg)); 1070898Skais if (error == SSL_MISS) { 1071898Skais mp->b_rptr = save_rptr; 1072898Skais mp->b_wptr = save_wptr; 1073898Skais KSSL_COUNTER(fallback_connections, 1); 1074898Skais return (KSSL_CMD_NOT_SUPPORTED); 1075898Skais } 1076898Skais if (ssl->hs_waitstate == wait_client_key_done) { 1077898Skais return (KSSL_CMD_QUEUED); 1078898Skais } else { 1079898Skais return (KSSL_CMD_NONE); 1080898Skais } 1081898Skais case content_alert: 10825850Svk199839 DTRACE_PROBE1(kssl_mblk__content_alert, mblk_t *, mp); 1083898Skais if (rec_sz != 2) { 10845850Svk199839 DTRACE_PROBE(kssl_err__illegal_param); 1085898Skais mp->b_rptr = real_recend; 1086898Skais desc = illegal_parameter; 1087898Skais goto sendalert; 1088898Skais } else { 1089898Skais level = *mp->b_rptr++; 1090898Skais desc = *mp->b_rptr++; 1091898Skais mp->b_rptr = real_recend; 1092898Skais if (level != alert_warning || desc != close_notify) { 1093898Skais if (ssl->sid.cached == B_TRUE) { 1094898Skais kssl_uncache_sid(&ssl->sid, 1095898Skais ssl->kssl_entry); 1096898Skais } 10975850Svk199839 DTRACE_PROBE2(kssl_err__bad_content_alert, 10985850Svk199839 SSL3AlertLevel, level, 10995850Svk199839 SSL3AlertDescription, desc); 1100898Skais ssl->fatal_alert = B_TRUE; 1101898Skais error = EBADMSG; 1102898Skais goto error; 1103898Skais } else { 1104898Skais ssl->close_notify = B_TRUE; 1105898Skais ssl->activeinput = B_FALSE; 1106898Skais freeb(mp); 1107898Skais return (KSSL_CMD_NONE); 1108898Skais } 1109898Skais } 1110898Skais case content_change_cipher_spec: 11115850Svk199839 DTRACE_PROBE1(kssl_mblk__change_cipher_spec, 11125850Svk199839 mblk_t *, mp); 1113898Skais if (ssl->hs_waitstate != wait_change_cipher) { 1114898Skais desc = unexpected_message; 1115898Skais } else if (rec_sz != 1 || *mp->b_rptr != 1) { 1116898Skais desc = illegal_parameter; 1117898Skais } else { 1118898Skais mp->b_rptr = real_recend; 1119898Skais ssl->hs_waitstate = wait_finished; 1120898Skais ssl->seq_num[KSSL_READ] = 0; 1121898Skais if ((error = kssl_spec_init(ssl, KSSL_READ)) != 0) { 11225850Svk199839 DTRACE_PROBE1(kssl_err__kssl_spec_init_error, 11235850Svk199839 int, error); 1124898Skais goto error; 1125898Skais } 1126898Skais ssl->activeinput = B_FALSE; 1127898Skais freeb(mp); 1128898Skais return (KSSL_CMD_NONE); 1129898Skais } 1130898Skais mp->b_rptr = real_recend; 11315850Svk199839 DTRACE_PROBE(kssl_err__change_cipher_spec); 1132898Skais goto sendalert; 1133898Skais 1134898Skais case content_application_data: 11355850Svk199839 DTRACE_PROBE1(kssl_mblk__content_app_data, 11365850Svk199839 mblk_t *, mp); 1137898Skais if (ssl->hs_waitstate != idle_handshake) { 11385850Svk199839 DTRACE_PROBE(kssl_err__content_app_data); 1139898Skais mp->b_rptr = real_recend; 1140898Skais desc = unexpected_message; 1141898Skais goto sendalert; 1142898Skais } 1143898Skais mp->b_wptr = recend; 1144898Skais *decrmp = mp; 1145898Skais ssl->activeinput = B_FALSE; 1146898Skais return (KSSL_CMD_DELIVER_PROXY); 1147898Skais 1148898Skais case content_handshake_v2: 11495850Svk199839 DTRACE_PROBE1(kssl_mblk__content_handshake_v2, 11505850Svk199839 mblk_t *, mp); 1151898Skais error = kssl_handle_v2client_hello(ssl, mp, rec_sz); 1152898Skais if (error == SSL_MISS) { 1153898Skais mp->b_rptr = save_rptr; 1154898Skais mp->b_wptr = save_wptr; 1155898Skais KSSL_COUNTER(fallback_connections, 1); 1156898Skais return (KSSL_CMD_NOT_SUPPORTED); 1157898Skais } else if (error != 0) { 11585850Svk199839 DTRACE_PROBE(kssl_err__v2client_hello_failed); 1159898Skais goto error; 1160898Skais } 1161898Skais freeb(mp); 1162898Skais return (KSSL_CMD_SEND); 1163898Skais default: 11645850Svk199839 DTRACE_PROBE1(kssl_mblk__unexpected_msg, 11655850Svk199839 mblk_t *, mp); 1166898Skais mp->b_rptr = real_recend; 1167898Skais desc = unexpected_message; 1168898Skais break; 1169898Skais } 1170898Skais 1171898Skais sendalert: 1172898Skais kssl_send_alert(ssl, alert_fatal, desc); 1173898Skais *decrmp = ssl->alert_sendbuf; 1174898Skais ssl->alert_sendbuf = NULL; 1175898Skais freeb(mp); 1176898Skais return ((*decrmp != NULL) ? KSSL_CMD_SEND : KSSL_CMD_NONE); 1177898Skais error: 1178898Skais freeb(mp); 1179898Skais return (KSSL_CMD_NONE); 1180898Skais } 1181898Skais 1182898Skais /* 1183898Skais * Initialize the context of an SSL connection, coming to the specified 1184*10520SBhargava.Yenduri@Sun.COM * address. The ssl structure is returned held. 1185898Skais */ 1186898Skais kssl_status_t 1187*10520SBhargava.Yenduri@Sun.COM kssl_init_context(kssl_ent_t kssl_ent, void *addr, boolean_t is_v4, 1188*10520SBhargava.Yenduri@Sun.COM int mss, kssl_ctx_t *kssl_ctxp) 1189898Skais { 1190898Skais ssl_t *ssl = kmem_cache_alloc(kssl_cache, KM_NOSLEEP); 1191898Skais 1192898Skais if (ssl == NULL) { 1193898Skais return (KSSL_STS_ERR); 1194898Skais } 1195898Skais 1196898Skais kssl_cache_count++; 1197898Skais 1198898Skais bzero(ssl, sizeof (ssl_t)); 1199898Skais 1200898Skais ssl->kssl_entry = (kssl_entry_t *)kssl_ent; 1201898Skais KSSL_ENTRY_REFHOLD(ssl->kssl_entry); 1202898Skais 1203*10520SBhargava.Yenduri@Sun.COM if (is_v4) { 1204*10520SBhargava.Yenduri@Sun.COM IN6_IPADDR_TO_V4MAPPED(*((ipaddr_t *)addr), &ssl->faddr); 1205*10520SBhargava.Yenduri@Sun.COM } else { 1206*10520SBhargava.Yenduri@Sun.COM ssl->faddr = *((in6_addr_t *)addr); /* struct assignment */ 1207*10520SBhargava.Yenduri@Sun.COM } 1208898Skais ssl->tcp_mss = mss; 1209898Skais ssl->sendalert_level = alert_warning; 1210898Skais ssl->sendalert_desc = close_notify; 1211898Skais ssl->sid.cached = B_FALSE; 1212898Skais 1213898Skais *kssl_ctxp = (kssl_ctx_t)ssl; 1214898Skais KSSL_SSL_REFHOLD(ssl); 1215898Skais return (KSSL_STS_OK); 1216898Skais } 1217898Skais 1218898Skais /* 1219898Skais * Builds SSL records out of the chain of mblks, and returns it. 1220*10520SBhargava.Yenduri@Sun.COM * Takes a copy of the message before encrypting it if it has another 1221898Skais * reference. 1222898Skais * In case of failure, NULL is returned, and the message will be 1223898Skais * freed by the caller. 1224898Skais * A NULL mp means a close_notify is requested. 1225898Skais */ 1226898Skais mblk_t * 1227898Skais kssl_build_record(kssl_ctx_t ctx, mblk_t *mp) 1228898Skais { 1229898Skais ssl_t *ssl = (ssl_t *)ctx; 1230898Skais mblk_t *retmp = mp, *bp = mp, *prevbp = mp, *copybp; 1231898Skais 1232898Skais ASSERT(ssl != NULL); 1233898Skais ASSERT(mp != NULL); 1234898Skais 1235898Skais do { 1236898Skais if (DB_REF(bp) > 1) { 1237898Skais /* 1238898Skais * Fortunately copyb() preserves the offset, 1239*10520SBhargava.Yenduri@Sun.COM * tail space and alignment so the copy is 1240898Skais * ready to be made an SSL record. 1241898Skais */ 1242898Skais if ((copybp = copyb(bp)) == NULL) 1243898Skais return (NULL); 1244898Skais 1245898Skais copybp->b_cont = bp->b_cont; 1246898Skais if (bp == mp) { 1247898Skais retmp = copybp; 1248898Skais } else { 1249898Skais prevbp->b_cont = copybp; 1250898Skais } 1251898Skais freeb(bp); 1252898Skais bp = copybp; 1253898Skais } 1254898Skais 1255898Skais if (kssl_build_single_record(ssl, bp) != KSSL_STS_OK) 1256898Skais return (NULL); 1257898Skais 1258898Skais prevbp = bp; 1259898Skais bp = bp->b_cont; 1260898Skais } while (bp != NULL); 1261898Skais 1262898Skais return (retmp); 1263898Skais } 1264898Skais 1265898Skais /* 1266*10520SBhargava.Yenduri@Sun.COM * Builds a single SSL record. 1267898Skais * In-line encryption of the record. 1268898Skais */ 1269898Skais static kssl_status_t 1270898Skais kssl_build_single_record(ssl_t *ssl, mblk_t *mp) 1271898Skais { 1272898Skais int len; 1273*10520SBhargava.Yenduri@Sun.COM int reclen; 1274898Skais uchar_t *recstart, *versionp; 1275898Skais KSSLCipherSpec *spec; 1276898Skais int mac_sz; 1277*10520SBhargava.Yenduri@Sun.COM int pad_sz; 1278898Skais 1279898Skais spec = &ssl->spec[KSSL_WRITE]; 1280898Skais mac_sz = spec->mac_hashsz; 1281898Skais 1282898Skais ASSERT(DB_REF(mp) == 1); 1283898Skais ASSERT((mp->b_rptr - mp->b_datap->db_base >= SSL3_HDR_LEN) && 1284898Skais (mp->b_datap->db_lim - mp->b_wptr >= mac_sz + spec->cipher_bsize)); 1285898Skais 1286898Skais len = MBLKL(mp); 1287898Skais 1288898Skais ASSERT(len > 0); 1289898Skais 1290898Skais mutex_enter(&ssl->kssl_lock); 1291898Skais 1292898Skais recstart = mp->b_rptr = mp->b_rptr - SSL3_HDR_LEN; 1293898Skais recstart[0] = content_application_data; 1294898Skais recstart[1] = ssl->major_version; 1295898Skais recstart[2] = ssl->minor_version; 1296898Skais versionp = &recstart[1]; 1297898Skais 1298898Skais reclen = len + mac_sz; 1299898Skais if (spec->cipher_type == type_block) { 1300898Skais pad_sz = spec->cipher_bsize - 1301898Skais (reclen & (spec->cipher_bsize - 1)); 1302898Skais ASSERT(reclen + pad_sz <= 1303898Skais SSL3_MAX_RECORD_LENGTH); 1304898Skais reclen += pad_sz; 1305898Skais } 1306898Skais recstart[3] = (reclen >> 8) & 0xff; 1307898Skais recstart[4] = reclen & 0xff; 1308898Skais 1309898Skais if (kssl_mac_encrypt_record(ssl, content_application_data, versionp, 1310898Skais recstart, mp) != 0) { 1311898Skais /* Do we need an internal_error Alert here? */ 1312898Skais mutex_exit(&ssl->kssl_lock); 1313898Skais return (KSSL_STS_ERR); 1314898Skais } 1315898Skais 1316898Skais KSSL_COUNTER(appdata_record_outs, 1); 1317898Skais mutex_exit(&ssl->kssl_lock); 1318898Skais return (KSSL_STS_OK); 1319898Skais } 1320