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 /* 22*9624SBhargava.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 #include <inet/ip6.h> 37898Skais 38898Skais #include <sys/systm.h> 39898Skais #include <sys/param.h> 40898Skais #include <sys/tihdr.h> 41898Skais 42898Skais #include "ksslimpl.h" 43898Skais #include "ksslproto.h" 44898Skais #include "ksslapi.h" 45898Skais 46898Skais static kssl_cmd_t kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, 47898Skais mblk_t **decrmp, kssl_callback_t cbfn, void *arg); 48898Skais static boolean_t kssl_enqueue(kssl_chain_t **head, void *item); 49898Skais static void kssl_dequeue(kssl_chain_t **head, void *item); 50898Skais static kssl_status_t kssl_build_single_record(ssl_t *ssl, mblk_t *mp); 51898Skais 52898Skais /* 53898Skais * The socket T_bind_req message is intercepted and re-routed here 54898Skais * to see is there is SSL relevant job to do, based on the kssl config 55898Skais * in the kssl_entry_tab. 56898Skais * Looks up the kernel SSL proxy table, to find an entry that matches the 57898Skais * same serveraddr, and has one of the following two criteria: 58898Skais * 1. in_port is an ssl_port. This endpoint can be used later as a fallback 59898Skais * to complete connections that cannot be handled by the SSL kernel proxy 60898Skais * (typically non supported ciphersuite). The cookie for the calling client 61898Skais * is saved with the kssl_entry to be retrieved for the fallback. 62898Skais * The function returns KSSL_HAS_PROXY. 63898Skais * 64898Skais * 2. in_port is a proxy port for another ssl port. The ssl port is then 65898Skais * substituted to the in_port in the bind_req TPI structure, so that 66898Skais * the bind falls through to the SSL port. At the end of this operation, 67898Skais * all the packets arriving to the SSL port will be delivered to an 68898Skais * accepted endpoint child of this bound socket. 69898Skais * The kssl_entry_t is returned in *ksslent, for later use by the 70898Skais * lower modules' SSL hooks that handle the Handshake messages. 71898Skais * The function returns KSSL_IS_PROXY. 72898Skais * 73898Skais * The function returns KSSL_NO_PROXY otherwise. We do not suppport 74898Skais * IPv6 addresses. 75898Skais */ 76898Skais 77898Skais kssl_endpt_type_t 78898Skais kssl_check_proxy(mblk_t *bindmp, void *cookie, kssl_ent_t *ksslent) 79898Skais { 80898Skais int i; 81898Skais kssl_endpt_type_t ret; 82898Skais kssl_entry_t *ep; 83898Skais sin_t *sin; 84*9624SBhargava.Yenduri@Sun.COM sin6_t *sin6; 85898Skais struct T_bind_req *tbr; 86898Skais ipaddr_t v4addr; 87898Skais in_port_t in_port; 88898Skais 89898Skais if (kssl_enabled == 0) { 90898Skais return (KSSL_NO_PROXY); 91898Skais } 92898Skais 93898Skais tbr = (struct T_bind_req *)bindmp->b_rptr; 94898Skais 95898Skais ret = KSSL_NO_PROXY; 96898Skais 97*9624SBhargava.Yenduri@Sun.COM sin = (sin_t *)(bindmp->b_rptr + tbr->ADDR_offset); 98898Skais 99898Skais switch (tbr->ADDR_length) { 100898Skais case sizeof (sin_t): 101898Skais in_port = ntohs(sin->sin_port); 102898Skais v4addr = sin->sin_addr.s_addr; 103898Skais break; 104898Skais 105898Skais case sizeof (sin6_t): 106*9624SBhargava.Yenduri@Sun.COM /* 107*9624SBhargava.Yenduri@Sun.COM * Handle any IPv4-mapped IPv6 address for now. 108*9624SBhargava.Yenduri@Sun.COM * Support of IPv6 will be added later. 109*9624SBhargava.Yenduri@Sun.COM */ 110*9624SBhargava.Yenduri@Sun.COM sin6 = (sin6_t *)sin; 111*9624SBhargava.Yenduri@Sun.COM if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 112*9624SBhargava.Yenduri@Sun.COM in_port = ntohs(sin6->sin6_port); 113*9624SBhargava.Yenduri@Sun.COM IN6_V4MAPPED_TO_IPADDR(&sin6->sin6_addr, v4addr); 114*9624SBhargava.Yenduri@Sun.COM break; 115*9624SBhargava.Yenduri@Sun.COM } 116*9624SBhargava.Yenduri@Sun.COM 117*9624SBhargava.Yenduri@Sun.COM /* fallthrough for normal IPv6 address */ 118898Skais default: 119898Skais return (ret); 120898Skais } 121898Skais 122898Skais mutex_enter(&kssl_tab_mutex); 123898Skais 124898Skais for (i = 0; i < kssl_entry_tab_size; i++) { 125898Skais if ((ep = kssl_entry_tab[i]) == NULL) 126898Skais continue; 127898Skais 128898Skais if ((ep->ke_laddr == v4addr) || (ep->ke_laddr == INADDR_ANY)) { 129898Skais 130898Skais /* This is an SSL port to fallback to */ 131898Skais if (ep->ke_ssl_port == in_port) { 132898Skais 133898Skais /* 134898Skais * Let's see first if there's at least 135898Skais * an endpoint for a proxy server. 136898Skais * If there's none, then we return as we have 137898Skais * no proxy, so that the bind() to the 138898Skais * transport layer goes through. 139898Skais * The calling module will ask for this 140898Skais * cookie if it wants to fall back to it, 141898Skais * so add this one to the list of fallback 142898Skais * clients. 143898Skais */ 144898Skais if (!kssl_enqueue((kssl_chain_t **) 145898Skais &(ep->ke_fallback_head), cookie)) { 146898Skais break; 147898Skais } 148898Skais 149898Skais /* 150898Skais * Now transform the T_BIND_REQ into 151898Skais * a T_BIND_ACK. 152898Skais */ 153898Skais tbr->PRIM_type = T_BIND_ACK; 154898Skais bindmp->b_datap->db_type = M_PCPROTO; 155898Skais 156898Skais KSSL_ENTRY_REFHOLD(ep); 157898Skais *ksslent = (kssl_ent_t)ep; 158898Skais 159898Skais ret = KSSL_HAS_PROXY; 160898Skais break; 161898Skais } 162898Skais 163898Skais /* This is a proxy port. */ 164898Skais if (ep->ke_proxy_port == in_port) { 165898Skais mblk_t *entmp; 166898Skais 167898Skais /* Append this entry to the bind_req mblk */ 168898Skais 169898Skais entmp = allocb(sizeof (kssl_entry_t), 170898Skais BPRI_MED); 171898Skais if (entmp == NULL) 172898Skais break; 173898Skais *((kssl_entry_t **)entmp->b_rptr) = ep; 174898Skais 175898Skais entmp->b_wptr = entmp->b_rptr + 176898Skais sizeof (kssl_entry_t); 177898Skais 178898Skais bindmp->b_cont = entmp; 179898Skais 180898Skais /* Add the caller's cookie to proxies list */ 181898Skais 182898Skais if (!kssl_enqueue((kssl_chain_t **) 183898Skais &(ep->ke_proxy_head), cookie)) { 184898Skais freeb(bindmp->b_cont); 185898Skais bindmp->b_cont = NULL; 186898Skais break; 187898Skais } 188898Skais 189898Skais /* 190898Skais * Make this look like the SSL port to the 191898Skais * transport below 192898Skais */ 193898Skais sin->sin_port = htons(ep->ke_ssl_port); 194898Skais 195898Skais tbr->PRIM_type = T_SSL_PROXY_BIND_REQ; 196898Skais 197898Skais KSSL_ENTRY_REFHOLD(ep); 198898Skais *ksslent = (kssl_ent_t)ep; 199898Skais 200898Skais ret = KSSL_IS_PROXY; 201898Skais break; 202898Skais } 203898Skais } 204898Skais } 205898Skais 206898Skais mutex_exit(&kssl_tab_mutex); 207898Skais return (ret); 208898Skais } 209898Skais 210898Skais /* 211898Skais * Retrieved an endpoint "bound" to the SSL entry. 212898Skais * Such endpoint has previously called kssl_check_proxy(), got itself 213898Skais * linked to the kssl_entry's ke_fallback_head list. 214898Skais * This routine returns the cookie from that SSL entry ke_fallback_head list. 215898Skais */ 216898Skais void * 217898Skais kssl_find_fallback(kssl_ent_t ksslent) 218898Skais { 219898Skais kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; 220898Skais 221898Skais if (kssl_entry->ke_fallback_head != NULL) 222898Skais return (kssl_entry->ke_fallback_head->fallback_bound); 223898Skais 224898Skais KSSL_COUNTER(proxy_fallback_failed, 1); 225898Skais 226898Skais return (NULL); 227898Skais } 228898Skais 229898Skais /* 230898Skais * Re-usable code for adding and removing an element to/from a chain that 231898Skais * matches "item" 232898Skais * The chain is simple-linked and NULL ended. 233898Skais */ 234898Skais 235898Skais /* 236898Skais * This routine returns TRUE if the item was either successfully added to 237898Skais * the chain, or is already there. It returns FALSE otherwise. 238898Skais */ 239898Skais static boolean_t 240898Skais kssl_enqueue(kssl_chain_t **head, void *item) 241898Skais { 242898Skais kssl_chain_t *newchain, *cur; 243898Skais 244898Skais /* Lookup the existing entries to avoid duplicates */ 245898Skais cur = *head; 246898Skais while (cur != NULL) { 247898Skais if (cur->item == item) { 248898Skais return (B_TRUE); 249898Skais } 250898Skais cur = cur->next; 251898Skais } 252898Skais 253898Skais newchain = kmem_alloc(sizeof (kssl_chain_t), KM_NOSLEEP); 254898Skais if (newchain == NULL) { 255898Skais return (B_FALSE); 256898Skais } 257898Skais 258898Skais newchain->item = item; 259898Skais newchain->next = *head; 260898Skais *head = newchain; 261898Skais return (B_TRUE); 262898Skais } 263898Skais 264898Skais static void 265898Skais kssl_dequeue(kssl_chain_t **head, void *item) 266898Skais { 267898Skais kssl_chain_t *prev, *cur; 268898Skais 269898Skais prev = cur = *head; 270898Skais while (cur != NULL) { 271898Skais if (cur->item == item) { 272898Skais if (cur == *head) 273898Skais *head = (*head)->next; 274898Skais else 275898Skais prev->next = cur->next; 276898Skais kmem_free(cur, sizeof (kssl_chain_t)); 277898Skais return; 278898Skais } 279898Skais prev = cur; 280898Skais cur = cur->next; 281898Skais } 282898Skais } 283898Skais 284898Skais /* 285898Skais * Holds the kssl_entry 286898Skais */ 287898Skais void 288898Skais kssl_hold_ent(kssl_ent_t ksslent) 289898Skais { 290898Skais KSSL_ENTRY_REFHOLD((kssl_entry_t *)ksslent); 291898Skais } 292898Skais 293898Skais /* 294898Skais * Releases the kssl_entry 295898Skais * If the caller passes a cookie, then it should be removed from both 296898Skais * proxies and fallbacks chains. 297898Skais */ 298898Skais void 299898Skais kssl_release_ent(kssl_ent_t ksslent, void *cookie, kssl_endpt_type_t endpt_type) 300898Skais { 301898Skais kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; 302898Skais 303898Skais if (cookie != NULL) { 304898Skais if (endpt_type == KSSL_IS_PROXY) 305898Skais ASSERT(kssl_entry->ke_proxy_head != NULL); 306898Skais kssl_dequeue( 307898Skais (kssl_chain_t **)&kssl_entry->ke_proxy_head, 308898Skais cookie); 309898Skais if (endpt_type == KSSL_HAS_PROXY) 310898Skais ASSERT(kssl_entry->ke_fallback_head != NULL); 311898Skais kssl_dequeue( 312898Skais (kssl_chain_t **)&kssl_entry->ke_fallback_head, 313898Skais cookie); 314898Skais } 315898Skais KSSL_ENTRY_REFRELE(kssl_entry); 316898Skais } 317898Skais 318898Skais /* 319898Skais * Holds the kssl context 320898Skais */ 321898Skais void 322898Skais kssl_hold_ctx(kssl_ctx_t ksslctx) 323898Skais { 324898Skais ssl_t *ssl = (ssl_t *)ksslctx; 325898Skais 326898Skais KSSL_SSL_REFHOLD(ssl); 327898Skais } 328898Skais 329898Skais /* 330898Skais * Releases the kssl_context 331898Skais */ 332898Skais void 333898Skais kssl_release_ctx(kssl_ctx_t ksslctx) 334898Skais { 335898Skais KSSL_SSL_REFRELE((ssl_t *)ksslctx); 336898Skais } 337898Skais 338898Skais /* 339898Skais * Packets are accumulated here, if there are packets already queued, 340898Skais * or if the context is active. 341898Skais * The context is active when an incoming record processing function 342898Skais * is already executing on a different thread. 343898Skais * Queued packets are handled either when an mblk arrived and completes 344898Skais * a record, or, when the active context processor finishes the task at 345898Skais * hand. 346898Skais * The caller has to keep calling this routine in a loop until it returns 347898Skais * B_FALSE in *more. The reason for this is SSL3: The protocol 348898Skais * allows the client to send its first application_data message right 349898Skais * after it had sent its Finished message, and not wait for the server 350898Skais * ChangeCipherSpec and Finished. This overlap means we can't batch up 351898Skais * a returned Handshake message to be sent on the wire 352898Skais * with a decrypted application_data to be delivered to the application. 353898Skais */ 354898Skais kssl_cmd_t 355898Skais kssl_input(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, boolean_t *more, 356898Skais kssl_callback_t cbfn, void *arg) 357898Skais { 358898Skais mblk_t *recmp, *outmp = NULL; 359898Skais kssl_cmd_t kssl_cmd; 360898Skais ssl_t *ssl; 361898Skais uint8_t *rec_sz_p; 362898Skais int mplen; 363898Skais SSL3ContentType content_type; 364898Skais uint16_t rec_sz; 365898Skais 366898Skais ASSERT(ctx != NULL); 367898Skais 368898Skais if (mp != NULL) { 369898Skais ASSERT(mp->b_prev == NULL && mp->b_next == NULL); 370898Skais } 371898Skais 372898Skais ssl = (ssl_t *)(ctx); 373898Skais 374898Skais *decrmp = NULL; 375898Skais *more = B_FALSE; 376898Skais 377898Skais mutex_enter(&ssl->kssl_lock); 378898Skais 379898Skais if (ssl->close_notify == B_TRUE) { 3805850Svk199839 DTRACE_PROBE(kssl_err__close_notify); 381898Skais goto sendnewalert; 382898Skais } 383898Skais 384898Skais /* Whomever is currently processing this connection will get to this */ 385898Skais if (ssl->activeinput) { 386898Skais if (mp != NULL) { 387898Skais KSSL_ENQUEUE_MP(ssl, mp); 388898Skais } 389898Skais mutex_exit(&ssl->kssl_lock); 390898Skais return (KSSL_CMD_NONE); 391898Skais } 392898Skais 393898Skais /* 394898Skais * Fast path for complete incoming application_data records on an empty 395898Skais * queue. 396898Skais * This is by far the most frequently encountered case 397898Skais */ 398898Skais 399898Skais if ((!ssl->activeinput) && (ssl->rec_ass_head == NULL) && 400898Skais ((mp != NULL) && (mplen = MBLKL(mp)) > SSL3_HDR_LEN)) { 401898Skais 4025850Svk199839 DTRACE_PROBE1(kssl_mblk__fast_path, mblk_t *, mp); 403898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 404898Skais 405898Skais if ((content_type == content_application_data) && 406898Skais (ssl->hs_waitstate == idle_handshake)) { 407898Skais rec_sz_p = SSL3_REC_SIZE(mp); 408898Skais rec_sz = BE16_TO_U16(rec_sz_p); 409898Skais 410898Skais if ((mp->b_cont == NULL) && (mplen == rec_sz)) { 411898Skais 4124859Skrishna DB_FLAGS(mp) &= ~DBLK_COOKED; 413898Skais *decrmp = mp; 414898Skais mutex_exit(&ssl->kssl_lock); 415898Skais return (KSSL_CMD_DELIVER_PROXY); 416898Skais } 417898Skais } 418898Skais } 419898Skais 420898Skais ssl->activeinput = B_TRUE; 421898Skais /* Accumulate at least one record */ 422898Skais if (mp != NULL) { 423898Skais KSSL_ENQUEUE_MP(ssl, mp); 424898Skais mp = NULL; 425898Skais } 426898Skais recmp = kssl_get_next_record(ssl); 427898Skais 428898Skais if (recmp == NULL) { 429898Skais ssl->activeinput = B_FALSE; 430898Skais if (ssl->alert_sendbuf != NULL) { 4315850Svk199839 DTRACE_PROBE(kssl_err__alert_to_send); 432898Skais goto sendalert; 433898Skais } 434898Skais /* Not even a complete header yet. wait for the rest */ 435898Skais mutex_exit(&ssl->kssl_lock); 436898Skais return (KSSL_CMD_NONE); 437898Skais } 438898Skais 439898Skais do { 4405850Svk199839 DTRACE_PROBE1(kssl_mblk__kssl_input_cycle, mblk_t *, recmp); 4414556Svk199839 content_type = (SSL3ContentType)recmp->b_rptr[0]; 4424556Svk199839 4434556Svk199839 switch (content_type) { 4444556Svk199839 case content_application_data: 445898Skais /* 446898Skais * application_data records are decrypted and 447898Skais * MAC-verified by the stream head, and in the context 448898Skais * a read()'ing thread. This avoids unfairly charging 449898Skais * the cost of handling this record on the whole system, 450898Skais * and prevents doing it while in the shared IP 451898Skais * perimeter. 452898Skais */ 453898Skais ssl->activeinput = B_FALSE; 454898Skais if (ssl->hs_waitstate != idle_handshake) { 4555850Svk199839 DTRACE_PROBE(kssl_err__waitstate_not_idle); 456898Skais goto sendnewalert; 457898Skais } 458898Skais outmp = recmp; 459898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 4604556Svk199839 break; 4614556Svk199839 case content_change_cipher_spec: 4624556Svk199839 case content_alert: 4634556Svk199839 case content_handshake: 4644556Svk199839 case content_handshake_v2: 465898Skais /* 466898Skais * If we're past the initial handshake, start letting 467898Skais * the stream head process all records, in particular 468898Skais * the close_notify. 469898Skais * This is needed to avoid processing them out of 470898Skais * sequence when previous application data packets are 471898Skais * waiting to be decrypted/MAC'ed and delivered. 472898Skais */ 473898Skais if (ssl->hs_waitstate == idle_handshake) { 474898Skais ssl->activeinput = B_FALSE; 475898Skais outmp = recmp; 476898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 477898Skais } else { 478898Skais kssl_cmd = kssl_handle_any_record(ssl, recmp, 479898Skais &outmp, cbfn, arg); 480898Skais } 4814556Svk199839 break; 4824556Svk199839 default: 4834556Svk199839 ssl->activeinput = B_FALSE; 4845850Svk199839 DTRACE_PROBE(kssl_err__invalid_content_type); 4854556Svk199839 goto sendnewalert; 486898Skais } 487898Skais 488898Skais /* Priority to Alert messages */ 489898Skais if (ssl->alert_sendbuf != NULL) { 4905850Svk199839 DTRACE_PROBE(kssl_err__alert_to_send_cycle); 491898Skais goto sendalert; 492898Skais } 493898Skais 494898Skais /* Then handshake messages */ 495898Skais if (ssl->handshake_sendbuf) { 496898Skais if (*decrmp != NULL) { 497898Skais linkb(*decrmp, ssl->handshake_sendbuf); 498898Skais } else { 499898Skais *decrmp = ssl->handshake_sendbuf; 500898Skais } 501898Skais ssl->handshake_sendbuf = NULL; 502898Skais 503898Skais *more = ((ssl->rec_ass_head != NULL) && 504898Skais (!ssl->activeinput)); 505898Skais mutex_exit(&ssl->kssl_lock); 506898Skais return (kssl_cmd); 507898Skais } 508898Skais 509898Skais if (ssl->hs_waitstate == idle_handshake) { 510898Skais *more = ((ssl->rec_ass_head != NULL) && 511898Skais (!ssl->activeinput)); 512898Skais } 513898Skais 514898Skais if (outmp != NULL) { 515898Skais *decrmp = outmp; 516898Skais /* 517898Skais * Don't process any packet after an application_data. 518898Skais * We could well receive the close_notify which should 519898Skais * be handled separately. 520898Skais */ 521898Skais mutex_exit(&ssl->kssl_lock); 522898Skais return (kssl_cmd); 523898Skais } 524898Skais /* 525898Skais * The current record isn't done yet. Don't start the next one 526898Skais */ 527898Skais if (ssl->activeinput) { 528898Skais mutex_exit(&ssl->kssl_lock); 529898Skais return (kssl_cmd); 530898Skais } 531898Skais } while ((recmp = kssl_get_next_record(ssl)) != NULL); 532898Skais 533898Skais mutex_exit(&ssl->kssl_lock); 534898Skais return (kssl_cmd); 535898Skais 536898Skais sendnewalert: 537898Skais kssl_send_alert(ssl, alert_fatal, unexpected_message); 538898Skais if (mp != NULL) { 539898Skais freeb(mp); 540898Skais } 541898Skais 542898Skais sendalert: 543898Skais *decrmp = ssl->alert_sendbuf; 544898Skais ssl->alert_sendbuf = NULL; 545898Skais mutex_exit(&ssl->kssl_lock); 546898Skais return (KSSL_CMD_SEND); 547898Skais } 548898Skais 549898Skais /* 5505850Svk199839 * Process mblk b_cont chain returned from stream head. The chain could 5515850Svk199839 * contain a mixture (albeit continuous) of processed and unprocessed 5525850Svk199839 * mblks. This situation could happen when more data was available in 5535850Svk199839 * stream head queue than requested. In such case the rest of processed 5545850Svk199839 * data would be putback(). 5555850Svk199839 * 5565850Svk199839 * Processed mblks in this function contain either a full or partial portion 5575850Svk199839 * of a decrypted and verified SSL record. The former case is produced 5585850Svk199839 * by the function itself, the latter case is explained above. 5595850Svk199839 * 5605850Svk199839 * In case of unprocessed mblks, decrypt and verify the MAC of an incoming 5615850Svk199839 * chain of application_data record. Each block has exactly one SSL record. 5625850Svk199839 * This routine recycles incoming mblks, and flags them as DBLK_COOKED. 563898Skais */ 564898Skais kssl_cmd_t 5655850Svk199839 kssl_handle_mblk(kssl_ctx_t ctx, mblk_t **mpp, mblk_t **outmp) 566898Skais { 567898Skais uchar_t *recend, *rec_sz_p; 568898Skais uchar_t *real_recend; 5691139Skais mblk_t *prevmp = NULL, *nextmp, *firstmp, *mp, *copybp; 570898Skais int mac_sz; 571898Skais uchar_t version[2]; 572898Skais uint16_t rec_sz; 573898Skais SSL3AlertDescription desc; 574898Skais SSL3ContentType content_type; 575898Skais ssl_t *ssl; 576898Skais KSSLCipherSpec *spec; 577898Skais int error = 0, ret; 578898Skais kssl_cmd_t kssl_cmd = KSSL_CMD_DELIVER_PROXY; 579898Skais boolean_t deliverit = B_FALSE; 580898Skais crypto_data_t cipher_data; 581898Skais 582898Skais ASSERT(ctx != NULL); 583898Skais 584898Skais ssl = (ssl_t *)(ctx); 585898Skais 5861139Skais mp = firstmp = *mpp; 587898Skais *outmp = NULL; 588898Skais 5895850Svk199839 /* 5905850Svk199839 * Skip over already processed mblks. This prevents a case where 5915850Svk199839 * struiocopyout() copies unprocessed data to userland. 5925850Svk199839 */ 5935850Svk199839 while ((mp != NULL) && (DB_FLAGS(mp) & DBLK_COOKED)) { 5945850Svk199839 ASSERT(DB_TYPE(mp) == M_DATA); 5955850Svk199839 DTRACE_PROBE1(kssl_mblk__already_processed_mblk, mblk_t *, mp); 5965850Svk199839 mp = mp->b_cont; 5975850Svk199839 } 5985850Svk199839 599898Skais more: 600898Skais 601898Skais while (mp != NULL) { 6025850Svk199839 /* only unprocessed mblks should reach us */ 6035850Svk199839 ASSERT(DB_TYPE(mp) == M_DATA); 6045850Svk199839 ASSERT(!(DB_FLAGS(mp) & DBLK_COOKED)); 605898Skais 606898Skais if (DB_REF(mp) > 1) { 607898Skais /* 608898Skais * Fortunately copyb() preserves the offset, 609898Skais * tail space and alignement so the copy is 610898Skais * ready to be made an SSL record. 611898Skais */ 612898Skais if ((copybp = copyb(mp)) == NULL) 613898Skais return (NULL); 614898Skais 615898Skais copybp->b_cont = mp->b_cont; 6161139Skais if (mp == firstmp) { 617898Skais *mpp = copybp; 6184556Svk199839 } else if (prevmp != NULL) { 619898Skais prevmp->b_cont = copybp; 620898Skais } 621898Skais freeb(mp); 622898Skais mp = copybp; 623898Skais } 624898Skais 6255850Svk199839 DTRACE_PROBE1(kssl_mblk__handle_record_cycle, mblk_t *, mp); 626898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 627898Skais 6284556Svk199839 switch (content_type) { 6294556Svk199839 case content_application_data: 6304556Svk199839 break; 6314556Svk199839 case content_change_cipher_spec: 6324556Svk199839 case content_alert: 6334556Svk199839 case content_handshake: 6344556Svk199839 case content_handshake_v2: 635898Skais nextmp = mp->b_cont; 636898Skais 637898Skais /* Remove this message */ 638898Skais if (prevmp != NULL) { 639898Skais prevmp->b_cont = nextmp; 640898Skais 641898Skais /* 642898Skais * If we had processed blocks that need to 643898Skais * be delivered, then remember that error code 644898Skais */ 645898Skais if (kssl_cmd == KSSL_CMD_DELIVER_PROXY) 646898Skais deliverit = B_TRUE; 647898Skais } 648898Skais 649898Skais mutex_enter(&ssl->kssl_lock); 6504556Svk199839 /* NOTE: This routine could free mp. */ 651898Skais kssl_cmd = kssl_handle_any_record(ssl, mp, outmp, 652898Skais NULL, NULL); 653898Skais 654898Skais if (ssl->alert_sendbuf != NULL) { 6554556Svk199839 mp = nextmp; 6565850Svk199839 DTRACE_PROBE(kssl_err__alert_after_handle_any); 657898Skais goto sendalert; 658898Skais } 659898Skais mutex_exit(&ssl->kssl_lock); 660898Skais 661898Skais if (deliverit) { 662898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 663898Skais } 664898Skais 665898Skais mp = nextmp; 6664556Svk199839 continue; /* to the while loop */ 6674556Svk199839 default: 6684556Svk199839 desc = decode_error; 6694556Svk199839 KSSL_COUNTER(internal_errors, 1); 6705850Svk199839 DTRACE_PROBE(kssl_err__decode_error); 6714556Svk199839 goto makealert; 672898Skais } 673898Skais 674898Skais version[0] = mp->b_rptr[1]; 675898Skais version[1] = mp->b_rptr[2]; 676898Skais rec_sz_p = SSL3_REC_SIZE(mp); 677898Skais rec_sz = BE16_TO_U16(rec_sz_p); 678898Skais 679898Skais mp->b_rptr += SSL3_HDR_LEN; 680898Skais recend = mp->b_rptr + rec_sz; 681898Skais real_recend = recend; 682898Skais 6834556Svk199839 /* 6844556Svk199839 * Check the assumption that each mblk contains exactly 6854556Svk199839 * one complete SSL record. We bail out if the check fails. 6864556Svk199839 */ 6874556Svk199839 ASSERT(recend == mp->b_wptr); 6884556Svk199839 if (recend != mp->b_wptr) { 6894556Svk199839 desc = decode_error; 6904556Svk199839 KSSL_COUNTER(internal_errors, 1); 6915850Svk199839 DTRACE_PROBE(kssl_err__not_complete_record); 6924556Svk199839 goto makealert; 6934556Svk199839 } 6944556Svk199839 695898Skais spec = &ssl->spec[KSSL_READ]; 696898Skais mac_sz = spec->mac_hashsz; 697898Skais if (spec->cipher_ctx != 0) { 6981139Skais 6991139Skais /* 7001139Skais * The record length must be a multiple of the 7011139Skais * block size for block ciphers. 7021139Skais * The cipher_bsize is always a power of 2. 7031139Skais */ 7041139Skais if ((spec->cipher_type == type_block) && 7051139Skais ((rec_sz & (spec->cipher_bsize - 1)) != 0)) { 7065850Svk199839 DTRACE_PROBE2(kssl_err__bad_record_size, 7075850Svk199839 uint16_t, rec_sz, 7085850Svk199839 int, spec->cipher_bsize); 7091139Skais KSSL_COUNTER(record_decrypt_failure, 1); 7101139Skais mp->b_rptr = recend; 7111139Skais desc = decrypt_error; 7121139Skais goto makealert; 7131139Skais } 7141139Skais 715898Skais cipher_data.cd_format = CRYPTO_DATA_RAW; 716898Skais cipher_data.cd_offset = 0; 717898Skais cipher_data.cd_length = rec_sz; 718898Skais cipher_data.cd_miscdata = NULL; 719898Skais cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; 720898Skais cipher_data.cd_raw.iov_len = rec_sz; 721898Skais error = crypto_decrypt_update(spec->cipher_ctx, 722898Skais &cipher_data, NULL, NULL); 723898Skais if (CRYPTO_ERR(error)) { 7245850Svk199839 DTRACE_PROBE1( 7255850Svk199839 kssl_err__crypto_decrypt_update_failed, 7265850Svk199839 int, error); 727898Skais KSSL_COUNTER(record_decrypt_failure, 1); 728898Skais mp->b_rptr = recend; 729898Skais desc = decrypt_error; 730898Skais goto makealert; 731898Skais } 732898Skais } 733898Skais if (spec->cipher_type == type_block) { 734898Skais uint_t pad_sz = recend[-1]; 735898Skais pad_sz++; 736898Skais if (pad_sz + mac_sz > rec_sz) { 7375850Svk199839 DTRACE_PROBE(kssl_err__pad_mac_bigger); 738898Skais mp->b_rptr = recend; 739898Skais desc = bad_record_mac; 740898Skais goto makealert; 741898Skais } 742898Skais rec_sz -= pad_sz; 743898Skais recend -= pad_sz; 744898Skais } 745898Skais if (mac_sz != 0) { 746898Skais uchar_t hash[MAX_HASH_LEN]; 747898Skais if (rec_sz < mac_sz) { 7485850Svk199839 DTRACE_PROBE(kssl_err__pad_smaller_mac); 749898Skais mp->b_rptr = real_recend; 750898Skais desc = bad_record_mac; 751898Skais goto makealert; 752898Skais } 753898Skais rec_sz -= mac_sz; 754898Skais recend -= mac_sz; 755898Skais ret = kssl_compute_record_mac(ssl, KSSL_READ, 7565850Svk199839 ssl->seq_num[KSSL_READ], content_type, 7575850Svk199839 version, mp->b_rptr, rec_sz, hash); 758898Skais if (ret != CRYPTO_SUCCESS || 759898Skais bcmp(hash, recend, mac_sz)) { 7605850Svk199839 DTRACE_PROBE1(kssl_mblk__MACmismatch_handlerec, 7615850Svk199839 mblk_t *, mp); 762898Skais mp->b_rptr = real_recend; 763898Skais desc = bad_record_mac; 7645850Svk199839 DTRACE_PROBE(kssl_err__msg_MAC_mismatch); 765898Skais KSSL_COUNTER(verify_mac_failure, 1); 766898Skais goto makealert; 767898Skais } 768898Skais ssl->seq_num[KSSL_READ]++; 769898Skais } 770898Skais 771898Skais if (ssl->hs_waitstate != idle_handshake) { 7725850Svk199839 DTRACE_PROBE1(kssl_err__unexpected_msg, 7735850Svk199839 SSL3WaitState, ssl->hs_waitstate); 774898Skais mp->b_rptr = real_recend; 775898Skais desc = unexpected_message; 776898Skais goto makealert; 777898Skais } 778898Skais mp->b_wptr = recend; 779898Skais 7804556Svk199839 DB_FLAGS(mp) |= DBLK_COOKED; 7815850Svk199839 DTRACE_PROBE1(kssl_mblk__dblk_cooked, mblk_t *, mp); 7824556Svk199839 KSSL_COUNTER(appdata_record_ins, 1); 7834556Svk199839 784898Skais prevmp = mp; 785898Skais mp = mp->b_cont; 786898Skais } 787898Skais 788898Skais return (kssl_cmd); 789898Skais 790898Skais makealert: 791898Skais nextmp = mp->b_cont; 792898Skais freeb(mp); 793898Skais mp = nextmp; 794898Skais mutex_enter(&ssl->kssl_lock); 795898Skais kssl_send_alert(ssl, alert_fatal, desc); 796898Skais 797898Skais if (ssl->alert_sendbuf == NULL) { 798898Skais /* internal memory allocation failure. just return. */ 7995850Svk199839 DTRACE_PROBE(kssl_err__alert_msg_alloc_failed); 800898Skais mutex_exit(&ssl->kssl_lock); 801898Skais 802898Skais if (mp) { 803898Skais prevmp = NULL; 804898Skais goto more; 805898Skais } 806898Skais 807898Skais return (KSSL_CMD_NONE); 808898Skais } 809898Skais kssl_cmd = KSSL_CMD_SEND; 810898Skais sendalert: 811898Skais if (*outmp == NULL) { 812898Skais *outmp = ssl->alert_sendbuf; 813898Skais } else { 814898Skais linkb(*outmp, ssl->alert_sendbuf); 815898Skais } 816898Skais ssl->alert_sendbuf = NULL; 817898Skais mutex_exit(&ssl->kssl_lock); 818898Skais 819898Skais if (mp) { 820898Skais prevmp = NULL; 821898Skais goto more; 822898Skais } 823898Skais 824898Skais return (kssl_cmd); 825898Skais } 826898Skais /* 827898Skais * This is the routine that handles incoming SSL records. 828898Skais * When called the first time, with a NULL context, this routine expects 829898Skais * a ClientHello SSL Handshake packet and shall allocate a context 830898Skais * of a new SSL connection. 831898Skais * During the rest of the handshake packets, the routine adjusts the 832898Skais * state of the context according to the record received. 833898Skais * After the ChangeCipherSpec message is received, the routine first 834898Skais * decrypts/authenticated the packet using the key materials in the 835898Skais * connection's context. 836898Skais * The return code tells the caller what to do with the returned packet. 837898Skais */ 838898Skais static kssl_cmd_t 839898Skais kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, 840898Skais kssl_callback_t cbfn, void *arg) 841898Skais { 842898Skais uchar_t *recend, *rec_sz_p; 843898Skais uchar_t version[2]; 844898Skais uchar_t *real_recend, *save_rptr, *save_wptr; 845898Skais int rhsz = SSL3_HDR_LEN; 846898Skais uint16_t rec_sz; 847898Skais int sz; 848898Skais int mac_sz; 849898Skais SSL3AlertDescription desc; 850898Skais SSL3AlertLevel level; 851898Skais SSL3ContentType content_type; 852898Skais ssl_t *ssl; 853898Skais KSSLCipherSpec *spec; 854898Skais int error = 0, ret; 855898Skais 856898Skais ASSERT(ctx != NULL); 857898Skais 858898Skais ssl = (ssl_t *)(ctx); 859898Skais 860898Skais *decrmp = NULL; 861898Skais 862898Skais save_rptr = mp->b_rptr; 863898Skais save_wptr = mp->b_wptr; 864898Skais 865898Skais ASSERT(MUTEX_HELD(&ssl->kssl_lock)); 866898Skais 867898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 868898Skais if (content_type == content_handshake_v2) { 869898Skais if (ssl->hs_waitstate == wait_client_hello) { 870898Skais /* V2 compatible ClientHello */ 871898Skais if (mp->b_rptr[3] == 0x03 && 872898Skais (mp->b_rptr[4] == 0x01 || 8735850Svk199839 mp->b_rptr[4] == 0x00)) { 874898Skais ssl->major_version = version[0] = mp->b_rptr[3]; 875898Skais ssl->minor_version = version[1] = mp->b_rptr[4]; 876898Skais } else { 877898Skais /* We don't support "pure" SSLv2 */ 8785850Svk199839 DTRACE_PROBE(kssl_err__no_SSLv2); 879898Skais desc = protocol_version; 880898Skais goto sendalert; 881898Skais } 882898Skais } 883898Skais rec_sz = (uint16_t)mp->b_rptr[1]; 884898Skais rhsz = 2; 885898Skais } else { 886898Skais ssl->major_version = version[0] = mp->b_rptr[1]; 887898Skais ssl->minor_version = version[1] = mp->b_rptr[2]; 888898Skais rec_sz_p = SSL3_REC_SIZE(mp); 889898Skais rec_sz = BE16_TO_U16(rec_sz_p); 890898Skais } 891898Skais 892898Skais mp->b_rptr += rhsz; 893898Skais recend = mp->b_rptr + rec_sz; 894898Skais real_recend = recend; 895898Skais 8964556Svk199839 /* 8974556Svk199839 * Check the assumption that each mblk contains exactly 8984556Svk199839 * one complete SSL record. We bail out if the check fails. 8994556Svk199839 */ 9004556Svk199839 ASSERT(recend == mp->b_wptr); 9014556Svk199839 if (recend != mp->b_wptr) { 9025850Svk199839 DTRACE_PROBE3(kssl_mblk__handle_any_record_recszerr, 9035850Svk199839 mblk_t *, mp, int, rhsz, int, rec_sz); 9045850Svk199839 DTRACE_PROBE(kssl_err__record_size); 9054556Svk199839 desc = decode_error; 9064556Svk199839 KSSL_COUNTER(internal_errors, 1); 9074556Svk199839 goto sendalert; 9084556Svk199839 } 9094556Svk199839 910898Skais spec = &ssl->spec[KSSL_READ]; 911898Skais mac_sz = spec->mac_hashsz; 912898Skais if (spec->cipher_ctx != 0) { 9131139Skais /* 9141139Skais * The record length must be a multiple of the 9151139Skais * block size for block ciphers. 9161139Skais */ 9171139Skais if ((spec->cipher_type == type_block) && 9181139Skais ((rec_sz & (spec->cipher_bsize - 1)) != 0)) { 9195850Svk199839 DTRACE_PROBE2(kssl_err__bad_record_size, 9205850Svk199839 uint16_t, rec_sz, int, spec->cipher_bsize); 9211139Skais KSSL_COUNTER(record_decrypt_failure, 1); 9221139Skais mp->b_rptr = recend; 9231139Skais desc = decrypt_error; 9241139Skais goto sendalert; 9251139Skais } 9261139Skais 927898Skais spec->cipher_data.cd_length = rec_sz; 928898Skais spec->cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; 929898Skais spec->cipher_data.cd_raw.iov_len = rec_sz; 930898Skais error = crypto_decrypt_update(spec->cipher_ctx, 931898Skais &spec->cipher_data, NULL, NULL); 932898Skais if (CRYPTO_ERR(error)) { 9335850Svk199839 DTRACE_PROBE1(kssl_err__crypto_decrypt_update_failed, 9345850Svk199839 int, error); 935898Skais KSSL_COUNTER(record_decrypt_failure, 1); 936898Skais mp->b_rptr = recend; 937898Skais desc = decrypt_error; 938898Skais goto sendalert; 939898Skais } 940898Skais } 941898Skais if (spec->cipher_type == type_block) { 942898Skais uint_t pad_sz = recend[-1]; 943898Skais pad_sz++; 944898Skais if (pad_sz + mac_sz > rec_sz) { 9455850Svk199839 DTRACE_PROBE2(kssl_err__pad_mac_mismatch, 9465850Svk199839 int, pad_sz, int, mac_sz); 947898Skais mp->b_rptr = recend; 948898Skais desc = bad_record_mac; 949898Skais goto sendalert; 950898Skais } 951898Skais rec_sz -= pad_sz; 952898Skais recend -= pad_sz; 953898Skais } 954898Skais if (mac_sz != 0) { 955898Skais uchar_t hash[MAX_HASH_LEN]; 956898Skais if (rec_sz < mac_sz) { 9575850Svk199839 DTRACE_PROBE1(kssl_err__mac_size_too_big, 9585850Svk199839 int, mac_sz); 959898Skais mp->b_rptr = real_recend; 960898Skais desc = bad_record_mac; 961898Skais goto sendalert; 962898Skais } 963898Skais rec_sz -= mac_sz; 964898Skais recend -= mac_sz; 965898Skais ret = kssl_compute_record_mac(ssl, KSSL_READ, 9665850Svk199839 ssl->seq_num[KSSL_READ], content_type, 9675850Svk199839 version, mp->b_rptr, rec_sz, hash); 968898Skais if (ret != CRYPTO_SUCCESS || 969898Skais bcmp(hash, recend, mac_sz)) { 9705850Svk199839 DTRACE_PROBE1(kssl_mblk__MACmismatch_anyrecord, 9715850Svk199839 mblk_t *, mp); 972898Skais mp->b_rptr = real_recend; 973898Skais desc = bad_record_mac; 9745850Svk199839 DTRACE_PROBE(kssl_err__msg_MAC_mismatch); 975898Skais KSSL_COUNTER(verify_mac_failure, 1); 976898Skais goto sendalert; 977898Skais } 978898Skais ssl->seq_num[KSSL_READ]++; 9795850Svk199839 DTRACE_PROBE1(kssl_mblk__after_compute_MAC, 9805850Svk199839 mblk_t *, mp); 981898Skais } 982898Skais 983898Skais switch (content_type) { 984898Skais case content_handshake: 985898Skais do { 9865850Svk199839 DTRACE_PROBE1(kssl_mblk__content_handshake_cycle, 9875850Svk199839 mblk_t *, mp); 988898Skais if (error != 0 || 989898Skais /* ignore client renegotiation for now */ 990898Skais ssl->hs_waitstate == idle_handshake) { 991898Skais mp->b_rptr = recend; 992898Skais } 993898Skais if (mp->b_rptr == recend) { 994898Skais mp->b_rptr = real_recend; 995898Skais if (error != 0) { 996898Skais goto error; 997898Skais } 998898Skais freeb(mp); 999898Skais 1000898Skais if (ssl->hs_waitstate == wait_client_key_done) 1001898Skais return (KSSL_CMD_QUEUED); 1002898Skais 1003898Skais return ((ssl->handshake_sendbuf != NULL) ? 1004898Skais KSSL_CMD_SEND : KSSL_CMD_NONE); 1005898Skais } 1006898Skais if (ssl->msg.state < MSG_BODY) { 1007898Skais if (ssl->msg.state == MSG_INIT) { 1008898Skais ssl->msg.type = 1009898Skais (SSL3HandshakeType)*mp->b_rptr++; 1010898Skais ssl->msg.state = MSG_INIT_LEN; 1011898Skais } 1012898Skais if (ssl->msg.state == MSG_INIT_LEN) { 1013898Skais int msglenb = 1014898Skais ssl->msg.msglen_bytes; 1015898Skais int msglen = ssl->msg.msglen; 1016898Skais while (mp->b_rptr < recend && 1017898Skais msglenb < 3) { 1018898Skais msglen = (msglen << 8) + 1019898Skais (uint_t)(*mp->b_rptr++); 1020898Skais msglenb++; 1021898Skais } 1022898Skais ssl->msg.msglen_bytes = msglenb; 1023898Skais ssl->msg.msglen = msglen; 1024898Skais if (msglenb == 3) { 1025898Skais ssl->msg.state = MSG_BODY; 1026898Skais } 1027898Skais } 1028898Skais if (mp->b_rptr == recend) { 1029898Skais mp->b_rptr = real_recend; 1030898Skais freeb(mp); 1031898Skais return (KSSL_CMD_NONE); 1032898Skais } 1033898Skais } 1034898Skais ASSERT(ssl->msg.state == MSG_BODY); 1035898Skais 1036898Skais sz = recend - mp->b_rptr; 1037898Skais 1038898Skais if (ssl->msg.head == NULL && 1039898Skais ssl->msg.msglen <= sz) { 1040898Skais continue; 1041898Skais } 1042898Skais if (ssl->msg.head != NULL) { 1043898Skais sz += msgdsize(ssl->msg.head); 1044898Skais if (ssl->msg.msglen <= sz) { 1045898Skais ssl->msg.tail->b_cont = mp; 1046898Skais mp = ssl->msg.head; 1047898Skais ssl->sslcnt = 100; 1048898Skais ssl->msg.head = NULL; 1049898Skais ssl->msg.tail = NULL; 1050898Skais if (pullupmsg(mp, -1)) { 1051898Skais recend = mp->b_rptr + sz; 1052898Skais ASSERT(recend <= mp->b_wptr); 1053898Skais continue; 1054898Skais } 1055898Skais mp->b_rptr = real_recend; 1056898Skais error = ENOMEM; 1057898Skais KSSL_COUNTER(alloc_fails, 1); 1058898Skais goto error; 1059898Skais } 1060898Skais } 1061898Skais 1062898Skais mp->b_wptr = recend; 1063898Skais 1064898Skais if (ssl->msg.head == NULL) { 1065898Skais ssl->msg.head = mp; 1066898Skais ssl->msg.tail = mp; 1067898Skais return (KSSL_CMD_NONE); 1068898Skais } else { 1069898Skais ssl->msg.tail->b_cont = mp; 1070898Skais ssl->msg.tail = mp; 1071898Skais return (KSSL_CMD_NONE); 1072898Skais } 1073898Skais } while (kssl_handle_handshake_message(ssl, mp, &error, cbfn, 1074898Skais arg)); 1075898Skais if (error == SSL_MISS) { 1076898Skais mp->b_rptr = save_rptr; 1077898Skais mp->b_wptr = save_wptr; 1078898Skais KSSL_COUNTER(fallback_connections, 1); 1079898Skais return (KSSL_CMD_NOT_SUPPORTED); 1080898Skais } 1081898Skais if (ssl->hs_waitstate == wait_client_key_done) { 1082898Skais return (KSSL_CMD_QUEUED); 1083898Skais } else { 1084898Skais return (KSSL_CMD_NONE); 1085898Skais } 1086898Skais case content_alert: 10875850Svk199839 DTRACE_PROBE1(kssl_mblk__content_alert, mblk_t *, mp); 1088898Skais if (rec_sz != 2) { 10895850Svk199839 DTRACE_PROBE(kssl_err__illegal_param); 1090898Skais mp->b_rptr = real_recend; 1091898Skais desc = illegal_parameter; 1092898Skais goto sendalert; 1093898Skais } else { 1094898Skais level = *mp->b_rptr++; 1095898Skais desc = *mp->b_rptr++; 1096898Skais mp->b_rptr = real_recend; 1097898Skais if (level != alert_warning || desc != close_notify) { 1098898Skais if (ssl->sid.cached == B_TRUE) { 1099898Skais kssl_uncache_sid(&ssl->sid, 1100898Skais ssl->kssl_entry); 1101898Skais ssl->sid.cached = B_FALSE; 1102898Skais } 11035850Svk199839 DTRACE_PROBE2(kssl_err__bad_content_alert, 11045850Svk199839 SSL3AlertLevel, level, 11055850Svk199839 SSL3AlertDescription, desc); 1106898Skais ssl->fatal_alert = B_TRUE; 1107898Skais error = EBADMSG; 1108898Skais goto error; 1109898Skais } else { 1110898Skais ssl->close_notify = B_TRUE; 1111898Skais ssl->activeinput = B_FALSE; 1112898Skais freeb(mp); 1113898Skais return (KSSL_CMD_NONE); 1114898Skais } 1115898Skais } 1116898Skais case content_change_cipher_spec: 11175850Svk199839 DTRACE_PROBE1(kssl_mblk__change_cipher_spec, 11185850Svk199839 mblk_t *, mp); 1119898Skais if (ssl->hs_waitstate != wait_change_cipher) { 1120898Skais desc = unexpected_message; 1121898Skais } else if (rec_sz != 1 || *mp->b_rptr != 1) { 1122898Skais desc = illegal_parameter; 1123898Skais } else { 1124898Skais mp->b_rptr = real_recend; 1125898Skais ssl->hs_waitstate = wait_finished; 1126898Skais ssl->seq_num[KSSL_READ] = 0; 1127898Skais if ((error = kssl_spec_init(ssl, KSSL_READ)) != 0) { 11285850Svk199839 DTRACE_PROBE1(kssl_err__kssl_spec_init_error, 11295850Svk199839 int, error); 1130898Skais goto error; 1131898Skais } 1132898Skais ssl->activeinput = B_FALSE; 1133898Skais freeb(mp); 1134898Skais return (KSSL_CMD_NONE); 1135898Skais } 1136898Skais mp->b_rptr = real_recend; 11375850Svk199839 DTRACE_PROBE(kssl_err__change_cipher_spec); 1138898Skais goto sendalert; 1139898Skais 1140898Skais case content_application_data: 11415850Svk199839 DTRACE_PROBE1(kssl_mblk__content_app_data, 11425850Svk199839 mblk_t *, mp); 1143898Skais if (ssl->hs_waitstate != idle_handshake) { 11445850Svk199839 DTRACE_PROBE(kssl_err__content_app_data); 1145898Skais mp->b_rptr = real_recend; 1146898Skais desc = unexpected_message; 1147898Skais goto sendalert; 1148898Skais } 1149898Skais mp->b_wptr = recend; 1150898Skais *decrmp = mp; 1151898Skais ssl->activeinput = B_FALSE; 1152898Skais return (KSSL_CMD_DELIVER_PROXY); 1153898Skais 1154898Skais case content_handshake_v2: 11555850Svk199839 DTRACE_PROBE1(kssl_mblk__content_handshake_v2, 11565850Svk199839 mblk_t *, mp); 1157898Skais error = kssl_handle_v2client_hello(ssl, mp, rec_sz); 1158898Skais if (error == SSL_MISS) { 1159898Skais mp->b_rptr = save_rptr; 1160898Skais mp->b_wptr = save_wptr; 1161898Skais KSSL_COUNTER(fallback_connections, 1); 1162898Skais return (KSSL_CMD_NOT_SUPPORTED); 1163898Skais } else if (error != 0) { 11645850Svk199839 DTRACE_PROBE(kssl_err__v2client_hello_failed); 1165898Skais goto error; 1166898Skais } 1167898Skais freeb(mp); 1168898Skais return (KSSL_CMD_SEND); 1169898Skais default: 11705850Svk199839 DTRACE_PROBE1(kssl_mblk__unexpected_msg, 11715850Svk199839 mblk_t *, mp); 1172898Skais mp->b_rptr = real_recend; 1173898Skais desc = unexpected_message; 1174898Skais break; 1175898Skais } 1176898Skais 1177898Skais sendalert: 1178898Skais kssl_send_alert(ssl, alert_fatal, desc); 1179898Skais *decrmp = ssl->alert_sendbuf; 1180898Skais ssl->alert_sendbuf = NULL; 1181898Skais freeb(mp); 1182898Skais return ((*decrmp != NULL) ? KSSL_CMD_SEND : KSSL_CMD_NONE); 1183898Skais error: 1184898Skais freeb(mp); 1185898Skais return (KSSL_CMD_NONE); 1186898Skais } 1187898Skais 1188898Skais /* 1189898Skais * Initialize the context of an SSL connection, coming to the specified 1190898Skais * address. 1191898Skais * the ssl structure returned is held. 1192898Skais */ 1193898Skais kssl_status_t 1194898Skais kssl_init_context(kssl_ent_t kssl_ent, ipaddr_t faddr, int mss, 1195898Skais kssl_ctx_t *kssl_ctxp) 1196898Skais { 1197898Skais ssl_t *ssl = kmem_cache_alloc(kssl_cache, KM_NOSLEEP); 1198898Skais 1199898Skais if (ssl == NULL) { 1200898Skais return (KSSL_STS_ERR); 1201898Skais } 1202898Skais 1203898Skais kssl_cache_count++; 1204898Skais 1205898Skais bzero(ssl, sizeof (ssl_t)); 1206898Skais 1207898Skais ssl->kssl_entry = (kssl_entry_t *)kssl_ent; 1208898Skais KSSL_ENTRY_REFHOLD(ssl->kssl_entry); 1209898Skais 1210898Skais ssl->faddr = faddr; 1211898Skais ssl->tcp_mss = mss; 1212898Skais ssl->sendalert_level = alert_warning; 1213898Skais ssl->sendalert_desc = close_notify; 1214898Skais ssl->sid.cached = B_FALSE; 1215898Skais 1216898Skais *kssl_ctxp = (kssl_ctx_t)ssl; 1217898Skais KSSL_SSL_REFHOLD(ssl); 1218898Skais return (KSSL_STS_OK); 1219898Skais } 1220898Skais 1221898Skais /* 1222898Skais * Builds SSL records out of the chain of mblks, and returns it. 1223898Skais * Taked a copy of the message before encypting it if it has another 1224898Skais * reference. 1225898Skais * In case of failure, NULL is returned, and the message will be 1226898Skais * freed by the caller. 1227898Skais * A NULL mp means a close_notify is requested. 1228898Skais */ 1229898Skais mblk_t * 1230898Skais kssl_build_record(kssl_ctx_t ctx, mblk_t *mp) 1231898Skais { 1232898Skais ssl_t *ssl = (ssl_t *)ctx; 1233898Skais mblk_t *retmp = mp, *bp = mp, *prevbp = mp, *copybp; 1234898Skais 1235898Skais ASSERT(ssl != NULL); 1236898Skais ASSERT(mp != NULL); 1237898Skais 1238898Skais do { 1239898Skais if (DB_REF(bp) > 1) { 1240898Skais /* 1241898Skais * Fortunately copyb() preserves the offset, 1242898Skais * tail space and alignement so the copy is 1243898Skais * ready to be made an SSL record. 1244898Skais */ 1245898Skais if ((copybp = copyb(bp)) == NULL) 1246898Skais return (NULL); 1247898Skais 1248898Skais copybp->b_cont = bp->b_cont; 1249898Skais if (bp == mp) { 1250898Skais retmp = copybp; 1251898Skais } else { 1252898Skais prevbp->b_cont = copybp; 1253898Skais } 1254898Skais freeb(bp); 1255898Skais bp = copybp; 1256898Skais } 1257898Skais 1258898Skais if (kssl_build_single_record(ssl, bp) != KSSL_STS_OK) 1259898Skais return (NULL); 1260898Skais 1261898Skais prevbp = bp; 1262898Skais bp = bp->b_cont; 1263898Skais } while (bp != NULL); 1264898Skais 1265898Skais return (retmp); 1266898Skais } 1267898Skais 1268898Skais /* 1269898Skais * Builds a single SSL record 1270898Skais * In-line encryption of the record. 1271898Skais */ 1272898Skais static kssl_status_t 1273898Skais kssl_build_single_record(ssl_t *ssl, mblk_t *mp) 1274898Skais { 1275898Skais int len; 1276898Skais int reclen = 0; 1277898Skais uchar_t *recstart, *versionp; 1278898Skais KSSLCipherSpec *spec; 1279898Skais int mac_sz; 1280898Skais int pad_sz = 0; 1281898Skais 1282898Skais 1283898Skais spec = &ssl->spec[KSSL_WRITE]; 1284898Skais mac_sz = spec->mac_hashsz; 1285898Skais 1286898Skais 1287898Skais ASSERT(DB_REF(mp) == 1); 1288898Skais ASSERT((mp->b_rptr - mp->b_datap->db_base >= SSL3_HDR_LEN) && 1289898Skais (mp->b_datap->db_lim - mp->b_wptr >= mac_sz + spec->cipher_bsize)); 1290898Skais 1291898Skais len = MBLKL(mp); 1292898Skais 1293898Skais ASSERT(len > 0); 1294898Skais 1295898Skais mutex_enter(&ssl->kssl_lock); 1296898Skais 1297898Skais recstart = mp->b_rptr = mp->b_rptr - SSL3_HDR_LEN; 1298898Skais recstart[0] = content_application_data; 1299898Skais recstart[1] = ssl->major_version; 1300898Skais recstart[2] = ssl->minor_version; 1301898Skais versionp = &recstart[1]; 1302898Skais 1303898Skais reclen = len + mac_sz; 1304898Skais if (spec->cipher_type == type_block) { 1305898Skais pad_sz = spec->cipher_bsize - 1306898Skais (reclen & (spec->cipher_bsize - 1)); 1307898Skais ASSERT(reclen + pad_sz <= 1308898Skais SSL3_MAX_RECORD_LENGTH); 1309898Skais reclen += pad_sz; 1310898Skais } 1311898Skais recstart[3] = (reclen >> 8) & 0xff; 1312898Skais recstart[4] = reclen & 0xff; 1313898Skais 1314898Skais if (kssl_mac_encrypt_record(ssl, content_application_data, versionp, 1315898Skais recstart, mp) != 0) { 1316898Skais /* Do we need an internal_error Alert here? */ 1317898Skais mutex_exit(&ssl->kssl_lock); 1318898Skais return (KSSL_STS_ERR); 1319898Skais } 1320898Skais 1321898Skais KSSL_COUNTER(appdata_record_outs, 1); 1322898Skais mutex_exit(&ssl->kssl_lock); 1323898Skais return (KSSL_STS_OK); 1324898Skais } 1325