1c28749e9Skais /* 2c28749e9Skais * CDDL HEADER START 3c28749e9Skais * 4c28749e9Skais * The contents of this file are subject to the terms of the 539d67566Skais * Common Development and Distribution License (the "License"). 639d67566Skais * You may not use this file except in compliance with the License. 7c28749e9Skais * 8c28749e9Skais * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9c28749e9Skais * or http://www.opensolaris.org/os/licensing. 10c28749e9Skais * See the License for the specific language governing permissions 11c28749e9Skais * and limitations under the License. 12c28749e9Skais * 13c28749e9Skais * When distributing Covered Code, include this CDDL HEADER in each 14c28749e9Skais * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15c28749e9Skais * If applicable, add the following below this CDDL HEADER, with the 16c28749e9Skais * fields enclosed by brackets "[]" replaced with your own identifying 17c28749e9Skais * information: Portions Copyright [yyyy] [name of copyright owner] 18c28749e9Skais * 19c28749e9Skais * CDDL HEADER END 20c28749e9Skais */ 21c28749e9Skais /* 2211d0a659SVladimir Kotal * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23c28749e9Skais */ 24c28749e9Skais 25c28749e9Skais #include <sys/types.h> 26c28749e9Skais #include <sys/stream.h> 27c28749e9Skais #include <sys/strsun.h> 28c28749e9Skais #include <sys/kmem.h> 29c28749e9Skais #include <sys/cpuvar.h> 30c28749e9Skais #include <sys/atomic.h> 31c28749e9Skais #include <sys/sysmacros.h> 32c28749e9Skais 33c28749e9Skais #include <inet/common.h> 34c28749e9Skais #include <inet/ip.h> 35c28749e9Skais 36c28749e9Skais #include <sys/systm.h> 37c28749e9Skais #include <sys/param.h> 38c28749e9Skais #include <sys/tihdr.h> 39c28749e9Skais 40c28749e9Skais #include "ksslimpl.h" 41c28749e9Skais #include "ksslproto.h" 42c28749e9Skais #include "ksslapi.h" 43c28749e9Skais 44c28749e9Skais static kssl_cmd_t kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, 45c28749e9Skais mblk_t **decrmp, kssl_callback_t cbfn, void *arg); 46c28749e9Skais static boolean_t kssl_enqueue(kssl_chain_t **head, void *item); 47c28749e9Skais static void kssl_dequeue(kssl_chain_t **head, void *item); 48c28749e9Skais static kssl_status_t kssl_build_single_record(ssl_t *ssl, mblk_t *mp); 49c28749e9Skais 50c28749e9Skais /* 51dd49f125SAnders Persson * The socket bind request is intercepted and re-routed here 52c28749e9Skais * to see is there is SSL relevant job to do, based on the kssl config 53c28749e9Skais * in the kssl_entry_tab. 54c28749e9Skais * Looks up the kernel SSL proxy table, to find an entry that matches the 55c28749e9Skais * same serveraddr, and has one of the following two criteria: 56c28749e9Skais * 1. in_port is an ssl_port. This endpoint can be used later as a fallback 57c28749e9Skais * to complete connections that cannot be handled by the SSL kernel proxy 58c28749e9Skais * (typically non supported ciphersuite). The cookie for the calling client 59c28749e9Skais * is saved with the kssl_entry to be retrieved for the fallback. 60c28749e9Skais * The function returns KSSL_HAS_PROXY. 61c28749e9Skais * 62c28749e9Skais * 2. in_port is a proxy port for another ssl port. The ssl port is then 63c28749e9Skais * substituted to the in_port in the bind_req TPI structure, so that 64c28749e9Skais * the bind falls through to the SSL port. At the end of this operation, 65c28749e9Skais * all the packets arriving to the SSL port will be delivered to an 66c28749e9Skais * accepted endpoint child of this bound socket. 67c28749e9Skais * The kssl_entry_t is returned in *ksslent, for later use by the 68c28749e9Skais * lower modules' SSL hooks that handle the Handshake messages. 69c28749e9Skais * The function returns KSSL_IS_PROXY. 70c28749e9Skais * 712ec7cc7fSKrishna Yenduri * The function returns KSSL_NO_PROXY otherwise. 72c28749e9Skais */ 73c28749e9Skais 74c28749e9Skais kssl_endpt_type_t 75dd49f125SAnders Persson kssl_check_proxy(struct sockaddr *addr, socklen_t len, void *cookie, 76dd49f125SAnders Persson kssl_ent_t *ksslent) 77c28749e9Skais { 78c28749e9Skais int i; 79c28749e9Skais kssl_endpt_type_t ret; 80c28749e9Skais kssl_entry_t *ep; 81c28749e9Skais sin_t *sin; 8252bf5e39SKrishna Yenduri sin6_t *sin6; 832ec7cc7fSKrishna Yenduri in6_addr_t mapped_v4addr; 842ec7cc7fSKrishna Yenduri in6_addr_t *v6addr; 85c28749e9Skais in_port_t in_port; 86c28749e9Skais 872ec7cc7fSKrishna Yenduri if (kssl_entry_tab_nentries == 0) { 88c28749e9Skais return (KSSL_NO_PROXY); 89c28749e9Skais } 90c28749e9Skais 91c28749e9Skais ret = KSSL_NO_PROXY; 92dd49f125SAnders Persson sin = (struct sockaddr_in *)addr; 93c28749e9Skais 94dd49f125SAnders Persson switch (len) { 95c28749e9Skais case sizeof (sin_t): 96c28749e9Skais in_port = ntohs(sin->sin_port); 972ec7cc7fSKrishna Yenduri IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &mapped_v4addr); 982ec7cc7fSKrishna Yenduri v6addr = &mapped_v4addr; 99c28749e9Skais break; 100c28749e9Skais 101c28749e9Skais case sizeof (sin6_t): 10252bf5e39SKrishna Yenduri sin6 = (sin6_t *)sin; 10352bf5e39SKrishna Yenduri in_port = ntohs(sin6->sin6_port); 1042ec7cc7fSKrishna Yenduri v6addr = &sin6->sin6_addr; 10552bf5e39SKrishna Yenduri break; 10652bf5e39SKrishna Yenduri 107c28749e9Skais default: 108c28749e9Skais return (ret); 109c28749e9Skais } 110c28749e9Skais 111c28749e9Skais mutex_enter(&kssl_tab_mutex); 112c28749e9Skais 113c28749e9Skais for (i = 0; i < kssl_entry_tab_size; i++) { 114c28749e9Skais if ((ep = kssl_entry_tab[i]) == NULL) 115c28749e9Skais continue; 116c28749e9Skais 1172ec7cc7fSKrishna Yenduri if (IN6_ARE_ADDR_EQUAL(&ep->ke_laddr, v6addr) || 1182ec7cc7fSKrishna Yenduri IN6_IS_ADDR_UNSPECIFIED(&ep->ke_laddr)) { 119c28749e9Skais 120c28749e9Skais /* This is an SSL port to fallback to */ 121c28749e9Skais if (ep->ke_ssl_port == in_port) { 122c28749e9Skais 123c28749e9Skais /* 124c28749e9Skais * Let's see first if there's at least 125c28749e9Skais * an endpoint for a proxy server. 126c28749e9Skais * If there's none, then we return as we have 127c28749e9Skais * no proxy, so that the bind() to the 128c28749e9Skais * transport layer goes through. 129c28749e9Skais * The calling module will ask for this 130c28749e9Skais * cookie if it wants to fall back to it, 131c28749e9Skais * so add this one to the list of fallback 132c28749e9Skais * clients. 133c28749e9Skais */ 134c28749e9Skais if (!kssl_enqueue((kssl_chain_t **) 135c28749e9Skais &(ep->ke_fallback_head), cookie)) { 136c28749e9Skais break; 137c28749e9Skais } 138c28749e9Skais 139c28749e9Skais KSSL_ENTRY_REFHOLD(ep); 140c28749e9Skais *ksslent = (kssl_ent_t)ep; 141c28749e9Skais 142c28749e9Skais ret = KSSL_HAS_PROXY; 143c28749e9Skais break; 144c28749e9Skais } 145c28749e9Skais 146c28749e9Skais /* This is a proxy port. */ 147c28749e9Skais if (ep->ke_proxy_port == in_port) { 148c28749e9Skais /* Add the caller's cookie to proxies list */ 149c28749e9Skais 150c28749e9Skais if (!kssl_enqueue((kssl_chain_t **) 151c28749e9Skais &(ep->ke_proxy_head), cookie)) { 152c28749e9Skais break; 153c28749e9Skais } 154c28749e9Skais 155c28749e9Skais /* 156c28749e9Skais * Make this look like the SSL port to the 157c28749e9Skais * transport below 158c28749e9Skais */ 159c28749e9Skais sin->sin_port = htons(ep->ke_ssl_port); 160c28749e9Skais 161c28749e9Skais KSSL_ENTRY_REFHOLD(ep); 162c28749e9Skais *ksslent = (kssl_ent_t)ep; 163c28749e9Skais 164c28749e9Skais ret = KSSL_IS_PROXY; 165c28749e9Skais break; 166c28749e9Skais } 167c28749e9Skais } 168c28749e9Skais } 169c28749e9Skais 170c28749e9Skais mutex_exit(&kssl_tab_mutex); 171c28749e9Skais return (ret); 172c28749e9Skais } 173c28749e9Skais 174c28749e9Skais /* 175c28749e9Skais * Retrieved an endpoint "bound" to the SSL entry. 176c28749e9Skais * Such endpoint has previously called kssl_check_proxy(), got itself 177c28749e9Skais * linked to the kssl_entry's ke_fallback_head list. 178c28749e9Skais * This routine returns the cookie from that SSL entry ke_fallback_head list. 179c28749e9Skais */ 180c28749e9Skais void * 181c28749e9Skais kssl_find_fallback(kssl_ent_t ksslent) 182c28749e9Skais { 183c28749e9Skais kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; 184c28749e9Skais 185c28749e9Skais if (kssl_entry->ke_fallback_head != NULL) 186c28749e9Skais return (kssl_entry->ke_fallback_head->fallback_bound); 187c28749e9Skais 188c28749e9Skais KSSL_COUNTER(proxy_fallback_failed, 1); 189c28749e9Skais 190c28749e9Skais return (NULL); 191c28749e9Skais } 192c28749e9Skais 193c28749e9Skais /* 194c28749e9Skais * Re-usable code for adding and removing an element to/from a chain that 195c28749e9Skais * matches "item" 196c28749e9Skais * The chain is simple-linked and NULL ended. 197c28749e9Skais */ 198c28749e9Skais 199c28749e9Skais /* 200c28749e9Skais * This routine returns TRUE if the item was either successfully added to 201c28749e9Skais * the chain, or is already there. It returns FALSE otherwise. 202c28749e9Skais */ 203c28749e9Skais static boolean_t 204c28749e9Skais kssl_enqueue(kssl_chain_t **head, void *item) 205c28749e9Skais { 206c28749e9Skais kssl_chain_t *newchain, *cur; 207c28749e9Skais 208c28749e9Skais /* Lookup the existing entries to avoid duplicates */ 209c28749e9Skais cur = *head; 210c28749e9Skais while (cur != NULL) { 211c28749e9Skais if (cur->item == item) { 212c28749e9Skais return (B_TRUE); 213c28749e9Skais } 214c28749e9Skais cur = cur->next; 215c28749e9Skais } 216c28749e9Skais 217c28749e9Skais newchain = kmem_alloc(sizeof (kssl_chain_t), KM_NOSLEEP); 218c28749e9Skais if (newchain == NULL) { 219c28749e9Skais return (B_FALSE); 220c28749e9Skais } 221c28749e9Skais 222c28749e9Skais newchain->item = item; 223c28749e9Skais newchain->next = *head; 224c28749e9Skais *head = newchain; 225c28749e9Skais return (B_TRUE); 226c28749e9Skais } 227c28749e9Skais 228c28749e9Skais static void 229c28749e9Skais kssl_dequeue(kssl_chain_t **head, void *item) 230c28749e9Skais { 231c28749e9Skais kssl_chain_t *prev, *cur; 232c28749e9Skais 233c28749e9Skais prev = cur = *head; 234c28749e9Skais while (cur != NULL) { 235c28749e9Skais if (cur->item == item) { 236c28749e9Skais if (cur == *head) 237c28749e9Skais *head = (*head)->next; 238c28749e9Skais else 239c28749e9Skais prev->next = cur->next; 240c28749e9Skais kmem_free(cur, sizeof (kssl_chain_t)); 241c28749e9Skais return; 242c28749e9Skais } 243c28749e9Skais prev = cur; 244c28749e9Skais cur = cur->next; 245c28749e9Skais } 246c28749e9Skais } 247c28749e9Skais 248c28749e9Skais /* 249c28749e9Skais * Holds the kssl_entry 250c28749e9Skais */ 251c28749e9Skais void 252c28749e9Skais kssl_hold_ent(kssl_ent_t ksslent) 253c28749e9Skais { 254c28749e9Skais KSSL_ENTRY_REFHOLD((kssl_entry_t *)ksslent); 255c28749e9Skais } 256c28749e9Skais 257c28749e9Skais /* 258c28749e9Skais * Releases the kssl_entry 259c28749e9Skais * If the caller passes a cookie, then it should be removed from both 260c28749e9Skais * proxies and fallbacks chains. 261c28749e9Skais */ 262c28749e9Skais void 263c28749e9Skais kssl_release_ent(kssl_ent_t ksslent, void *cookie, kssl_endpt_type_t endpt_type) 264c28749e9Skais { 265c28749e9Skais kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent; 266c28749e9Skais 267c28749e9Skais if (cookie != NULL) { 2682ec7cc7fSKrishna Yenduri if (endpt_type == KSSL_IS_PROXY) { 269c28749e9Skais ASSERT(kssl_entry->ke_proxy_head != NULL); 270c28749e9Skais kssl_dequeue( 271c28749e9Skais (kssl_chain_t **)&kssl_entry->ke_proxy_head, 272c28749e9Skais cookie); 2732ec7cc7fSKrishna Yenduri } 2742ec7cc7fSKrishna Yenduri if (endpt_type == KSSL_HAS_PROXY) { 275c28749e9Skais ASSERT(kssl_entry->ke_fallback_head != NULL); 276c28749e9Skais kssl_dequeue( 277c28749e9Skais (kssl_chain_t **)&kssl_entry->ke_fallback_head, 278c28749e9Skais cookie); 279c28749e9Skais } 2802ec7cc7fSKrishna Yenduri } 281c28749e9Skais KSSL_ENTRY_REFRELE(kssl_entry); 282c28749e9Skais } 283c28749e9Skais 284c28749e9Skais /* 285c28749e9Skais * Releases the kssl_context 286c28749e9Skais */ 287c28749e9Skais void 288c28749e9Skais kssl_release_ctx(kssl_ctx_t ksslctx) 289c28749e9Skais { 290dd49f125SAnders Persson kssl_free_context((ssl_t *)ksslctx); 291dd49f125SAnders Persson } 292dd49f125SAnders Persson 293dd49f125SAnders Persson /* 294dd49f125SAnders Persson * Done with asynchronous processing 295dd49f125SAnders Persson */ 296dd49f125SAnders Persson void 297dd49f125SAnders Persson kssl_async_done(kssl_ctx_t ksslctx) 298dd49f125SAnders Persson { 299dd49f125SAnders Persson ssl_t *ssl = (ssl_t *)ksslctx; 300dd49f125SAnders Persson 301dd49f125SAnders Persson mutex_enter(&ssl->kssl_lock); 302dd49f125SAnders Persson if (--ssl->async_ops_pending == 0) 303dd49f125SAnders Persson cv_signal(&ssl->async_cv); 304dd49f125SAnders Persson mutex_exit(&ssl->kssl_lock); 305c28749e9Skais } 306c28749e9Skais 307c28749e9Skais /* 308c28749e9Skais * Packets are accumulated here, if there are packets already queued, 309c28749e9Skais * or if the context is active. 310c28749e9Skais * The context is active when an incoming record processing function 311c28749e9Skais * is already executing on a different thread. 312c28749e9Skais * Queued packets are handled either when an mblk arrived and completes 313c28749e9Skais * a record, or, when the active context processor finishes the task at 314c28749e9Skais * hand. 315c28749e9Skais * The caller has to keep calling this routine in a loop until it returns 316c28749e9Skais * B_FALSE in *more. The reason for this is SSL3: The protocol 317c28749e9Skais * allows the client to send its first application_data message right 318c28749e9Skais * after it had sent its Finished message, and not wait for the server 319c28749e9Skais * ChangeCipherSpec and Finished. This overlap means we can't batch up 320c28749e9Skais * a returned Handshake message to be sent on the wire 321c28749e9Skais * with a decrypted application_data to be delivered to the application. 322c28749e9Skais */ 323c28749e9Skais kssl_cmd_t 324c28749e9Skais kssl_input(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, boolean_t *more, 325c28749e9Skais kssl_callback_t cbfn, void *arg) 326c28749e9Skais { 327c28749e9Skais mblk_t *recmp, *outmp = NULL; 328c28749e9Skais kssl_cmd_t kssl_cmd; 329c28749e9Skais ssl_t *ssl; 330c28749e9Skais uint8_t *rec_sz_p; 331c28749e9Skais int mplen; 332c28749e9Skais SSL3ContentType content_type; 333c28749e9Skais uint16_t rec_sz; 334c28749e9Skais 335c28749e9Skais ASSERT(ctx != NULL); 336c28749e9Skais 337c28749e9Skais if (mp != NULL) { 338c28749e9Skais ASSERT(mp->b_prev == NULL && mp->b_next == NULL); 339c28749e9Skais } 340c28749e9Skais 341c28749e9Skais ssl = (ssl_t *)(ctx); 342c28749e9Skais 343c28749e9Skais *decrmp = NULL; 344c28749e9Skais *more = B_FALSE; 345c28749e9Skais 346c28749e9Skais mutex_enter(&ssl->kssl_lock); 347c28749e9Skais 348*9b1bd49fSVladimir Kotal if (ssl->close_notify_clnt == B_TRUE) { 34951dd2c77Svk199839 DTRACE_PROBE(kssl_err__close_notify); 350c28749e9Skais goto sendnewalert; 351c28749e9Skais } 352c28749e9Skais 353c28749e9Skais /* Whomever is currently processing this connection will get to this */ 354c28749e9Skais if (ssl->activeinput) { 355c28749e9Skais if (mp != NULL) { 356c28749e9Skais KSSL_ENQUEUE_MP(ssl, mp); 357c28749e9Skais } 358c28749e9Skais mutex_exit(&ssl->kssl_lock); 359c28749e9Skais return (KSSL_CMD_NONE); 360c28749e9Skais } 361c28749e9Skais 362c28749e9Skais /* 363c28749e9Skais * Fast path for complete incoming application_data records on an empty 364c28749e9Skais * queue. 365c28749e9Skais * This is by far the most frequently encountered case 366c28749e9Skais */ 367c28749e9Skais 368c28749e9Skais if ((!ssl->activeinput) && (ssl->rec_ass_head == NULL) && 369c28749e9Skais ((mp != NULL) && (mplen = MBLKL(mp)) > SSL3_HDR_LEN)) { 370c28749e9Skais 37151dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__fast_path, mblk_t *, mp); 372c28749e9Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 373c28749e9Skais 374c28749e9Skais if ((content_type == content_application_data) && 375c28749e9Skais (ssl->hs_waitstate == idle_handshake)) { 376c28749e9Skais rec_sz_p = SSL3_REC_SIZE(mp); 377c28749e9Skais rec_sz = BE16_TO_U16(rec_sz_p); 378c28749e9Skais 379c28749e9Skais if ((mp->b_cont == NULL) && (mplen == rec_sz)) { 380c28749e9Skais 381c28749e9Skais *decrmp = mp; 382c28749e9Skais mutex_exit(&ssl->kssl_lock); 383c28749e9Skais return (KSSL_CMD_DELIVER_PROXY); 384c28749e9Skais } 385c28749e9Skais } 386c28749e9Skais } 387c28749e9Skais 388c28749e9Skais ssl->activeinput = B_TRUE; 389c28749e9Skais /* Accumulate at least one record */ 390c28749e9Skais if (mp != NULL) { 391c28749e9Skais KSSL_ENQUEUE_MP(ssl, mp); 392c28749e9Skais mp = NULL; 393c28749e9Skais } 394c28749e9Skais recmp = kssl_get_next_record(ssl); 395c28749e9Skais 396c28749e9Skais if (recmp == NULL) { 397c28749e9Skais ssl->activeinput = B_FALSE; 398c28749e9Skais if (ssl->alert_sendbuf != NULL) { 39951dd2c77Svk199839 DTRACE_PROBE(kssl_err__alert_to_send); 400c28749e9Skais goto sendalert; 401c28749e9Skais } 402c28749e9Skais /* Not even a complete header yet. wait for the rest */ 403c28749e9Skais mutex_exit(&ssl->kssl_lock); 404c28749e9Skais return (KSSL_CMD_NONE); 405c28749e9Skais } 406c28749e9Skais 407c28749e9Skais do { 40851dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__kssl_input_cycle, mblk_t *, recmp); 40984706141Svk199839 content_type = (SSL3ContentType)recmp->b_rptr[0]; 41084706141Svk199839 41184706141Svk199839 switch (content_type) { 41284706141Svk199839 case content_application_data: 413c28749e9Skais /* 414c28749e9Skais * application_data records are decrypted and 415c28749e9Skais * MAC-verified by the stream head, and in the context 416c28749e9Skais * a read()'ing thread. This avoids unfairly charging 417c28749e9Skais * the cost of handling this record on the whole system, 418c28749e9Skais * and prevents doing it while in the shared IP 419c28749e9Skais * perimeter. 420c28749e9Skais */ 421c28749e9Skais ssl->activeinput = B_FALSE; 422c28749e9Skais if (ssl->hs_waitstate != idle_handshake) { 42351dd2c77Svk199839 DTRACE_PROBE(kssl_err__waitstate_not_idle); 424c28749e9Skais goto sendnewalert; 425c28749e9Skais } 426c28749e9Skais outmp = recmp; 427c28749e9Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 42884706141Svk199839 break; 42984706141Svk199839 case content_change_cipher_spec: 43084706141Svk199839 case content_alert: 43184706141Svk199839 case content_handshake: 43284706141Svk199839 case content_handshake_v2: 433c28749e9Skais /* 434c28749e9Skais * If we're past the initial handshake, start letting 435c28749e9Skais * the stream head process all records, in particular 436c28749e9Skais * the close_notify. 437c28749e9Skais * This is needed to avoid processing them out of 438c28749e9Skais * sequence when previous application data packets are 439c28749e9Skais * waiting to be decrypted/MAC'ed and delivered. 440c28749e9Skais */ 441c28749e9Skais if (ssl->hs_waitstate == idle_handshake) { 442c28749e9Skais ssl->activeinput = B_FALSE; 443c28749e9Skais outmp = recmp; 444c28749e9Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 445c28749e9Skais } else { 446c28749e9Skais kssl_cmd = kssl_handle_any_record(ssl, recmp, 447c28749e9Skais &outmp, cbfn, arg); 448c28749e9Skais } 44984706141Svk199839 break; 45084706141Svk199839 default: 45184706141Svk199839 ssl->activeinput = B_FALSE; 45251dd2c77Svk199839 DTRACE_PROBE(kssl_err__invalid_content_type); 45384706141Svk199839 goto sendnewalert; 454c28749e9Skais } 455c28749e9Skais 456c28749e9Skais /* Priority to Alert messages */ 457c28749e9Skais if (ssl->alert_sendbuf != NULL) { 45851dd2c77Svk199839 DTRACE_PROBE(kssl_err__alert_to_send_cycle); 459c28749e9Skais goto sendalert; 460c28749e9Skais } 461c28749e9Skais 462c28749e9Skais /* Then handshake messages */ 463c28749e9Skais if (ssl->handshake_sendbuf) { 464c28749e9Skais if (*decrmp != NULL) { 465c28749e9Skais linkb(*decrmp, ssl->handshake_sendbuf); 466c28749e9Skais } else { 467c28749e9Skais *decrmp = ssl->handshake_sendbuf; 468c28749e9Skais } 469c28749e9Skais ssl->handshake_sendbuf = NULL; 470c28749e9Skais 471c28749e9Skais *more = ((ssl->rec_ass_head != NULL) && 472c28749e9Skais (!ssl->activeinput)); 473c28749e9Skais mutex_exit(&ssl->kssl_lock); 474c28749e9Skais return (kssl_cmd); 475c28749e9Skais } 476c28749e9Skais 477c28749e9Skais if (ssl->hs_waitstate == idle_handshake) { 478c28749e9Skais *more = ((ssl->rec_ass_head != NULL) && 479c28749e9Skais (!ssl->activeinput)); 480c28749e9Skais } 481c28749e9Skais 482c28749e9Skais if (outmp != NULL) { 483c28749e9Skais *decrmp = outmp; 484c28749e9Skais /* 485c28749e9Skais * Don't process any packet after an application_data. 486c28749e9Skais * We could well receive the close_notify which should 487c28749e9Skais * be handled separately. 488c28749e9Skais */ 489c28749e9Skais mutex_exit(&ssl->kssl_lock); 490c28749e9Skais return (kssl_cmd); 491c28749e9Skais } 492c28749e9Skais /* 493c28749e9Skais * The current record isn't done yet. Don't start the next one 494c28749e9Skais */ 495c28749e9Skais if (ssl->activeinput) { 496c28749e9Skais mutex_exit(&ssl->kssl_lock); 497c28749e9Skais return (kssl_cmd); 498c28749e9Skais } 499c28749e9Skais } while ((recmp = kssl_get_next_record(ssl)) != NULL); 500c28749e9Skais 501c28749e9Skais mutex_exit(&ssl->kssl_lock); 502c28749e9Skais return (kssl_cmd); 503c28749e9Skais 504c28749e9Skais sendnewalert: 505c28749e9Skais kssl_send_alert(ssl, alert_fatal, unexpected_message); 506c28749e9Skais if (mp != NULL) { 507c28749e9Skais freeb(mp); 508c28749e9Skais } 509c28749e9Skais 510c28749e9Skais sendalert: 511c28749e9Skais *decrmp = ssl->alert_sendbuf; 512c28749e9Skais ssl->alert_sendbuf = NULL; 513c28749e9Skais mutex_exit(&ssl->kssl_lock); 514c28749e9Skais return (KSSL_CMD_SEND); 515c28749e9Skais } 516c28749e9Skais 517c28749e9Skais /* 518dd49f125SAnders Persson * Decrypt and verify the MAC of an incoming chain of application_data record. 519dd49f125SAnders Persson * Each block has exactly one SSL record. 520c28749e9Skais */ 521c28749e9Skais kssl_cmd_t 52251dd2c77Svk199839 kssl_handle_mblk(kssl_ctx_t ctx, mblk_t **mpp, mblk_t **outmp) 523c28749e9Skais { 524c28749e9Skais uchar_t *recend, *rec_sz_p; 525c28749e9Skais uchar_t *real_recend; 52639d67566Skais mblk_t *prevmp = NULL, *nextmp, *firstmp, *mp, *copybp; 527c28749e9Skais int mac_sz; 528c28749e9Skais uchar_t version[2]; 529c28749e9Skais uint16_t rec_sz; 530c28749e9Skais SSL3AlertDescription desc; 531c28749e9Skais SSL3ContentType content_type; 532c28749e9Skais ssl_t *ssl; 533c28749e9Skais KSSLCipherSpec *spec; 5342ec7cc7fSKrishna Yenduri int error, ret; 535c28749e9Skais kssl_cmd_t kssl_cmd = KSSL_CMD_DELIVER_PROXY; 536c28749e9Skais boolean_t deliverit = B_FALSE; 537c28749e9Skais crypto_data_t cipher_data; 538c28749e9Skais 539c28749e9Skais ASSERT(ctx != NULL); 540c28749e9Skais 541c28749e9Skais ssl = (ssl_t *)(ctx); 542c28749e9Skais 54339d67566Skais mp = firstmp = *mpp; 544c28749e9Skais *outmp = NULL; 545c28749e9Skais more: 546c28749e9Skais 547c28749e9Skais while (mp != NULL) { 54851dd2c77Svk199839 ASSERT(DB_TYPE(mp) == M_DATA); 549c28749e9Skais 550c28749e9Skais if (DB_REF(mp) > 1) { 551c28749e9Skais /* 552c28749e9Skais * Fortunately copyb() preserves the offset, 5532ec7cc7fSKrishna Yenduri * tail space and alignment so the copy is 554c28749e9Skais * ready to be made an SSL record. 555c28749e9Skais */ 556c28749e9Skais if ((copybp = copyb(mp)) == NULL) 557c28749e9Skais return (NULL); 558c28749e9Skais 559c28749e9Skais copybp->b_cont = mp->b_cont; 56039d67566Skais if (mp == firstmp) { 561c28749e9Skais *mpp = copybp; 56284706141Svk199839 } else if (prevmp != NULL) { 563c28749e9Skais prevmp->b_cont = copybp; 564c28749e9Skais } 565c28749e9Skais freeb(mp); 566c28749e9Skais mp = copybp; 567c28749e9Skais } 568c28749e9Skais 56951dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__handle_record_cycle, mblk_t *, mp); 570c28749e9Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 571c28749e9Skais 57284706141Svk199839 switch (content_type) { 57384706141Svk199839 case content_application_data: 57484706141Svk199839 break; 57584706141Svk199839 case content_change_cipher_spec: 57684706141Svk199839 case content_alert: 57784706141Svk199839 case content_handshake: 57884706141Svk199839 case content_handshake_v2: 579c28749e9Skais nextmp = mp->b_cont; 580c28749e9Skais 581c28749e9Skais /* Remove this message */ 582c28749e9Skais if (prevmp != NULL) { 583c28749e9Skais prevmp->b_cont = nextmp; 584c28749e9Skais 585c28749e9Skais /* 586c28749e9Skais * If we had processed blocks that need to 587c28749e9Skais * be delivered, then remember that error code 588c28749e9Skais */ 589c28749e9Skais if (kssl_cmd == KSSL_CMD_DELIVER_PROXY) 590c28749e9Skais deliverit = B_TRUE; 591c28749e9Skais } 592c28749e9Skais 593c28749e9Skais mutex_enter(&ssl->kssl_lock); 59484706141Svk199839 /* NOTE: This routine could free mp. */ 595c28749e9Skais kssl_cmd = kssl_handle_any_record(ssl, mp, outmp, 596c28749e9Skais NULL, NULL); 597c28749e9Skais 598c28749e9Skais if (ssl->alert_sendbuf != NULL) { 59984706141Svk199839 mp = nextmp; 60051dd2c77Svk199839 DTRACE_PROBE(kssl_err__alert_after_handle_any); 601c28749e9Skais goto sendalert; 602c28749e9Skais } 603c28749e9Skais mutex_exit(&ssl->kssl_lock); 604c28749e9Skais 605c28749e9Skais if (deliverit) { 606c28749e9Skais kssl_cmd = KSSL_CMD_DELIVER_PROXY; 607c28749e9Skais } 608c28749e9Skais 609c28749e9Skais mp = nextmp; 61084706141Svk199839 continue; /* to the while loop */ 61184706141Svk199839 default: 61284706141Svk199839 desc = decode_error; 61384706141Svk199839 KSSL_COUNTER(internal_errors, 1); 61451dd2c77Svk199839 DTRACE_PROBE(kssl_err__decode_error); 61584706141Svk199839 goto makealert; 616c28749e9Skais } 617c28749e9Skais 618c28749e9Skais version[0] = mp->b_rptr[1]; 619c28749e9Skais version[1] = mp->b_rptr[2]; 620c28749e9Skais rec_sz_p = SSL3_REC_SIZE(mp); 621c28749e9Skais rec_sz = BE16_TO_U16(rec_sz_p); 622c28749e9Skais 623c28749e9Skais mp->b_rptr += SSL3_HDR_LEN; 624c28749e9Skais recend = mp->b_rptr + rec_sz; 625c28749e9Skais real_recend = recend; 626c28749e9Skais 62784706141Svk199839 /* 62884706141Svk199839 * Check the assumption that each mblk contains exactly 62984706141Svk199839 * one complete SSL record. We bail out if the check fails. 63084706141Svk199839 */ 63184706141Svk199839 ASSERT(recend == mp->b_wptr); 63284706141Svk199839 if (recend != mp->b_wptr) { 63384706141Svk199839 desc = decode_error; 63484706141Svk199839 KSSL_COUNTER(internal_errors, 1); 63551dd2c77Svk199839 DTRACE_PROBE(kssl_err__not_complete_record); 63684706141Svk199839 goto makealert; 63784706141Svk199839 } 63884706141Svk199839 639c28749e9Skais spec = &ssl->spec[KSSL_READ]; 640c28749e9Skais mac_sz = spec->mac_hashsz; 641c28749e9Skais if (spec->cipher_ctx != 0) { 64239d67566Skais 64339d67566Skais /* 64439d67566Skais * The record length must be a multiple of the 64539d67566Skais * block size for block ciphers. 64639d67566Skais * The cipher_bsize is always a power of 2. 64739d67566Skais */ 64839d67566Skais if ((spec->cipher_type == type_block) && 64939d67566Skais ((rec_sz & (spec->cipher_bsize - 1)) != 0)) { 65051dd2c77Svk199839 DTRACE_PROBE2(kssl_err__bad_record_size, 65151dd2c77Svk199839 uint16_t, rec_sz, 65251dd2c77Svk199839 int, spec->cipher_bsize); 65339d67566Skais KSSL_COUNTER(record_decrypt_failure, 1); 65439d67566Skais mp->b_rptr = recend; 65539d67566Skais desc = decrypt_error; 65639d67566Skais goto makealert; 65739d67566Skais } 65839d67566Skais 659c28749e9Skais cipher_data.cd_format = CRYPTO_DATA_RAW; 660c28749e9Skais cipher_data.cd_offset = 0; 661c28749e9Skais cipher_data.cd_length = rec_sz; 662c28749e9Skais cipher_data.cd_miscdata = NULL; 663c28749e9Skais cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; 664c28749e9Skais cipher_data.cd_raw.iov_len = rec_sz; 665c28749e9Skais error = crypto_decrypt_update(spec->cipher_ctx, 666c28749e9Skais &cipher_data, NULL, NULL); 667c28749e9Skais if (CRYPTO_ERR(error)) { 66851dd2c77Svk199839 DTRACE_PROBE1( 66951dd2c77Svk199839 kssl_err__crypto_decrypt_update_failed, 67051dd2c77Svk199839 int, error); 671c28749e9Skais KSSL_COUNTER(record_decrypt_failure, 1); 672c28749e9Skais mp->b_rptr = recend; 673c28749e9Skais desc = decrypt_error; 674c28749e9Skais goto makealert; 675c28749e9Skais } 676c28749e9Skais } 677c28749e9Skais if (spec->cipher_type == type_block) { 678c28749e9Skais uint_t pad_sz = recend[-1]; 679c28749e9Skais pad_sz++; 680c28749e9Skais if (pad_sz + mac_sz > rec_sz) { 68151dd2c77Svk199839 DTRACE_PROBE(kssl_err__pad_mac_bigger); 682c28749e9Skais mp->b_rptr = recend; 683c28749e9Skais desc = bad_record_mac; 684c28749e9Skais goto makealert; 685c28749e9Skais } 686c28749e9Skais rec_sz -= pad_sz; 687c28749e9Skais recend -= pad_sz; 688c28749e9Skais } 689c28749e9Skais if (mac_sz != 0) { 690c28749e9Skais uchar_t hash[MAX_HASH_LEN]; 691c28749e9Skais if (rec_sz < mac_sz) { 69251dd2c77Svk199839 DTRACE_PROBE(kssl_err__pad_smaller_mac); 693c28749e9Skais mp->b_rptr = real_recend; 694c28749e9Skais desc = bad_record_mac; 695c28749e9Skais goto makealert; 696c28749e9Skais } 697c28749e9Skais rec_sz -= mac_sz; 698c28749e9Skais recend -= mac_sz; 699c28749e9Skais ret = kssl_compute_record_mac(ssl, KSSL_READ, 700c28749e9Skais ssl->seq_num[KSSL_READ], content_type, 701c28749e9Skais version, mp->b_rptr, rec_sz, hash); 702c28749e9Skais if (ret != CRYPTO_SUCCESS || 703c28749e9Skais bcmp(hash, recend, mac_sz)) { 70451dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__MACmismatch_handlerec, 70551dd2c77Svk199839 mblk_t *, mp); 706c28749e9Skais mp->b_rptr = real_recend; 707c28749e9Skais desc = bad_record_mac; 70851dd2c77Svk199839 DTRACE_PROBE(kssl_err__msg_MAC_mismatch); 709c28749e9Skais KSSL_COUNTER(verify_mac_failure, 1); 710c28749e9Skais goto makealert; 711c28749e9Skais } 712c28749e9Skais ssl->seq_num[KSSL_READ]++; 713c28749e9Skais } 714c28749e9Skais 715c28749e9Skais if (ssl->hs_waitstate != idle_handshake) { 71651dd2c77Svk199839 DTRACE_PROBE1(kssl_err__unexpected_msg, 71751dd2c77Svk199839 SSL3WaitState, ssl->hs_waitstate); 718c28749e9Skais mp->b_rptr = real_recend; 719c28749e9Skais desc = unexpected_message; 720c28749e9Skais goto makealert; 721c28749e9Skais } 722c28749e9Skais mp->b_wptr = recend; 723c28749e9Skais 72451dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__dblk_cooked, mblk_t *, mp); 72584706141Svk199839 KSSL_COUNTER(appdata_record_ins, 1); 72684706141Svk199839 727c28749e9Skais prevmp = mp; 728c28749e9Skais mp = mp->b_cont; 729c28749e9Skais } 730c28749e9Skais 731c28749e9Skais return (kssl_cmd); 732c28749e9Skais 733c28749e9Skais makealert: 734c28749e9Skais nextmp = mp->b_cont; 735c28749e9Skais freeb(mp); 736c28749e9Skais mp = nextmp; 737c28749e9Skais mutex_enter(&ssl->kssl_lock); 738c28749e9Skais kssl_send_alert(ssl, alert_fatal, desc); 739c28749e9Skais 740c28749e9Skais if (ssl->alert_sendbuf == NULL) { 741c28749e9Skais /* internal memory allocation failure. just return. */ 74251dd2c77Svk199839 DTRACE_PROBE(kssl_err__alert_msg_alloc_failed); 743c28749e9Skais mutex_exit(&ssl->kssl_lock); 744c28749e9Skais 745c28749e9Skais if (mp) { 746c28749e9Skais prevmp = NULL; 747c28749e9Skais goto more; 748c28749e9Skais } 749c28749e9Skais 750c28749e9Skais return (KSSL_CMD_NONE); 751c28749e9Skais } 752c28749e9Skais kssl_cmd = KSSL_CMD_SEND; 753c28749e9Skais sendalert: 754c28749e9Skais if (*outmp == NULL) { 755c28749e9Skais *outmp = ssl->alert_sendbuf; 756c28749e9Skais } else { 757c28749e9Skais linkb(*outmp, ssl->alert_sendbuf); 758c28749e9Skais } 759c28749e9Skais ssl->alert_sendbuf = NULL; 760c28749e9Skais mutex_exit(&ssl->kssl_lock); 761c28749e9Skais 762c28749e9Skais if (mp) { 763c28749e9Skais prevmp = NULL; 764c28749e9Skais goto more; 765c28749e9Skais } 766c28749e9Skais 767c28749e9Skais return (kssl_cmd); 768c28749e9Skais } 769c28749e9Skais /* 770c28749e9Skais * This is the routine that handles incoming SSL records. 771c28749e9Skais * When called the first time, with a NULL context, this routine expects 772c28749e9Skais * a ClientHello SSL Handshake packet and shall allocate a context 773c28749e9Skais * of a new SSL connection. 774c28749e9Skais * During the rest of the handshake packets, the routine adjusts the 775c28749e9Skais * state of the context according to the record received. 776c28749e9Skais * After the ChangeCipherSpec message is received, the routine first 777c28749e9Skais * decrypts/authenticated the packet using the key materials in the 778c28749e9Skais * connection's context. 779c28749e9Skais * The return code tells the caller what to do with the returned packet. 780c28749e9Skais */ 781c28749e9Skais static kssl_cmd_t 782c28749e9Skais kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, 783c28749e9Skais kssl_callback_t cbfn, void *arg) 784c28749e9Skais { 785c28749e9Skais uchar_t *recend, *rec_sz_p; 786c28749e9Skais uchar_t version[2]; 787c28749e9Skais uchar_t *real_recend, *save_rptr, *save_wptr; 788c28749e9Skais int rhsz = SSL3_HDR_LEN; 789c28749e9Skais uint16_t rec_sz; 790c28749e9Skais int sz; 791c28749e9Skais int mac_sz; 792c28749e9Skais SSL3AlertDescription desc; 793c28749e9Skais SSL3AlertLevel level; 794c28749e9Skais SSL3ContentType content_type; 795c28749e9Skais ssl_t *ssl; 796c28749e9Skais KSSLCipherSpec *spec; 797c28749e9Skais int error = 0, ret; 798c28749e9Skais 799c28749e9Skais ASSERT(ctx != NULL); 800c28749e9Skais 801c28749e9Skais ssl = (ssl_t *)(ctx); 802c28749e9Skais 803c28749e9Skais *decrmp = NULL; 804c28749e9Skais 805c28749e9Skais save_rptr = mp->b_rptr; 806c28749e9Skais save_wptr = mp->b_wptr; 807c28749e9Skais 808c28749e9Skais ASSERT(MUTEX_HELD(&ssl->kssl_lock)); 809c28749e9Skais 810c28749e9Skais content_type = (SSL3ContentType)mp->b_rptr[0]; 811c28749e9Skais if (content_type == content_handshake_v2) { 812c28749e9Skais if (ssl->hs_waitstate == wait_client_hello) { 813c28749e9Skais /* V2 compatible ClientHello */ 814c28749e9Skais if (mp->b_rptr[3] == 0x03 && 815c28749e9Skais (mp->b_rptr[4] == 0x01 || 816c28749e9Skais mp->b_rptr[4] == 0x00)) { 817c28749e9Skais ssl->major_version = version[0] = mp->b_rptr[3]; 818c28749e9Skais ssl->minor_version = version[1] = mp->b_rptr[4]; 819c28749e9Skais } else { 820c28749e9Skais /* We don't support "pure" SSLv2 */ 82151dd2c77Svk199839 DTRACE_PROBE(kssl_err__no_SSLv2); 8227dd0d8ffSVladimir Kotal ssl->major_version = mp->b_rptr[3]; 8237dd0d8ffSVladimir Kotal ssl->minor_version = mp->b_rptr[4]; 824c28749e9Skais desc = protocol_version; 825c28749e9Skais goto sendalert; 826c28749e9Skais } 827c28749e9Skais } 828c28749e9Skais rec_sz = (uint16_t)mp->b_rptr[1]; 829c28749e9Skais rhsz = 2; 830c28749e9Skais } else { 831c28749e9Skais ssl->major_version = version[0] = mp->b_rptr[1]; 832c28749e9Skais ssl->minor_version = version[1] = mp->b_rptr[2]; 833c28749e9Skais rec_sz_p = SSL3_REC_SIZE(mp); 834c28749e9Skais rec_sz = BE16_TO_U16(rec_sz_p); 835c28749e9Skais } 836c28749e9Skais 837c28749e9Skais mp->b_rptr += rhsz; 838c28749e9Skais recend = mp->b_rptr + rec_sz; 839c28749e9Skais real_recend = recend; 840c28749e9Skais 84184706141Svk199839 /* 84284706141Svk199839 * Check the assumption that each mblk contains exactly 84384706141Svk199839 * one complete SSL record. We bail out if the check fails. 84484706141Svk199839 */ 84584706141Svk199839 ASSERT(recend == mp->b_wptr); 84684706141Svk199839 if (recend != mp->b_wptr) { 84751dd2c77Svk199839 DTRACE_PROBE3(kssl_mblk__handle_any_record_recszerr, 84851dd2c77Svk199839 mblk_t *, mp, int, rhsz, int, rec_sz); 84951dd2c77Svk199839 DTRACE_PROBE(kssl_err__record_size); 85084706141Svk199839 desc = decode_error; 85184706141Svk199839 KSSL_COUNTER(internal_errors, 1); 85284706141Svk199839 goto sendalert; 85384706141Svk199839 } 85484706141Svk199839 855c28749e9Skais spec = &ssl->spec[KSSL_READ]; 856c28749e9Skais mac_sz = spec->mac_hashsz; 857c28749e9Skais if (spec->cipher_ctx != 0) { 85839d67566Skais /* 85939d67566Skais * The record length must be a multiple of the 86039d67566Skais * block size for block ciphers. 86139d67566Skais */ 86239d67566Skais if ((spec->cipher_type == type_block) && 86339d67566Skais ((rec_sz & (spec->cipher_bsize - 1)) != 0)) { 86451dd2c77Svk199839 DTRACE_PROBE2(kssl_err__bad_record_size, 86551dd2c77Svk199839 uint16_t, rec_sz, int, spec->cipher_bsize); 86639d67566Skais KSSL_COUNTER(record_decrypt_failure, 1); 86739d67566Skais mp->b_rptr = recend; 86839d67566Skais desc = decrypt_error; 86939d67566Skais goto sendalert; 87039d67566Skais } 87139d67566Skais 872c28749e9Skais spec->cipher_data.cd_length = rec_sz; 873c28749e9Skais spec->cipher_data.cd_raw.iov_base = (char *)mp->b_rptr; 874c28749e9Skais spec->cipher_data.cd_raw.iov_len = rec_sz; 875c28749e9Skais error = crypto_decrypt_update(spec->cipher_ctx, 876c28749e9Skais &spec->cipher_data, NULL, NULL); 877c28749e9Skais if (CRYPTO_ERR(error)) { 87851dd2c77Svk199839 DTRACE_PROBE1(kssl_err__crypto_decrypt_update_failed, 87951dd2c77Svk199839 int, error); 880c28749e9Skais KSSL_COUNTER(record_decrypt_failure, 1); 881c28749e9Skais mp->b_rptr = recend; 882c28749e9Skais desc = decrypt_error; 883c28749e9Skais goto sendalert; 884c28749e9Skais } 885c28749e9Skais } 886c28749e9Skais if (spec->cipher_type == type_block) { 887c28749e9Skais uint_t pad_sz = recend[-1]; 888c28749e9Skais pad_sz++; 889c28749e9Skais if (pad_sz + mac_sz > rec_sz) { 89051dd2c77Svk199839 DTRACE_PROBE2(kssl_err__pad_mac_mismatch, 89151dd2c77Svk199839 int, pad_sz, int, mac_sz); 892c28749e9Skais mp->b_rptr = recend; 893c28749e9Skais desc = bad_record_mac; 894c28749e9Skais goto sendalert; 895c28749e9Skais } 896c28749e9Skais rec_sz -= pad_sz; 897c28749e9Skais recend -= pad_sz; 898c28749e9Skais } 899c28749e9Skais if (mac_sz != 0) { 900c28749e9Skais uchar_t hash[MAX_HASH_LEN]; 901c28749e9Skais if (rec_sz < mac_sz) { 90251dd2c77Svk199839 DTRACE_PROBE1(kssl_err__mac_size_too_big, 90351dd2c77Svk199839 int, mac_sz); 904c28749e9Skais mp->b_rptr = real_recend; 905c28749e9Skais desc = bad_record_mac; 906c28749e9Skais goto sendalert; 907c28749e9Skais } 908c28749e9Skais rec_sz -= mac_sz; 909c28749e9Skais recend -= mac_sz; 910c28749e9Skais ret = kssl_compute_record_mac(ssl, KSSL_READ, 911c28749e9Skais ssl->seq_num[KSSL_READ], content_type, 912c28749e9Skais version, mp->b_rptr, rec_sz, hash); 913c28749e9Skais if (ret != CRYPTO_SUCCESS || 914c28749e9Skais bcmp(hash, recend, mac_sz)) { 91551dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__MACmismatch_anyrecord, 91651dd2c77Svk199839 mblk_t *, mp); 917c28749e9Skais mp->b_rptr = real_recend; 918c28749e9Skais desc = bad_record_mac; 91951dd2c77Svk199839 DTRACE_PROBE(kssl_err__msg_MAC_mismatch); 920c28749e9Skais KSSL_COUNTER(verify_mac_failure, 1); 921c28749e9Skais goto sendalert; 922c28749e9Skais } 923c28749e9Skais ssl->seq_num[KSSL_READ]++; 92451dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__after_compute_MAC, 92551dd2c77Svk199839 mblk_t *, mp); 926c28749e9Skais } 927c28749e9Skais 928c28749e9Skais switch (content_type) { 929c28749e9Skais case content_handshake: 930c28749e9Skais do { 93151dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__content_handshake_cycle, 93251dd2c77Svk199839 mblk_t *, mp); 933c28749e9Skais if (error != 0 || 934c28749e9Skais /* ignore client renegotiation for now */ 935c28749e9Skais ssl->hs_waitstate == idle_handshake) { 936c28749e9Skais mp->b_rptr = recend; 93711d0a659SVladimir Kotal DTRACE_PROBE(kssl_renegotiation_request); 938c28749e9Skais } 939c28749e9Skais if (mp->b_rptr == recend) { 940c28749e9Skais mp->b_rptr = real_recend; 941c28749e9Skais if (error != 0) { 942c28749e9Skais goto error; 943c28749e9Skais } 944c28749e9Skais freeb(mp); 945c28749e9Skais 946c28749e9Skais if (ssl->hs_waitstate == wait_client_key_done) 947c28749e9Skais return (KSSL_CMD_QUEUED); 948c28749e9Skais 949c28749e9Skais return ((ssl->handshake_sendbuf != NULL) ? 950c28749e9Skais KSSL_CMD_SEND : KSSL_CMD_NONE); 951c28749e9Skais } 952c28749e9Skais if (ssl->msg.state < MSG_BODY) { 953c28749e9Skais if (ssl->msg.state == MSG_INIT) { 954c28749e9Skais ssl->msg.type = 955c28749e9Skais (SSL3HandshakeType)*mp->b_rptr++; 956c28749e9Skais ssl->msg.state = MSG_INIT_LEN; 957c28749e9Skais } 958c28749e9Skais if (ssl->msg.state == MSG_INIT_LEN) { 959c28749e9Skais int msglenb = 960c28749e9Skais ssl->msg.msglen_bytes; 961c28749e9Skais int msglen = ssl->msg.msglen; 962c28749e9Skais while (mp->b_rptr < recend && 963c28749e9Skais msglenb < 3) { 964c28749e9Skais msglen = (msglen << 8) + 965c28749e9Skais (uint_t)(*mp->b_rptr++); 966c28749e9Skais msglenb++; 967c28749e9Skais } 968c28749e9Skais ssl->msg.msglen_bytes = msglenb; 969c28749e9Skais ssl->msg.msglen = msglen; 970c28749e9Skais if (msglenb == 3) { 971c28749e9Skais ssl->msg.state = MSG_BODY; 972c28749e9Skais } 973c28749e9Skais } 974c28749e9Skais if (mp->b_rptr == recend) { 975c28749e9Skais mp->b_rptr = real_recend; 976c28749e9Skais freeb(mp); 977c28749e9Skais return (KSSL_CMD_NONE); 978c28749e9Skais } 979c28749e9Skais } 980c28749e9Skais ASSERT(ssl->msg.state == MSG_BODY); 981c28749e9Skais 982c28749e9Skais sz = recend - mp->b_rptr; 983c28749e9Skais 984c28749e9Skais if (ssl->msg.head == NULL && 985c28749e9Skais ssl->msg.msglen <= sz) { 986c28749e9Skais continue; 987c28749e9Skais } 988c28749e9Skais if (ssl->msg.head != NULL) { 989c28749e9Skais sz += msgdsize(ssl->msg.head); 990c28749e9Skais if (ssl->msg.msglen <= sz) { 991c28749e9Skais ssl->msg.tail->b_cont = mp; 992c28749e9Skais mp = ssl->msg.head; 993c28749e9Skais ssl->sslcnt = 100; 994c28749e9Skais ssl->msg.head = NULL; 995c28749e9Skais ssl->msg.tail = NULL; 996c28749e9Skais if (pullupmsg(mp, -1)) { 997c28749e9Skais recend = mp->b_rptr + sz; 998c28749e9Skais ASSERT(recend <= mp->b_wptr); 999c28749e9Skais continue; 1000c28749e9Skais } 1001c28749e9Skais mp->b_rptr = real_recend; 1002c28749e9Skais error = ENOMEM; 1003c28749e9Skais KSSL_COUNTER(alloc_fails, 1); 1004c28749e9Skais goto error; 1005c28749e9Skais } 1006c28749e9Skais } 1007c28749e9Skais 1008c28749e9Skais mp->b_wptr = recend; 1009c28749e9Skais 1010c28749e9Skais if (ssl->msg.head == NULL) { 1011c28749e9Skais ssl->msg.head = mp; 1012c28749e9Skais ssl->msg.tail = mp; 1013c28749e9Skais return (KSSL_CMD_NONE); 1014c28749e9Skais } else { 1015c28749e9Skais ssl->msg.tail->b_cont = mp; 1016c28749e9Skais ssl->msg.tail = mp; 1017c28749e9Skais return (KSSL_CMD_NONE); 1018c28749e9Skais } 1019c28749e9Skais } while (kssl_handle_handshake_message(ssl, mp, &error, cbfn, 1020c28749e9Skais arg)); 1021c28749e9Skais if (error == SSL_MISS) { 1022c28749e9Skais mp->b_rptr = save_rptr; 1023c28749e9Skais mp->b_wptr = save_wptr; 1024c28749e9Skais KSSL_COUNTER(fallback_connections, 1); 1025c28749e9Skais return (KSSL_CMD_NOT_SUPPORTED); 1026c28749e9Skais } 1027c28749e9Skais if (ssl->hs_waitstate == wait_client_key_done) { 1028c28749e9Skais return (KSSL_CMD_QUEUED); 1029c28749e9Skais } else { 1030c28749e9Skais return (KSSL_CMD_NONE); 1031c28749e9Skais } 1032c28749e9Skais case content_alert: 103351dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__content_alert, mblk_t *, mp); 1034c28749e9Skais if (rec_sz != 2) { 103551dd2c77Svk199839 DTRACE_PROBE(kssl_err__illegal_param); 1036c28749e9Skais mp->b_rptr = real_recend; 1037c28749e9Skais desc = illegal_parameter; 1038c28749e9Skais goto sendalert; 1039c28749e9Skais } else { 1040c28749e9Skais level = *mp->b_rptr++; 1041c28749e9Skais desc = *mp->b_rptr++; 1042c28749e9Skais mp->b_rptr = real_recend; 1043c28749e9Skais if (level != alert_warning || desc != close_notify) { 1044c28749e9Skais if (ssl->sid.cached == B_TRUE) { 1045c28749e9Skais kssl_uncache_sid(&ssl->sid, 1046c28749e9Skais ssl->kssl_entry); 1047c28749e9Skais } 104851dd2c77Svk199839 DTRACE_PROBE2(kssl_err__bad_content_alert, 104951dd2c77Svk199839 SSL3AlertLevel, level, 105051dd2c77Svk199839 SSL3AlertDescription, desc); 1051c28749e9Skais ssl->fatal_alert = B_TRUE; 1052c28749e9Skais error = EBADMSG; 1053c28749e9Skais goto error; 1054c28749e9Skais } else { 1055*9b1bd49fSVladimir Kotal ssl->close_notify_clnt = B_TRUE; 1056c28749e9Skais ssl->activeinput = B_FALSE; 1057c28749e9Skais freeb(mp); 1058c28749e9Skais return (KSSL_CMD_NONE); 1059c28749e9Skais } 1060c28749e9Skais } 1061c28749e9Skais case content_change_cipher_spec: 106251dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__change_cipher_spec, 106351dd2c77Svk199839 mblk_t *, mp); 1064c28749e9Skais if (ssl->hs_waitstate != wait_change_cipher) { 1065c28749e9Skais desc = unexpected_message; 1066c28749e9Skais } else if (rec_sz != 1 || *mp->b_rptr != 1) { 1067c28749e9Skais desc = illegal_parameter; 1068c28749e9Skais } else { 1069c28749e9Skais mp->b_rptr = real_recend; 1070c28749e9Skais ssl->hs_waitstate = wait_finished; 1071c28749e9Skais ssl->seq_num[KSSL_READ] = 0; 1072c28749e9Skais if ((error = kssl_spec_init(ssl, KSSL_READ)) != 0) { 107351dd2c77Svk199839 DTRACE_PROBE1(kssl_err__kssl_spec_init_error, 107451dd2c77Svk199839 int, error); 1075c28749e9Skais goto error; 1076c28749e9Skais } 1077c28749e9Skais ssl->activeinput = B_FALSE; 1078c28749e9Skais freeb(mp); 1079c28749e9Skais return (KSSL_CMD_NONE); 1080c28749e9Skais } 1081c28749e9Skais mp->b_rptr = real_recend; 108251dd2c77Svk199839 DTRACE_PROBE(kssl_err__change_cipher_spec); 1083c28749e9Skais goto sendalert; 1084c28749e9Skais 1085c28749e9Skais case content_application_data: 108651dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__content_app_data, 108751dd2c77Svk199839 mblk_t *, mp); 1088c28749e9Skais if (ssl->hs_waitstate != idle_handshake) { 108951dd2c77Svk199839 DTRACE_PROBE(kssl_err__content_app_data); 1090c28749e9Skais mp->b_rptr = real_recend; 1091c28749e9Skais desc = unexpected_message; 1092c28749e9Skais goto sendalert; 1093c28749e9Skais } 1094c28749e9Skais mp->b_wptr = recend; 1095c28749e9Skais *decrmp = mp; 1096c28749e9Skais ssl->activeinput = B_FALSE; 1097c28749e9Skais return (KSSL_CMD_DELIVER_PROXY); 1098c28749e9Skais 1099c28749e9Skais case content_handshake_v2: 110051dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__content_handshake_v2, 110151dd2c77Svk199839 mblk_t *, mp); 1102c28749e9Skais error = kssl_handle_v2client_hello(ssl, mp, rec_sz); 1103c28749e9Skais if (error == SSL_MISS) { 1104c28749e9Skais mp->b_rptr = save_rptr; 1105c28749e9Skais mp->b_wptr = save_wptr; 1106c28749e9Skais KSSL_COUNTER(fallback_connections, 1); 1107c28749e9Skais return (KSSL_CMD_NOT_SUPPORTED); 1108c28749e9Skais } else if (error != 0) { 110951dd2c77Svk199839 DTRACE_PROBE(kssl_err__v2client_hello_failed); 1110c28749e9Skais goto error; 1111c28749e9Skais } 1112c28749e9Skais freeb(mp); 1113c28749e9Skais return (KSSL_CMD_SEND); 1114c28749e9Skais default: 111551dd2c77Svk199839 DTRACE_PROBE1(kssl_mblk__unexpected_msg, 111651dd2c77Svk199839 mblk_t *, mp); 1117c28749e9Skais mp->b_rptr = real_recend; 1118c28749e9Skais desc = unexpected_message; 1119c28749e9Skais break; 1120c28749e9Skais } 1121c28749e9Skais 1122c28749e9Skais sendalert: 1123c28749e9Skais kssl_send_alert(ssl, alert_fatal, desc); 1124c28749e9Skais *decrmp = ssl->alert_sendbuf; 1125c28749e9Skais ssl->alert_sendbuf = NULL; 1126c28749e9Skais freeb(mp); 1127c28749e9Skais return ((*decrmp != NULL) ? KSSL_CMD_SEND : KSSL_CMD_NONE); 1128c28749e9Skais error: 1129c28749e9Skais freeb(mp); 1130c28749e9Skais return (KSSL_CMD_NONE); 1131c28749e9Skais } 1132c28749e9Skais 1133c28749e9Skais /* 1134c28749e9Skais * Initialize the context of an SSL connection, coming to the specified 11352ec7cc7fSKrishna Yenduri * address. The ssl structure is returned held. 1136c28749e9Skais */ 1137c28749e9Skais kssl_status_t 1138dd49f125SAnders Persson kssl_init_context(kssl_ent_t kssl_ent, struct sockaddr *addr, int mss, 1139dd49f125SAnders Persson kssl_ctx_t *kssl_ctxp) 1140c28749e9Skais { 1141c28749e9Skais ssl_t *ssl = kmem_cache_alloc(kssl_cache, KM_NOSLEEP); 1142dd49f125SAnders Persson struct sockaddr_in *sin = (struct sockaddr_in *)addr; 1143c28749e9Skais 1144c28749e9Skais if (ssl == NULL) { 1145c28749e9Skais return (KSSL_STS_ERR); 1146c28749e9Skais } 1147c28749e9Skais 1148c28749e9Skais bzero(ssl, sizeof (ssl_t)); 1149c28749e9Skais 1150c28749e9Skais ssl->kssl_entry = (kssl_entry_t *)kssl_ent; 1151c28749e9Skais KSSL_ENTRY_REFHOLD(ssl->kssl_entry); 1152c28749e9Skais 1153dd49f125SAnders Persson if (sin->sin_family == AF_INET) { 1154dd49f125SAnders Persson IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &ssl->faddr); 11552ec7cc7fSKrishna Yenduri } else { 1156dd49f125SAnders Persson /* struct assignment */ 1157dd49f125SAnders Persson ssl->faddr = ((struct sockaddr_in6 *)addr)->sin6_addr; 11582ec7cc7fSKrishna Yenduri } 1159c28749e9Skais ssl->tcp_mss = mss; 1160c28749e9Skais ssl->sendalert_level = alert_warning; 1161c28749e9Skais ssl->sendalert_desc = close_notify; 1162c28749e9Skais ssl->sid.cached = B_FALSE; 1163c28749e9Skais 1164c28749e9Skais *kssl_ctxp = (kssl_ctx_t)ssl; 1165c28749e9Skais return (KSSL_STS_OK); 1166c28749e9Skais } 1167c28749e9Skais 1168dd49f125SAnders Persson void 1169dd49f125SAnders Persson kssl_set_mss(kssl_ctx_t ctx, uint32_t mss) 1170dd49f125SAnders Persson { 1171dd49f125SAnders Persson ssl_t *ssl = (ssl_t *)ctx; 1172dd49f125SAnders Persson ssl->tcp_mss = mss; 1173dd49f125SAnders Persson } 1174dd49f125SAnders Persson 1175c28749e9Skais /* 1176c28749e9Skais * Builds SSL records out of the chain of mblks, and returns it. 11772ec7cc7fSKrishna Yenduri * Takes a copy of the message before encrypting it if it has another 1178c28749e9Skais * reference. 1179c28749e9Skais * In case of failure, NULL is returned, and the message will be 1180c28749e9Skais * freed by the caller. 1181c28749e9Skais * A NULL mp means a close_notify is requested. 1182c28749e9Skais */ 1183c28749e9Skais mblk_t * 1184c28749e9Skais kssl_build_record(kssl_ctx_t ctx, mblk_t *mp) 1185c28749e9Skais { 1186c28749e9Skais ssl_t *ssl = (ssl_t *)ctx; 1187c28749e9Skais mblk_t *retmp = mp, *bp = mp, *prevbp = mp, *copybp; 1188c28749e9Skais 1189c28749e9Skais ASSERT(ssl != NULL); 1190*9b1bd49fSVladimir Kotal 1191*9b1bd49fSVladimir Kotal /* 1192*9b1bd49fSVladimir Kotal * Produce new close_notify message. This is necessary to perform 1193*9b1bd49fSVladimir Kotal * proper cleanup w.r.t. SSL protocol spec by sending close_notify SSL 1194*9b1bd49fSVladimir Kotal * alert record if running with KSSL proxy. 1195*9b1bd49fSVladimir Kotal * This should be done prior to sending the FIN so the client side can 1196*9b1bd49fSVladimir Kotal * attempt to do graceful cleanup. Ideally, we should wait for client's 1197*9b1bd49fSVladimir Kotal * close_notify but not all clients send it which would hang the 1198*9b1bd49fSVladimir Kotal * connection. This way of closing the SSL session (Incomplete Close) 1199*9b1bd49fSVladimir Kotal * prevents truncation attacks for protocols without end-of-data 1200*9b1bd49fSVladimir Kotal * markers (as opposed to the Premature Close). 1201*9b1bd49fSVladimir Kotal * Checking the close_notify_srvr flag will prevent from sending the 1202*9b1bd49fSVladimir Kotal * close_notify message twice in case of duplicate shutdown() calls. 1203*9b1bd49fSVladimir Kotal */ 1204*9b1bd49fSVladimir Kotal if (mp == NULL && !ssl->close_notify_srvr) { 1205*9b1bd49fSVladimir Kotal kssl_send_alert(ssl, alert_warning, close_notify); 1206*9b1bd49fSVladimir Kotal if (ssl->alert_sendbuf == NULL) 1207*9b1bd49fSVladimir Kotal return (NULL); 1208*9b1bd49fSVladimir Kotal mp = bp = retmp = prevbp = ssl->alert_sendbuf; 1209*9b1bd49fSVladimir Kotal ssl->alert_sendbuf = NULL; 1210*9b1bd49fSVladimir Kotal ssl->close_notify_srvr = B_TRUE; 1211*9b1bd49fSVladimir Kotal } 1212*9b1bd49fSVladimir Kotal 1213c28749e9Skais ASSERT(mp != NULL); 1214*9b1bd49fSVladimir Kotal ASSERT(bp != NULL); 1215c28749e9Skais 1216c28749e9Skais do { 1217c28749e9Skais if (DB_REF(bp) > 1) { 1218c28749e9Skais /* 1219c28749e9Skais * Fortunately copyb() preserves the offset, 12202ec7cc7fSKrishna Yenduri * tail space and alignment so the copy is 1221c28749e9Skais * ready to be made an SSL record. 1222c28749e9Skais */ 1223c28749e9Skais if ((copybp = copyb(bp)) == NULL) 1224c28749e9Skais return (NULL); 1225c28749e9Skais 1226c28749e9Skais copybp->b_cont = bp->b_cont; 1227c28749e9Skais if (bp == mp) { 1228c28749e9Skais retmp = copybp; 1229c28749e9Skais } else { 1230c28749e9Skais prevbp->b_cont = copybp; 1231c28749e9Skais } 1232c28749e9Skais freeb(bp); 1233c28749e9Skais bp = copybp; 1234c28749e9Skais } 1235c28749e9Skais 1236c28749e9Skais if (kssl_build_single_record(ssl, bp) != KSSL_STS_OK) 1237c28749e9Skais return (NULL); 1238c28749e9Skais 1239c28749e9Skais prevbp = bp; 1240c28749e9Skais bp = bp->b_cont; 1241c28749e9Skais } while (bp != NULL); 1242c28749e9Skais 1243c28749e9Skais return (retmp); 1244c28749e9Skais } 1245c28749e9Skais 1246c28749e9Skais /* 1247*9b1bd49fSVladimir Kotal * Builds a single SSL record by prepending SSL header (optional) and performing 1248*9b1bd49fSVladimir Kotal * encryption and MAC. The encryption of the record is done in-line. 1249*9b1bd49fSVladimir Kotal * Expects an mblk with associated dblk's base to have space for the SSL header 1250*9b1bd49fSVladimir Kotal * or an mblk which already has the header present. In both cases it presumes 1251*9b1bd49fSVladimir Kotal * that the mblk's dblk limit has space for the MAC + padding. 1252*9b1bd49fSVladimir Kotal * If the close_notify_srvr flag is set it is presumed that the mblk already 1253*9b1bd49fSVladimir Kotal * contains SSL header in which case only the record length field will be 1254*9b1bd49fSVladimir Kotal * adjusted with the MAC/padding size. 1255c28749e9Skais */ 1256c28749e9Skais static kssl_status_t 1257c28749e9Skais kssl_build_single_record(ssl_t *ssl, mblk_t *mp) 1258c28749e9Skais { 1259c28749e9Skais int len; 12602ec7cc7fSKrishna Yenduri int reclen; 1261c28749e9Skais uchar_t *recstart, *versionp; 1262c28749e9Skais KSSLCipherSpec *spec; 1263c28749e9Skais int mac_sz; 12642ec7cc7fSKrishna Yenduri int pad_sz; 1265c28749e9Skais 1266c28749e9Skais spec = &ssl->spec[KSSL_WRITE]; 1267c28749e9Skais mac_sz = spec->mac_hashsz; 1268c28749e9Skais 1269c28749e9Skais ASSERT(DB_REF(mp) == 1); 1270*9b1bd49fSVladimir Kotal /* The dblk must always have space for the padding and MAC suffix. */ 1271*9b1bd49fSVladimir Kotal ASSERT(mp->b_datap->db_lim - mp->b_wptr >= mac_sz + spec->cipher_bsize); 1272c28749e9Skais 1273*9b1bd49fSVladimir Kotal /* kssl_send_alert() constructs the SSL header by itself. */ 1274*9b1bd49fSVladimir Kotal if (!ssl->close_notify_srvr) 1275*9b1bd49fSVladimir Kotal len = MBLKL(mp) - SSL3_HDR_LEN; 1276*9b1bd49fSVladimir Kotal else 1277c28749e9Skais len = MBLKL(mp); 1278c28749e9Skais 1279c28749e9Skais ASSERT(len > 0); 1280c28749e9Skais 1281c28749e9Skais mutex_enter(&ssl->kssl_lock); 1282c28749e9Skais 1283*9b1bd49fSVladimir Kotal recstart = mp->b_rptr; 1284*9b1bd49fSVladimir Kotal if (!ssl->close_notify_srvr) { 1285*9b1bd49fSVladimir Kotal /* The dblk must have space for the SSL header prefix. */ 1286*9b1bd49fSVladimir Kotal ASSERT(mp->b_rptr - mp->b_datap->db_base >= SSL3_HDR_LEN); 1287c28749e9Skais recstart = mp->b_rptr = mp->b_rptr - SSL3_HDR_LEN; 1288c28749e9Skais recstart[0] = content_application_data; 1289c28749e9Skais recstart[1] = ssl->major_version; 1290c28749e9Skais recstart[2] = ssl->minor_version; 1291*9b1bd49fSVladimir Kotal } 1292c28749e9Skais versionp = &recstart[1]; 1293c28749e9Skais 1294c28749e9Skais reclen = len + mac_sz; 1295c28749e9Skais if (spec->cipher_type == type_block) { 1296c28749e9Skais pad_sz = spec->cipher_bsize - 1297c28749e9Skais (reclen & (spec->cipher_bsize - 1)); 1298c28749e9Skais ASSERT(reclen + pad_sz <= 1299c28749e9Skais SSL3_MAX_RECORD_LENGTH); 1300c28749e9Skais reclen += pad_sz; 1301c28749e9Skais } 1302c28749e9Skais recstart[3] = (reclen >> 8) & 0xff; 1303c28749e9Skais recstart[4] = reclen & 0xff; 1304c28749e9Skais 1305*9b1bd49fSVladimir Kotal if (kssl_mac_encrypt_record(ssl, recstart[0], versionp, 1306c28749e9Skais recstart, mp) != 0) { 1307c28749e9Skais /* Do we need an internal_error Alert here? */ 1308c28749e9Skais mutex_exit(&ssl->kssl_lock); 1309c28749e9Skais return (KSSL_STS_ERR); 1310c28749e9Skais } 1311c28749e9Skais 1312*9b1bd49fSVladimir Kotal /* Alert messages are accounted in kssl_send_alert(). */ 1313*9b1bd49fSVladimir Kotal if (recstart[0] == content_application_data) 1314c28749e9Skais KSSL_COUNTER(appdata_record_outs, 1); 1315c28749e9Skais mutex_exit(&ssl->kssl_lock); 1316c28749e9Skais return (KSSL_STS_OK); 1317c28749e9Skais } 1318