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*5850Svk199839 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23898Skais * Use is subject to license terms. 24898Skais */ 25898Skais 26898Skais #pragma ident "%Z%%M% %I% %E% SMI" 27898Skais 28898Skais #include <sys/types.h> 29898Skais #include <sys/stream.h> 30898Skais #include <sys/strsun.h> 31898Skais #include <sys/kmem.h> 32898Skais #include <sys/cpuvar.h> 33898Skais #include <sys/atomic.h> 34898Skais #include <sys/sysmacros.h> 35898Skais 36898Skais #include <inet/common.h> 37898Skais #include <inet/ip.h> 38898Skais #include <inet/ip6.h> 39898Skais 40898Skais #include <sys/systm.h> 41898Skais #include <sys/param.h> 42898Skais #include <sys/tihdr.h> 43898Skais 44898Skais #include "ksslimpl.h" 45898Skais #include "ksslproto.h" 46898Skais #include "ksslapi.h" 47898Skais 48898Skais static kssl_cmd_t kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, 49898Skais mblk_t **decrmp, kssl_callback_t cbfn, void *arg); 50898Skais static boolean_t kssl_enqueue(kssl_chain_t **head, void *item); 51898Skais static void kssl_dequeue(kssl_chain_t **head, void *item); 52898Skais static kssl_status_t kssl_build_single_record(ssl_t *ssl, mblk_t *mp); 53898Skais 54898Skais /* 55898Skais * The socket T_bind_req message is intercepted and re-routed here 56898Skais * to see is there is SSL relevant job to do, based on the kssl config 57898Skais * in the kssl_entry_tab. 58898Skais * Looks up the kernel SSL proxy table, to find an entry that matches the 59898Skais * same serveraddr, and has one of the following two criteria: 60898Skais * 1. in_port is an ssl_port. This endpoint can be used later as a fallback 61898Skais * to complete connections that cannot be handled by the SSL kernel proxy 62898Skais * (typically non supported ciphersuite). The cookie for the calling client 63898Skais * is saved with the kssl_entry to be retrieved for the fallback. 64898Skais * The function returns KSSL_HAS_PROXY. 65898Skais * 66898Skais * 2. in_port is a proxy port for another ssl port. The ssl port is then 67898Skais * substituted to the in_port in the bind_req TPI structure, so that 68898Skais * the bind falls through to the SSL port. At the end of this operation, 69898Skais * all the packets arriving to the SSL port will be delivered to an 70898Skais * accepted endpoint child of this bound socket. 71898Skais * The kssl_entry_t is returned in *ksslent, for later use by the 72898Skais * lower modules' SSL hooks that handle the Handshake messages. 73898Skais * The function returns KSSL_IS_PROXY. 74898Skais * 75898Skais * The function returns KSSL_NO_PROXY otherwise. We do not suppport 76898Skais * IPv6 addresses. 77898Skais */ 78898Skais 79898Skais kssl_endpt_type_t 80898Skais kssl_check_proxy(mblk_t *bindmp, void *cookie, kssl_ent_t *ksslent) 81898Skais { 82898Skais int i; 83898Skais kssl_endpt_type_t ret; 84898Skais kssl_entry_t *ep; 85898Skais sin_t *sin; 86898Skais struct T_bind_req *tbr; 87898Skais ipaddr_t v4addr; 88898Skais in_port_t in_port; 89898Skais 90898Skais if (kssl_enabled == 0) { 91898Skais return (KSSL_NO_PROXY); 92898Skais } 93898Skais 94898Skais tbr = (struct T_bind_req *)bindmp->b_rptr; 95898Skais 96898Skais ret = KSSL_NO_PROXY; 97898Skais 98898Skais 99898Skais switch (tbr->ADDR_length) { 100898Skais case sizeof (sin_t): 101898Skais sin = (sin_t *)(bindmp->b_rptr + tbr->ADDR_length); 102898Skais in_port = ntohs(sin->sin_port); 103898Skais v4addr = sin->sin_addr.s_addr; 104898Skais break; 105898Skais 106898Skais case sizeof (sin6_t): 107898Skais /* Future support of IPv6 goes here */ 108898Skais default: 109898Skais /* Should ASSERT() here? */ 110898Skais return (ret); 111898Skais } 112898Skais 113898Skais mutex_enter(&kssl_tab_mutex); 114898Skais 115898Skais for (i = 0; i < kssl_entry_tab_size; i++) { 116898Skais if ((ep = kssl_entry_tab[i]) == NULL) 117898Skais continue; 118898Skais 119898Skais if ((ep->ke_laddr == v4addr) || (ep->ke_laddr == INADDR_ANY)) { 120898Skais 121898Skais /* This is an SSL port to fallback to */ 122898Skais if (ep->ke_ssl_port == in_port) { 123898Skais 124898Skais /* 125898Skais * Let's see first if there's at least 126898Skais * an endpoint for a proxy server. 127898Skais * If there's none, then we return as we have 128898Skais * no proxy, so that the bind() to the 129898Skais * transport layer goes through. 130898Skais * The calling module will ask for this 131898Skais * cookie if it wants to fall back to it, 132898Skais * so add this one to the list of fallback 133898Skais * clients. 134898Skais */ 135898Skais if (!kssl_enqueue((kssl_chain_t **) 136898Skais &(ep->ke_fallback_head), cookie)) { 137898Skais break; 138898Skais } 139898Skais 140898Skais /* 141898Skais * Now transform the T_BIND_REQ into 142898Skais * a T_BIND_ACK. 143898Skais */ 144898Skais tbr->PRIM_type = T_BIND_ACK; 145898Skais bindmp->b_datap->db_type = M_PCPROTO; 146898Skais 147898Skais KSSL_ENTRY_REFHOLD(ep); 148898Skais *ksslent = (kssl_ent_t)ep; 149898Skais 150898Skais ret = KSSL_HAS_PROXY; 151898Skais break; 152898Skais } 153898Skais 154898Skais /* This is a proxy port. */ 155898Skais if (ep->ke_proxy_port == in_port) { 156898Skais mblk_t *entmp; 157898Skais 158898Skais /* Append this entry to the bind_req mblk */ 159898Skais 160898Skais entmp = allocb(sizeof (kssl_entry_t), 161898Skais BPRI_MED); 162898Skais if (entmp == NULL) 163898Skais break; 164898Skais *((kssl_entry_t **)entmp->b_rptr) = ep; 165898Skais 166898Skais entmp->b_wptr = entmp->b_rptr + 167898Skais sizeof (kssl_entry_t); 168898Skais 169898Skais bindmp->b_cont = entmp; 170898Skais 171898Skais /* Add the caller's cookie to proxies list */ 172898Skais 173898Skais if (!kssl_enqueue((kssl_chain_t **) 174898Skais &(ep->ke_proxy_head), cookie)) { 175898Skais freeb(bindmp->b_cont); 176898Skais bindmp->b_cont = NULL; 177898Skais break; 178898Skais } 179898Skais 180898Skais /* 181898Skais * Make this look like the SSL port to the 182898Skais * transport below 183898Skais */ 184898Skais sin->sin_port = htons(ep->ke_ssl_port); 185898Skais 186898Skais tbr->PRIM_type = T_SSL_PROXY_BIND_REQ; 187898Skais 188898Skais KSSL_ENTRY_REFHOLD(ep); 189898Skais *ksslent = (kssl_ent_t)ep; 190898Skais 191898Skais ret = KSSL_IS_PROXY; 192898Skais break; 193898Skais } 194898Skais } 195898Skais } 196898Skais 197898Skais mutex_exit(&kssl_tab_mutex); 198898Skais return (ret); 199898Skais } 200898Skais 201898Skais /* 202898Skais * Retrieved an endpoint "bound" to the SSL entry. 203898Skais * Such endpoint has previously called kssl_check_proxy(), got itself 204898Skais * linked to the kssl_entry's ke_fallback_head list. 205898Skais * This routine returns the cookie from that SSL entry ke_fallback_head list. 206898Skais */ 207898Skais void * 208898Skais kssl_find_fallback(kssl_ent_t ksslent) 209898Skais { 210898Skais kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; 211898Skais 212898Skais if (kssl_entry->ke_fallback_head != NULL) 213898Skais return (kssl_entry->ke_fallback_head->fallback_bound); 214898Skais 215898Skais KSSL_COUNTER(proxy_fallback_failed, 1); 216898Skais 217898Skais return (NULL); 218898Skais } 219898Skais 220898Skais /* 221898Skais * Re-usable code for adding and removing an element to/from a chain that 222898Skais * matches "item" 223898Skais * The chain is simple-linked and NULL ended. 224898Skais */ 225898Skais 226898Skais /* 227898Skais * This routine returns TRUE if the item was either successfully added to 228898Skais * the chain, or is already there. It returns FALSE otherwise. 229898Skais */ 230898Skais static boolean_t 231898Skais kssl_enqueue(kssl_chain_t **head, void *item) 232898Skais { 233898Skais kssl_chain_t *newchain, *cur; 234898Skais 235898Skais /* Lookup the existing entries to avoid duplicates */ 236898Skais cur = *head; 237898Skais while (cur != NULL) { 238898Skais if (cur->item == item) { 239898Skais return (B_TRUE); 240898Skais } 241898Skais cur = cur->next; 242898Skais } 243898Skais 244898Skais newchain = kmem_alloc(sizeof (kssl_chain_t), KM_NOSLEEP); 245898Skais if (newchain == NULL) { 246898Skais return (B_FALSE); 247898Skais } 248898Skais 249898Skais newchain->item = item; 250898Skais newchain->next = *head; 251898Skais *head = newchain; 252898Skais return (B_TRUE); 253898Skais } 254898Skais 255898Skais static void 256898Skais kssl_dequeue(kssl_chain_t **head, void *item) 257898Skais { 258898Skais kssl_chain_t *prev, *cur; 259898Skais 260898Skais prev = cur = *head; 261898Skais while (cur != NULL) { 262898Skais if (cur->item == item) { 263898Skais if (cur == *head) 264898Skais *head = (*head)->next; 265898Skais else 266898Skais prev->next = cur->next; 267898Skais kmem_free(cur, sizeof (kssl_chain_t)); 268898Skais return; 269898Skais } 270898Skais prev = cur; 271898Skais cur = cur->next; 272898Skais } 273898Skais } 274898Skais 275898Skais /* 276898Skais * Holds the kssl_entry 277898Skais */ 278898Skais void 279898Skais kssl_hold_ent(kssl_ent_t ksslent) 280898Skais { 281898Skais KSSL_ENTRY_REFHOLD((kssl_entry_t *)ksslent); 282898Skais } 283898Skais 284898Skais /* 285898Skais * Releases the kssl_entry 286898Skais * If the caller passes a cookie, then it should be removed from both 287898Skais * proxies and fallbacks chains. 288898Skais */ 289898Skais void 290898Skais kssl_release_ent(kssl_ent_t ksslent, void *cookie, kssl_endpt_type_t endpt_type) 291898Skais { 292898Skais kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; 293898Skais 294898Skais if (cookie != NULL) { 295898Skais if (endpt_type == KSSL_IS_PROXY) 296898Skais ASSERT(kssl_entry->ke_proxy_head != NULL); 297898Skais kssl_dequeue( 298898Skais (kssl_chain_t **)&kssl_entry->ke_proxy_head, 299898Skais cookie); 300898Skais if (endpt_type == KSSL_HAS_PROXY) 301898Skais ASSERT(kssl_entry->ke_fallback_head != NULL); 302898Skais kssl_dequeue( 303898Skais (kssl_chain_t **)&kssl_entry->ke_fallback_head, 304898Skais cookie); 305898Skais } 306898Skais KSSL_ENTRY_REFRELE(kssl_entry); 307898Skais } 308898Skais 309898Skais /* 310898Skais * Holds the kssl context 311898Skais */ 312898Skais void 313898Skais kssl_hold_ctx(kssl_ctx_t ksslctx) 314898Skais { 315898Skais ssl_t *ssl = (ssl_t *)ksslctx; 316898Skais 317898Skais KSSL_SSL_REFHOLD(ssl); 318898Skais } 319898Skais 320898Skais /* 321898Skais * Releases the kssl_context 322898Skais */ 323898Skais void 324898Skais kssl_release_ctx(kssl_ctx_t ksslctx) 325898Skais { 326898Skais KSSL_SSL_REFRELE((ssl_t *)ksslctx); 327898Skais } 328898Skais 329898Skais /* 330898Skais * Packets are accumulated here, if there are packets already queued, 331898Skais * or if the context is active. 332898Skais * The context is active when an incoming record processing function 333898Skais * is already executing on a different thread. 334898Skais * Queued packets are handled either when an mblk arrived and completes 335898Skais * a record, or, when the active context processor finishes the task at 336898Skais * hand. 337898Skais * The caller has to keep calling this routine in a loop until it returns 338898Skais * B_FALSE in *more. The reason for this is SSL3: The protocol 339898Skais * allows the client to send its first application_data message right 340898Skais * after it had sent its Finished message, and not wait for the server 341898Skais * ChangeCipherSpec and Finished. This overlap means we can't batch up 342898Skais * a returned Handshake message to be sent on the wire 343898Skais * with a decrypted application_data to be delivered to the application. 344898Skais */ 345898Skais kssl_cmd_t 346898Skais kssl_input(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, boolean_t *more, 347898Skais kssl_callback_t cbfn, void *arg) 348898Skais { 349898Skais mblk_t *recmp, *outmp = NULL; 350898Skais kssl_cmd_t kssl_cmd; 351898Skais ssl_t *ssl; 352898Skais uint8_t *rec_sz_p; 353898Skais int mplen; 354898Skais SSL3ContentType content_type; 355898Skais uint16_t rec_sz; 356898Skais 357898Skais ASSERT(ctx != NULL); 358898Skais 359898Skais if (mp != NULL) { 360898Skais ASSERT(mp->b_prev == NULL && mp->b_next == NULL); 361898Skais } 362898Skais 363898Skais ssl = (ssl_t *)(ctx); 364898Skais 365898Skais *decrmp = NULL; 366898Skais *more = B_FALSE; 367898Skais 368898Skais mutex_enter(&ssl->kssl_lock); 369898Skais 370898Skais if (ssl->close_notify == B_TRUE) { 371*5850Svk199839 DTRACE_PROBE(kssl_err__close_notify); 372898Skais goto sendnewalert; 373898Skais } 374898Skais 375898Skais /* Whomever is currently processing this connection will get to this */ 376898Skais if (ssl->activeinput) { 377898Skais if (mp != NULL) { 378898Skais KSSL_ENQUEUE_MP(ssl, mp); 379898Skais } 380898Skais mutex_exit(&ssl->kssl_lock); 381898Skais return (KSSL_CMD_NONE); 382898Skais } 383898Skais 384898Skais /* 385898Skais * Fast path for complete incoming application_data records on an empty 386898Skais * queue. 387898Skais * This is by far the most frequently encountered case 388898Skais */ 389898Skais 390898Skais if ((!ssl->activeinput) && (ssl->rec_ass_head == NULL) && 391898Skais ((mp != NULL) && (mplen = MBLKL(mp)) > SSL3_HDR_LEN)) { 392898Skais 393*5850Svk199839 DTRACE_PROBE1(kssl_mblk__fast_path, mblk_t *, mp); 394898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 395898Skais 396898Skais if ((content_type == content_application_data) && 397898Skais (ssl->hs_waitstate == idle_handshake)) { 398898Skais rec_sz_p = SSL3_REC_SIZE(mp); 399898Skais rec_sz = BE16_TO_U16(rec_sz_p); 400898Skais 401898Skais if ((mp->b_cont == NULL) && (mplen == rec_sz)) { 402898Skais 4034859Skrishna DB_FLAGS(mp) &= ~DBLK_COOKED; 404898Skais *decrmp = mp; 405898Skais mutex_exit(&ssl->kssl_lock); 406898Skais return (KSSL_CMD_DELIVER_PROXY); 407898Skais } 408898Skais } 409898Skais } 410898Skais 411898Skais ssl->activeinput = B_TRUE; 412898Skais /* Accumulate at least one record */ 413898Skais if (mp != NULL) { 414898Skais KSSL_ENQUEUE_MP(ssl, mp); 415898Skais mp = NULL; 416898Skais } 417898Skais recmp = kssl_get_next_record(ssl); 418898Skais 419898Skais if (recmp == NULL) { 420898Skais ssl->activeinput = B_FALSE; 421898Skais if (ssl->alert_sendbuf != NULL) { 422*5850Svk199839 DTRACE_PROBE(kssl_err__alert_to_send); 423898Skais goto sendalert; 424898Skais } 425898Skais /* Not even a complete header yet. wait for the rest */ 426898Skais mutex_exit(&ssl->kssl_lock); 427898Skais return (KSSL_CMD_NONE); 428898Skais } 429898Skais 430898Skais do { 431*5850Svk199839 DTRACE_PROBE1(kssl_mblk__kssl_input_cycle, mblk_t *, recmp); 4324556Svk199839 content_type = (SSL3ContentType)recmp->b_rptr[0]; 4334556Svk199839 4344556Svk199839 switch (content_type) { 4354556Svk199839 case content_application_data: 436898Skais /* 437898Skais * application_data records are decrypted and 438898Skais * MAC-verified by the stream head, and in the context 439898Skais * a read()'ing thread. This avoids unfairly charging 440898Skais * the cost of handling this record on the whole system, 441898Skais * and prevents doing it while in the shared IP 442898Skais * perimeter. 443898Skais */ 444898Skais ssl->activeinput = B_FALSE; 445898Skais if (ssl->hs_waitstate != idle_handshake) { 446*5850Svk199839 DTRACE_PROBE(kssl_err__waitstate_not_idle); 447898Skais goto sendnewalert; 448898Skais } 449898Skais outmp = recmp; 450898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 4514556Svk199839 break; 4524556Svk199839 case content_change_cipher_spec: 4534556Svk199839 case content_alert: 4544556Svk199839 case content_handshake: 4554556Svk199839 case content_handshake_v2: 456898Skais /* 457898Skais * If we're past the initial handshake, start letting 458898Skais * the stream head process all records, in particular 459898Skais * the close_notify. 460898Skais * This is needed to avoid processing them out of 461898Skais * sequence when previous application data packets are 462898Skais * waiting to be decrypted/MAC'ed and delivered. 463898Skais */ 464898Skais if (ssl->hs_waitstate == idle_handshake) { 465898Skais ssl->activeinput = B_FALSE; 466898Skais outmp = recmp; 467898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 468898Skais } else { 469898Skais kssl_cmd = kssl_handle_any_record(ssl, recmp, 470898Skais &outmp, cbfn, arg); 471898Skais } 4724556Svk199839 break; 4734556Svk199839 default: 4744556Svk199839 ssl->activeinput = B_FALSE; 475*5850Svk199839 DTRACE_PROBE(kssl_err__invalid_content_type); 4764556Svk199839 goto sendnewalert; 477898Skais } 478898Skais 479898Skais /* Priority to Alert messages */ 480898Skais if (ssl->alert_sendbuf != NULL) { 481*5850Svk199839 DTRACE_PROBE(kssl_err__alert_to_send_cycle); 482898Skais goto sendalert; 483898Skais } 484898Skais 485898Skais /* Then handshake messages */ 486898Skais if (ssl->handshake_sendbuf) { 487898Skais if (*decrmp != NULL) { 488898Skais linkb(*decrmp, ssl->handshake_sendbuf); 489898Skais } else { 490898Skais *decrmp = ssl->handshake_sendbuf; 491898Skais } 492898Skais ssl->handshake_sendbuf = NULL; 493898Skais 494898Skais *more = ((ssl->rec_ass_head != NULL) && 495898Skais (!ssl->activeinput)); 496898Skais mutex_exit(&ssl->kssl_lock); 497898Skais return (kssl_cmd); 498898Skais } 499898Skais 500898Skais if (ssl->hs_waitstate == idle_handshake) { 501898Skais *more = ((ssl->rec_ass_head != NULL) && 502898Skais (!ssl->activeinput)); 503898Skais } 504898Skais 505898Skais if (outmp != NULL) { 506898Skais *decrmp = outmp; 507898Skais /* 508898Skais * Don't process any packet after an application_data. 509898Skais * We could well receive the close_notify which should 510898Skais * be handled separately. 511898Skais */ 512898Skais mutex_exit(&ssl->kssl_lock); 513898Skais return (kssl_cmd); 514898Skais } 515898Skais /* 516898Skais * The current record isn't done yet. Don't start the next one 517898Skais */ 518898Skais if (ssl->activeinput) { 519898Skais mutex_exit(&ssl->kssl_lock); 520898Skais return (kssl_cmd); 521898Skais } 522898Skais } while ((recmp = kssl_get_next_record(ssl)) != NULL); 523898Skais 524898Skais mutex_exit(&ssl->kssl_lock); 525898Skais return (kssl_cmd); 526898Skais 527898Skais sendnewalert: 528898Skais kssl_send_alert(ssl, alert_fatal, unexpected_message); 529898Skais if (mp != NULL) { 530898Skais freeb(mp); 531898Skais } 532898Skais 533898Skais sendalert: 534898Skais *decrmp = ssl->alert_sendbuf; 535898Skais ssl->alert_sendbuf = NULL; 536898Skais mutex_exit(&ssl->kssl_lock); 537898Skais return (KSSL_CMD_SEND); 538898Skais } 539898Skais 540898Skais /* 541*5850Svk199839 * Process mblk b_cont chain returned from stream head. The chain could 542*5850Svk199839 * contain a mixture (albeit continuous) of processed and unprocessed 543*5850Svk199839 * mblks. This situation could happen when more data was available in 544*5850Svk199839 * stream head queue than requested. In such case the rest of processed 545*5850Svk199839 * data would be putback(). 546*5850Svk199839 * 547*5850Svk199839 * Processed mblks in this function contain either a full or partial portion 548*5850Svk199839 * of a decrypted and verified SSL record. The former case is produced 549*5850Svk199839 * by the function itself, the latter case is explained above. 550*5850Svk199839 * 551*5850Svk199839 * In case of unprocessed mblks, decrypt and verify the MAC of an incoming 552*5850Svk199839 * chain of application_data record. Each block has exactly one SSL record. 553*5850Svk199839 * This routine recycles incoming mblks, and flags them as DBLK_COOKED. 554898Skais */ 555898Skais kssl_cmd_t 556*5850Svk199839 kssl_handle_mblk(kssl_ctx_t ctx, mblk_t **mpp, mblk_t **outmp) 557898Skais { 558898Skais uchar_t *recend, *rec_sz_p; 559898Skais uchar_t *real_recend; 5601139Skais mblk_t *prevmp = NULL, *nextmp, *firstmp, *mp, *copybp; 561898Skais int mac_sz; 562898Skais uchar_t version[2]; 563898Skais uint16_t rec_sz; 564898Skais SSL3AlertDescription desc; 565898Skais SSL3ContentType content_type; 566898Skais ssl_t *ssl; 567898Skais KSSLCipherSpec *spec; 568898Skais int error = 0, ret; 569898Skais kssl_cmd_t kssl_cmd = KSSL_CMD_DELIVER_PROXY; 570898Skais boolean_t deliverit = B_FALSE; 571898Skais crypto_data_t cipher_data; 572898Skais 573898Skais ASSERT(ctx != NULL); 574898Skais 575898Skais ssl = (ssl_t *)(ctx); 576898Skais 5771139Skais mp = firstmp = *mpp; 578898Skais *outmp = NULL; 579898Skais 580*5850Svk199839 /* 581*5850Svk199839 * Skip over already processed mblks. This prevents a case where 582*5850Svk199839 * struiocopyout() copies unprocessed data to userland. 583*5850Svk199839 */ 584*5850Svk199839 while ((mp != NULL) && (DB_FLAGS(mp) & DBLK_COOKED)) { 585*5850Svk199839 ASSERT(DB_TYPE(mp) == M_DATA); 586*5850Svk199839 DTRACE_PROBE1(kssl_mblk__already_processed_mblk, mblk_t *, mp); 587*5850Svk199839 mp = mp->b_cont; 588*5850Svk199839 } 589*5850Svk199839 590898Skais more: 591898Skais 592898Skais while (mp != NULL) { 593*5850Svk199839 /* only unprocessed mblks should reach us */ 594*5850Svk199839 ASSERT(DB_TYPE(mp) == M_DATA); 595*5850Svk199839 ASSERT(!(DB_FLAGS(mp) & DBLK_COOKED)); 596898Skais 597898Skais if (DB_REF(mp) > 1) { 598898Skais /* 599898Skais * Fortunately copyb() preserves the offset, 600898Skais * tail space and alignement so the copy is 601898Skais * ready to be made an SSL record. 602898Skais */ 603898Skais if ((copybp = copyb(mp)) == NULL) 604898Skais return (NULL); 605898Skais 606898Skais copybp->b_cont = mp->b_cont; 6071139Skais if (mp == firstmp) { 608898Skais *mpp = copybp; 6094556Svk199839 } else if (prevmp != NULL) { 610898Skais prevmp->b_cont = copybp; 611898Skais } 612898Skais freeb(mp); 613898Skais mp = copybp; 614898Skais } 615898Skais 616*5850Svk199839 DTRACE_PROBE1(kssl_mblk__handle_record_cycle, mblk_t *, mp); 617898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 618898Skais 6194556Svk199839 switch (content_type) { 6204556Svk199839 case content_application_data: 6214556Svk199839 break; 6224556Svk199839 case content_change_cipher_spec: 6234556Svk199839 case content_alert: 6244556Svk199839 case content_handshake: 6254556Svk199839 case content_handshake_v2: 626898Skais nextmp = mp->b_cont; 627898Skais 628898Skais /* Remove this message */ 629898Skais if (prevmp != NULL) { 630898Skais prevmp->b_cont = nextmp; 631898Skais 632898Skais /* 633898Skais * If we had processed blocks that need to 634898Skais * be delivered, then remember that error code 635898Skais */ 636898Skais if (kssl_cmd == KSSL_CMD_DELIVER_PROXY) 637898Skais deliverit = B_TRUE; 638898Skais } 639898Skais 640898Skais mutex_enter(&ssl->kssl_lock); 6414556Svk199839 /* NOTE: This routine could free mp. */ 642898Skais kssl_cmd = kssl_handle_any_record(ssl, mp, outmp, 643898Skais NULL, NULL); 644898Skais 645898Skais if (ssl->alert_sendbuf != NULL) { 6464556Svk199839 mp = nextmp; 647*5850Svk199839 DTRACE_PROBE(kssl_err__alert_after_handle_any); 648898Skais goto sendalert; 649898Skais } 650898Skais mutex_exit(&ssl->kssl_lock); 651898Skais 652898Skais if (deliverit) { 653898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 654898Skais } 655898Skais 656898Skais mp = nextmp; 6574556Svk199839 continue; /* to the while loop */ 6584556Svk199839 default: 6594556Svk199839 desc = decode_error; 6604556Svk199839 KSSL_COUNTER(internal_errors, 1); 661*5850Svk199839 DTRACE_PROBE(kssl_err__decode_error); 6624556Svk199839 goto makealert; 663898Skais } 664898Skais 665898Skais version[0] = mp->b_rptr[1]; 666898Skais version[1] = mp->b_rptr[2]; 667898Skais rec_sz_p = SSL3_REC_SIZE(mp); 668898Skais rec_sz = BE16_TO_U16(rec_sz_p); 669898Skais 670898Skais mp->b_rptr += SSL3_HDR_LEN; 671898Skais recend = mp->b_rptr + rec_sz; 672898Skais real_recend = recend; 673898Skais 6744556Svk199839 /* 6754556Svk199839 * Check the assumption that each mblk contains exactly 6764556Svk199839 * one complete SSL record. We bail out if the check fails. 6774556Svk199839 */ 6784556Svk199839 ASSERT(recend == mp->b_wptr); 6794556Svk199839 if (recend != mp->b_wptr) { 6804556Svk199839 desc = decode_error; 6814556Svk199839 KSSL_COUNTER(internal_errors, 1); 682*5850Svk199839 DTRACE_PROBE(kssl_err__not_complete_record); 6834556Svk199839 goto makealert; 6844556Svk199839 } 6854556Svk199839 686898Skais spec = &ssl->spec[KSSL_READ]; 687898Skais mac_sz = spec->mac_hashsz; 688898Skais if (spec->cipher_ctx != 0) { 6891139Skais 6901139Skais /* 6911139Skais * The record length must be a multiple of the 6921139Skais * block size for block ciphers. 6931139Skais * The cipher_bsize is always a power of 2. 6941139Skais */ 6951139Skais if ((spec->cipher_type == type_block) && 6961139Skais ((rec_sz & (spec->cipher_bsize - 1)) != 0)) { 697*5850Svk199839 DTRACE_PROBE2(kssl_err__bad_record_size, 698*5850Svk199839 uint16_t, rec_sz, 699*5850Svk199839 int, spec->cipher_bsize); 7001139Skais KSSL_COUNTER(record_decrypt_failure, 1); 7011139Skais mp->b_rptr = recend; 7021139Skais desc = decrypt_error; 7031139Skais goto makealert; 7041139Skais } 7051139Skais 706898Skais cipher_data.cd_format = CRYPTO_DATA_RAW; 707898Skais cipher_data.cd_offset = 0; 708898Skais cipher_data.cd_length = rec_sz; 709898Skais cipher_data.cd_miscdata = NULL; 710898Skais cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; 711898Skais cipher_data.cd_raw.iov_len = rec_sz; 712898Skais error = crypto_decrypt_update(spec->cipher_ctx, 713898Skais &cipher_data, NULL, NULL); 714898Skais if (CRYPTO_ERR(error)) { 715*5850Svk199839 DTRACE_PROBE1( 716*5850Svk199839 kssl_err__crypto_decrypt_update_failed, 717*5850Svk199839 int, error); 718898Skais KSSL_COUNTER(record_decrypt_failure, 1); 719898Skais mp->b_rptr = recend; 720898Skais desc = decrypt_error; 721898Skais goto makealert; 722898Skais } 723898Skais } 724898Skais if (spec->cipher_type == type_block) { 725898Skais uint_t pad_sz = recend[-1]; 726898Skais pad_sz++; 727898Skais if (pad_sz + mac_sz > rec_sz) { 728*5850Svk199839 DTRACE_PROBE(kssl_err__pad_mac_bigger); 729898Skais mp->b_rptr = recend; 730898Skais desc = bad_record_mac; 731898Skais goto makealert; 732898Skais } 733898Skais rec_sz -= pad_sz; 734898Skais recend -= pad_sz; 735898Skais } 736898Skais if (mac_sz != 0) { 737898Skais uchar_t hash[MAX_HASH_LEN]; 738898Skais if (rec_sz < mac_sz) { 739*5850Svk199839 DTRACE_PROBE(kssl_err__pad_smaller_mac); 740898Skais mp->b_rptr = real_recend; 741898Skais desc = bad_record_mac; 742898Skais goto makealert; 743898Skais } 744898Skais rec_sz -= mac_sz; 745898Skais recend -= mac_sz; 746898Skais ret = kssl_compute_record_mac(ssl, KSSL_READ, 747*5850Svk199839 ssl->seq_num[KSSL_READ], content_type, 748*5850Svk199839 version, mp->b_rptr, rec_sz, hash); 749898Skais if (ret != CRYPTO_SUCCESS || 750898Skais bcmp(hash, recend, mac_sz)) { 751*5850Svk199839 DTRACE_PROBE1(kssl_mblk__MACmismatch_handlerec, 752*5850Svk199839 mblk_t *, mp); 753898Skais mp->b_rptr = real_recend; 754898Skais desc = bad_record_mac; 755*5850Svk199839 DTRACE_PROBE(kssl_err__msg_MAC_mismatch); 756898Skais KSSL_COUNTER(verify_mac_failure, 1); 757898Skais goto makealert; 758898Skais } 759898Skais ssl->seq_num[KSSL_READ]++; 760898Skais } 761898Skais 762898Skais if (ssl->hs_waitstate != idle_handshake) { 763*5850Svk199839 DTRACE_PROBE1(kssl_err__unexpected_msg, 764*5850Svk199839 SSL3WaitState, ssl->hs_waitstate); 765898Skais mp->b_rptr = real_recend; 766898Skais desc = unexpected_message; 767898Skais goto makealert; 768898Skais } 769898Skais mp->b_wptr = recend; 770898Skais 7714556Svk199839 DB_FLAGS(mp) |= DBLK_COOKED; 772*5850Svk199839 DTRACE_PROBE1(kssl_mblk__dblk_cooked, mblk_t *, mp); 7734556Svk199839 KSSL_COUNTER(appdata_record_ins, 1); 7744556Svk199839 775898Skais prevmp = mp; 776898Skais mp = mp->b_cont; 777898Skais } 778898Skais 779898Skais return (kssl_cmd); 780898Skais 781898Skais makealert: 782898Skais nextmp = mp->b_cont; 783898Skais freeb(mp); 784898Skais mp = nextmp; 785898Skais mutex_enter(&ssl->kssl_lock); 786898Skais kssl_send_alert(ssl, alert_fatal, desc); 787898Skais 788898Skais if (ssl->alert_sendbuf == NULL) { 789898Skais /* internal memory allocation failure. just return. */ 790*5850Svk199839 DTRACE_PROBE(kssl_err__alert_msg_alloc_failed); 791898Skais mutex_exit(&ssl->kssl_lock); 792898Skais 793898Skais if (mp) { 794898Skais prevmp = NULL; 795898Skais goto more; 796898Skais } 797898Skais 798898Skais return (KSSL_CMD_NONE); 799898Skais } 800898Skais kssl_cmd = KSSL_CMD_SEND; 801898Skais sendalert: 802898Skais if (*outmp == NULL) { 803898Skais *outmp = ssl->alert_sendbuf; 804898Skais } else { 805898Skais linkb(*outmp, ssl->alert_sendbuf); 806898Skais } 807898Skais ssl->alert_sendbuf = NULL; 808898Skais mutex_exit(&ssl->kssl_lock); 809898Skais 810898Skais if (mp) { 811898Skais prevmp = NULL; 812898Skais goto more; 813898Skais } 814898Skais 815898Skais return (kssl_cmd); 816898Skais } 817898Skais /* 818898Skais * This is the routine that handles incoming SSL records. 819898Skais * When called the first time, with a NULL context, this routine expects 820898Skais * a ClientHello SSL Handshake packet and shall allocate a context 821898Skais * of a new SSL connection. 822898Skais * During the rest of the handshake packets, the routine adjusts the 823898Skais * state of the context according to the record received. 824898Skais * After the ChangeCipherSpec message is received, the routine first 825898Skais * decrypts/authenticated the packet using the key materials in the 826898Skais * connection's context. 827898Skais * The return code tells the caller what to do with the returned packet. 828898Skais */ 829898Skais static kssl_cmd_t 830898Skais kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, 831898Skais kssl_callback_t cbfn, void *arg) 832898Skais { 833898Skais uchar_t *recend, *rec_sz_p; 834898Skais uchar_t version[2]; 835898Skais uchar_t *real_recend, *save_rptr, *save_wptr; 836898Skais int rhsz = SSL3_HDR_LEN; 837898Skais uint16_t rec_sz; 838898Skais int sz; 839898Skais int mac_sz; 840898Skais SSL3AlertDescription desc; 841898Skais SSL3AlertLevel level; 842898Skais SSL3ContentType content_type; 843898Skais ssl_t *ssl; 844898Skais KSSLCipherSpec *spec; 845898Skais int error = 0, ret; 846898Skais 847898Skais ASSERT(ctx != NULL); 848898Skais 849898Skais ssl = (ssl_t *)(ctx); 850898Skais 851898Skais *decrmp = NULL; 852898Skais 853898Skais save_rptr = mp->b_rptr; 854898Skais save_wptr = mp->b_wptr; 855898Skais 856898Skais ASSERT(MUTEX_HELD(&ssl->kssl_lock)); 857898Skais 858898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 859898Skais if (content_type == content_handshake_v2) { 860898Skais if (ssl->hs_waitstate == wait_client_hello) { 861898Skais /* V2 compatible ClientHello */ 862898Skais if (mp->b_rptr[3] == 0x03 && 863898Skais (mp->b_rptr[4] == 0x01 || 864*5850Svk199839 mp->b_rptr[4] == 0x00)) { 865898Skais ssl->major_version = version[0] = mp->b_rptr[3]; 866898Skais ssl->minor_version = version[1] = mp->b_rptr[4]; 867898Skais } else { 868898Skais /* We don't support "pure" SSLv2 */ 869*5850Svk199839 DTRACE_PROBE(kssl_err__no_SSLv2); 870898Skais desc = protocol_version; 871898Skais goto sendalert; 872898Skais } 873898Skais } 874898Skais rec_sz = (uint16_t)mp->b_rptr[1]; 875898Skais rhsz = 2; 876898Skais } else { 877898Skais ssl->major_version = version[0] = mp->b_rptr[1]; 878898Skais ssl->minor_version = version[1] = mp->b_rptr[2]; 879898Skais rec_sz_p = SSL3_REC_SIZE(mp); 880898Skais rec_sz = BE16_TO_U16(rec_sz_p); 881898Skais } 882898Skais 883898Skais mp->b_rptr += rhsz; 884898Skais recend = mp->b_rptr + rec_sz; 885898Skais real_recend = recend; 886898Skais 8874556Svk199839 /* 8884556Svk199839 * Check the assumption that each mblk contains exactly 8894556Svk199839 * one complete SSL record. We bail out if the check fails. 8904556Svk199839 */ 8914556Svk199839 ASSERT(recend == mp->b_wptr); 8924556Svk199839 if (recend != mp->b_wptr) { 893*5850Svk199839 DTRACE_PROBE3(kssl_mblk__handle_any_record_recszerr, 894*5850Svk199839 mblk_t *, mp, int, rhsz, int, rec_sz); 895*5850Svk199839 DTRACE_PROBE(kssl_err__record_size); 8964556Svk199839 desc = decode_error; 8974556Svk199839 KSSL_COUNTER(internal_errors, 1); 8984556Svk199839 goto sendalert; 8994556Svk199839 } 9004556Svk199839 901898Skais spec = &ssl->spec[KSSL_READ]; 902898Skais mac_sz = spec->mac_hashsz; 903898Skais if (spec->cipher_ctx != 0) { 9041139Skais /* 9051139Skais * The record length must be a multiple of the 9061139Skais * block size for block ciphers. 9071139Skais */ 9081139Skais if ((spec->cipher_type == type_block) && 9091139Skais ((rec_sz & (spec->cipher_bsize - 1)) != 0)) { 910*5850Svk199839 DTRACE_PROBE2(kssl_err__bad_record_size, 911*5850Svk199839 uint16_t, rec_sz, int, spec->cipher_bsize); 9121139Skais KSSL_COUNTER(record_decrypt_failure, 1); 9131139Skais mp->b_rptr = recend; 9141139Skais desc = decrypt_error; 9151139Skais goto sendalert; 9161139Skais } 9171139Skais 918898Skais spec->cipher_data.cd_length = rec_sz; 919898Skais spec->cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; 920898Skais spec->cipher_data.cd_raw.iov_len = rec_sz; 921898Skais error = crypto_decrypt_update(spec->cipher_ctx, 922898Skais &spec->cipher_data, NULL, NULL); 923898Skais if (CRYPTO_ERR(error)) { 924*5850Svk199839 DTRACE_PROBE1(kssl_err__crypto_decrypt_update_failed, 925*5850Svk199839 int, error); 926898Skais KSSL_COUNTER(record_decrypt_failure, 1); 927898Skais mp->b_rptr = recend; 928898Skais desc = decrypt_error; 929898Skais goto sendalert; 930898Skais } 931898Skais } 932898Skais if (spec->cipher_type == type_block) { 933898Skais uint_t pad_sz = recend[-1]; 934898Skais pad_sz++; 935898Skais if (pad_sz + mac_sz > rec_sz) { 936*5850Svk199839 DTRACE_PROBE2(kssl_err__pad_mac_mismatch, 937*5850Svk199839 int, pad_sz, int, mac_sz); 938898Skais mp->b_rptr = recend; 939898Skais desc = bad_record_mac; 940898Skais goto sendalert; 941898Skais } 942898Skais rec_sz -= pad_sz; 943898Skais recend -= pad_sz; 944898Skais } 945898Skais if (mac_sz != 0) { 946898Skais uchar_t hash[MAX_HASH_LEN]; 947898Skais if (rec_sz < mac_sz) { 948*5850Svk199839 DTRACE_PROBE1(kssl_err__mac_size_too_big, 949*5850Svk199839 int, mac_sz); 950898Skais mp->b_rptr = real_recend; 951898Skais desc = bad_record_mac; 952898Skais goto sendalert; 953898Skais } 954898Skais rec_sz -= mac_sz; 955898Skais recend -= mac_sz; 956898Skais ret = kssl_compute_record_mac(ssl, KSSL_READ, 957*5850Svk199839 ssl->seq_num[KSSL_READ], content_type, 958*5850Svk199839 version, mp->b_rptr, rec_sz, hash); 959898Skais if (ret != CRYPTO_SUCCESS || 960898Skais bcmp(hash, recend, mac_sz)) { 961*5850Svk199839 DTRACE_PROBE1(kssl_mblk__MACmismatch_anyrecord, 962*5850Svk199839 mblk_t *, mp); 963898Skais mp->b_rptr = real_recend; 964898Skais desc = bad_record_mac; 965*5850Svk199839 DTRACE_PROBE(kssl_err__msg_MAC_mismatch); 966898Skais KSSL_COUNTER(verify_mac_failure, 1); 967898Skais goto sendalert; 968898Skais } 969898Skais ssl->seq_num[KSSL_READ]++; 970*5850Svk199839 DTRACE_PROBE1(kssl_mblk__after_compute_MAC, 971*5850Svk199839 mblk_t *, mp); 972898Skais } 973898Skais 974898Skais switch (content_type) { 975898Skais case content_handshake: 976898Skais do { 977*5850Svk199839 DTRACE_PROBE1(kssl_mblk__content_handshake_cycle, 978*5850Svk199839 mblk_t *, mp); 979898Skais if (error != 0 || 980898Skais /* ignore client renegotiation for now */ 981898Skais ssl->hs_waitstate == idle_handshake) { 982898Skais mp->b_rptr = recend; 983898Skais } 984898Skais if (mp->b_rptr == recend) { 985898Skais mp->b_rptr = real_recend; 986898Skais if (error != 0) { 987898Skais goto error; 988898Skais } 989898Skais freeb(mp); 990898Skais 991898Skais if (ssl->hs_waitstate == wait_client_key_done) 992898Skais return (KSSL_CMD_QUEUED); 993898Skais 994898Skais return ((ssl->handshake_sendbuf != NULL) ? 995898Skais KSSL_CMD_SEND : KSSL_CMD_NONE); 996898Skais } 997898Skais if (ssl->msg.state < MSG_BODY) { 998898Skais if (ssl->msg.state == MSG_INIT) { 999898Skais ssl->msg.type = 1000898Skais (SSL3HandshakeType)*mp->b_rptr++; 1001898Skais ssl->msg.state = MSG_INIT_LEN; 1002898Skais } 1003898Skais if (ssl->msg.state == MSG_INIT_LEN) { 1004898Skais int msglenb = 1005898Skais ssl->msg.msglen_bytes; 1006898Skais int msglen = ssl->msg.msglen; 1007898Skais while (mp->b_rptr < recend && 1008898Skais msglenb < 3) { 1009898Skais msglen = (msglen << 8) + 1010898Skais (uint_t)(*mp->b_rptr++); 1011898Skais msglenb++; 1012898Skais } 1013898Skais ssl->msg.msglen_bytes = msglenb; 1014898Skais ssl->msg.msglen = msglen; 1015898Skais if (msglenb == 3) { 1016898Skais ssl->msg.state = MSG_BODY; 1017898Skais } 1018898Skais } 1019898Skais if (mp->b_rptr == recend) { 1020898Skais mp->b_rptr = real_recend; 1021898Skais freeb(mp); 1022898Skais return (KSSL_CMD_NONE); 1023898Skais } 1024898Skais } 1025898Skais ASSERT(ssl->msg.state == MSG_BODY); 1026898Skais 1027898Skais sz = recend - mp->b_rptr; 1028898Skais 1029898Skais if (ssl->msg.head == NULL && 1030898Skais ssl->msg.msglen <= sz) { 1031898Skais continue; 1032898Skais } 1033898Skais if (ssl->msg.head != NULL) { 1034898Skais sz += msgdsize(ssl->msg.head); 1035898Skais if (ssl->msg.msglen <= sz) { 1036898Skais ssl->msg.tail->b_cont = mp; 1037898Skais mp = ssl->msg.head; 1038898Skais ssl->sslcnt = 100; 1039898Skais ssl->msg.head = NULL; 1040898Skais ssl->msg.tail = NULL; 1041898Skais if (pullupmsg(mp, -1)) { 1042898Skais recend = mp->b_rptr + sz; 1043898Skais ASSERT(recend <= mp->b_wptr); 1044898Skais continue; 1045898Skais } 1046898Skais mp->b_rptr = real_recend; 1047898Skais error = ENOMEM; 1048898Skais KSSL_COUNTER(alloc_fails, 1); 1049898Skais goto error; 1050898Skais } 1051898Skais } 1052898Skais 1053898Skais mp->b_wptr = recend; 1054898Skais 1055898Skais if (ssl->msg.head == NULL) { 1056898Skais ssl->msg.head = mp; 1057898Skais ssl->msg.tail = mp; 1058898Skais return (KSSL_CMD_NONE); 1059898Skais } else { 1060898Skais ssl->msg.tail->b_cont = mp; 1061898Skais ssl->msg.tail = mp; 1062898Skais return (KSSL_CMD_NONE); 1063898Skais } 1064898Skais } while (kssl_handle_handshake_message(ssl, mp, &error, cbfn, 1065898Skais arg)); 1066898Skais if (error == SSL_MISS) { 1067898Skais mp->b_rptr = save_rptr; 1068898Skais mp->b_wptr = save_wptr; 1069898Skais KSSL_COUNTER(fallback_connections, 1); 1070898Skais return (KSSL_CMD_NOT_SUPPORTED); 1071898Skais } 1072898Skais if (ssl->hs_waitstate == wait_client_key_done) { 1073898Skais return (KSSL_CMD_QUEUED); 1074898Skais } else { 1075898Skais return (KSSL_CMD_NONE); 1076898Skais } 1077898Skais case content_alert: 1078*5850Svk199839 DTRACE_PROBE1(kssl_mblk__content_alert, mblk_t *, mp); 1079898Skais if (rec_sz != 2) { 1080*5850Svk199839 DTRACE_PROBE(kssl_err__illegal_param); 1081898Skais mp->b_rptr = real_recend; 1082898Skais desc = illegal_parameter; 1083898Skais goto sendalert; 1084898Skais } else { 1085898Skais level = *mp->b_rptr++; 1086898Skais desc = *mp->b_rptr++; 1087898Skais mp->b_rptr = real_recend; 1088898Skais if (level != alert_warning || desc != close_notify) { 1089898Skais if (ssl->sid.cached == B_TRUE) { 1090898Skais kssl_uncache_sid(&ssl->sid, 1091898Skais ssl->kssl_entry); 1092898Skais ssl->sid.cached = B_FALSE; 1093898Skais } 1094*5850Svk199839 DTRACE_PROBE2(kssl_err__bad_content_alert, 1095*5850Svk199839 SSL3AlertLevel, level, 1096*5850Svk199839 SSL3AlertDescription, desc); 1097898Skais ssl->fatal_alert = B_TRUE; 1098898Skais error = EBADMSG; 1099898Skais goto error; 1100898Skais } else { 1101898Skais ssl->close_notify = B_TRUE; 1102898Skais ssl->activeinput = B_FALSE; 1103898Skais freeb(mp); 1104898Skais return (KSSL_CMD_NONE); 1105898Skais } 1106898Skais } 1107898Skais case content_change_cipher_spec: 1108*5850Svk199839 DTRACE_PROBE1(kssl_mblk__change_cipher_spec, 1109*5850Svk199839 mblk_t *, mp); 1110898Skais if (ssl->hs_waitstate != wait_change_cipher) { 1111898Skais desc = unexpected_message; 1112898Skais } else if (rec_sz != 1 || *mp->b_rptr != 1) { 1113898Skais desc = illegal_parameter; 1114898Skais } else { 1115898Skais mp->b_rptr = real_recend; 1116898Skais ssl->hs_waitstate = wait_finished; 1117898Skais ssl->seq_num[KSSL_READ] = 0; 1118898Skais if ((error = kssl_spec_init(ssl, KSSL_READ)) != 0) { 1119*5850Svk199839 DTRACE_PROBE1(kssl_err__kssl_spec_init_error, 1120*5850Svk199839 int, error); 1121898Skais goto error; 1122898Skais } 1123898Skais ssl->activeinput = B_FALSE; 1124898Skais freeb(mp); 1125898Skais return (KSSL_CMD_NONE); 1126898Skais } 1127898Skais mp->b_rptr = real_recend; 1128*5850Svk199839 DTRACE_PROBE(kssl_err__change_cipher_spec); 1129898Skais goto sendalert; 1130898Skais 1131898Skais case content_application_data: 1132*5850Svk199839 DTRACE_PROBE1(kssl_mblk__content_app_data, 1133*5850Svk199839 mblk_t *, mp); 1134898Skais if (ssl->hs_waitstate != idle_handshake) { 1135*5850Svk199839 DTRACE_PROBE(kssl_err__content_app_data); 1136898Skais mp->b_rptr = real_recend; 1137898Skais desc = unexpected_message; 1138898Skais goto sendalert; 1139898Skais } 1140898Skais mp->b_wptr = recend; 1141898Skais *decrmp = mp; 1142898Skais ssl->activeinput = B_FALSE; 1143898Skais return (KSSL_CMD_DELIVER_PROXY); 1144898Skais 1145898Skais case content_handshake_v2: 1146*5850Svk199839 DTRACE_PROBE1(kssl_mblk__content_handshake_v2, 1147*5850Svk199839 mblk_t *, mp); 1148898Skais error = kssl_handle_v2client_hello(ssl, mp, rec_sz); 1149898Skais if (error == SSL_MISS) { 1150898Skais mp->b_rptr = save_rptr; 1151898Skais mp->b_wptr = save_wptr; 1152898Skais KSSL_COUNTER(fallback_connections, 1); 1153898Skais return (KSSL_CMD_NOT_SUPPORTED); 1154898Skais } else if (error != 0) { 1155*5850Svk199839 DTRACE_PROBE(kssl_err__v2client_hello_failed); 1156898Skais goto error; 1157898Skais } 1158898Skais freeb(mp); 1159898Skais return (KSSL_CMD_SEND); 1160898Skais default: 1161*5850Svk199839 DTRACE_PROBE1(kssl_mblk__unexpected_msg, 1162*5850Svk199839 mblk_t *, mp); 1163898Skais mp->b_rptr = real_recend; 1164898Skais desc = unexpected_message; 1165898Skais break; 1166898Skais } 1167898Skais 1168898Skais sendalert: 1169898Skais kssl_send_alert(ssl, alert_fatal, desc); 1170898Skais *decrmp = ssl->alert_sendbuf; 1171898Skais ssl->alert_sendbuf = NULL; 1172898Skais freeb(mp); 1173898Skais return ((*decrmp != NULL) ? KSSL_CMD_SEND : KSSL_CMD_NONE); 1174898Skais error: 1175898Skais freeb(mp); 1176898Skais return (KSSL_CMD_NONE); 1177898Skais } 1178898Skais 1179898Skais /* 1180898Skais * Initialize the context of an SSL connection, coming to the specified 1181898Skais * address. 1182898Skais * the ssl structure returned is held. 1183898Skais */ 1184898Skais kssl_status_t 1185898Skais kssl_init_context(kssl_ent_t kssl_ent, ipaddr_t faddr, int mss, 1186898Skais kssl_ctx_t *kssl_ctxp) 1187898Skais { 1188898Skais ssl_t *ssl = kmem_cache_alloc(kssl_cache, KM_NOSLEEP); 1189898Skais 1190898Skais if (ssl == NULL) { 1191898Skais return (KSSL_STS_ERR); 1192898Skais } 1193898Skais 1194898Skais kssl_cache_count++; 1195898Skais 1196898Skais bzero(ssl, sizeof (ssl_t)); 1197898Skais 1198898Skais ssl->kssl_entry = (kssl_entry_t *)kssl_ent; 1199898Skais KSSL_ENTRY_REFHOLD(ssl->kssl_entry); 1200898Skais 1201898Skais ssl->faddr = faddr; 1202898Skais ssl->tcp_mss = mss; 1203898Skais ssl->sendalert_level = alert_warning; 1204898Skais ssl->sendalert_desc = close_notify; 1205898Skais ssl->sid.cached = B_FALSE; 1206898Skais 1207898Skais *kssl_ctxp = (kssl_ctx_t)ssl; 1208898Skais KSSL_SSL_REFHOLD(ssl); 1209898Skais return (KSSL_STS_OK); 1210898Skais } 1211898Skais 1212898Skais /* 1213898Skais * Builds SSL records out of the chain of mblks, and returns it. 1214898Skais * Taked a copy of the message before encypting it if it has another 1215898Skais * reference. 1216898Skais * In case of failure, NULL is returned, and the message will be 1217898Skais * freed by the caller. 1218898Skais * A NULL mp means a close_notify is requested. 1219898Skais */ 1220898Skais mblk_t * 1221898Skais kssl_build_record(kssl_ctx_t ctx, mblk_t *mp) 1222898Skais { 1223898Skais ssl_t *ssl = (ssl_t *)ctx; 1224898Skais mblk_t *retmp = mp, *bp = mp, *prevbp = mp, *copybp; 1225898Skais 1226898Skais ASSERT(ssl != NULL); 1227898Skais ASSERT(mp != NULL); 1228898Skais 1229898Skais do { 1230898Skais if (DB_REF(bp) > 1) { 1231898Skais /* 1232898Skais * Fortunately copyb() preserves the offset, 1233898Skais * tail space and alignement so the copy is 1234898Skais * ready to be made an SSL record. 1235898Skais */ 1236898Skais if ((copybp = copyb(bp)) == NULL) 1237898Skais return (NULL); 1238898Skais 1239898Skais copybp->b_cont = bp->b_cont; 1240898Skais if (bp == mp) { 1241898Skais retmp = copybp; 1242898Skais } else { 1243898Skais prevbp->b_cont = copybp; 1244898Skais } 1245898Skais freeb(bp); 1246898Skais bp = copybp; 1247898Skais } 1248898Skais 1249898Skais if (kssl_build_single_record(ssl, bp) != KSSL_STS_OK) 1250898Skais return (NULL); 1251898Skais 1252898Skais prevbp = bp; 1253898Skais bp = bp->b_cont; 1254898Skais } while (bp != NULL); 1255898Skais 1256898Skais return (retmp); 1257898Skais } 1258898Skais 1259898Skais /* 1260898Skais * Builds a single SSL record 1261898Skais * In-line encryption of the record. 1262898Skais */ 1263898Skais static kssl_status_t 1264898Skais kssl_build_single_record(ssl_t *ssl, mblk_t *mp) 1265898Skais { 1266898Skais int len; 1267898Skais int reclen = 0; 1268898Skais uchar_t *recstart, *versionp; 1269898Skais KSSLCipherSpec *spec; 1270898Skais int mac_sz; 1271898Skais int pad_sz = 0; 1272898Skais 1273898Skais 1274898Skais spec = &ssl->spec[KSSL_WRITE]; 1275898Skais mac_sz = spec->mac_hashsz; 1276898Skais 1277898Skais 1278898Skais ASSERT(DB_REF(mp) == 1); 1279898Skais ASSERT((mp->b_rptr - mp->b_datap->db_base >= SSL3_HDR_LEN) && 1280898Skais (mp->b_datap->db_lim - mp->b_wptr >= mac_sz + spec->cipher_bsize)); 1281898Skais 1282898Skais len = MBLKL(mp); 1283898Skais 1284898Skais ASSERT(len > 0); 1285898Skais 1286898Skais mutex_enter(&ssl->kssl_lock); 1287898Skais 1288898Skais recstart = mp->b_rptr = mp->b_rptr - SSL3_HDR_LEN; 1289898Skais recstart[0] = content_application_data; 1290898Skais recstart[1] = ssl->major_version; 1291898Skais recstart[2] = ssl->minor_version; 1292898Skais versionp = &recstart[1]; 1293898Skais 1294898Skais reclen = len + mac_sz; 1295898Skais if (spec->cipher_type == type_block) { 1296898Skais pad_sz = spec->cipher_bsize - 1297898Skais (reclen & (spec->cipher_bsize - 1)); 1298898Skais ASSERT(reclen + pad_sz <= 1299898Skais SSL3_MAX_RECORD_LENGTH); 1300898Skais reclen += pad_sz; 1301898Skais } 1302898Skais recstart[3] = (reclen >> 8) & 0xff; 1303898Skais recstart[4] = reclen & 0xff; 1304898Skais 1305898Skais if (kssl_mac_encrypt_record(ssl, content_application_data, versionp, 1306898Skais recstart, mp) != 0) { 1307898Skais /* Do we need an internal_error Alert here? */ 1308898Skais mutex_exit(&ssl->kssl_lock); 1309898Skais return (KSSL_STS_ERR); 1310898Skais } 1311898Skais 1312898Skais KSSL_COUNTER(appdata_record_outs, 1); 1313898Skais mutex_exit(&ssl->kssl_lock); 1314898Skais return (KSSL_STS_OK); 1315898Skais } 1316