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*4556Svk199839 * Copyright 2007 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/cmn_err.h> 32898Skais #include <sys/kmem.h> 33898Skais #include <sys/cpuvar.h> 34898Skais #include <sys/atomic.h> 35898Skais #include <sys/sysmacros.h> 36898Skais 37898Skais #include <inet/common.h> 38898Skais #include <inet/ip.h> 39898Skais #include <inet/ip6.h> 40898Skais 41898Skais #include <sys/systm.h> 42898Skais #include <sys/param.h> 43898Skais #include <sys/tihdr.h> 44898Skais 45898Skais #include "ksslimpl.h" 46898Skais #include "ksslproto.h" 47898Skais #include "ksslapi.h" 48898Skais 49898Skais static kssl_cmd_t kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, 50898Skais mblk_t **decrmp, kssl_callback_t cbfn, void *arg); 51898Skais static boolean_t kssl_enqueue(kssl_chain_t **head, void *item); 52898Skais static void kssl_dequeue(kssl_chain_t **head, void *item); 53898Skais static kssl_status_t kssl_build_single_record(ssl_t *ssl, mblk_t *mp); 54898Skais 55898Skais /* 56898Skais * The socket T_bind_req message is intercepted and re-routed here 57898Skais * to see is there is SSL relevant job to do, based on the kssl config 58898Skais * in the kssl_entry_tab. 59898Skais * Looks up the kernel SSL proxy table, to find an entry that matches the 60898Skais * same serveraddr, and has one of the following two criteria: 61898Skais * 1. in_port is an ssl_port. This endpoint can be used later as a fallback 62898Skais * to complete connections that cannot be handled by the SSL kernel proxy 63898Skais * (typically non supported ciphersuite). The cookie for the calling client 64898Skais * is saved with the kssl_entry to be retrieved for the fallback. 65898Skais * The function returns KSSL_HAS_PROXY. 66898Skais * 67898Skais * 2. in_port is a proxy port for another ssl port. The ssl port is then 68898Skais * substituted to the in_port in the bind_req TPI structure, so that 69898Skais * the bind falls through to the SSL port. At the end of this operation, 70898Skais * all the packets arriving to the SSL port will be delivered to an 71898Skais * accepted endpoint child of this bound socket. 72898Skais * The kssl_entry_t is returned in *ksslent, for later use by the 73898Skais * lower modules' SSL hooks that handle the Handshake messages. 74898Skais * The function returns KSSL_IS_PROXY. 75898Skais * 76898Skais * The function returns KSSL_NO_PROXY otherwise. We do not suppport 77898Skais * IPv6 addresses. 78898Skais */ 79898Skais 80898Skais kssl_endpt_type_t 81898Skais kssl_check_proxy(mblk_t *bindmp, void *cookie, kssl_ent_t *ksslent) 82898Skais { 83898Skais int i; 84898Skais kssl_endpt_type_t ret; 85898Skais kssl_entry_t *ep; 86898Skais sin_t *sin; 87898Skais struct T_bind_req *tbr; 88898Skais ipaddr_t v4addr; 89898Skais in_port_t in_port; 90898Skais 91898Skais if (kssl_enabled == 0) { 92898Skais return (KSSL_NO_PROXY); 93898Skais } 94898Skais 95898Skais tbr = (struct T_bind_req *)bindmp->b_rptr; 96898Skais 97898Skais ret = KSSL_NO_PROXY; 98898Skais 99898Skais 100898Skais switch (tbr->ADDR_length) { 101898Skais case sizeof (sin_t): 102898Skais sin = (sin_t *)(bindmp->b_rptr + tbr->ADDR_length); 103898Skais in_port = ntohs(sin->sin_port); 104898Skais v4addr = sin->sin_addr.s_addr; 105898Skais break; 106898Skais 107898Skais case sizeof (sin6_t): 108898Skais /* Future support of IPv6 goes here */ 109898Skais default: 110898Skais /* Should ASSERT() here? */ 111898Skais return (ret); 112898Skais } 113898Skais 114898Skais mutex_enter(&kssl_tab_mutex); 115898Skais 116898Skais for (i = 0; i < kssl_entry_tab_size; i++) { 117898Skais if ((ep = kssl_entry_tab[i]) == NULL) 118898Skais continue; 119898Skais 120898Skais if ((ep->ke_laddr == v4addr) || (ep->ke_laddr == INADDR_ANY)) { 121898Skais 122898Skais /* This is an SSL port to fallback to */ 123898Skais if (ep->ke_ssl_port == in_port) { 124898Skais 125898Skais /* 126898Skais * Let's see first if there's at least 127898Skais * an endpoint for a proxy server. 128898Skais * If there's none, then we return as we have 129898Skais * no proxy, so that the bind() to the 130898Skais * transport layer goes through. 131898Skais * The calling module will ask for this 132898Skais * cookie if it wants to fall back to it, 133898Skais * so add this one to the list of fallback 134898Skais * clients. 135898Skais */ 136898Skais if (!kssl_enqueue((kssl_chain_t **) 137898Skais &(ep->ke_fallback_head), cookie)) { 138898Skais break; 139898Skais } 140898Skais 141898Skais /* 142898Skais * Now transform the T_BIND_REQ into 143898Skais * a T_BIND_ACK. 144898Skais */ 145898Skais tbr->PRIM_type = T_BIND_ACK; 146898Skais bindmp->b_datap->db_type = M_PCPROTO; 147898Skais 148898Skais KSSL_ENTRY_REFHOLD(ep); 149898Skais *ksslent = (kssl_ent_t)ep; 150898Skais 151898Skais ret = KSSL_HAS_PROXY; 152898Skais break; 153898Skais } 154898Skais 155898Skais /* This is a proxy port. */ 156898Skais if (ep->ke_proxy_port == in_port) { 157898Skais mblk_t *entmp; 158898Skais 159898Skais /* Append this entry to the bind_req mblk */ 160898Skais 161898Skais entmp = allocb(sizeof (kssl_entry_t), 162898Skais BPRI_MED); 163898Skais if (entmp == NULL) 164898Skais break; 165898Skais *((kssl_entry_t **)entmp->b_rptr) = ep; 166898Skais 167898Skais entmp->b_wptr = entmp->b_rptr + 168898Skais sizeof (kssl_entry_t); 169898Skais 170898Skais bindmp->b_cont = entmp; 171898Skais 172898Skais /* Add the caller's cookie to proxies list */ 173898Skais 174898Skais if (!kssl_enqueue((kssl_chain_t **) 175898Skais &(ep->ke_proxy_head), cookie)) { 176898Skais freeb(bindmp->b_cont); 177898Skais bindmp->b_cont = NULL; 178898Skais break; 179898Skais } 180898Skais 181898Skais /* 182898Skais * Make this look like the SSL port to the 183898Skais * transport below 184898Skais */ 185898Skais sin->sin_port = htons(ep->ke_ssl_port); 186898Skais 187898Skais tbr->PRIM_type = T_SSL_PROXY_BIND_REQ; 188898Skais 189898Skais KSSL_ENTRY_REFHOLD(ep); 190898Skais *ksslent = (kssl_ent_t)ep; 191898Skais 192898Skais ret = KSSL_IS_PROXY; 193898Skais break; 194898Skais } 195898Skais } 196898Skais } 197898Skais 198898Skais mutex_exit(&kssl_tab_mutex); 199898Skais return (ret); 200898Skais } 201898Skais 202898Skais /* 203898Skais * Retrieved an endpoint "bound" to the SSL entry. 204898Skais * Such endpoint has previously called kssl_check_proxy(), got itself 205898Skais * linked to the kssl_entry's ke_fallback_head list. 206898Skais * This routine returns the cookie from that SSL entry ke_fallback_head list. 207898Skais */ 208898Skais void * 209898Skais kssl_find_fallback(kssl_ent_t ksslent) 210898Skais { 211898Skais kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; 212898Skais 213898Skais if (kssl_entry->ke_fallback_head != NULL) 214898Skais return (kssl_entry->ke_fallback_head->fallback_bound); 215898Skais 216898Skais KSSL_COUNTER(proxy_fallback_failed, 1); 217898Skais 218898Skais return (NULL); 219898Skais } 220898Skais 221898Skais /* 222898Skais * Re-usable code for adding and removing an element to/from a chain that 223898Skais * matches "item" 224898Skais * The chain is simple-linked and NULL ended. 225898Skais */ 226898Skais 227898Skais /* 228898Skais * This routine returns TRUE if the item was either successfully added to 229898Skais * the chain, or is already there. It returns FALSE otherwise. 230898Skais */ 231898Skais static boolean_t 232898Skais kssl_enqueue(kssl_chain_t **head, void *item) 233898Skais { 234898Skais kssl_chain_t *newchain, *cur; 235898Skais 236898Skais /* Lookup the existing entries to avoid duplicates */ 237898Skais cur = *head; 238898Skais while (cur != NULL) { 239898Skais if (cur->item == item) { 240898Skais return (B_TRUE); 241898Skais } 242898Skais cur = cur->next; 243898Skais } 244898Skais 245898Skais newchain = kmem_alloc(sizeof (kssl_chain_t), KM_NOSLEEP); 246898Skais if (newchain == NULL) { 247898Skais return (B_FALSE); 248898Skais } 249898Skais 250898Skais newchain->item = item; 251898Skais newchain->next = *head; 252898Skais *head = newchain; 253898Skais return (B_TRUE); 254898Skais } 255898Skais 256898Skais static void 257898Skais kssl_dequeue(kssl_chain_t **head, void *item) 258898Skais { 259898Skais kssl_chain_t *prev, *cur; 260898Skais 261898Skais prev = cur = *head; 262898Skais while (cur != NULL) { 263898Skais if (cur->item == item) { 264898Skais if (cur == *head) 265898Skais *head = (*head)->next; 266898Skais else 267898Skais prev->next = cur->next; 268898Skais kmem_free(cur, sizeof (kssl_chain_t)); 269898Skais return; 270898Skais } 271898Skais prev = cur; 272898Skais cur = cur->next; 273898Skais } 274898Skais } 275898Skais 276898Skais /* 277898Skais * Holds the kssl_entry 278898Skais */ 279898Skais void 280898Skais kssl_hold_ent(kssl_ent_t ksslent) 281898Skais { 282898Skais KSSL_ENTRY_REFHOLD((kssl_entry_t *)ksslent); 283898Skais } 284898Skais 285898Skais /* 286898Skais * Releases the kssl_entry 287898Skais * If the caller passes a cookie, then it should be removed from both 288898Skais * proxies and fallbacks chains. 289898Skais */ 290898Skais void 291898Skais kssl_release_ent(kssl_ent_t ksslent, void *cookie, kssl_endpt_type_t endpt_type) 292898Skais { 293898Skais kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; 294898Skais 295898Skais if (cookie != NULL) { 296898Skais if (endpt_type == KSSL_IS_PROXY) 297898Skais ASSERT(kssl_entry->ke_proxy_head != NULL); 298898Skais kssl_dequeue( 299898Skais (kssl_chain_t **)&kssl_entry->ke_proxy_head, 300898Skais cookie); 301898Skais if (endpt_type == KSSL_HAS_PROXY) 302898Skais ASSERT(kssl_entry->ke_fallback_head != NULL); 303898Skais kssl_dequeue( 304898Skais (kssl_chain_t **)&kssl_entry->ke_fallback_head, 305898Skais cookie); 306898Skais } 307898Skais KSSL_ENTRY_REFRELE(kssl_entry); 308898Skais } 309898Skais 310898Skais /* 311898Skais * Holds the kssl context 312898Skais */ 313898Skais void 314898Skais kssl_hold_ctx(kssl_ctx_t ksslctx) 315898Skais { 316898Skais ssl_t *ssl = (ssl_t *)ksslctx; 317898Skais 318898Skais KSSL_SSL_REFHOLD(ssl); 319898Skais } 320898Skais 321898Skais /* 322898Skais * Releases the kssl_context 323898Skais */ 324898Skais void 325898Skais kssl_release_ctx(kssl_ctx_t ksslctx) 326898Skais { 327898Skais KSSL_SSL_REFRELE((ssl_t *)ksslctx); 328898Skais } 329898Skais 330898Skais /* 331898Skais * Packets are accumulated here, if there are packets already queued, 332898Skais * or if the context is active. 333898Skais * The context is active when an incoming record processing function 334898Skais * is already executing on a different thread. 335898Skais * Queued packets are handled either when an mblk arrived and completes 336898Skais * a record, or, when the active context processor finishes the task at 337898Skais * hand. 338898Skais * The caller has to keep calling this routine in a loop until it returns 339898Skais * B_FALSE in *more. The reason for this is SSL3: The protocol 340898Skais * allows the client to send its first application_data message right 341898Skais * after it had sent its Finished message, and not wait for the server 342898Skais * ChangeCipherSpec and Finished. This overlap means we can't batch up 343898Skais * a returned Handshake message to be sent on the wire 344898Skais * with a decrypted application_data to be delivered to the application. 345898Skais */ 346898Skais kssl_cmd_t 347898Skais kssl_input(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, boolean_t *more, 348898Skais kssl_callback_t cbfn, void *arg) 349898Skais { 350898Skais mblk_t *recmp, *outmp = NULL; 351898Skais kssl_cmd_t kssl_cmd; 352898Skais ssl_t *ssl; 353898Skais uint8_t *rec_sz_p; 354898Skais int mplen; 355898Skais SSL3ContentType content_type; 356898Skais uint16_t rec_sz; 357898Skais 358898Skais ASSERT(ctx != NULL); 359898Skais 360898Skais if (mp != NULL) { 361898Skais ASSERT(mp->b_prev == NULL && mp->b_next == NULL); 362898Skais } 363898Skais 364898Skais ssl = (ssl_t *)(ctx); 365898Skais 366898Skais *decrmp = NULL; 367898Skais *more = B_FALSE; 368898Skais 369898Skais mutex_enter(&ssl->kssl_lock); 370898Skais 371898Skais if (ssl->close_notify == B_TRUE) { 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 393898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 394898Skais 395898Skais if ((content_type == content_application_data) && 396898Skais (ssl->hs_waitstate == idle_handshake)) { 397898Skais rec_sz_p = SSL3_REC_SIZE(mp); 398898Skais rec_sz = BE16_TO_U16(rec_sz_p); 399898Skais 400898Skais if ((mp->b_cont == NULL) && (mplen == rec_sz)) { 401898Skais 402898Skais mp->b_flag &= ~DBLK_COOKED; 403898Skais *decrmp = mp; 404898Skais mutex_exit(&ssl->kssl_lock); 405898Skais return (KSSL_CMD_DELIVER_PROXY); 406898Skais } 407898Skais } 408898Skais } 409898Skais 410898Skais ssl->activeinput = B_TRUE; 411898Skais /* Accumulate at least one record */ 412898Skais if (mp != NULL) { 413898Skais KSSL_ENQUEUE_MP(ssl, mp); 414898Skais mp = NULL; 415898Skais } 416898Skais recmp = kssl_get_next_record(ssl); 417898Skais 418898Skais if (recmp == NULL) { 419898Skais ssl->activeinput = B_FALSE; 420898Skais if (ssl->alert_sendbuf != NULL) { 421898Skais goto sendalert; 422898Skais } 423898Skais /* Not even a complete header yet. wait for the rest */ 424898Skais mutex_exit(&ssl->kssl_lock); 425898Skais return (KSSL_CMD_NONE); 426898Skais } 427898Skais 428898Skais do { 429*4556Svk199839 content_type = (SSL3ContentType)recmp->b_rptr[0]; 430*4556Svk199839 431*4556Svk199839 switch (content_type) { 432*4556Svk199839 case content_application_data: 433898Skais /* 434898Skais * application_data records are decrypted and 435898Skais * MAC-verified by the stream head, and in the context 436898Skais * a read()'ing thread. This avoids unfairly charging 437898Skais * the cost of handling this record on the whole system, 438898Skais * and prevents doing it while in the shared IP 439898Skais * perimeter. 440898Skais */ 441898Skais ssl->activeinput = B_FALSE; 442898Skais if (ssl->hs_waitstate != idle_handshake) { 443898Skais goto sendnewalert; 444898Skais } 445898Skais outmp = recmp; 446898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 447*4556Svk199839 break; 448*4556Svk199839 case content_change_cipher_spec: 449*4556Svk199839 case content_alert: 450*4556Svk199839 case content_handshake: 451*4556Svk199839 case content_handshake_v2: 452898Skais /* 453898Skais * If we're past the initial handshake, start letting 454898Skais * the stream head process all records, in particular 455898Skais * the close_notify. 456898Skais * This is needed to avoid processing them out of 457898Skais * sequence when previous application data packets are 458898Skais * waiting to be decrypted/MAC'ed and delivered. 459898Skais */ 460898Skais if (ssl->hs_waitstate == idle_handshake) { 461898Skais ssl->activeinput = B_FALSE; 462898Skais outmp = recmp; 463898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 464898Skais } else { 465898Skais kssl_cmd = kssl_handle_any_record(ssl, recmp, 466898Skais &outmp, cbfn, arg); 467898Skais } 468*4556Svk199839 break; 469*4556Svk199839 default: 470*4556Svk199839 ssl->activeinput = B_FALSE; 471*4556Svk199839 goto sendnewalert; 472898Skais } 473898Skais 474898Skais /* Priority to Alert messages */ 475898Skais if (ssl->alert_sendbuf != NULL) { 476898Skais goto sendalert; 477898Skais } 478898Skais 479898Skais /* Then handshake messages */ 480898Skais if (ssl->handshake_sendbuf) { 481898Skais if (*decrmp != NULL) { 482898Skais linkb(*decrmp, ssl->handshake_sendbuf); 483898Skais } else { 484898Skais *decrmp = ssl->handshake_sendbuf; 485898Skais } 486898Skais ssl->handshake_sendbuf = NULL; 487898Skais 488898Skais *more = ((ssl->rec_ass_head != NULL) && 489898Skais (!ssl->activeinput)); 490898Skais mutex_exit(&ssl->kssl_lock); 491898Skais return (kssl_cmd); 492898Skais } 493898Skais 494898Skais if (ssl->hs_waitstate == idle_handshake) { 495898Skais *more = ((ssl->rec_ass_head != NULL) && 496898Skais (!ssl->activeinput)); 497898Skais } 498898Skais 499898Skais if (outmp != NULL) { 500898Skais *decrmp = outmp; 501898Skais /* 502898Skais * Don't process any packet after an application_data. 503898Skais * We could well receive the close_notify which should 504898Skais * be handled separately. 505898Skais */ 506898Skais mutex_exit(&ssl->kssl_lock); 507898Skais return (kssl_cmd); 508898Skais } 509898Skais /* 510898Skais * The current record isn't done yet. Don't start the next one 511898Skais */ 512898Skais if (ssl->activeinput) { 513898Skais mutex_exit(&ssl->kssl_lock); 514898Skais return (kssl_cmd); 515898Skais } 516898Skais } while ((recmp = kssl_get_next_record(ssl)) != NULL); 517898Skais 518898Skais mutex_exit(&ssl->kssl_lock); 519898Skais return (kssl_cmd); 520898Skais 521898Skais sendnewalert: 522898Skais kssl_send_alert(ssl, alert_fatal, unexpected_message); 523898Skais if (mp != NULL) { 524898Skais freeb(mp); 525898Skais } 526898Skais 527898Skais sendalert: 528898Skais *decrmp = ssl->alert_sendbuf; 529898Skais ssl->alert_sendbuf = NULL; 530898Skais mutex_exit(&ssl->kssl_lock); 531898Skais return (KSSL_CMD_SEND); 532898Skais } 533898Skais 534898Skais /* 535898Skais * Decrypt and verify the MAC of an incoming chain of application_data record. 536898Skais * Each block has exactly one SSL record. 537898Skais * This routine recycles its incoming mblk, and flags it as DBLK_COOKED 538898Skais */ 539898Skais kssl_cmd_t 540898Skais kssl_handle_record(kssl_ctx_t ctx, mblk_t **mpp, mblk_t **outmp) 541898Skais { 542898Skais uchar_t *recend, *rec_sz_p; 543898Skais uchar_t *real_recend; 5441139Skais mblk_t *prevmp = NULL, *nextmp, *firstmp, *mp, *copybp; 545898Skais int mac_sz; 546898Skais uchar_t version[2]; 547898Skais uint16_t rec_sz; 548898Skais SSL3AlertDescription desc; 549898Skais SSL3ContentType content_type; 550898Skais ssl_t *ssl; 551898Skais KSSLCipherSpec *spec; 552898Skais int error = 0, ret; 553898Skais kssl_cmd_t kssl_cmd = KSSL_CMD_DELIVER_PROXY; 554898Skais boolean_t deliverit = B_FALSE; 555898Skais crypto_data_t cipher_data; 556898Skais 557898Skais ASSERT(ctx != NULL); 558898Skais 559898Skais ssl = (ssl_t *)(ctx); 560898Skais 5611139Skais mp = firstmp = *mpp; 562898Skais *outmp = NULL; 563898Skais 564898Skais more: 565898Skais 566898Skais while (mp != NULL) { 567898Skais 568898Skais if (DB_REF(mp) > 1) { 569898Skais /* 570898Skais * Fortunately copyb() preserves the offset, 571898Skais * tail space and alignement so the copy is 572898Skais * ready to be made an SSL record. 573898Skais */ 574898Skais if ((copybp = copyb(mp)) == NULL) 575898Skais return (NULL); 576898Skais 577898Skais copybp->b_cont = mp->b_cont; 5781139Skais if (mp == firstmp) { 579898Skais *mpp = copybp; 580*4556Svk199839 } else if (prevmp != NULL) { 581898Skais prevmp->b_cont = copybp; 582898Skais } 583898Skais freeb(mp); 584898Skais mp = copybp; 585898Skais } 586898Skais 587898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 588898Skais 589*4556Svk199839 switch (content_type) { 590*4556Svk199839 case content_application_data: 591*4556Svk199839 break; 592*4556Svk199839 case content_change_cipher_spec: 593*4556Svk199839 case content_alert: 594*4556Svk199839 case content_handshake: 595*4556Svk199839 case content_handshake_v2: 596898Skais nextmp = mp->b_cont; 597898Skais 598898Skais /* Remove this message */ 599898Skais if (prevmp != NULL) { 600898Skais prevmp->b_cont = nextmp; 601898Skais 602898Skais /* 603898Skais * If we had processed blocks that need to 604898Skais * be delivered, then remember that error code 605898Skais */ 606898Skais if (kssl_cmd == KSSL_CMD_DELIVER_PROXY) 607898Skais deliverit = B_TRUE; 608898Skais } 609898Skais 610898Skais mutex_enter(&ssl->kssl_lock); 611*4556Svk199839 /* NOTE: This routine could free mp. */ 612898Skais kssl_cmd = kssl_handle_any_record(ssl, mp, outmp, 613898Skais NULL, NULL); 614898Skais 615898Skais if (ssl->alert_sendbuf != NULL) { 616*4556Svk199839 mp = nextmp; 617898Skais goto sendalert; 618898Skais } 619898Skais mutex_exit(&ssl->kssl_lock); 620898Skais 621898Skais if (deliverit) { 622898Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 623898Skais } 624898Skais 625898Skais mp = nextmp; 626*4556Svk199839 continue; /* to the while loop */ 627*4556Svk199839 default: 628*4556Svk199839 desc = decode_error; 629*4556Svk199839 KSSL_COUNTER(internal_errors, 1); 630*4556Svk199839 goto makealert; 631898Skais } 632898Skais 633898Skais version[0] = mp->b_rptr[1]; 634898Skais version[1] = mp->b_rptr[2]; 635898Skais rec_sz_p = SSL3_REC_SIZE(mp); 636898Skais rec_sz = BE16_TO_U16(rec_sz_p); 637898Skais 638898Skais mp->b_rptr += SSL3_HDR_LEN; 639898Skais recend = mp->b_rptr + rec_sz; 640898Skais real_recend = recend; 641898Skais 642*4556Svk199839 /* 643*4556Svk199839 * Check the assumption that each mblk contains exactly 644*4556Svk199839 * one complete SSL record. We bail out if the check fails. 645*4556Svk199839 */ 646*4556Svk199839 ASSERT(recend == mp->b_wptr); 647*4556Svk199839 if (recend != mp->b_wptr) { 648*4556Svk199839 desc = decode_error; 649*4556Svk199839 KSSL_COUNTER(internal_errors, 1); 650*4556Svk199839 goto makealert; 651*4556Svk199839 } 652*4556Svk199839 653898Skais spec = &ssl->spec[KSSL_READ]; 654898Skais mac_sz = spec->mac_hashsz; 655898Skais if (spec->cipher_ctx != 0) { 6561139Skais 6571139Skais /* 6581139Skais * The record length must be a multiple of the 6591139Skais * block size for block ciphers. 6601139Skais * The cipher_bsize is always a power of 2. 6611139Skais */ 6621139Skais if ((spec->cipher_type == type_block) && 6631139Skais ((rec_sz & (spec->cipher_bsize - 1)) != 0)) { 6641139Skais #ifdef DEBUG 6651139Skais cmn_err(CE_WARN, "kssl_handle_record: " 6661139Skais "bad record size"); 6671139Skais #endif /* DEBUG */ 6681139Skais KSSL_COUNTER(record_decrypt_failure, 1); 6691139Skais mp->b_rptr = recend; 6701139Skais desc = decrypt_error; 6711139Skais goto makealert; 6721139Skais } 6731139Skais 674898Skais cipher_data.cd_format = CRYPTO_DATA_RAW; 675898Skais cipher_data.cd_offset = 0; 676898Skais cipher_data.cd_length = rec_sz; 677898Skais cipher_data.cd_miscdata = NULL; 678898Skais cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; 679898Skais cipher_data.cd_raw.iov_len = rec_sz; 680898Skais error = crypto_decrypt_update(spec->cipher_ctx, 681898Skais &cipher_data, NULL, NULL); 682898Skais if (CRYPTO_ERR(error)) { 683898Skais #ifdef DEBUG 684898Skais cmn_err(CE_WARN, "kssl_handle_record: " 685898Skais "crypto_decrypt_update failed: 0x%02X", 686898Skais error); 687898Skais #endif /* DEBUG */ 688898Skais KSSL_COUNTER(record_decrypt_failure, 1); 689898Skais mp->b_rptr = recend; 690898Skais desc = decrypt_error; 691898Skais goto makealert; 692898Skais } 693898Skais } 694898Skais if (spec->cipher_type == type_block) { 695898Skais uint_t pad_sz = recend[-1]; 696898Skais pad_sz++; 697898Skais if (pad_sz + mac_sz > rec_sz) { 698898Skais mp->b_rptr = recend; 699898Skais desc = bad_record_mac; 700898Skais goto makealert; 701898Skais } 702898Skais rec_sz -= pad_sz; 703898Skais recend -= pad_sz; 704898Skais } 705898Skais if (mac_sz != 0) { 706898Skais uchar_t hash[MAX_HASH_LEN]; 707898Skais if (rec_sz < mac_sz) { 708898Skais mp->b_rptr = real_recend; 709898Skais desc = bad_record_mac; 710898Skais goto makealert; 711898Skais } 712898Skais rec_sz -= mac_sz; 713898Skais recend -= mac_sz; 714898Skais ret = kssl_compute_record_mac(ssl, KSSL_READ, 715898Skais ssl->seq_num[KSSL_READ], content_type, 716898Skais version, mp->b_rptr, rec_sz, hash); 717898Skais if (ret != CRYPTO_SUCCESS || 718898Skais bcmp(hash, recend, mac_sz)) { 719898Skais mp->b_rptr = real_recend; 720898Skais desc = bad_record_mac; 721898Skais #ifdef DEBUG 722898Skais cmn_err(CE_WARN, "kssl_handle_record: " 723898Skais "msg MAC mismatch"); 724898Skais #endif /* DEBUG */ 725898Skais KSSL_COUNTER(verify_mac_failure, 1); 726898Skais goto makealert; 727898Skais } 728898Skais ssl->seq_num[KSSL_READ]++; 729898Skais } 730898Skais 731898Skais if (ssl->hs_waitstate != idle_handshake) { 732898Skais mp->b_rptr = real_recend; 733898Skais desc = unexpected_message; 734898Skais goto makealert; 735898Skais } 736898Skais mp->b_wptr = recend; 737898Skais 738*4556Svk199839 DB_FLAGS(mp) |= DBLK_COOKED; 739*4556Svk199839 KSSL_COUNTER(appdata_record_ins, 1); 740*4556Svk199839 741898Skais prevmp = mp; 742898Skais mp = mp->b_cont; 743898Skais } 744898Skais 745898Skais return (kssl_cmd); 746898Skais 747898Skais makealert: 748898Skais nextmp = mp->b_cont; 749898Skais freeb(mp); 750898Skais mp = nextmp; 751898Skais mutex_enter(&ssl->kssl_lock); 752898Skais kssl_send_alert(ssl, alert_fatal, desc); 753898Skais 754898Skais if (ssl->alert_sendbuf == NULL) { 755898Skais /* internal memory allocation failure. just return. */ 756898Skais #ifdef DEBUG 757898Skais cmn_err(CE_WARN, "kssl_handle_record: " 758898Skais "alert message allocation failed"); 759898Skais #endif /* DEBUG */ 760898Skais mutex_exit(&ssl->kssl_lock); 761898Skais 762898Skais if (mp) { 763898Skais prevmp = NULL; 764898Skais goto more; 765898Skais } 766898Skais 767898Skais return (KSSL_CMD_NONE); 768898Skais } 769898Skais kssl_cmd = KSSL_CMD_SEND; 770898Skais sendalert: 771898Skais if (*outmp == NULL) { 772898Skais *outmp = ssl->alert_sendbuf; 773898Skais } else { 774898Skais linkb(*outmp, ssl->alert_sendbuf); 775898Skais } 776898Skais ssl->alert_sendbuf = NULL; 777898Skais mutex_exit(&ssl->kssl_lock); 778898Skais 779898Skais if (mp) { 780898Skais prevmp = NULL; 781898Skais goto more; 782898Skais } 783898Skais 784898Skais return (kssl_cmd); 785898Skais } 786898Skais /* 787898Skais * This is the routine that handles incoming SSL records. 788898Skais * When called the first time, with a NULL context, this routine expects 789898Skais * a ClientHello SSL Handshake packet and shall allocate a context 790898Skais * of a new SSL connection. 791898Skais * During the rest of the handshake packets, the routine adjusts the 792898Skais * state of the context according to the record received. 793898Skais * After the ChangeCipherSpec message is received, the routine first 794898Skais * decrypts/authenticated the packet using the key materials in the 795898Skais * connection's context. 796898Skais * The return code tells the caller what to do with the returned packet. 797898Skais */ 798898Skais static kssl_cmd_t 799898Skais kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, 800898Skais kssl_callback_t cbfn, void *arg) 801898Skais { 802898Skais uchar_t *recend, *rec_sz_p; 803898Skais uchar_t version[2]; 804898Skais uchar_t *real_recend, *save_rptr, *save_wptr; 805898Skais int rhsz = SSL3_HDR_LEN; 806898Skais uint16_t rec_sz; 807898Skais int sz; 808898Skais int mac_sz; 809898Skais SSL3AlertDescription desc; 810898Skais SSL3AlertLevel level; 811898Skais SSL3ContentType content_type; 812898Skais ssl_t *ssl; 813898Skais KSSLCipherSpec *spec; 814898Skais int error = 0, ret; 815898Skais 816898Skais ASSERT(ctx != NULL); 817898Skais 818898Skais ssl = (ssl_t *)(ctx); 819898Skais 820898Skais *decrmp = NULL; 821898Skais 822898Skais save_rptr = mp->b_rptr; 823898Skais save_wptr = mp->b_wptr; 824898Skais 825898Skais ASSERT(MUTEX_HELD(&ssl->kssl_lock)); 826898Skais 827898Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 828898Skais if (content_type == content_handshake_v2) { 829898Skais if (ssl->hs_waitstate == wait_client_hello) { 830898Skais /* V2 compatible ClientHello */ 831898Skais if (mp->b_rptr[3] == 0x03 && 832898Skais (mp->b_rptr[4] == 0x01 || 833898Skais mp->b_rptr[4] == 0x00)) { 834898Skais ssl->major_version = version[0] = mp->b_rptr[3]; 835898Skais ssl->minor_version = version[1] = mp->b_rptr[4]; 836898Skais } else { 837898Skais /* We don't support "pure" SSLv2 */ 838898Skais desc = protocol_version; 839898Skais goto sendalert; 840898Skais } 841898Skais } 842898Skais rec_sz = (uint16_t)mp->b_rptr[1]; 843898Skais rhsz = 2; 844898Skais } else { 845898Skais ssl->major_version = version[0] = mp->b_rptr[1]; 846898Skais ssl->minor_version = version[1] = mp->b_rptr[2]; 847898Skais rec_sz_p = SSL3_REC_SIZE(mp); 848898Skais rec_sz = BE16_TO_U16(rec_sz_p); 849898Skais } 850898Skais 851898Skais mp->b_rptr += rhsz; 852898Skais recend = mp->b_rptr + rec_sz; 853898Skais real_recend = recend; 854898Skais 855*4556Svk199839 /* 856*4556Svk199839 * Check the assumption that each mblk contains exactly 857*4556Svk199839 * one complete SSL record. We bail out if the check fails. 858*4556Svk199839 */ 859*4556Svk199839 ASSERT(recend == mp->b_wptr); 860*4556Svk199839 if (recend != mp->b_wptr) { 861*4556Svk199839 desc = decode_error; 862*4556Svk199839 KSSL_COUNTER(internal_errors, 1); 863*4556Svk199839 goto sendalert; 864*4556Svk199839 } 865*4556Svk199839 866898Skais spec = &ssl->spec[KSSL_READ]; 867898Skais mac_sz = spec->mac_hashsz; 868898Skais if (spec->cipher_ctx != 0) { 8691139Skais /* 8701139Skais * The record length must be a multiple of the 8711139Skais * block size for block ciphers. 8721139Skais */ 8731139Skais if ((spec->cipher_type == type_block) && 8741139Skais ((rec_sz & (spec->cipher_bsize - 1)) != 0)) { 8751139Skais #ifdef DEBUG 8761139Skais cmn_err(CE_WARN, "kssl_handle_any_record: " 8771139Skais "bad record size"); 8781139Skais #endif /* DEBUG */ 8791139Skais KSSL_COUNTER(record_decrypt_failure, 1); 8801139Skais mp->b_rptr = recend; 8811139Skais desc = decrypt_error; 8821139Skais goto sendalert; 8831139Skais } 8841139Skais 885898Skais spec->cipher_data.cd_length = rec_sz; 886898Skais spec->cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; 887898Skais spec->cipher_data.cd_raw.iov_len = rec_sz; 888898Skais error = crypto_decrypt_update(spec->cipher_ctx, 889898Skais &spec->cipher_data, NULL, NULL); 890898Skais if (CRYPTO_ERR(error)) { 891898Skais #ifdef DEBUG 892898Skais cmn_err(CE_WARN, 893898Skais "kssl_handle_any_record: crypto_decrypt_update " 894898Skais "failed: 0x%02X", error); 895898Skais #endif /* DEBUG */ 896898Skais KSSL_COUNTER(record_decrypt_failure, 1); 897898Skais mp->b_rptr = recend; 898898Skais desc = decrypt_error; 899898Skais goto sendalert; 900898Skais } 901898Skais } 902898Skais if (spec->cipher_type == type_block) { 903898Skais uint_t pad_sz = recend[-1]; 904898Skais pad_sz++; 905898Skais if (pad_sz + mac_sz > rec_sz) { 906898Skais mp->b_rptr = recend; 907898Skais desc = bad_record_mac; 908898Skais goto sendalert; 909898Skais } 910898Skais rec_sz -= pad_sz; 911898Skais recend -= pad_sz; 912898Skais } 913898Skais if (mac_sz != 0) { 914898Skais uchar_t hash[MAX_HASH_LEN]; 915898Skais if (rec_sz < mac_sz) { 916898Skais mp->b_rptr = real_recend; 917898Skais desc = bad_record_mac; 918898Skais goto sendalert; 919898Skais } 920898Skais rec_sz -= mac_sz; 921898Skais recend -= mac_sz; 922898Skais ret = kssl_compute_record_mac(ssl, KSSL_READ, 923898Skais ssl->seq_num[KSSL_READ], content_type, 924898Skais version, mp->b_rptr, rec_sz, hash); 925898Skais if (ret != CRYPTO_SUCCESS || 926898Skais bcmp(hash, recend, mac_sz)) { 927898Skais mp->b_rptr = real_recend; 928898Skais desc = bad_record_mac; 929898Skais #ifdef DEBUG 930898Skais cmn_err(CE_WARN, "kssl_handle_any_record: " 931898Skais "msg MAC mismatch"); 932898Skais #endif /* DEBUG */ 933898Skais KSSL_COUNTER(verify_mac_failure, 1); 934898Skais goto sendalert; 935898Skais } 936898Skais ssl->seq_num[KSSL_READ]++; 937898Skais } 938898Skais 939898Skais switch (content_type) { 940898Skais case content_handshake: 941898Skais do { 942898Skais if (error != 0 || 943898Skais /* ignore client renegotiation for now */ 944898Skais ssl->hs_waitstate == idle_handshake) { 945898Skais mp->b_rptr = recend; 946898Skais } 947898Skais if (mp->b_rptr == recend) { 948898Skais mp->b_rptr = real_recend; 949898Skais if (error != 0) { 950898Skais goto error; 951898Skais } 952898Skais freeb(mp); 953898Skais 954898Skais if (ssl->hs_waitstate == wait_client_key_done) 955898Skais return (KSSL_CMD_QUEUED); 956898Skais 957898Skais return ((ssl->handshake_sendbuf != NULL) ? 958898Skais KSSL_CMD_SEND : KSSL_CMD_NONE); 959898Skais } 960898Skais if (ssl->msg.state < MSG_BODY) { 961898Skais if (ssl->msg.state == MSG_INIT) { 962898Skais ssl->msg.type = 963898Skais (SSL3HandshakeType)*mp->b_rptr++; 964898Skais ssl->msg.state = MSG_INIT_LEN; 965898Skais } 966898Skais if (ssl->msg.state == MSG_INIT_LEN) { 967898Skais int msglenb = 968898Skais ssl->msg.msglen_bytes; 969898Skais int msglen = ssl->msg.msglen; 970898Skais while (mp->b_rptr < recend && 971898Skais msglenb < 3) { 972898Skais msglen = (msglen << 8) + 973898Skais (uint_t)(*mp->b_rptr++); 974898Skais msglenb++; 975898Skais } 976898Skais ssl->msg.msglen_bytes = msglenb; 977898Skais ssl->msg.msglen = msglen; 978898Skais if (msglenb == 3) { 979898Skais ssl->msg.state = MSG_BODY; 980898Skais } 981898Skais } 982898Skais if (mp->b_rptr == recend) { 983898Skais mp->b_rptr = real_recend; 984898Skais freeb(mp); 985898Skais return (KSSL_CMD_NONE); 986898Skais } 987898Skais } 988898Skais ASSERT(ssl->msg.state == MSG_BODY); 989898Skais 990898Skais sz = recend - mp->b_rptr; 991898Skais 992898Skais if (ssl->msg.head == NULL && 993898Skais ssl->msg.msglen <= sz) { 994898Skais continue; 995898Skais } 996898Skais if (ssl->msg.head != NULL) { 997898Skais sz += msgdsize(ssl->msg.head); 998898Skais if (ssl->msg.msglen <= sz) { 999898Skais ssl->msg.tail->b_cont = mp; 1000898Skais mp = ssl->msg.head; 1001898Skais ssl->sslcnt = 100; 1002898Skais ssl->msg.head = NULL; 1003898Skais ssl->msg.tail = NULL; 1004898Skais if (pullupmsg(mp, -1)) { 1005898Skais recend = mp->b_rptr + sz; 1006898Skais ASSERT(recend <= mp->b_wptr); 1007898Skais continue; 1008898Skais } 1009898Skais mp->b_rptr = real_recend; 1010898Skais error = ENOMEM; 1011898Skais KSSL_COUNTER(alloc_fails, 1); 1012898Skais goto error; 1013898Skais } 1014898Skais } 1015898Skais 1016898Skais mp->b_wptr = recend; 1017898Skais 1018898Skais if (ssl->msg.head == NULL) { 1019898Skais ssl->msg.head = mp; 1020898Skais ssl->msg.tail = mp; 1021898Skais return (KSSL_CMD_NONE); 1022898Skais } else { 1023898Skais ssl->msg.tail->b_cont = mp; 1024898Skais ssl->msg.tail = mp; 1025898Skais return (KSSL_CMD_NONE); 1026898Skais } 1027898Skais } while (kssl_handle_handshake_message(ssl, mp, &error, cbfn, 1028898Skais arg)); 1029898Skais if (error == SSL_MISS) { 1030898Skais mp->b_rptr = save_rptr; 1031898Skais mp->b_wptr = save_wptr; 1032898Skais KSSL_COUNTER(fallback_connections, 1); 1033898Skais return (KSSL_CMD_NOT_SUPPORTED); 1034898Skais } 1035898Skais if (ssl->hs_waitstate == wait_client_key_done) { 1036898Skais return (KSSL_CMD_QUEUED); 1037898Skais } else { 1038898Skais return (KSSL_CMD_NONE); 1039898Skais } 1040898Skais case content_alert: 1041898Skais if (rec_sz != 2) { 1042898Skais mp->b_rptr = real_recend; 1043898Skais desc = illegal_parameter; 1044898Skais goto sendalert; 1045898Skais } else { 1046898Skais level = *mp->b_rptr++; 1047898Skais desc = *mp->b_rptr++; 1048898Skais mp->b_rptr = real_recend; 1049898Skais if (level != alert_warning || desc != close_notify) { 1050898Skais if (ssl->sid.cached == B_TRUE) { 1051898Skais kssl_uncache_sid(&ssl->sid, 1052898Skais ssl->kssl_entry); 1053898Skais ssl->sid.cached = B_FALSE; 1054898Skais } 1055898Skais ssl->fatal_alert = B_TRUE; 1056898Skais error = EBADMSG; 1057898Skais goto error; 1058898Skais } else { 1059898Skais ssl->close_notify = B_TRUE; 1060898Skais ssl->activeinput = B_FALSE; 1061898Skais freeb(mp); 1062898Skais return (KSSL_CMD_NONE); 1063898Skais } 1064898Skais } 1065898Skais case content_change_cipher_spec: 1066898Skais if (ssl->hs_waitstate != wait_change_cipher) { 1067898Skais desc = unexpected_message; 1068898Skais } else if (rec_sz != 1 || *mp->b_rptr != 1) { 1069898Skais desc = illegal_parameter; 1070898Skais } else { 1071898Skais mp->b_rptr = real_recend; 1072898Skais ssl->hs_waitstate = wait_finished; 1073898Skais ssl->seq_num[KSSL_READ] = 0; 1074898Skais if ((error = kssl_spec_init(ssl, KSSL_READ)) != 0) { 1075898Skais #ifdef DEBUG 1076898Skais cmn_err(CE_WARN, 1077898Skais "kssl_spec_init returned error " 1078898Skais "0x%02X", error); 1079898Skais #endif /* DEBUG */ 1080898Skais goto error; 1081898Skais } 1082898Skais ssl->activeinput = B_FALSE; 1083898Skais freeb(mp); 1084898Skais return (KSSL_CMD_NONE); 1085898Skais } 1086898Skais mp->b_rptr = real_recend; 1087898Skais goto sendalert; 1088898Skais 1089898Skais case content_application_data: 1090898Skais if (ssl->hs_waitstate != idle_handshake) { 1091898Skais mp->b_rptr = real_recend; 1092898Skais desc = unexpected_message; 1093898Skais goto sendalert; 1094898Skais } 1095898Skais mp->b_wptr = recend; 1096898Skais *decrmp = mp; 1097898Skais ssl->activeinput = B_FALSE; 1098898Skais return (KSSL_CMD_DELIVER_PROXY); 1099898Skais 1100898Skais case content_handshake_v2: 1101898Skais error = kssl_handle_v2client_hello(ssl, mp, rec_sz); 1102898Skais if (error == SSL_MISS) { 1103898Skais mp->b_rptr = save_rptr; 1104898Skais mp->b_wptr = save_wptr; 1105898Skais KSSL_COUNTER(fallback_connections, 1); 1106898Skais return (KSSL_CMD_NOT_SUPPORTED); 1107898Skais } else if (error != 0) { 1108898Skais goto error; 1109898Skais } 1110898Skais freeb(mp); 1111898Skais return (KSSL_CMD_SEND); 1112898Skais default: 1113898Skais mp->b_rptr = real_recend; 1114898Skais desc = unexpected_message; 1115898Skais break; 1116898Skais } 1117898Skais 1118898Skais sendalert: 1119898Skais kssl_send_alert(ssl, alert_fatal, desc); 1120898Skais *decrmp = ssl->alert_sendbuf; 1121898Skais ssl->alert_sendbuf = NULL; 1122898Skais freeb(mp); 1123898Skais return ((*decrmp != NULL) ? KSSL_CMD_SEND : KSSL_CMD_NONE); 1124898Skais error: 1125898Skais freeb(mp); 1126898Skais return (KSSL_CMD_NONE); 1127898Skais } 1128898Skais 1129898Skais /* 1130898Skais * Initialize the context of an SSL connection, coming to the specified 1131898Skais * address. 1132898Skais * the ssl structure returned is held. 1133898Skais */ 1134898Skais kssl_status_t 1135898Skais kssl_init_context(kssl_ent_t kssl_ent, ipaddr_t faddr, int mss, 1136898Skais kssl_ctx_t *kssl_ctxp) 1137898Skais { 1138898Skais ssl_t *ssl = kmem_cache_alloc(kssl_cache, KM_NOSLEEP); 1139898Skais 1140898Skais if (ssl == NULL) { 1141898Skais return (KSSL_STS_ERR); 1142898Skais } 1143898Skais 1144898Skais kssl_cache_count++; 1145898Skais 1146898Skais bzero(ssl, sizeof (ssl_t)); 1147898Skais 1148898Skais ssl->kssl_entry = (kssl_entry_t *)kssl_ent; 1149898Skais KSSL_ENTRY_REFHOLD(ssl->kssl_entry); 1150898Skais 1151898Skais ssl->faddr = faddr; 1152898Skais ssl->tcp_mss = mss; 1153898Skais ssl->sendalert_level = alert_warning; 1154898Skais ssl->sendalert_desc = close_notify; 1155898Skais ssl->sid.cached = B_FALSE; 1156898Skais 1157898Skais *kssl_ctxp = (kssl_ctx_t)ssl; 1158898Skais KSSL_SSL_REFHOLD(ssl); 1159898Skais return (KSSL_STS_OK); 1160898Skais } 1161898Skais 1162898Skais /* 1163898Skais * Builds SSL records out of the chain of mblks, and returns it. 1164898Skais * Taked a copy of the message before encypting it if it has another 1165898Skais * reference. 1166898Skais * In case of failure, NULL is returned, and the message will be 1167898Skais * freed by the caller. 1168898Skais * A NULL mp means a close_notify is requested. 1169898Skais */ 1170898Skais mblk_t * 1171898Skais kssl_build_record(kssl_ctx_t ctx, mblk_t *mp) 1172898Skais { 1173898Skais ssl_t *ssl = (ssl_t *)ctx; 1174898Skais mblk_t *retmp = mp, *bp = mp, *prevbp = mp, *copybp; 1175898Skais 1176898Skais ASSERT(ssl != NULL); 1177898Skais ASSERT(mp != NULL); 1178898Skais 1179898Skais do { 1180898Skais if (DB_REF(bp) > 1) { 1181898Skais /* 1182898Skais * Fortunately copyb() preserves the offset, 1183898Skais * tail space and alignement so the copy is 1184898Skais * ready to be made an SSL record. 1185898Skais */ 1186898Skais if ((copybp = copyb(bp)) == NULL) 1187898Skais return (NULL); 1188898Skais 1189898Skais copybp->b_cont = bp->b_cont; 1190898Skais if (bp == mp) { 1191898Skais retmp = copybp; 1192898Skais } else { 1193898Skais prevbp->b_cont = copybp; 1194898Skais } 1195898Skais freeb(bp); 1196898Skais bp = copybp; 1197898Skais } 1198898Skais 1199898Skais if (kssl_build_single_record(ssl, bp) != KSSL_STS_OK) 1200898Skais return (NULL); 1201898Skais 1202898Skais prevbp = bp; 1203898Skais bp = bp->b_cont; 1204898Skais } while (bp != NULL); 1205898Skais 1206898Skais return (retmp); 1207898Skais } 1208898Skais 1209898Skais /* 1210898Skais * Builds a single SSL record 1211898Skais * In-line encryption of the record. 1212898Skais */ 1213898Skais static kssl_status_t 1214898Skais kssl_build_single_record(ssl_t *ssl, mblk_t *mp) 1215898Skais { 1216898Skais int len; 1217898Skais int reclen = 0; 1218898Skais uchar_t *recstart, *versionp; 1219898Skais KSSLCipherSpec *spec; 1220898Skais int mac_sz; 1221898Skais int pad_sz = 0; 1222898Skais 1223898Skais 1224898Skais spec = &ssl->spec[KSSL_WRITE]; 1225898Skais mac_sz = spec->mac_hashsz; 1226898Skais 1227898Skais 1228898Skais ASSERT(DB_REF(mp) == 1); 1229898Skais ASSERT((mp->b_rptr - mp->b_datap->db_base >= SSL3_HDR_LEN) && 1230898Skais (mp->b_datap->db_lim - mp->b_wptr >= mac_sz + spec->cipher_bsize)); 1231898Skais 1232898Skais len = MBLKL(mp); 1233898Skais 1234898Skais ASSERT(len > 0); 1235898Skais 1236898Skais mutex_enter(&ssl->kssl_lock); 1237898Skais 1238898Skais recstart = mp->b_rptr = mp->b_rptr - SSL3_HDR_LEN; 1239898Skais recstart[0] = content_application_data; 1240898Skais recstart[1] = ssl->major_version; 1241898Skais recstart[2] = ssl->minor_version; 1242898Skais versionp = &recstart[1]; 1243898Skais 1244898Skais reclen = len + mac_sz; 1245898Skais if (spec->cipher_type == type_block) { 1246898Skais pad_sz = spec->cipher_bsize - 1247898Skais (reclen & (spec->cipher_bsize - 1)); 1248898Skais ASSERT(reclen + pad_sz <= 1249898Skais SSL3_MAX_RECORD_LENGTH); 1250898Skais reclen += pad_sz; 1251898Skais } 1252898Skais recstart[3] = (reclen >> 8) & 0xff; 1253898Skais recstart[4] = reclen & 0xff; 1254898Skais 1255898Skais if (kssl_mac_encrypt_record(ssl, content_application_data, versionp, 1256898Skais recstart, mp) != 0) { 1257898Skais /* Do we need an internal_error Alert here? */ 1258898Skais mutex_exit(&ssl->kssl_lock); 1259898Skais return (KSSL_STS_ERR); 1260898Skais } 1261898Skais 1262898Skais KSSL_COUNTER(appdata_record_outs, 1); 1263898Skais mutex_exit(&ssl->kssl_lock); 1264898Skais return (KSSL_STS_OK); 1265898Skais } 1266