xref: /onnv-gate/usr/src/uts/common/inet/kssl/ksslrec.c (revision 12696:3dfea19a9dc1)
1898Skais /*
2898Skais  * CDDL HEADER START
3898Skais  *
4898Skais  * The contents of this file are subject to the terms of the
51724Skrishna  * Common Development and Distribution License (the "License").
61724Skrishna  * 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 /*
2212381SVladimir.Kotal@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23898Skais  */
24898Skais 
25898Skais #include <sys/types.h>
26898Skais #include <sys/stream.h>
27898Skais #include <sys/strsubr.h>
28898Skais #include <sys/stropts.h>
29898Skais #include <sys/strsun.h>
30898Skais #define	_SUN_TPI_VERSION 2
31898Skais #include <sys/ddi.h>
32898Skais #include <sys/sunddi.h>
33898Skais #include <sys/debug.h>
34898Skais #include <sys/vtrace.h>
35898Skais #include <sys/kmem.h>
36898Skais #include <sys/cpuvar.h>
37898Skais #include <sys/atomic.h>
38898Skais #include <sys/sysmacros.h>
39898Skais 
40898Skais #include <sys/errno.h>
41898Skais #include <sys/isa_defs.h>
42898Skais #include <sys/md5.h>
43898Skais #include <sys/sha1.h>
44898Skais #include <sys/random.h>
45898Skais #include <inet/common.h>
46898Skais #include <netinet/in.h>
47898Skais 
48898Skais #include <sys/systm.h>
49898Skais #include <sys/param.h>
50898Skais 
51898Skais #include "ksslimpl.h"
52898Skais #include "ksslapi.h"
53898Skais #include "ksslproto.h"
54898Skais 
55898Skais static ssl3CipherSuiteDef cipher_suite_defs[] = {
566788Skrishna 	/* 2 X 16 byte keys +  2 x 20 byte MAC secrets, no IVs */
57898Skais 	{SSL_RSA_WITH_RC4_128_SHA,	cipher_rc4,	mac_sha,	72},
586788Skrishna 
596788Skrishna 	/* 2 X 16 byte keys +  2 x 16 byte MAC secrets, no IVs */
60898Skais 	{SSL_RSA_WITH_RC4_128_MD5,	cipher_rc4,	mac_md5,	64},
616788Skrishna 
626788Skrishna 	/* 2 X 8 byte keys +  2 x 20 byte MAC secrets, 2 x 8 byte IVs */
63898Skais 	{SSL_RSA_WITH_DES_CBC_SHA,	cipher_des,	mac_sha,	72},
646788Skrishna 
656788Skrishna 	/* 2 X 24 byte keys +  2 x 20 byte MAC secrets, 2 x 8 byte IVs */
66898Skais 	{SSL_RSA_WITH_3DES_EDE_CBC_SHA,	cipher_3des,	mac_sha,	104},
676788Skrishna 
686788Skrishna 	/* 2 X 16 byte keys +  2 x 20 byte MAC secrets, 2 x 16 byte IVs */
696788Skrishna 	{TLS_RSA_WITH_AES_128_CBC_SHA,	cipher_aes128,	mac_sha,	104},
706788Skrishna 
716788Skrishna 	/* 2 X 32 byte keys +  2 x 20 byte MAC secrets, 2 x 16 byte IVs */
726788Skrishna 	{TLS_RSA_WITH_AES_256_CBC_SHA,	cipher_aes256,	mac_sha,	136},
736788Skrishna 
74898Skais 	{SSL_RSA_WITH_NULL_SHA,		cipher_null,	mac_sha,	40}
75898Skais };
76898Skais 
77898Skais static int cipher_suite_defs_nentries =
78898Skais     sizeof (cipher_suite_defs) / sizeof (cipher_suite_defs[0]);
79898Skais 
80898Skais static KSSLMACDef mac_defs[] = { /* indexed by SSL3MACAlgorithm */
81898Skais 	/* macsz padsz HashInit HashUpdate HashFinal */
82898Skais 
83898Skais 	{MD5_HASH_LEN, SSL3_MD5_PAD_LEN,
84898Skais 	    (hashinit_func_t)MD5Init, (hashupdate_func_t)MD5Update,
85898Skais 	    (hashfinal_func_t)MD5Final},
86898Skais 
87898Skais 	{SHA1_HASH_LEN, SSL3_SHA1_PAD_LEN,
88898Skais 	    (hashinit_func_t)SHA1Init, (hashupdate_func_t)SHA1Update,
89898Skais 	    (hashfinal_func_t)SHA1Final},
90898Skais };
91898Skais 
92898Skais static uchar_t kssl_pad_1[60] = {
93898Skais     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
94898Skais     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
95898Skais     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
96898Skais     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
97898Skais     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
98898Skais     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
99898Skais     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
100898Skais     0x36, 0x36, 0x36, 0x36
101898Skais };
102898Skais static uchar_t kssl_pad_2[60] = {
103898Skais     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
104898Skais     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
105898Skais     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
106898Skais     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
107898Skais     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
108898Skais     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
109898Skais     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
110898Skais     0x5c, 0x5c, 0x5c, 0x5c
111898Skais };
112898Skais 
113898Skais static boolean_t kssl_synchronous = B_FALSE;
114898Skais 
115898Skais static void kssl_update_handshake_hashes(ssl_t *, uchar_t *, uint_t);
116898Skais static int kssl_compute_handshake_hashes(ssl_t *, SSL3Hashes *, uint32_t);
117898Skais static int kssl_handle_client_hello(ssl_t *, mblk_t *, int);
118898Skais static int kssl_handle_client_key_exchange(ssl_t *, mblk_t *, int,
119898Skais     kssl_callback_t, void *);
120898Skais static int kssl_send_server_hello(ssl_t *);
121898Skais static int kssl_send_certificate_and_server_hello_done(ssl_t *);
122898Skais static int kssl_send_change_cipher_specs(ssl_t *);
123898Skais static int kssl_send_finished(ssl_t *, int);
124898Skais static int kssl_handle_finished(ssl_t *, mblk_t *, int);
125898Skais static void kssl_get_hello_random(uchar_t *);
126898Skais static uchar_t *kssl_rsa_unwrap(uchar_t *, size_t *);
127898Skais static void kssl_cache_sid(sslSessionID *, kssl_entry_t *);
12810520SBhargava.Yenduri@Sun.COM static void kssl_lookup_sid(sslSessionID *, uchar_t *, in6_addr_t *,
129898Skais     kssl_entry_t *);
130898Skais static int kssl_generate_tls_ms(ssl_t *, uchar_t *, size_t);
131898Skais static void kssl_generate_ssl_ms(ssl_t *, uchar_t *, size_t);
132898Skais static int kssl_generate_tls_keyblock(ssl_t *);
133898Skais static void kssl_generate_keyblock(ssl_t *);
134898Skais static void kssl_ssl3_key_material_derive_step(ssl_t *, uchar_t *, size_t,
135898Skais     int, uchar_t *, int);
136898Skais static int kssl_tls_PRF(ssl_t *, uchar_t *, size_t,
137898Skais     uchar_t *, size_t, uchar_t *, size_t, uchar_t *, size_t);
138898Skais static int kssl_tls_P_hash(crypto_mechanism_t *, crypto_key_t *,
139898Skais     size_t, uchar_t *, size_t, uchar_t *, size_t, uchar_t *, size_t);
140898Skais static void kssl_cke_done(void *, int);
141898Skais 
142898Skais #define	HMAC_INIT(m, k, c) \
143898Skais 	rv = crypto_mac_init(m, k, NULL, c, NULL); if (CRYPTO_ERR(rv)) goto end;
144898Skais 
145898Skais #define	HMAC_UPDATE(c, d, l) \
146898Skais 	dd.cd_raw.iov_base = (char *)d; \
147898Skais 	dd.cd_length = dd.cd_raw.iov_len = l; \
148898Skais 	rv = crypto_mac_update(c, &dd, NULL); if (CRYPTO_ERR(rv)) goto end;
149898Skais 
150898Skais #define	HMAC_FINAL(c, d, l) \
151898Skais 	mac.cd_raw.iov_base = (char *)d; \
152898Skais 	mac.cd_length = mac.cd_raw.iov_len = l; \
153898Skais 	rv = crypto_mac_final(c, &mac, NULL); if (CRYPTO_ERR(rv)) goto end;
154898Skais 
1554859Skrishna /*
1564859Skrishna  * This hack can go away once we have SSL3 MAC support by KCF
1574859Skrishna  * software providers (See 4873559).
1584859Skrishna  */
1594859Skrishna extern int kcf_md5_threshold;
1604859Skrishna 
161898Skais int
kssl_compute_record_mac(ssl_t * ssl,int direction,uint64_t seq_num,SSL3ContentType ct,uchar_t * versionp,uchar_t * buf,int len,uchar_t * digest)162898Skais kssl_compute_record_mac(
163898Skais 	ssl_t *ssl,
164898Skais 	int direction,
165898Skais 	uint64_t seq_num,
166898Skais 	SSL3ContentType ct,
167898Skais 	uchar_t *versionp,
168898Skais 	uchar_t *buf,
169898Skais 	int len,
170898Skais 	uchar_t *digest)
171898Skais {
172898Skais 	KSSL_HASHCTX mac_ctx;
173898Skais 	KSSL_HASHCTX *ctx = &mac_ctx;
174898Skais 	uchar_t temp[16], *p;
175898Skais 	KSSLCipherSpec *spec;
1764859Skrishna 	boolean_t hash_use_ok = B_FALSE;
177898Skais 	int rv = 0;
178898Skais 
179898Skais 	spec = &ssl->spec[direction];
180898Skais 
181898Skais 	if (spec->mac_hashsz == 0) {
182898Skais 		return (1);
183898Skais 	}
184898Skais 
185898Skais 	p = temp;
186898Skais 
187898Skais 	*p++ = (seq_num >> 56) & 0xff;
188898Skais 	*p++ = (seq_num >> 48) & 0xff;
189898Skais 	*p++ = (seq_num >> 40) & 0xff;
190898Skais 	*p++ = (seq_num >> 32) & 0xff;
191898Skais 	*p++ = (seq_num >> 24) & 0xff;
192898Skais 	*p++ = (seq_num >> 16) & 0xff;
193898Skais 	*p++ = (seq_num >> 8) & 0xff;
194898Skais 	*p++ = (seq_num) & 0xff;
195898Skais 	*p++ = (uchar_t)ct;
196898Skais 	if (IS_TLS(ssl)) {
197898Skais 		*p++ = versionp[0];
198898Skais 		*p++ = versionp[1];
199898Skais 	}
200898Skais 	*p++ = (len >> 8) & 0xff;
201898Skais 	*p++ = (len) & 0xff;
202898Skais 
2034859Skrishna 	if (IS_TLS(ssl) || (spec->hmac_mech.cm_type != CRYPTO_MECH_INVALID &&
2044859Skrishna 	    len >= kcf_md5_threshold)) {
205898Skais 		crypto_data_t dd, mac;
2064859Skrishna 		struct uio uio_pt;
2074859Skrishna 		struct iovec iovarray_pt[2];
2084859Skrishna 
2094859Skrishna 		/* init the array of iovecs for use in the uio struct */
2104859Skrishna 		iovarray_pt[0].iov_base = (char *)temp;
2114859Skrishna 		iovarray_pt[0].iov_len = (p - temp);
2124859Skrishna 		iovarray_pt[1].iov_base = (char *)buf;
2134859Skrishna 		iovarray_pt[1].iov_len = len;
214898Skais 
2154859Skrishna 		/* init the uio struct for use in the crypto_data_t struct */
2164859Skrishna 		bzero(&uio_pt, sizeof (uio_pt));
2174859Skrishna 		uio_pt.uio_iov = iovarray_pt;
2184859Skrishna 		uio_pt.uio_iovcnt = 2;
2194859Skrishna 		uio_pt.uio_segflg = UIO_SYSSPACE;
2204859Skrishna 
2214859Skrishna 		dd.cd_format = CRYPTO_DATA_UIO;
222898Skais 		dd.cd_offset = 0;
2234859Skrishna 		dd.cd_length =  (p - temp) + len;
2244859Skrishna 		dd.cd_miscdata = NULL;
2254859Skrishna 		dd.cd_uio = &uio_pt;
2264859Skrishna 
227898Skais 		mac.cd_format = CRYPTO_DATA_RAW;
228898Skais 		mac.cd_offset = 0;
2294859Skrishna 		mac.cd_raw.iov_base = (char *)digest;
2304859Skrishna 		mac.cd_length = mac.cd_raw.iov_len = spec->mac_hashsz;
231898Skais 
2324859Skrishna 		/*
2334859Skrishna 		 * The calling context can tolerate a blocking call here.
23412644SAnders.Persson@Sun.COM 		 * For outgoing traffic, we are in user context when called
23512644SAnders.Persson@Sun.COM 		 * from kssl_data_out_cb(). For incoming traffic past the
23612644SAnders.Persson@Sun.COM 		 * SSL handshake, we are in user context when called from
23712644SAnders.Persson@Sun.COM 		 * kssl_data_in_proc_cb(). During the SSL handshake, we are
23812644SAnders.Persson@Sun.COM 		 * called for client_finished message handling from a taskq
23912644SAnders.Persson@Sun.COM 		 * thread.
2404859Skrishna 		 */
2414859Skrishna 		rv = crypto_mac(&spec->hmac_mech, &dd, &spec->hmac_key,
2424859Skrishna 		    NULL, &mac, NULL);
2434859Skrishna 
244898Skais 		if (CRYPTO_ERR(rv)) {
2454859Skrishna 			hash_use_ok = (rv == CRYPTO_MECH_NOT_SUPPORTED &&
2464859Skrishna 			    !IS_TLS(ssl));
2474859Skrishna 			if (!hash_use_ok) {
2485850Svk199839 				DTRACE_PROBE1(kssl_err__crypto_mac_error,
2495850Svk199839 				    int, rv);
2504859Skrishna 				KSSL_COUNTER(compute_mac_failure, 1);
2514859Skrishna 			}
252898Skais 		}
2534859Skrishna 	} else
2544859Skrishna 		hash_use_ok = B_TRUE;
2554859Skrishna 
2564859Skrishna 	if (hash_use_ok) {
257898Skais 		bcopy(&(ssl->mac_ctx[direction][0]), ctx,
2585850Svk199839 		    sizeof (KSSL_HASHCTX));
259898Skais 		spec->MAC_HashUpdate((void *)ctx, temp, p - temp);
260898Skais 		spec->MAC_HashUpdate((void *)ctx, buf, len);
261898Skais 		spec->MAC_HashFinal(digest, (void *)ctx);
262898Skais 
263898Skais 		bcopy(&(ssl->mac_ctx[direction][1]), ctx,
2645850Svk199839 		    sizeof (KSSL_HASHCTX));
265898Skais 		spec->MAC_HashUpdate((void *)ctx, digest, spec->mac_hashsz);
266898Skais 		spec->MAC_HashFinal(digest, (void *)ctx);
267898Skais 	}
268898Skais 
269898Skais 	return (rv);
270898Skais }
271898Skais 
272898Skais /*
273898Skais  * Handles handshake messages.
274898Skais  * Messages to be replied are returned in handshake_sendbuf.
275898Skais  */
276898Skais int
kssl_handle_handshake_message(ssl_t * ssl,mblk_t * mp,int * err,kssl_callback_t cbfn,void * arg)277898Skais kssl_handle_handshake_message(ssl_t *ssl, mblk_t *mp, int *err,
278898Skais     kssl_callback_t cbfn, void *arg)
279898Skais {
280898Skais 	uint32_t msglen;
281898Skais 	uchar_t msghdr[4];
282898Skais 
283898Skais 	ASSERT(ssl->msg.state == MSG_BODY);
284898Skais 	ASSERT(ssl->msg.msglen_bytes == 3);
285898Skais 	ASSERT(mp->b_wptr >= mp->b_rptr + ssl->msg.msglen);
286898Skais 
287898Skais 	ssl->sslcnt++;
288898Skais 	msglen = ssl->msg.msglen;
289898Skais 
290898Skais 	if (ssl->msg.type == client_hello) {
291898Skais 		MD5Init(&ssl->hs_md5);
292898Skais 		SHA1Init(&ssl->hs_sha1);
293898Skais 	}
294898Skais 
295898Skais 	if (ssl->msg.type == finished && ssl->resumed == B_FALSE) {
296898Skais 		if (kssl_compute_handshake_hashes(ssl, &ssl->hs_hashes,
297898Skais 		    sender_client) != 0) {
298898Skais 			*err = SSL_MISS;
299898Skais 			return (0);
300898Skais 		}
301898Skais 	}
302898Skais 
303898Skais 	if (ssl->msg.type != finished || ssl->resumed == B_FALSE) {
304898Skais 		msghdr[0] = (uchar_t)ssl->msg.type;
305898Skais 
306898Skais 		msghdr[1] = (uchar_t)(msglen >> 16);
307898Skais 		msghdr[2] = (uchar_t)(msglen >> 8);
308898Skais 		msghdr[3] = (uchar_t)(msglen);
309898Skais 		kssl_update_handshake_hashes(ssl, msghdr, 4);
310898Skais 		kssl_update_handshake_hashes(ssl, mp->b_rptr, msglen);
311898Skais 	}
312898Skais 
313898Skais 	ssl->msg.state = MSG_INIT;
314898Skais 	ssl->msg.msglen = 0;
315898Skais 	ssl->msg.msglen_bytes = 0;
316898Skais 
317898Skais 	switch (ssl->msg.type) {
318898Skais 	case client_hello:
319898Skais 		if (ssl->hs_waitstate != wait_client_hello) {
320898Skais 			kssl_send_alert(ssl, alert_fatal,
321898Skais 			    unexpected_message);
322898Skais 			*err = EBADMSG;
323898Skais 			ssl->activeinput = B_FALSE;
324898Skais 			return (1);
325898Skais 		}
326898Skais 		*err = kssl_handle_client_hello(ssl, mp, msglen);
327898Skais 		if (*err == SSL_MISS) {
328898Skais 			ssl->activeinput = B_FALSE;
329898Skais 			return (0);
330898Skais 		}
331898Skais 		return (1);
332898Skais 	case client_key_exchange:
333898Skais 		if (ssl->hs_waitstate != wait_client_key) {
334898Skais 			kssl_send_alert(ssl, alert_fatal,
335898Skais 			    unexpected_message);
336898Skais 			*err = EBADMSG;
337898Skais 			ssl->activeinput = B_FALSE;
338898Skais 			return (1);
339898Skais 		}
340898Skais 		*err = kssl_handle_client_key_exchange(ssl, mp,
341898Skais 		    msglen, cbfn, arg);
342898Skais 		return (1);
343898Skais 	case finished:
344898Skais 		if (ssl->hs_waitstate != wait_finished) {
345898Skais 			kssl_send_alert(ssl, alert_fatal,
3465850Svk199839 			    unexpected_message);
347898Skais 			*err = EBADMSG;
348898Skais 			ssl->activeinput = B_FALSE;
349898Skais 			return (1);
350898Skais 		}
351898Skais 		*err = kssl_handle_finished(ssl, mp, msglen);
352898Skais 		return (1);
353898Skais 	default:
354898Skais 		kssl_send_alert(ssl, alert_fatal, unexpected_message);
355898Skais 		ssl->activeinput = B_FALSE;
356898Skais 		*err = EBADMSG;
357898Skais 		return (1);
358898Skais 	}
359898Skais }
360898Skais 
361898Skais static void
kssl_update_handshake_hashes(ssl_t * ssl,uchar_t * buf,uint_t len)362898Skais kssl_update_handshake_hashes(ssl_t *ssl, uchar_t *buf, uint_t len)
363898Skais {
364898Skais 	MD5Update(&ssl->hs_md5, buf, len);
365898Skais 	SHA1Update(&ssl->hs_sha1, buf, len);
366898Skais }
367898Skais 
368898Skais static int
kssl_compute_handshake_hashes(ssl_t * ssl,SSL3Hashes * hashes,uint32_t sender)369898Skais kssl_compute_handshake_hashes(
370898Skais 	ssl_t *ssl,
371898Skais 	SSL3Hashes *hashes,
372898Skais 	uint32_t sender)
373898Skais {
374898Skais 	MD5_CTX md5 = ssl->hs_md5;	/* clone md5 context */
375898Skais 	SHA1_CTX sha1 = ssl->hs_sha1;	/* clone sha1 context */
376898Skais 	MD5_CTX *md5ctx = &md5;
377898Skais 	SHA1_CTX *sha1ctx = &sha1;
378898Skais 
379898Skais 	if (IS_TLS(ssl)) {
380898Skais 		uchar_t seed[MD5_HASH_LEN + SHA1_HASH_LEN];
381898Skais 		char *label;
382898Skais 
383898Skais 		/*
384898Skais 		 * Do not take another hash step here.
385898Skais 		 * Just complete the operation.
386898Skais 		 */
387898Skais 		MD5Final(hashes->md5, md5ctx);
388898Skais 		SHA1Final(hashes->sha1, sha1ctx);
389898Skais 
390898Skais 		bcopy(hashes->md5, seed, MD5_HASH_LEN);
391898Skais 		bcopy(hashes->sha1, seed + MD5_HASH_LEN, SHA1_HASH_LEN);
392898Skais 
393898Skais 		if (sender == sender_client)
394898Skais 			label = TLS_CLIENT_FINISHED_LABEL;
395898Skais 		else
396898Skais 			label = TLS_SERVER_FINISHED_LABEL;
397898Skais 
398898Skais 		return (kssl_tls_PRF(ssl,
3995850Svk199839 		    ssl->sid.master_secret,
4005850Svk199839 		    (size_t)SSL3_MASTER_SECRET_LEN,
4015850Svk199839 		    (uchar_t *)label, strlen(label),
4025850Svk199839 		    seed, (size_t)(MD5_HASH_LEN + SHA1_HASH_LEN),
4035850Svk199839 		    hashes->tlshash, (size_t)TLS_FINISHED_SIZE));
404898Skais 	} else {
405898Skais 		uchar_t s[4];
406898Skais 		s[0] = (sender >> 24) & 0xff;
407898Skais 		s[1] = (sender >> 16) & 0xff;
408898Skais 		s[2] = (sender >> 8) & 0xff;
409898Skais 		s[3] = (sender) & 0xff;
410898Skais 
411898Skais 		MD5Update(md5ctx, s, 4);
412898Skais 		MD5Update(md5ctx, ssl->sid.master_secret,
413898Skais 		    SSL3_MASTER_SECRET_LEN);
414898Skais 		MD5Update(md5ctx, kssl_pad_1, SSL3_MD5_PAD_LEN);
415898Skais 		MD5Final(hashes->md5, md5ctx);
416898Skais 
417898Skais 		MD5Init(md5ctx);
418898Skais 		MD5Update(md5ctx, ssl->sid.master_secret,
419898Skais 		    SSL3_MASTER_SECRET_LEN);
420898Skais 		MD5Update(md5ctx, kssl_pad_2, SSL3_MD5_PAD_LEN);
421898Skais 		MD5Update(md5ctx, hashes->md5, MD5_HASH_LEN);
422898Skais 		MD5Final(hashes->md5, md5ctx);
423898Skais 
424898Skais 		SHA1Update(sha1ctx, s, 4);
425898Skais 		SHA1Update(sha1ctx, ssl->sid.master_secret,
426898Skais 		    SSL3_MASTER_SECRET_LEN);
427898Skais 		SHA1Update(sha1ctx, kssl_pad_1, SSL3_SHA1_PAD_LEN);
428898Skais 		SHA1Final(hashes->sha1, sha1ctx);
429898Skais 
430898Skais 		SHA1Init(sha1ctx);
431898Skais 		SHA1Update(sha1ctx, ssl->sid.master_secret,
432898Skais 		    SSL3_MASTER_SECRET_LEN);
433898Skais 		SHA1Update(sha1ctx, kssl_pad_2, SSL3_SHA1_PAD_LEN);
434898Skais 		SHA1Update(sha1ctx, hashes->sha1, SHA1_HASH_LEN);
435898Skais 		SHA1Final(hashes->sha1, sha1ctx);
436898Skais 		return (0);
437898Skais 	}
438898Skais }
439898Skais 
440898Skais 
44110118SBhargava.Yenduri@Sun.COM /*
44210118SBhargava.Yenduri@Sun.COM  * Minimum message length for a client hello =
44310118SBhargava.Yenduri@Sun.COM  * 2-byte client_version +
44410118SBhargava.Yenduri@Sun.COM  * 32-byte random +
44510118SBhargava.Yenduri@Sun.COM  * 1-byte session_id length +
44610118SBhargava.Yenduri@Sun.COM  * 2-byte cipher_suites length +
44710118SBhargava.Yenduri@Sun.COM  * 1-byte compression_methods length +
44810118SBhargava.Yenduri@Sun.COM  * 1-byte CompressionMethod.null
44910118SBhargava.Yenduri@Sun.COM  */
450898Skais #define	KSSL_SSL3_CH_MIN_MSGLEN	(39)
451898Skais 
45211984SVladimir.Kotal@Sun.COM /*
45311984SVladimir.Kotal@Sun.COM  * Process SSL/TLS Client Hello message. Return 0 on success, errno value
45411984SVladimir.Kotal@Sun.COM  * or SSL_MISS if no cipher suite of the server matches the list received
45511984SVladimir.Kotal@Sun.COM  * in the message.
45611984SVladimir.Kotal@Sun.COM  */
457898Skais static int
kssl_handle_client_hello(ssl_t * ssl,mblk_t * mp,int msglen)458898Skais kssl_handle_client_hello(ssl_t *ssl, mblk_t *mp, int msglen)
459898Skais {
460898Skais 	uchar_t *msgend;
461898Skais 	int err;
462898Skais 	SSL3AlertDescription desc = illegal_parameter;
46310118SBhargava.Yenduri@Sun.COM 	uint_t sidlen, cslen, cmlen;
464898Skais 	uchar_t *suitesp;
465898Skais 	uint_t i, j;
46612381SVladimir.Kotal@Sun.COM 	uint16_t suite, selected_suite;
467898Skais 	int ch_msglen = KSSL_SSL3_CH_MIN_MSGLEN;
46812381SVladimir.Kotal@Sun.COM 	boolean_t suite_found = B_FALSE;
469898Skais 
470898Skais 	ASSERT(mp->b_wptr >= mp->b_rptr + msglen);
471898Skais 	ASSERT(ssl->msg.type == client_hello);
472898Skais 	ASSERT(ssl->hs_waitstate == wait_client_hello);
473898Skais 	ASSERT(ssl->resumed == B_FALSE);
474898Skais 
475898Skais 	if (msglen < ch_msglen) {
47611984SVladimir.Kotal@Sun.COM 		DTRACE_PROBE2(kssl_err__msglen_less_than_minimum,
47711984SVladimir.Kotal@Sun.COM 		    int, msglen, int, ch_msglen);
478898Skais 		goto falert;
479898Skais 	}
480898Skais 
481898Skais 	msgend = mp->b_rptr + msglen;
482898Skais 
483898Skais 	/* Support SSLv3 (version == 3.0) or TLS (version == 3.1) */
484898Skais 	if (ssl->major_version != 3 || (ssl->major_version == 3 &&
4855850Svk199839 	    ssl->minor_version != 0 && ssl->minor_version != 1)) {
4865850Svk199839 		DTRACE_PROBE2(kssl_err__SSL_version_not_supported,
4875850Svk199839 		    uchar_t, ssl->major_version,
4885850Svk199839 		    uchar_t, ssl->minor_version);
489898Skais 		desc = handshake_failure;
490898Skais 		goto falert;
491898Skais 	}
492898Skais 	mp->b_rptr += 2; /* skip the version bytes */
493898Skais 
49411984SVladimir.Kotal@Sun.COM 	/* read client random field */
495898Skais 	bcopy(mp->b_rptr, ssl->client_random, SSL3_RANDOM_LENGTH);
496898Skais 	mp->b_rptr += SSL3_RANDOM_LENGTH;
497898Skais 
49811984SVladimir.Kotal@Sun.COM 	/* read session ID length */
499898Skais 	ASSERT(ssl->sid.cached == B_FALSE);
500898Skais 	sidlen = *mp->b_rptr++;
501898Skais 	ch_msglen += sidlen;
502898Skais 	if (msglen < ch_msglen) {
50311984SVladimir.Kotal@Sun.COM 		DTRACE_PROBE2(kssl_err__invalid_message_length_after_ver,
50411984SVladimir.Kotal@Sun.COM 		    int, msglen, int, ch_msglen);
505898Skais 		goto falert;
506898Skais 	}
507898Skais 	if (sidlen != SSL3_SESSIONID_BYTES) {
508898Skais 		mp->b_rptr += sidlen;
509898Skais 	} else {
51010520SBhargava.Yenduri@Sun.COM 		kssl_lookup_sid(&ssl->sid, mp->b_rptr, &ssl->faddr,
511898Skais 		    ssl->kssl_entry);
512898Skais 		mp->b_rptr += SSL3_SESSIONID_BYTES;
513898Skais 	}
514898Skais 
51511984SVladimir.Kotal@Sun.COM 	/* read cipher suite length */
51610118SBhargava.Yenduri@Sun.COM 	cslen = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1];
517898Skais 	mp->b_rptr += 2;
51810118SBhargava.Yenduri@Sun.COM 	ch_msglen += cslen;
51910118SBhargava.Yenduri@Sun.COM 
52010118SBhargava.Yenduri@Sun.COM 	/*
52110118SBhargava.Yenduri@Sun.COM 	 * This check can't be a "!=" since there can be
52210118SBhargava.Yenduri@Sun.COM 	 * compression methods other than CompressionMethod.null.
52310118SBhargava.Yenduri@Sun.COM 	 * Also, there can be extra data (TLS extensions) after the
52412381SVladimir.Kotal@Sun.COM 	 * compression methods field.
52510118SBhargava.Yenduri@Sun.COM 	 */
52610118SBhargava.Yenduri@Sun.COM 	if (msglen < ch_msglen) {
52711984SVladimir.Kotal@Sun.COM 		DTRACE_PROBE2(kssl_err__invalid_message_length_after_cslen,
52811984SVladimir.Kotal@Sun.COM 		    int, msglen, int, ch_msglen);
529898Skais 		goto falert;
530898Skais 	}
53110118SBhargava.Yenduri@Sun.COM 
53212381SVladimir.Kotal@Sun.COM 	/* The length has to be even since a cipher suite is 2-byte long. */
53310118SBhargava.Yenduri@Sun.COM 	if (cslen & 0x1) {
53411984SVladimir.Kotal@Sun.COM 		DTRACE_PROBE1(kssl_err__uneven_cipher_suite_length,
53511984SVladimir.Kotal@Sun.COM 		    uint_t, cslen);
536898Skais 		goto falert;
537898Skais 	}
538898Skais 	suitesp = mp->b_rptr;
53912381SVladimir.Kotal@Sun.COM 
54012381SVladimir.Kotal@Sun.COM 	/* session resumption checks */
541898Skais 	if (ssl->sid.cached == B_TRUE) {
542898Skais 		suite = ssl->sid.cipher_suite;
54310118SBhargava.Yenduri@Sun.COM 		for (j = 0; j < cslen; j += 2) {
54412381SVladimir.Kotal@Sun.COM 			DTRACE_PROBE2(kssl_cipher_suite_check_resumpt,
54512381SVladimir.Kotal@Sun.COM 			    uint16_t, suite,
54612381SVladimir.Kotal@Sun.COM 			    uint16_t,
54712381SVladimir.Kotal@Sun.COM 			    (uint16_t)((suitesp[j] << 8) + suitesp[j+1]));
54812381SVladimir.Kotal@Sun.COM 			/* Check for regular (true) cipher suite. */
549898Skais 			if (suitesp[j] == ((suite >> 8) & 0xff) &&
550898Skais 			    suitesp[j + 1] == (suite & 0xff)) {
55112381SVladimir.Kotal@Sun.COM 				DTRACE_PROBE1(kssl_cipher_suite_found_resumpt,
55212381SVladimir.Kotal@Sun.COM 				    uint16_t, suite);
55312381SVladimir.Kotal@Sun.COM 				suite_found = B_TRUE;
55412381SVladimir.Kotal@Sun.COM 				selected_suite = suite;
55512381SVladimir.Kotal@Sun.COM 			}
55612381SVladimir.Kotal@Sun.COM 
55712381SVladimir.Kotal@Sun.COM 			/* Check for SCSV. */
55812381SVladimir.Kotal@Sun.COM 			if (suitesp[j] ==  ((SSL_SCSV >> 8) & 0xff) &&
55912381SVladimir.Kotal@Sun.COM 			    suitesp[j + 1] == (SSL_SCSV & 0xff)) {
56012381SVladimir.Kotal@Sun.COM 				DTRACE_PROBE(kssl_scsv_found_resumpt);
56112381SVladimir.Kotal@Sun.COM 				ssl->secure_renegotiation = B_TRUE;
56212381SVladimir.Kotal@Sun.COM 			}
56312381SVladimir.Kotal@Sun.COM 
56412381SVladimir.Kotal@Sun.COM 			/*
56512381SVladimir.Kotal@Sun.COM 			 * If we got cipher suite match and SCSV we can
56612381SVladimir.Kotal@Sun.COM 			 * terminate the cycle now.
56712381SVladimir.Kotal@Sun.COM 			 */
56812381SVladimir.Kotal@Sun.COM 			if (suite_found && ssl->secure_renegotiation)
569898Skais 				break;
570898Skais 		}
57112381SVladimir.Kotal@Sun.COM 		if (suite_found)
572898Skais 			goto suite_found;
573898Skais 		kssl_uncache_sid(&ssl->sid, ssl->kssl_entry);
574898Skais 	}
575898Skais 
57612381SVladimir.Kotal@Sun.COM 	/* Check if this server is capable of the cipher suite. */
577898Skais 	for (i = 0; i < ssl->kssl_entry->kssl_cipherSuites_nentries; i++) {
578898Skais 		suite = ssl->kssl_entry->kssl_cipherSuites[i];
57910118SBhargava.Yenduri@Sun.COM 		for (j = 0; j < cslen; j += 2) {
58012381SVladimir.Kotal@Sun.COM 			DTRACE_PROBE2(kssl_cipher_suite_check, uint16_t, suite,
58112381SVladimir.Kotal@Sun.COM 			    uint16_t,
58212381SVladimir.Kotal@Sun.COM 			    (uint16_t)((suitesp[j] << 8) + suitesp[j+1]));
58312381SVladimir.Kotal@Sun.COM 			/* Check for regular (true) cipher suite. */
584898Skais 			if (suitesp[j] == ((suite >> 8) & 0xff) &&
585898Skais 			    suitesp[j + 1] == (suite & 0xff)) {
58612381SVladimir.Kotal@Sun.COM 				DTRACE_PROBE1(kssl_cipher_suite_found,
58712381SVladimir.Kotal@Sun.COM 				    uint16_t, suite);
58812381SVladimir.Kotal@Sun.COM 				suite_found = B_TRUE;
58912381SVladimir.Kotal@Sun.COM 				selected_suite = suite;
59012381SVladimir.Kotal@Sun.COM 			}
59112381SVladimir.Kotal@Sun.COM 
59212381SVladimir.Kotal@Sun.COM 			/* Check for SCSV. */
59312381SVladimir.Kotal@Sun.COM 			if (suitesp[j] ==  ((SSL_SCSV >> 8) & 0xff) &&
59412381SVladimir.Kotal@Sun.COM 			    suitesp[j + 1] == (SSL_SCSV & 0xff)) {
59512381SVladimir.Kotal@Sun.COM 				DTRACE_PROBE(kssl_scsv_found);
59612381SVladimir.Kotal@Sun.COM 				ssl->secure_renegotiation = B_TRUE;
59712381SVladimir.Kotal@Sun.COM 			}
59812381SVladimir.Kotal@Sun.COM 
59912381SVladimir.Kotal@Sun.COM 			/*
60012381SVladimir.Kotal@Sun.COM 			 * If we got cipher suite match and SCSV or went
60112381SVladimir.Kotal@Sun.COM 			 * through the whole list of client cipher suites
60212381SVladimir.Kotal@Sun.COM 			 * (hence we know if SCSV was present or not) we
60312381SVladimir.Kotal@Sun.COM 			 * can terminate the cycle now.
60412381SVladimir.Kotal@Sun.COM 			 */
60512381SVladimir.Kotal@Sun.COM 			if (suite_found &&
60612381SVladimir.Kotal@Sun.COM 			    (ssl->secure_renegotiation || (i > 0)))
607898Skais 				break;
608898Skais 		}
60912381SVladimir.Kotal@Sun.COM 		if (suite_found)
610898Skais 			break;
611898Skais 	}
61212381SVladimir.Kotal@Sun.COM 	if (!suite_found) {
613898Skais 		if (ssl->sslcnt == 1) {
61411984SVladimir.Kotal@Sun.COM 			DTRACE_PROBE(kssl_no_cipher_suite_found);
615898Skais 			KSSL_COUNTER(no_suite_found, 1);
61611984SVladimir.Kotal@Sun.COM 			/*
61711984SVladimir.Kotal@Sun.COM 			 * If there is no fallback point terminate the
61811984SVladimir.Kotal@Sun.COM 			 * handshake with SSL alert otherwise return with
61911984SVladimir.Kotal@Sun.COM 			 * SSL_MISS.
62011984SVladimir.Kotal@Sun.COM 			 */
62111984SVladimir.Kotal@Sun.COM 			if (ssl->kssl_entry->ke_fallback_head == NULL) {
62211984SVladimir.Kotal@Sun.COM 				DTRACE_PROBE(kssl_no_fallback);
62311984SVladimir.Kotal@Sun.COM 				desc = handshake_failure;
62411984SVladimir.Kotal@Sun.COM 				goto falert;
62511984SVladimir.Kotal@Sun.COM 			} else {
62611984SVladimir.Kotal@Sun.COM 				return (SSL_MISS);
62711984SVladimir.Kotal@Sun.COM 			}
628898Skais 		}
629898Skais 		desc = handshake_failure;
6305850Svk199839 		DTRACE_PROBE(kssl_err__no_cipher_suites_found);
631898Skais 		goto falert;
632898Skais 	}
633898Skais 
634898Skais suite_found:
63510118SBhargava.Yenduri@Sun.COM 	mp->b_rptr += cslen;
636898Skais 
63710118SBhargava.Yenduri@Sun.COM 	/*
63810118SBhargava.Yenduri@Sun.COM 	 * Check for the mandatory CompressionMethod.null. We do not
63910118SBhargava.Yenduri@Sun.COM 	 * support any other compression methods.
64010118SBhargava.Yenduri@Sun.COM 	 */
64110118SBhargava.Yenduri@Sun.COM 	cmlen = *mp->b_rptr++;
64210118SBhargava.Yenduri@Sun.COM 	ch_msglen += cmlen - 1;	/* -1 accounts for the null method */
64310118SBhargava.Yenduri@Sun.COM 	if (msglen < ch_msglen) {
64411984SVladimir.Kotal@Sun.COM 		DTRACE_PROBE2(kssl_err__invalid_message_length_after_complen,
64511984SVladimir.Kotal@Sun.COM 		    int, msglen, int, ch_msglen);
64610118SBhargava.Yenduri@Sun.COM 		goto falert;
64710118SBhargava.Yenduri@Sun.COM 	}
64810118SBhargava.Yenduri@Sun.COM 
64911984SVladimir.Kotal@Sun.COM 	/*
65011984SVladimir.Kotal@Sun.COM 	 * Search for null compression method (encoded as 0 byte) in the
65111984SVladimir.Kotal@Sun.COM 	 * compression methods field.
65211984SVladimir.Kotal@Sun.COM 	 */
65310118SBhargava.Yenduri@Sun.COM 	while (cmlen >= 1) {
65410118SBhargava.Yenduri@Sun.COM 		if (*mp->b_rptr++ == 0)
65510118SBhargava.Yenduri@Sun.COM 			break;
65610118SBhargava.Yenduri@Sun.COM 		cmlen--;
65710118SBhargava.Yenduri@Sun.COM 	}
65810118SBhargava.Yenduri@Sun.COM 
65910118SBhargava.Yenduri@Sun.COM 	if (cmlen == 0) {
660898Skais 		desc = handshake_failure;
66111984SVladimir.Kotal@Sun.COM 		DTRACE_PROBE(kssl_err__no_null_compression_method);
662898Skais 		goto falert;
663898Skais 	}
664898Skais 
66512381SVladimir.Kotal@Sun.COM 	/* Find the suite in the internal cipher suite table. */
666898Skais 	for (i = 0; i < cipher_suite_defs_nentries; i++) {
66712381SVladimir.Kotal@Sun.COM 		if (selected_suite == cipher_suite_defs[i].suite) {
668898Skais 			break;
669898Skais 		}
670898Skais 	}
671898Skais 
67212381SVladimir.Kotal@Sun.COM 	/* Get past the remaining compression methods (minus null method). */
67312381SVladimir.Kotal@Sun.COM 	mp->b_rptr += cmlen - 1;
67412381SVladimir.Kotal@Sun.COM 
675898Skais 	ASSERT(i < cipher_suite_defs_nentries);
676898Skais 
67712381SVladimir.Kotal@Sun.COM 	ssl->pending_cipher_suite = selected_suite;
678898Skais 	ssl->pending_malg = cipher_suite_defs[i].malg;
679898Skais 	ssl->pending_calg = cipher_suite_defs[i].calg;
680898Skais 	ssl->pending_keyblksz = cipher_suite_defs[i].keyblksz;
681898Skais 
68212381SVladimir.Kotal@Sun.COM 	/* Parse TLS extensions (if any). */
68312381SVladimir.Kotal@Sun.COM 	if (ch_msglen + 2 < msglen) {
68412381SVladimir.Kotal@Sun.COM 		/* Get the length of the extensions. */
68512381SVladimir.Kotal@Sun.COM 		uint16_t ext_total_len = ((uint_t)mp->b_rptr[0] << 8) +
68612381SVladimir.Kotal@Sun.COM 		    (uint_t)mp->b_rptr[1];
68712381SVladimir.Kotal@Sun.COM 		DTRACE_PROBE1(kssl_total_length_extensions, uint16_t,
68812381SVladimir.Kotal@Sun.COM 		    ext_total_len);
68912381SVladimir.Kotal@Sun.COM 		/*
69012381SVladimir.Kotal@Sun.COM 		 * Consider zero extensions length as invalid extension
69112381SVladimir.Kotal@Sun.COM 		 * encoding.
69212381SVladimir.Kotal@Sun.COM 		 */
69312381SVladimir.Kotal@Sun.COM 		if (ext_total_len == 0) {
69412381SVladimir.Kotal@Sun.COM 			DTRACE_PROBE1(kssl_err__zero_extensions_length,
69512381SVladimir.Kotal@Sun.COM 			    mblk_t *, mp);
69612381SVladimir.Kotal@Sun.COM 			goto falert;
69712381SVladimir.Kotal@Sun.COM 		}
69812381SVladimir.Kotal@Sun.COM 		ch_msglen += 2;
69912381SVladimir.Kotal@Sun.COM 		if (ch_msglen + ext_total_len > msglen) {
70012381SVladimir.Kotal@Sun.COM 			DTRACE_PROBE2(kssl_err__invalid_extensions_length,
70112381SVladimir.Kotal@Sun.COM 			    int, msglen, int, ch_msglen);
70212381SVladimir.Kotal@Sun.COM 			goto falert;
70312381SVladimir.Kotal@Sun.COM 		}
70412381SVladimir.Kotal@Sun.COM 		mp->b_rptr += 2;
70512381SVladimir.Kotal@Sun.COM 
70612381SVladimir.Kotal@Sun.COM 		/*
70712381SVladimir.Kotal@Sun.COM 		 * Go through the TLS extensions. This is only done to check
70812381SVladimir.Kotal@Sun.COM 		 * for the presence of renegotiation_info extension. We do not
70912381SVladimir.Kotal@Sun.COM 		 * support any other TLS extensions and hence ignore them.
71012381SVladimir.Kotal@Sun.COM 		 */
71112381SVladimir.Kotal@Sun.COM 		while (mp->b_rptr < msgend) {
71212381SVladimir.Kotal@Sun.COM 			uint16_t ext_len, ext_type;
71312381SVladimir.Kotal@Sun.COM 
71412381SVladimir.Kotal@Sun.COM 			/*
71512381SVladimir.Kotal@Sun.COM 			 * Check that the extension has at least type and
71612381SVladimir.Kotal@Sun.COM 			 * length (2 + 2 bytes).
71712381SVladimir.Kotal@Sun.COM 			 */
71812381SVladimir.Kotal@Sun.COM 			if (ch_msglen + 4 > msglen) {
71912381SVladimir.Kotal@Sun.COM 				DTRACE_PROBE(kssl_err__invalid_ext_format);
72012381SVladimir.Kotal@Sun.COM 				goto falert;
72112381SVladimir.Kotal@Sun.COM 			}
72212381SVladimir.Kotal@Sun.COM 
72312381SVladimir.Kotal@Sun.COM 			/* Get extension type and length */
72412381SVladimir.Kotal@Sun.COM 			ext_type = ((uint_t)mp->b_rptr[0] << 8) +
72512381SVladimir.Kotal@Sun.COM 			    (uint_t)mp->b_rptr[1];
72612381SVladimir.Kotal@Sun.COM 			mp->b_rptr += 2;
72712381SVladimir.Kotal@Sun.COM 			ext_len = ((uint_t)mp->b_rptr[0] << 8) +
72812381SVladimir.Kotal@Sun.COM 			    (uint_t)mp->b_rptr[1];
72912381SVladimir.Kotal@Sun.COM 			mp->b_rptr += 2;
73012381SVladimir.Kotal@Sun.COM 			ch_msglen += 4;
73112381SVladimir.Kotal@Sun.COM 			DTRACE_PROBE3(kssl_ext_detected, uint16_t, ext_type,
73212381SVladimir.Kotal@Sun.COM 			    uint16_t, ext_len, mblk_t *, mp);
73312381SVladimir.Kotal@Sun.COM 
73412381SVladimir.Kotal@Sun.COM 			/*
73512381SVladimir.Kotal@Sun.COM 			 * Make sure the contents of the extension are
73612381SVladimir.Kotal@Sun.COM 			 * accessible.
73712381SVladimir.Kotal@Sun.COM 			 */
73812381SVladimir.Kotal@Sun.COM 			if (ch_msglen + ext_len > msglen) {
73912381SVladimir.Kotal@Sun.COM 				DTRACE_PROBE1(
74012381SVladimir.Kotal@Sun.COM 				    kssl_err__invalid_ext_len,
74112381SVladimir.Kotal@Sun.COM 				    uint16_t, ext_len);
74212381SVladimir.Kotal@Sun.COM 				goto falert;
74312381SVladimir.Kotal@Sun.COM 			}
74412381SVladimir.Kotal@Sun.COM 
74512381SVladimir.Kotal@Sun.COM 			switch (ext_type) {
74612381SVladimir.Kotal@Sun.COM 			case TLSEXT_RENEGOTIATION_INFO:
74712381SVladimir.Kotal@Sun.COM 				/*
74812381SVladimir.Kotal@Sun.COM 				 * Search for empty "renegotiation_info"
74912381SVladimir.Kotal@Sun.COM 				 * extension (encoded as ff 01 00 01 00).
75012381SVladimir.Kotal@Sun.COM 				 */
75112381SVladimir.Kotal@Sun.COM 				DTRACE_PROBE(kssl_reneg_info_found);
75212381SVladimir.Kotal@Sun.COM 				if ((ext_len != 1) ||
75312381SVladimir.Kotal@Sun.COM 				    (*mp->b_rptr != 0)) {
75412381SVladimir.Kotal@Sun.COM 					DTRACE_PROBE2(
75512381SVladimir.Kotal@Sun.COM 					    kssl_err__non_empty_reneg_info,
75612381SVladimir.Kotal@Sun.COM 					    uint16_t, ext_len,
75712381SVladimir.Kotal@Sun.COM 					    mblk_t *, mp);
75812381SVladimir.Kotal@Sun.COM 					goto falert;
75912381SVladimir.Kotal@Sun.COM 				}
76012381SVladimir.Kotal@Sun.COM 				ssl->secure_renegotiation = B_TRUE;
76112381SVladimir.Kotal@Sun.COM 				break;
76212381SVladimir.Kotal@Sun.COM 			default:
76312381SVladimir.Kotal@Sun.COM 				/* FALLTHRU */
76412381SVladimir.Kotal@Sun.COM 				break;
76512381SVladimir.Kotal@Sun.COM 			}
76612381SVladimir.Kotal@Sun.COM 
76712381SVladimir.Kotal@Sun.COM 			/* jump to the next extension */
76812381SVladimir.Kotal@Sun.COM 			ch_msglen += ext_len;
76912381SVladimir.Kotal@Sun.COM 			mp->b_rptr += ext_len;
77012381SVladimir.Kotal@Sun.COM 		}
77112381SVladimir.Kotal@Sun.COM 	}
77212381SVladimir.Kotal@Sun.COM 
77312381SVladimir.Kotal@Sun.COM 	mp->b_rptr = msgend;
77412381SVladimir.Kotal@Sun.COM 
775898Skais 	if (ssl->sid.cached == B_TRUE) {
776898Skais 		err = kssl_send_server_hello(ssl);
777898Skais 		if (err != 0) {
778898Skais 			return (err);
779898Skais 		}
780898Skais 		if (IS_TLS(ssl))
781898Skais 			err = kssl_generate_tls_keyblock(ssl);
782898Skais 		else
783898Skais 			kssl_generate_keyblock(ssl);
784898Skais 
785898Skais 		err = kssl_send_change_cipher_specs(ssl);
786898Skais 		if (err != 0) {
787898Skais 			return (err);
788898Skais 		}
789898Skais 
790898Skais 		err = kssl_send_finished(ssl, 1);
791898Skais 		if (err != 0)
792898Skais 			return (err);
793898Skais 
794898Skais 		err = kssl_compute_handshake_hashes(ssl, &ssl->hs_hashes,
7955850Svk199839 		    sender_client);
796898Skais 		if (err != 0)
797898Skais 			return (err);
798898Skais 
799898Skais 		ssl->hs_waitstate = wait_change_cipher;
800898Skais 		ssl->resumed = B_TRUE;
801898Skais 		ssl->activeinput = B_FALSE;
802898Skais 		KSSL_COUNTER(resumed_sessions, 1);
803898Skais 		return (0);
804898Skais 	}
805898Skais 
806898Skais 	(void) random_get_pseudo_bytes(ssl->sid.session_id,
807898Skais 	    SSL3_SESSIONID_BYTES);
808898Skais 	ssl->sid.client_addr = ssl->faddr;
80912381SVladimir.Kotal@Sun.COM 	ssl->sid.cipher_suite = selected_suite;
810898Skais 
811898Skais 	err = kssl_send_server_hello(ssl);
812898Skais 	if (err != 0) {
813898Skais 		return (err);
814898Skais 	}
815898Skais 	err = kssl_send_certificate_and_server_hello_done(ssl);
816898Skais 	if (err != 0) {
817898Skais 		return (err);
818898Skais 	}
819898Skais 	KSSL_COUNTER(full_handshakes, 1);
820898Skais 	ssl->hs_waitstate = wait_client_key;
821898Skais 	ssl->activeinput = B_FALSE;
822898Skais 	return (0);
823898Skais 
824898Skais falert:
825898Skais 	kssl_send_alert(ssl, alert_fatal, desc);
826898Skais 	return (EBADMSG);
827898Skais }
828898Skais 
82910520SBhargava.Yenduri@Sun.COM #define	SET_HASH_INDEX(index, s, clnt_addr) {				\
83010520SBhargava.Yenduri@Sun.COM 	int addr;							\
83110520SBhargava.Yenduri@Sun.COM 									\
83210520SBhargava.Yenduri@Sun.COM 	IN6_V4MAPPED_TO_IPADDR(clnt_addr, addr);			\
83310520SBhargava.Yenduri@Sun.COM 	index = addr ^ (((int)(s)[0] << 24) | ((int)(s)[1] << 16) |	\
83410520SBhargava.Yenduri@Sun.COM 	    ((int)(s)[2] << 8) | (int)(s)[SSL3_SESSIONID_BYTES - 1]);	\
83510520SBhargava.Yenduri@Sun.COM }
83610520SBhargava.Yenduri@Sun.COM 
83710520SBhargava.Yenduri@Sun.COM /*
83810520SBhargava.Yenduri@Sun.COM  * Creates a cache entry. Sets the sid->cached flag
83910520SBhargava.Yenduri@Sun.COM  * and sid->time fields. So, the caller should not set them.
84010520SBhargava.Yenduri@Sun.COM  */
841898Skais static void
kssl_cache_sid(sslSessionID * sid,kssl_entry_t * kssl_entry)842898Skais kssl_cache_sid(sslSessionID *sid, kssl_entry_t *kssl_entry)
843898Skais {
844898Skais 	uint_t index;
845898Skais 	uchar_t *s = sid->session_id;
846898Skais 	kmutex_t *lock;
847898Skais 
84810520SBhargava.Yenduri@Sun.COM 	ASSERT(sid->cached == B_FALSE);
849898Skais 
85010520SBhargava.Yenduri@Sun.COM 	/* set the values before creating the cache entry */
85110520SBhargava.Yenduri@Sun.COM 	sid->cached = B_TRUE;
85211066Srafael.vanoni@sun.com 	sid->time = ddi_get_lbolt();
853898Skais 
85410520SBhargava.Yenduri@Sun.COM 	SET_HASH_INDEX(index, s, &sid->client_addr);
855898Skais 	index %= kssl_entry->sid_cache_nentries;
856898Skais 
857898Skais 	lock = &(kssl_entry->sid_cache[index].se_lock);
858898Skais 	mutex_enter(lock);
859898Skais 	kssl_entry->sid_cache[index].se_used++;
860898Skais 	bcopy(sid, &(kssl_entry->sid_cache[index].se_sid), sizeof (*sid));
861898Skais 	mutex_exit(lock);
86210520SBhargava.Yenduri@Sun.COM 
86310520SBhargava.Yenduri@Sun.COM 	KSSL_COUNTER(sid_cached, 1);
864898Skais }
865898Skais 
86610520SBhargava.Yenduri@Sun.COM /*
86710520SBhargava.Yenduri@Sun.COM  * Invalidates the cache entry, if any. Clears the sid->cached flag
86810520SBhargava.Yenduri@Sun.COM  * as a side effect.
86910520SBhargava.Yenduri@Sun.COM  */
87010520SBhargava.Yenduri@Sun.COM void
kssl_uncache_sid(sslSessionID * sid,kssl_entry_t * kssl_entry)87110520SBhargava.Yenduri@Sun.COM kssl_uncache_sid(sslSessionID *sid, kssl_entry_t *kssl_entry)
872898Skais {
873898Skais 	uint_t index;
87410520SBhargava.Yenduri@Sun.COM 	uchar_t *s = sid->session_id;
875898Skais 	sslSessionID *csid;
87610520SBhargava.Yenduri@Sun.COM 	kmutex_t *lock;
877898Skais 
87810520SBhargava.Yenduri@Sun.COM 	ASSERT(sid->cached == B_TRUE);
87910520SBhargava.Yenduri@Sun.COM 	sid->cached = B_FALSE;
880898Skais 
88110520SBhargava.Yenduri@Sun.COM 	SET_HASH_INDEX(index, s, &sid->client_addr);
882898Skais 	index %= kssl_entry->sid_cache_nentries;
883898Skais 
884898Skais 	lock = &(kssl_entry->sid_cache[index].se_lock);
885898Skais 	mutex_enter(lock);
886898Skais 	csid = &(kssl_entry->sid_cache[index].se_sid);
88710520SBhargava.Yenduri@Sun.COM 	if (!(IN6_ARE_ADDR_EQUAL(&csid->client_addr, &sid->client_addr)) ||
88810520SBhargava.Yenduri@Sun.COM 	    bcmp(csid->session_id, s, SSL3_SESSIONID_BYTES)) {
88910520SBhargava.Yenduri@Sun.COM 		mutex_exit(lock);
89010520SBhargava.Yenduri@Sun.COM 		return;
89110520SBhargava.Yenduri@Sun.COM 	}
89210520SBhargava.Yenduri@Sun.COM 	csid->cached = B_FALSE;
89310520SBhargava.Yenduri@Sun.COM 	mutex_exit(lock);
89410520SBhargava.Yenduri@Sun.COM 
89510520SBhargava.Yenduri@Sun.COM 	KSSL_COUNTER(sid_uncached, 1);
89610520SBhargava.Yenduri@Sun.COM }
89710520SBhargava.Yenduri@Sun.COM 
89810520SBhargava.Yenduri@Sun.COM static void
kssl_lookup_sid(sslSessionID * sid,uchar_t * s,in6_addr_t * faddr,kssl_entry_t * kssl_entry)89910520SBhargava.Yenduri@Sun.COM kssl_lookup_sid(sslSessionID *sid, uchar_t *s, in6_addr_t *faddr,
90010520SBhargava.Yenduri@Sun.COM     kssl_entry_t *kssl_entry)
90110520SBhargava.Yenduri@Sun.COM {
90210520SBhargava.Yenduri@Sun.COM 	uint_t index;
90310520SBhargava.Yenduri@Sun.COM 	kmutex_t *lock;
90410520SBhargava.Yenduri@Sun.COM 	sslSessionID *csid;
90510520SBhargava.Yenduri@Sun.COM 
90610520SBhargava.Yenduri@Sun.COM 	KSSL_COUNTER(sid_cache_lookups, 1);
90710520SBhargava.Yenduri@Sun.COM 
90810520SBhargava.Yenduri@Sun.COM 	SET_HASH_INDEX(index, s, faddr);
90910520SBhargava.Yenduri@Sun.COM 	index %= kssl_entry->sid_cache_nentries;
91010520SBhargava.Yenduri@Sun.COM 
91110520SBhargava.Yenduri@Sun.COM 	lock = &(kssl_entry->sid_cache[index].se_lock);
91210520SBhargava.Yenduri@Sun.COM 	mutex_enter(lock);
91310520SBhargava.Yenduri@Sun.COM 	csid = &(kssl_entry->sid_cache[index].se_sid);
91410520SBhargava.Yenduri@Sun.COM 	if (csid->cached == B_FALSE ||
91510520SBhargava.Yenduri@Sun.COM 	    !IN6_ARE_ADDR_EQUAL(&csid->client_addr, faddr) ||
916898Skais 	    bcmp(csid->session_id, s, SSL3_SESSIONID_BYTES)) {
917898Skais 		mutex_exit(lock);
918898Skais 		return;
919898Skais 	}
920898Skais 
92111066Srafael.vanoni@sun.com 	if (TICK_TO_SEC(ddi_get_lbolt() - csid->time) >
92211066Srafael.vanoni@sun.com 	    kssl_entry->sid_cache_timeout) {
923898Skais 		csid->cached = B_FALSE;
924898Skais 		mutex_exit(lock);
925898Skais 		return;
926898Skais 	}
927898Skais 
928898Skais 	bcopy(csid, sid, sizeof (*sid));
929898Skais 	mutex_exit(lock);
930898Skais 	ASSERT(sid->cached == B_TRUE);
931898Skais 
932898Skais 	KSSL_COUNTER(sid_cache_hits, 1);
933898Skais }
934898Skais 
935898Skais static uchar_t *
kssl_rsa_unwrap(uchar_t * buf,size_t * lenp)936898Skais kssl_rsa_unwrap(uchar_t *buf, size_t *lenp)
937898Skais {
938898Skais 	size_t len = *lenp;
939898Skais 	int i = 2;
940898Skais 
941898Skais 	if (buf[0] != 0 || buf[1] != 2) {
942898Skais 		return (NULL);
943898Skais 	}
944898Skais 
945898Skais 	while (i < len) {
946898Skais 		if (buf[i++] == 0) {
947898Skais 			*lenp = len - i;
948898Skais 			break;
949898Skais 		}
950898Skais 	}
951898Skais 
952898Skais 	if (i == len) {
953898Skais 		return (NULL);
954898Skais 	}
955898Skais 
956898Skais 	return (buf + i);
957898Skais }
958898Skais 
959898Skais 
960898Skais #define	KSSL_SSL3_SH_RECLEN	(74)
961898Skais #define	KSSL_SSL3_FIN_MSGLEN	(36)
96212381SVladimir.Kotal@Sun.COM #define	KSSL_EMPTY_RENEG_INFO_LEN	(7)
963898Skais 
964898Skais #define	KSSL_SSL3_MAX_CCP_FIN_MSGLEN	(128)	/* comfortable upper bound */
965898Skais 
96612381SVladimir.Kotal@Sun.COM /*
96712381SVladimir.Kotal@Sun.COM  * Send ServerHello record to the client.
96812381SVladimir.Kotal@Sun.COM  */
969898Skais static int
kssl_send_server_hello(ssl_t * ssl)970898Skais kssl_send_server_hello(ssl_t *ssl)
971898Skais {
972898Skais 	mblk_t *mp;
973898Skais 	uchar_t *buf;
974898Skais 	uchar_t *msgstart;
97512381SVladimir.Kotal@Sun.COM 	uint16_t reclen = KSSL_SSL3_SH_RECLEN;
976898Skais 
977898Skais 	mp = allocb(ssl->tcp_mss, BPRI_HI);
978898Skais 	if (mp == NULL) {
979898Skais 		KSSL_COUNTER(alloc_fails, 1);
980898Skais 		return (ENOMEM);
981898Skais 	}
982898Skais 	ssl->handshake_sendbuf = mp;
983898Skais 	buf = mp->b_wptr;
984898Skais 
98512381SVladimir.Kotal@Sun.COM 	if (ssl->secure_renegotiation)
98612381SVladimir.Kotal@Sun.COM 		reclen += KSSL_EMPTY_RENEG_INFO_LEN;
98712381SVladimir.Kotal@Sun.COM 
988898Skais 	/* 5 byte record header */
989898Skais 	buf[0] = content_handshake;
990898Skais 	buf[1] = ssl->major_version;
991898Skais 	buf[2] = ssl->minor_version;
99212381SVladimir.Kotal@Sun.COM 	buf[3] = reclen >> 8;
99312381SVladimir.Kotal@Sun.COM 	buf[4] = reclen & 0xff;
994898Skais 	buf += SSL3_HDR_LEN;
995898Skais 
996898Skais 	msgstart = buf;
997898Skais 
998898Skais 	/* 6 byte message header */
999898Skais 	buf[0] = (uchar_t)server_hello;			/* message type */
1000898Skais 	buf[1] = 0;					/* message len byte 0 */
100112381SVladimir.Kotal@Sun.COM 	buf[2] = ((reclen - 4) >> 8) &
1002898Skais 	    0xff;					/* message len byte 1 */
100312381SVladimir.Kotal@Sun.COM 	buf[3] = (reclen - 4) & 0xff;	/* message len byte 2 */
1004898Skais 
1005898Skais 	buf[4] = ssl->major_version;	/* version byte 0 */
1006898Skais 	buf[5] = ssl->minor_version;	/* version byte 1 */
1007898Skais 
1008898Skais 	buf += 6;
1009898Skais 
1010898Skais 	kssl_get_hello_random(ssl->server_random);
1011898Skais 	bcopy(ssl->server_random, buf, SSL3_RANDOM_LENGTH);
1012898Skais 	buf += SSL3_RANDOM_LENGTH;
1013898Skais 
1014898Skais 	buf[0] = SSL3_SESSIONID_BYTES;
1015898Skais 	bcopy(ssl->sid.session_id, buf + 1, SSL3_SESSIONID_BYTES);
1016898Skais 	buf += SSL3_SESSIONID_BYTES + 1;
1017898Skais 
1018898Skais 	buf[0] = (ssl->pending_cipher_suite >> 8) & 0xff;
1019898Skais 	buf[1] = ssl->pending_cipher_suite & 0xff;
1020898Skais 
1021898Skais 	buf[2] = 0;	/* No compression */
102212381SVladimir.Kotal@Sun.COM 	buf += 3;
1023898Skais 
102412381SVladimir.Kotal@Sun.COM 	/*
102512381SVladimir.Kotal@Sun.COM 	 * Add "renegotiation_info" extension if the ClientHello message
102612381SVladimir.Kotal@Sun.COM 	 * contained either SCSV value in cipher suite list or
102712381SVladimir.Kotal@Sun.COM 	 * "renegotiation_info" extension. This is per RFC 5746, section 3.6.
102812381SVladimir.Kotal@Sun.COM 	 */
102912381SVladimir.Kotal@Sun.COM 	if (ssl->secure_renegotiation) {
103012381SVladimir.Kotal@Sun.COM 		/* Extensions length */
103112381SVladimir.Kotal@Sun.COM 		buf[0] = 0x00;
103212381SVladimir.Kotal@Sun.COM 		buf[1] = 0x05;
103312381SVladimir.Kotal@Sun.COM 		/* empty renegotiation_info extension encoding (section 3.2) */
103412381SVladimir.Kotal@Sun.COM 		buf[2] = 0xff;
103512381SVladimir.Kotal@Sun.COM 		buf[3] = 0x01;
103612381SVladimir.Kotal@Sun.COM 		buf[4] = 0x00;
103712381SVladimir.Kotal@Sun.COM 		buf[5] = 0x01;
103812381SVladimir.Kotal@Sun.COM 		buf[6] = 0x00;
103912381SVladimir.Kotal@Sun.COM 		buf += KSSL_EMPTY_RENEG_INFO_LEN;
104012381SVladimir.Kotal@Sun.COM 	}
104112381SVladimir.Kotal@Sun.COM 
104212381SVladimir.Kotal@Sun.COM 	mp->b_wptr = buf;
1043898Skais 	ASSERT(mp->b_wptr < mp->b_datap->db_lim);
1044898Skais 
104512381SVladimir.Kotal@Sun.COM 	kssl_update_handshake_hashes(ssl, msgstart, reclen);
1046898Skais 	return (0);
1047898Skais }
1048898Skais 
1049898Skais static void
kssl_get_hello_random(uchar_t * buf)1050898Skais kssl_get_hello_random(uchar_t *buf)
1051898Skais {
1052898Skais 	timestruc_t ts;
1053898Skais 	time_t sec;
1054898Skais 
1055898Skais 	gethrestime(&ts);
1056898Skais 	sec = ts.tv_sec;
1057898Skais 
1058898Skais 	buf[0] = (sec >> 24) & 0xff;
1059898Skais 	buf[1] = (sec >> 16) & 0xff;
1060898Skais 	buf[2] = (sec >> 8) & 0xff;
1061898Skais 	buf[3] = (sec) & 0xff;
1062898Skais 
1063898Skais 	(void) random_get_pseudo_bytes(&buf[4], SSL3_RANDOM_LENGTH - 4);
1064898Skais 
1065898Skais 	/* Should this be caching? */
1066898Skais }
1067898Skais 
1068898Skais static int
kssl_tls_P_hash(crypto_mechanism_t * mech,crypto_key_t * key,size_t hashlen,uchar_t * label,size_t label_len,uchar_t * seed,size_t seedlen,uchar_t * data,size_t datalen)1069898Skais kssl_tls_P_hash(crypto_mechanism_t *mech, crypto_key_t *key,
1070898Skais 	size_t hashlen,
1071898Skais 	uchar_t *label, size_t label_len,
1072898Skais 	uchar_t *seed, size_t seedlen,
1073898Skais 	uchar_t *data, size_t datalen)
1074898Skais {
1075898Skais 	int rv = 0;
1076898Skais 	uchar_t A1[MAX_HASH_LEN], result[MAX_HASH_LEN];
107712644SAnders.Persson@Sun.COM 	int bytes_left = (int)datalen;
1078898Skais 	crypto_data_t dd, mac;
1079898Skais 	crypto_context_t ctx;
1080898Skais 
1081898Skais 	dd.cd_format = CRYPTO_DATA_RAW;
1082898Skais 	dd.cd_offset = 0;
1083898Skais 	mac.cd_format = CRYPTO_DATA_RAW;
1084898Skais 	mac.cd_offset = 0;
1085898Skais 
1086898Skais 	/*
108710520SBhargava.Yenduri@Sun.COM 	 * A(i) = HMAC_hash(secret, seed + A(i-1));
1088898Skais 	 * A(0) = seed;
1089898Skais 	 *
1090898Skais 	 * Compute A(1):
1091898Skais 	 * A(1) = HMAC_hash(secret, label + seed)
1092898Skais 	 *
1093898Skais 	 */
1094898Skais 	HMAC_INIT(mech, key, &ctx);
1095898Skais 	HMAC_UPDATE(ctx, label, label_len);
1096898Skais 	HMAC_UPDATE(ctx, seed, seedlen);
1097898Skais 	HMAC_FINAL(ctx, A1, hashlen);
1098898Skais 
1099898Skais 	/* Compute A(2) ... A(n) */
1100898Skais 	while (bytes_left > 0) {
1101898Skais 		HMAC_INIT(mech, key, &ctx);
1102898Skais 		HMAC_UPDATE(ctx, A1, hashlen);
1103898Skais 		HMAC_UPDATE(ctx, label, label_len);
1104898Skais 		HMAC_UPDATE(ctx, seed, seedlen);
1105898Skais 		HMAC_FINAL(ctx, result, hashlen);
1106898Skais 
1107898Skais 		/*
1108898Skais 		 * The A(i) value is stored in "result".
1109898Skais 		 * Save the results of the MAC so it can be input to next
1110898Skais 		 * iteration.
1111898Skais 		 */
1112898Skais 		if (bytes_left > hashlen) {
1113898Skais 			/* Store the chunk result */
1114898Skais 			bcopy(result, data, hashlen);
1115898Skais 			data += hashlen;
1116898Skais 
1117898Skais 			bytes_left -= hashlen;
1118898Skais 
1119898Skais 			/* Update A1 for next iteration */
1120898Skais 			HMAC_INIT(mech, key, &ctx);
1121898Skais 			HMAC_UPDATE(ctx, A1, hashlen);
1122898Skais 			HMAC_FINAL(ctx, A1, hashlen);
1123898Skais 
1124898Skais 		} else {
1125898Skais 			bcopy(result, data, bytes_left);
1126898Skais 			data += bytes_left;
1127898Skais 			bytes_left = 0;
1128898Skais 		}
1129898Skais 	}
1130898Skais end:
1131898Skais 	if (CRYPTO_ERR(rv)) {
11325850Svk199839 		DTRACE_PROBE1(kssl_err__crypto_mac_error, int, rv);
1133898Skais 		KSSL_COUNTER(compute_mac_failure, 1);
1134898Skais 	}
1135898Skais 	return (rv);
1136898Skais }
1137898Skais 
1138898Skais /* ARGSUSED */
1139898Skais static int
kssl_tls_PRF(ssl_t * ssl,uchar_t * secret,size_t secret_len,uchar_t * label,size_t label_len,uchar_t * seed,size_t seed_len,uchar_t * prfresult,size_t prfresult_len)1140898Skais kssl_tls_PRF(ssl_t *ssl,
1141898Skais 	uchar_t *secret, size_t secret_len,
1142898Skais 	uchar_t *label, size_t label_len,
1143898Skais 	uchar_t *seed, size_t seed_len,
1144898Skais 	uchar_t *prfresult, size_t prfresult_len)
1145898Skais {
1146898Skais 	/*
1147898Skais 	 * RFC 2246:
1148898Skais 	 *  PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
1149898Skais 	 *				P_SHA1(S2, label + seed);
1150898Skais 	 * S1 = 1st half of secret.
1151898Skais 	 * S1 = 2nd half of secret.
1152898Skais 	 *
1153898Skais 	 */
1154898Skais 
115510520SBhargava.Yenduri@Sun.COM 	int rv, i;
11566788Skrishna 	uchar_t psha1[MAX_KEYBLOCK_LENGTH];
1157898Skais 	crypto_key_t S1, S2;
1158898Skais 
1159898Skais 	/* length of secret keys is ceil(length/2) */
1160898Skais 	size_t slen = roundup(secret_len, 2) / 2;
1161898Skais 
11626788Skrishna 	if (prfresult_len >  MAX_KEYBLOCK_LENGTH) {
11635850Svk199839 		DTRACE_PROBE1(kssl_err__unexpected_keyblock_size,
11645850Svk199839 		    size_t, prfresult_len);
1165898Skais 		return (CRYPTO_ARGUMENTS_BAD);
1166898Skais 	}
1167898Skais 
1168898Skais 	ASSERT(prfresult != NULL);
1169898Skais 	ASSERT(label != NULL);
1170898Skais 	ASSERT(seed != NULL);
1171898Skais 
1172898Skais 	S1.ck_data   = secret;
1173898Skais 	S1.ck_length = slen * 8; /* bits */
1174898Skais 	S1.ck_format = CRYPTO_KEY_RAW;
1175898Skais 
1176898Skais 	S2.ck_data   = secret + slen;
1177898Skais 	S2.ck_length = slen * 8; /* bits */
1178898Skais 	S2.ck_format = CRYPTO_KEY_RAW;
1179898Skais 
1180898Skais 	rv = kssl_tls_P_hash(&hmac_md5_mech, &S1, MD5_HASH_LEN,
11815850Svk199839 	    label, label_len,
11825850Svk199839 	    seed, seed_len,
11835850Svk199839 	    prfresult, prfresult_len);
1184898Skais 	if (CRYPTO_ERR(rv))
1185898Skais 		goto end;
1186898Skais 
1187898Skais 	rv = kssl_tls_P_hash(&hmac_sha1_mech, &S2, SHA1_HASH_LEN,
11885850Svk199839 	    label, label_len,
11895850Svk199839 	    seed, seed_len,
11905850Svk199839 	    psha1, prfresult_len);
1191898Skais 	if (CRYPTO_ERR(rv))
1192898Skais 		goto end;
1193898Skais 
1194898Skais 	for (i = 0; i < prfresult_len; i++)
1195898Skais 		prfresult[i] ^= psha1[i];
1196898Skais 
1197898Skais end:
1198898Skais 	if (CRYPTO_ERR(rv))
1199898Skais 		bzero(prfresult, prfresult_len);
1200898Skais 
1201898Skais 	return (rv);
1202898Skais }
1203898Skais 
12041724Skrishna #define	IS_BAD_PRE_MASTER_SECRET(pms, pmslen, ssl)			\
12051724Skrishna 	(pms == NULL || pmslen != SSL3_PRE_MASTER_SECRET_LEN ||		\
12061724Skrishna 	pms[0] != ssl->major_version || pms[1] != ssl->minor_version)
12071724Skrishna 
12081724Skrishna #define	FAKE_PRE_MASTER_SECRET(pms, pmslen, ssl, buf) {			\
12091724Skrishna 		KSSL_COUNTER(bad_pre_master_secret, 1);			\
12101724Skrishna 		pms = buf;						\
12111724Skrishna 		pmslen = SSL3_PRE_MASTER_SECRET_LEN;			\
12121724Skrishna 		pms[0] = ssl->major_version;				\
12131724Skrishna 		pms[1] = ssl->minor_version;				\
12141724Skrishna 		(void) random_get_pseudo_bytes(&buf[2], pmslen - 2);	\
12151724Skrishna }
12161724Skrishna 
1217898Skais static int
kssl_generate_tls_ms(ssl_t * ssl,uchar_t * pms,size_t pmslen)1218898Skais kssl_generate_tls_ms(ssl_t *ssl, uchar_t *pms, size_t pmslen)
1219898Skais {
12201724Skrishna 	uchar_t buf[SSL3_PRE_MASTER_SECRET_LEN];
1221898Skais 	uchar_t seed[SSL3_RANDOM_LENGTH * 2];
1222898Skais 
1223898Skais 	/*
1224898Skais 	 * Computing the master secret:
1225898Skais 	 * ----------------------------
1226898Skais 	 * master_secret = PRF (pms, "master secret",
1227898Skais 	 *		ClientHello.random + ServerHello.random);
1228898Skais 	 */
1229898Skais 	bcopy(ssl->client_random, seed, SSL3_RANDOM_LENGTH);
1230898Skais 	bcopy(ssl->server_random, seed + SSL3_RANDOM_LENGTH,
12315850Svk199839 	    SSL3_RANDOM_LENGTH);
1232898Skais 
12331724Skrishna 	/* if pms is bad fake it to thwart Bleichenbacher attack */
12341724Skrishna 	if (IS_BAD_PRE_MASTER_SECRET(pms, pmslen, ssl)) {
12355850Svk199839 		DTRACE_PROBE(kssl_err__under_Bleichenbacher_attack);
12361724Skrishna 		FAKE_PRE_MASTER_SECRET(pms, pmslen, ssl, buf);
12371724Skrishna 	}
12381724Skrishna 
1239898Skais 	return (kssl_tls_PRF(ssl,
12405850Svk199839 	    pms, pmslen,
12415850Svk199839 	    (uchar_t *)TLS_MASTER_SECRET_LABEL,
12425850Svk199839 	    (size_t)strlen(TLS_MASTER_SECRET_LABEL),
12435850Svk199839 	    seed, sizeof (seed),
12445850Svk199839 	    ssl->sid.master_secret,
12455850Svk199839 	    (size_t)sizeof (ssl->sid.master_secret)));
1246898Skais }
1247898Skais 
12481724Skrishna 
1249898Skais static void
kssl_generate_ssl_ms(ssl_t * ssl,uchar_t * pms,size_t pmslen)1250898Skais kssl_generate_ssl_ms(ssl_t *ssl, uchar_t *pms, size_t pmslen)
1251898Skais {
1252898Skais 	uchar_t buf[SSL3_PRE_MASTER_SECRET_LEN];
1253898Skais 	uchar_t *ms;
1254898Skais 	int hlen = MD5_HASH_LEN;
1255898Skais 
1256898Skais 	ms = ssl->sid.master_secret;
1257898Skais 
1258898Skais 	/* if pms is bad fake it to thwart Bleichenbacher attack */
12591724Skrishna 	if (IS_BAD_PRE_MASTER_SECRET(pms, pmslen, ssl)) {
12605850Svk199839 		DTRACE_PROBE(kssl_err__under_Bleichenbacher_attack);
12611724Skrishna 		FAKE_PRE_MASTER_SECRET(pms, pmslen, ssl, buf);
1262898Skais 	}
12631724Skrishna 
1264898Skais 	kssl_ssl3_key_material_derive_step(ssl, pms, pmslen, 1, ms, 0);
1265898Skais 	kssl_ssl3_key_material_derive_step(ssl, pms, pmslen, 2, ms + hlen, 0);
1266898Skais 	kssl_ssl3_key_material_derive_step(ssl, pms, pmslen, 3, ms + 2 * hlen,
1267898Skais 	    0);
1268898Skais }
1269898Skais 
1270898Skais static int
kssl_generate_tls_keyblock(ssl_t * ssl)1271898Skais kssl_generate_tls_keyblock(ssl_t *ssl)
1272898Skais {
1273898Skais 	uchar_t seed[2 * SSL3_RANDOM_LENGTH];
1274898Skais 
1275898Skais 	bcopy(ssl->server_random, seed, SSL3_RANDOM_LENGTH);
1276898Skais 	bcopy(ssl->client_random, seed + SSL3_RANDOM_LENGTH,
12775850Svk199839 	    SSL3_RANDOM_LENGTH);
1278898Skais 
1279898Skais 	return (kssl_tls_PRF(ssl, ssl->sid.master_secret,
12805850Svk199839 	    (size_t)SSL3_MASTER_SECRET_LEN,
12815850Svk199839 	    (uchar_t *)TLS_KEY_EXPANSION_LABEL,
12825850Svk199839 	    (size_t)strlen(TLS_KEY_EXPANSION_LABEL),
12835850Svk199839 	    seed, (size_t)sizeof (seed),
12845850Svk199839 	    ssl->pending_keyblock,
12855850Svk199839 	    (size_t)ssl->pending_keyblksz));
1286898Skais 
1287898Skais }
1288898Skais 
1289898Skais static void
kssl_generate_keyblock(ssl_t * ssl)1290898Skais kssl_generate_keyblock(ssl_t *ssl)
1291898Skais {
1292898Skais 	uchar_t *ms;
1293898Skais 	size_t mslen = SSL3_MASTER_SECRET_LEN;
1294898Skais 	int hlen = MD5_HASH_LEN;
1295898Skais 	uchar_t *keys = ssl->pending_keyblock;
1296898Skais 	int steps = howmany(ssl->pending_keyblksz, hlen);
1297898Skais 	int i;
1298898Skais 
1299898Skais 	ms = ssl->sid.master_secret;
1300898Skais 
1301898Skais 	ASSERT(hlen * steps <= MAX_KEYBLOCK_LENGTH);
1302898Skais 
1303898Skais 	for (i = 1; i <= steps; i++) {
1304898Skais 		kssl_ssl3_key_material_derive_step(ssl, ms, mslen, i, keys, 1);
1305898Skais 		keys += hlen;
1306898Skais 	}
1307898Skais }
1308898Skais 
13096788Skrishna static char *ssl3_key_derive_seeds[9] = {"A", "BB", "CCC", "DDDD", "EEEEE",
13106788Skrishna 	"FFFFFF", "GGGGGGG", "HHHHHHHH", "IIIIIIIII"};
1311898Skais 
1312898Skais static void
kssl_ssl3_key_material_derive_step(ssl_t * ssl,uchar_t * secret,size_t secretlen,int step,uchar_t * dst,int sr_first)1313898Skais kssl_ssl3_key_material_derive_step(
1314898Skais 	ssl_t *ssl,
1315898Skais 	uchar_t *secret,
1316898Skais 	size_t secretlen,
1317898Skais 	int step,
1318898Skais 	uchar_t *dst,
1319898Skais 	int sr_first)
1320898Skais {
1321898Skais 	SHA1_CTX sha1, *sha1ctx;
1322898Skais 	MD5_CTX md5, *md5ctx;
1323898Skais 	uchar_t sha1_hash[SHA1_HASH_LEN];
1324898Skais 
1325898Skais 	sha1ctx = &sha1;
1326898Skais 	md5ctx = &md5;
1327898Skais 
1328898Skais 	ASSERT(step <=
1329898Skais 	    sizeof (ssl3_key_derive_seeds) /
1330898Skais 	    sizeof (ssl3_key_derive_seeds[0]));
1331898Skais 	step--;
1332898Skais 
1333898Skais 	SHA1Init(sha1ctx);
1334898Skais 	SHA1Update(sha1ctx, (uchar_t *)ssl3_key_derive_seeds[step],
1335898Skais 	    step + 1);
1336898Skais 	SHA1Update(sha1ctx, secret, secretlen);
1337898Skais 	if (sr_first) {
1338898Skais 		SHA1Update(sha1ctx, ssl->server_random, SSL3_RANDOM_LENGTH);
1339898Skais 		SHA1Update(sha1ctx, ssl->client_random, SSL3_RANDOM_LENGTH);
1340898Skais 	} else {
1341898Skais 		SHA1Update(sha1ctx, ssl->client_random, SSL3_RANDOM_LENGTH);
1342898Skais 		SHA1Update(sha1ctx, ssl->server_random, SSL3_RANDOM_LENGTH);
1343898Skais 	}
1344898Skais 	SHA1Final(sha1_hash, sha1ctx);
1345898Skais 
1346898Skais 	MD5Init(md5ctx);
1347898Skais 	MD5Update(md5ctx, secret, secretlen);
1348898Skais 	MD5Update(md5ctx, sha1_hash, SHA1_HASH_LEN);
1349898Skais 	MD5Final(dst, md5ctx);
1350898Skais }
1351898Skais 
1352898Skais static int
kssl_send_certificate_and_server_hello_done(ssl_t * ssl)1353898Skais kssl_send_certificate_and_server_hello_done(ssl_t *ssl)
1354898Skais {
1355898Skais 	int cur_reclen;
1356898Skais 	int mss;
1357898Skais 	int len, copylen;
1358898Skais 	mblk_t *mp;
1359898Skais 	uchar_t *cert_buf;
1360898Skais 	int cert_len;
1361898Skais 	uchar_t *msgbuf;
1362898Skais 	Certificate_t *cert;
136312381SVladimir.Kotal@Sun.COM 	uint16_t reclen = KSSL_SSL3_SH_RECLEN;
1364898Skais 
1365898Skais 	cert = ssl->kssl_entry->ke_server_certificate;
1366898Skais 	if (cert == NULL) {
13675850Svk199839 		return (ENOENT);
1368898Skais 	}
1369898Skais 	cert_buf = cert->msg;
1370898Skais 	cert_len = cert->len;
1371898Skais 
137212381SVladimir.Kotal@Sun.COM 	if (ssl->secure_renegotiation)
137312381SVladimir.Kotal@Sun.COM 		reclen += KSSL_EMPTY_RENEG_INFO_LEN;
137412381SVladimir.Kotal@Sun.COM 
1375898Skais 	mp = ssl->handshake_sendbuf;
1376898Skais 	mss = ssl->tcp_mss;
1377898Skais 	ASSERT(mp != NULL);
1378898Skais 	cur_reclen = mp->b_wptr - mp->b_rptr - SSL3_HDR_LEN;
137912381SVladimir.Kotal@Sun.COM 	ASSERT(cur_reclen == reclen);
1380898Skais 	/* Assume MSS is at least 80 bytes */
1381898Skais 	ASSERT(mss > cur_reclen + SSL3_HDR_LEN);
1382898Skais 	ASSERT(cur_reclen < SSL3_MAX_RECORD_LENGTH); /* XXX */
1383898Skais 
1384898Skais 	copylen = mss - (cur_reclen + SSL3_HDR_LEN);
1385898Skais 	len = cert_len;
1386898Skais 	copylen = MIN(copylen, len);
1387898Skais 	copylen = MIN(copylen, SSL3_MAX_RECORD_LENGTH - cur_reclen);
1388898Skais 
1389898Skais 	/* new record always starts in a new mblk for simplicity */
1390898Skais 	msgbuf = cert_buf;
1391898Skais 	for (;;) {
1392898Skais 		ASSERT(mp->b_wptr + copylen <= mp->b_datap->db_lim);
1393898Skais 		bcopy(msgbuf, mp->b_wptr, copylen);
1394898Skais 		msgbuf += copylen;
1395898Skais 		mp->b_wptr += copylen;
1396898Skais 		cur_reclen += copylen;
1397898Skais 		len -= copylen;
1398898Skais 		if (len == 0) {
1399898Skais 			break;
1400898Skais 		}
1401898Skais 		if (cur_reclen == SSL3_MAX_RECORD_LENGTH) {
1402898Skais 			cur_reclen = 0;
1403898Skais 		}
1404898Skais 		copylen = MIN(len, mss);
1405898Skais 		copylen = MIN(copylen, SSL3_MAX_RECORD_LENGTH - cur_reclen);
1406898Skais 		mp->b_cont = allocb(copylen, BPRI_HI);
1407898Skais 		if (mp->b_cont == NULL) {
1408898Skais 			KSSL_COUNTER(alloc_fails, 1);
1409898Skais 			freemsg(ssl->handshake_sendbuf);
1410898Skais 			ssl->handshake_sendbuf = NULL;
1411898Skais 			return (ENOMEM);
1412898Skais 		}
1413898Skais 		mp = mp->b_cont;
1414898Skais 		if (cur_reclen == 0) {
1415898Skais 			mp->b_wptr[0] = content_handshake;
1416898Skais 			mp->b_wptr[1] = ssl->major_version;
1417898Skais 			mp->b_wptr[2] = ssl->minor_version;
141812381SVladimir.Kotal@Sun.COM 			cur_reclen = MIN(len, reclen);
1419898Skais 			mp->b_wptr[3] = (cur_reclen >> 8) & 0xff;
1420898Skais 			mp->b_wptr[4] = (cur_reclen) & 0xff;
1421898Skais 			mp->b_wptr += SSL3_HDR_LEN;
1422898Skais 			cur_reclen = 0;
1423898Skais 			copylen = MIN(copylen, mss - SSL3_HDR_LEN);
1424898Skais 		}
1425898Skais 	}
1426898Skais 
1427898Skais 	/* adjust the record length field for the first record */
1428898Skais 	mp = ssl->handshake_sendbuf;
142912381SVladimir.Kotal@Sun.COM 	cur_reclen = MIN(reclen + cert_len, SSL3_MAX_RECORD_LENGTH);
1430898Skais 	mp->b_rptr[3] = (cur_reclen >> 8) & 0xff;
1431898Skais 	mp->b_rptr[4] = (cur_reclen) & 0xff;
1432898Skais 
1433898Skais 	kssl_update_handshake_hashes(ssl, cert_buf, cert_len);
1434898Skais 
1435898Skais 	return (0);
1436898Skais }
1437898Skais 
1438898Skais static int
kssl_send_change_cipher_specs(ssl_t * ssl)1439898Skais kssl_send_change_cipher_specs(ssl_t *ssl)
1440898Skais {
1441898Skais 	mblk_t *mp, *newmp;
1442898Skais 	uchar_t *buf;
1443898Skais 
1444898Skais 	mp = ssl->handshake_sendbuf;
1445898Skais 
1446898Skais 	/* We're most likely to hit the fast path for resumed sessions */
1447898Skais 	if ((mp != NULL) &&
1448898Skais 	    (mp->b_datap->db_lim - mp->b_wptr > KSSL_SSL3_MAX_CCP_FIN_MSGLEN)) {
1449898Skais 		buf = mp->b_wptr;
1450898Skais 	} else {
1451898Skais 		newmp = allocb(KSSL_SSL3_MAX_CCP_FIN_MSGLEN, BPRI_HI);
1452898Skais 
1453898Skais 		if (newmp == NULL)
1454898Skais 			return (ENOMEM);	/* need to do better job! */
1455898Skais 
1456898Skais 		if (mp == NULL) {
1457898Skais 			ssl->handshake_sendbuf = newmp;
1458898Skais 		} else {
1459898Skais 			linkb(ssl->handshake_sendbuf, newmp);
1460898Skais 		}
1461898Skais 		mp = newmp;
1462898Skais 		buf = mp->b_rptr;
1463898Skais 	}
1464898Skais 
1465898Skais 	/* 5 byte record header */
1466898Skais 	buf[0] = content_change_cipher_spec;
1467898Skais 	buf[1] = ssl->major_version;
1468898Skais 	buf[2] = ssl->minor_version;
1469898Skais 	buf[3] = 0;
1470898Skais 	buf[4] = 1;
1471898Skais 	buf += SSL3_HDR_LEN;
1472898Skais 
1473898Skais 	buf[0] = 1;
1474898Skais 
1475898Skais 	mp->b_wptr = buf + 1;
1476898Skais 	ASSERT(mp->b_wptr < mp->b_datap->db_lim);
1477898Skais 
1478898Skais 	ssl->seq_num[KSSL_WRITE] = 0;
1479898Skais 	return (kssl_spec_init(ssl, KSSL_WRITE));
1480898Skais }
1481898Skais 
1482898Skais int
kssl_spec_init(ssl_t * ssl,int dir)1483898Skais kssl_spec_init(ssl_t *ssl, int dir)
1484898Skais {
1485898Skais 	KSSL_HASHCTX *ctx;
1486898Skais 	KSSLCipherSpec *spec = &ssl->spec[dir];
1487898Skais 	int ret = 0;
1488898Skais 
1489898Skais 	spec->mac_hashsz = mac_defs[ssl->pending_malg].hashsz;
1490898Skais 	spec->mac_padsz = mac_defs[ssl->pending_malg].padsz;
1491898Skais 
1492898Skais 	spec->MAC_HashInit = mac_defs[ssl->pending_malg].HashInit;
1493898Skais 	spec->MAC_HashUpdate = mac_defs[ssl->pending_malg].HashUpdate;
1494898Skais 	spec->MAC_HashFinal = mac_defs[ssl->pending_malg].HashFinal;
1495898Skais 
1496898Skais 	if (dir == KSSL_READ) {
1497898Skais 		bcopy(ssl->pending_keyblock, ssl->mac_secret[dir],
1498898Skais 		    spec->mac_hashsz);
1499898Skais 	} else {
1500898Skais 		bcopy(&(ssl->pending_keyblock[spec->mac_hashsz]),
1501898Skais 		    ssl->mac_secret[dir], spec->mac_hashsz);
1502898Skais 	}
1503898Skais 
1504898Skais 	/* Pre-compute these here. will save cycles on each record later */
1505898Skais 	if (!IS_TLS(ssl)) {
1506898Skais 		ctx = &ssl->mac_ctx[dir][0];
1507898Skais 		spec->MAC_HashInit((void *)ctx);
1508898Skais 		spec->MAC_HashUpdate((void *)ctx, ssl->mac_secret[dir],
1509898Skais 		    spec->mac_hashsz);
1510898Skais 		spec->MAC_HashUpdate((void *)ctx, kssl_pad_1,
15115850Svk199839 		    spec->mac_padsz);
1512898Skais 
1513898Skais 		ctx = &ssl->mac_ctx[dir][1];
1514898Skais 		spec->MAC_HashInit((void *)ctx);
1515898Skais 		spec->MAC_HashUpdate((void *)ctx, ssl->mac_secret[dir],
1516898Skais 		    spec->mac_hashsz);
1517898Skais 		spec->MAC_HashUpdate((void *)ctx, kssl_pad_2,
15185850Svk199839 		    spec->mac_padsz);
1519898Skais 	}
1520898Skais 
1521898Skais 	spec->cipher_type = cipher_defs[ssl->pending_calg].type;
1522898Skais 	spec->cipher_mech.cm_type = cipher_defs[ssl->pending_calg].mech_type;
1523898Skais 	spec->cipher_bsize = cipher_defs[ssl->pending_calg].bsize;
1524898Skais 	spec->cipher_keysz = cipher_defs[ssl->pending_calg].keysz;
1525898Skais 
1526898Skais 	if (spec->cipher_ctx != NULL) {
1527898Skais 		crypto_cancel_ctx(spec->cipher_ctx);
1528898Skais 		spec->cipher_ctx = 0;
1529898Skais 	}
1530898Skais 
1531898Skais 	/*
15324859Skrishna 	 * Initialize HMAC keys for TLS and SSL3 HMAC keys
15334859Skrishna 	 * for SSL 3.0.
1534898Skais 	 */
1535898Skais 	if (IS_TLS(ssl)) {
1536898Skais 		if (ssl->pending_malg == mac_md5) {
1537898Skais 			spec->hmac_mech = hmac_md5_mech;
1538898Skais 		} else if (ssl->pending_malg == mac_sha) {
1539898Skais 			spec->hmac_mech = hmac_sha1_mech;
1540898Skais 		}
1541898Skais 
1542898Skais 		spec->hmac_key.ck_format = CRYPTO_KEY_RAW;
1543898Skais 		spec->hmac_key.ck_data = ssl->mac_secret[dir];
1544898Skais 		spec->hmac_key.ck_length = spec->mac_hashsz * 8;
15454859Skrishna 	} else {
15464859Skrishna 		static uint32_t param;
15474859Skrishna 
15484859Skrishna 		spec->hmac_mech.cm_type = CRYPTO_MECH_INVALID;
15494859Skrishna 		spec->hmac_mech.cm_param = (caddr_t)&param;
15504859Skrishna 		spec->hmac_mech.cm_param_len = sizeof (param);
15514859Skrishna 		if (ssl->pending_malg == mac_md5) {
15524859Skrishna 			spec->hmac_mech.cm_type =
15534859Skrishna 			    crypto_mech2id("CKM_SSL3_MD5_MAC");
15544859Skrishna 			param = MD5_HASH_LEN;
15554859Skrishna 		} else if (ssl->pending_malg == mac_sha) {
15564859Skrishna 			spec->hmac_mech.cm_type =
15574859Skrishna 			    crypto_mech2id("CKM_SSL3_SHA1_MAC");
15584859Skrishna 			param = SHA1_HASH_LEN;
15594859Skrishna 		}
15604859Skrishna 
15614859Skrishna 		spec->hmac_key.ck_format = CRYPTO_KEY_RAW;
15624859Skrishna 		spec->hmac_key.ck_data = ssl->mac_secret[dir];
15634859Skrishna 		spec->hmac_key.ck_length = spec->mac_hashsz * 8;
1564898Skais 	}
1565898Skais 
1566898Skais 	/* We're done if this is the nil cipher */
1567898Skais 	if (spec->cipher_keysz == 0) {
1568898Skais 		return (0);
1569898Skais 	}
1570898Skais 
1571898Skais 	/* Initialize the key and the active context */
1572898Skais 	spec->cipher_key.ck_format = CRYPTO_KEY_RAW;
1573898Skais 	spec->cipher_key.ck_length = 8 * spec->cipher_keysz; /* in bits */
1574898Skais 
1575898Skais 	if (cipher_defs[ssl->pending_calg].bsize > 0) {
1576898Skais 		/* client_write_IV */
1577898Skais 		spec->cipher_mech.cm_param =
1578898Skais 		    (caddr_t)&(ssl->pending_keyblock[2 * spec->mac_hashsz +
1579898Skais 		    2 * spec->cipher_keysz]);
1580898Skais 		spec->cipher_mech.cm_param_len = spec->cipher_bsize;
1581898Skais 	}
1582898Skais 	spec->cipher_data.cd_format = CRYPTO_DATA_RAW;
1583898Skais 	if (dir == KSSL_READ) {
1584898Skais 		spec->cipher_mech.cm_param_len =
1585898Skais 		    cipher_defs[ssl->pending_calg].bsize;
1586898Skais 
15872800Skrishna 		/* client_write_key */
1588898Skais 		spec->cipher_key.ck_data =
1589898Skais 		    &(ssl->pending_keyblock[2 * spec->mac_hashsz]);
1590898Skais 
1591898Skais 		ret = crypto_decrypt_init(&(spec->cipher_mech),
15925850Svk199839 		    &(spec->cipher_key), NULL, &spec->cipher_ctx, NULL);
1593898Skais 		if (CRYPTO_ERR(ret)) {
15945850Svk199839 			DTRACE_PROBE1(kssl_err__crypto_decrypt_init_read,
15955850Svk199839 			    int, ret);
1596898Skais 		}
1597898Skais 	} else {
1598898Skais 		if (cipher_defs[ssl->pending_calg].bsize > 0) {
159910118SBhargava.Yenduri@Sun.COM 			/* server_write_IV */
1600898Skais 			spec->cipher_mech.cm_param += spec->cipher_bsize;
1601898Skais 		}
160210118SBhargava.Yenduri@Sun.COM 
1603898Skais 		/* server_write_key */
1604898Skais 		spec->cipher_key.ck_data =
1605898Skais 		    &(ssl->pending_keyblock[2 * spec->mac_hashsz +
1606898Skais 		    spec->cipher_keysz]);
1607898Skais 
1608898Skais 		ret = crypto_encrypt_init(&(spec->cipher_mech),
16095850Svk199839 		    &(spec->cipher_key), NULL, &spec->cipher_ctx, NULL);
1610898Skais 		if (CRYPTO_ERR(ret))
16115850Svk199839 			DTRACE_PROBE1(kssl_err__crypto_encrypt_init_non_read,
16125850Svk199839 			    int, ret);
1613898Skais 	}
1614898Skais 	return (ret);
1615898Skais }
1616898Skais 
1617898Skais static int
kssl_send_finished(ssl_t * ssl,int update_hsh)1618898Skais kssl_send_finished(ssl_t *ssl, int update_hsh)
1619898Skais {
1620898Skais 	mblk_t *mp;
1621898Skais 	uchar_t *buf;
1622898Skais 	uchar_t *rstart;
1623898Skais 	uchar_t *versionp;
1624898Skais 	SSL3Hashes ssl3hashes;
162512644SAnders.Persson@Sun.COM 	uchar_t finish_len;
162610520SBhargava.Yenduri@Sun.COM 	int ret;
162712381SVladimir.Kotal@Sun.COM 	uint16_t adj_len = 0;
1628898Skais 
1629898Skais 	mp = ssl->handshake_sendbuf;
1630898Skais 	ASSERT(mp != NULL);
1631898Skais 	buf = mp->b_wptr;
163212381SVladimir.Kotal@Sun.COM 	if (ssl->secure_renegotiation)
163312381SVladimir.Kotal@Sun.COM 		adj_len = KSSL_EMPTY_RENEG_INFO_LEN;
163412381SVladimir.Kotal@Sun.COM 	/*
163512381SVladimir.Kotal@Sun.COM 	 * It should be either a message with Server Hello record or just plain
163612381SVladimir.Kotal@Sun.COM 	 * SSL header (data packet).
163712381SVladimir.Kotal@Sun.COM 	 */
163812381SVladimir.Kotal@Sun.COM 	ASSERT(buf - mp->b_rptr ==
163912381SVladimir.Kotal@Sun.COM 	    SSL3_HDR_LEN + KSSL_SSL3_SH_RECLEN + SSL3_HDR_LEN + 1 + adj_len ||
164012381SVladimir.Kotal@Sun.COM 	    buf - mp->b_rptr == SSL3_HDR_LEN + 1);
1641898Skais 
1642898Skais 	rstart = buf;
1643898Skais 
1644898Skais 	if (IS_TLS(ssl))
1645898Skais 		finish_len = TLS_FINISHED_SIZE;
1646898Skais 	else
1647898Skais 		finish_len = KSSL_SSL3_FIN_MSGLEN;
1648898Skais 
1649898Skais 	/* 5 byte record header */
1650898Skais 	buf[0] = content_handshake;
1651898Skais 	buf[1] = ssl->major_version;
1652898Skais 	buf[2] = ssl->minor_version;
1653898Skais 	buf[3] = 0;
1654898Skais 	buf[4] = 4 + finish_len;
1655898Skais 
1656898Skais 	versionp = &buf[1];
1657898Skais 
1658898Skais 	buf += SSL3_HDR_LEN;
1659898Skais 
1660898Skais 	/* 4 byte message header */
1661898Skais 	buf[0] = (uchar_t)finished;	/* message type */
1662898Skais 	buf[1] = 0;			/* message len byte 0 */
1663898Skais 	buf[2] = 0;			/* message len byte 1 */
1664898Skais 	buf[3] = finish_len;	/* message len byte 2 */
1665898Skais 	buf += 4;
1666898Skais 
1667898Skais 	if (IS_TLS(ssl)) {
1668898Skais 		bcopy(ssl->hs_hashes.md5, ssl3hashes.md5,
16695850Svk199839 		    sizeof (ssl3hashes.md5));
1670898Skais 		bcopy(ssl->hs_hashes.sha1, ssl3hashes.sha1,
16715850Svk199839 		    sizeof (ssl3hashes.sha1));
1672898Skais 	}
1673898Skais 
1674898Skais 	/* Compute hashes for the SENDER side */
1675898Skais 	ret = kssl_compute_handshake_hashes(ssl, &ssl3hashes, sender_server);
1676898Skais 	if (ret != 0)
1677898Skais 		return (ret);
1678898Skais 
1679898Skais 	if (IS_TLS(ssl)) {
1680898Skais 		bcopy(ssl3hashes.tlshash, buf, sizeof (ssl3hashes.tlshash));
1681898Skais 	} else {
1682898Skais 		bcopy(ssl3hashes.md5, buf, MD5_HASH_LEN);
1683898Skais 		bcopy(ssl3hashes.sha1, buf + MD5_HASH_LEN, SHA1_HASH_LEN);
1684898Skais 	}
1685898Skais 
1686898Skais 	if (update_hsh) {
1687898Skais 		kssl_update_handshake_hashes(ssl, buf - 4, finish_len + 4);
1688898Skais 	}
1689898Skais 
1690898Skais 	mp->b_wptr = buf + finish_len;
1691898Skais 
1692898Skais 	ret = kssl_mac_encrypt_record(ssl, content_handshake, versionp,
1693898Skais 	    rstart, mp);
1694898Skais 	ASSERT(mp->b_wptr <= mp->b_datap->db_lim);
1695898Skais 
1696898Skais 	return (ret);
1697898Skais }
1698898Skais 
1699898Skais int
kssl_mac_encrypt_record(ssl_t * ssl,SSL3ContentType ct,uchar_t * versionp,uchar_t * rstart,mblk_t * mp)1700898Skais kssl_mac_encrypt_record(ssl_t *ssl,
1701898Skais 	SSL3ContentType ct,
1702898Skais 	uchar_t *versionp,
1703898Skais 	uchar_t *rstart,
1704898Skais 	mblk_t *mp)
1705898Skais {
1706898Skais 	KSSLCipherSpec *spec;
1707898Skais 	int mac_sz;
1708898Skais 	int ret = 0;
1709898Skais 	uint16_t rec_sz;
1710898Skais 	int pad_sz;
1711898Skais 	int i;
1712898Skais 
1713898Skais 	ASSERT(ssl != NULL);
1714898Skais 	ASSERT(rstart >= mp->b_rptr);
1715898Skais 	ASSERT(rstart < mp->b_wptr);
1716898Skais 
1717898Skais 	spec = &ssl->spec[KSSL_WRITE];
1718898Skais 	mac_sz = spec->mac_hashsz;
1719898Skais 
1720898Skais 	rec_sz = (mp->b_wptr - rstart) - SSL3_HDR_LEN;
1721898Skais 	ASSERT(rec_sz > 0);
1722898Skais 
1723898Skais 	if (mac_sz != 0) {
1724898Skais 		ASSERT(mp->b_wptr + mac_sz <= mp->b_datap->db_lim);
1725898Skais 		ret = kssl_compute_record_mac(ssl, KSSL_WRITE,
1726898Skais 		    ssl->seq_num[KSSL_WRITE], ct, versionp,
1727898Skais 		    rstart + SSL3_HDR_LEN, rec_sz, mp->b_wptr);
1728898Skais 		if (ret == CRYPTO_SUCCESS) {
1729898Skais 			ssl->seq_num[KSSL_WRITE]++;
1730898Skais 			mp->b_wptr += mac_sz;
1731898Skais 			rec_sz += mac_sz;
1732898Skais 		} else {
1733898Skais 			return (ret);
1734898Skais 		}
1735898Skais 	}
1736898Skais 
1737898Skais 	if (spec->cipher_type == type_block) {
1738898Skais 		pad_sz = spec->cipher_bsize -
1739898Skais 		    (rec_sz & (spec->cipher_bsize - 1));
1740898Skais 		ASSERT(mp->b_wptr + pad_sz <= mp->b_datap->db_lim);
1741898Skais 		for (i = 0; i < pad_sz; i++) {
1742898Skais 			mp->b_wptr[i] = pad_sz - 1;
1743898Skais 		}
1744898Skais 		mp->b_wptr += pad_sz;
1745898Skais 		rec_sz += pad_sz;
1746898Skais 	}
1747898Skais 
1748898Skais 	ASSERT(rec_sz <= SSL3_MAX_RECORD_LENGTH);
1749898Skais 
1750898Skais 	U16_TO_BE16(rec_sz, rstart + 3);
1751898Skais 
1752898Skais 	if (spec->cipher_ctx == 0)
1753898Skais 		return (ret);
1754898Skais 
1755898Skais 	spec->cipher_data.cd_length = rec_sz;
1756898Skais 	spec->cipher_data.cd_raw.iov_base = (char *)(rstart + SSL3_HDR_LEN);
1757898Skais 	spec->cipher_data.cd_raw.iov_len = rec_sz;
1758898Skais 	/* One record at a time. Otherwise, gotta allocate the crypt_data_t */
1759898Skais 	ret = crypto_encrypt_update(spec->cipher_ctx, &spec->cipher_data,
1760898Skais 	    NULL, NULL);
1761898Skais 	if (CRYPTO_ERR(ret)) {
17625850Svk199839 		DTRACE_PROBE1(kssl_err__crypto_encrypt_update,
17635850Svk199839 		    int, ret);
1764898Skais 	}
1765898Skais 	return (ret);
1766898Skais }
1767898Skais 
176812623SVladimir.Kotal@Sun.COM /*
176912623SVladimir.Kotal@Sun.COM  * Produce SSL alert message (SSLv3/TLS) or error message (SSLv2). For SSLv2
177012623SVladimir.Kotal@Sun.COM  * it is only done to tear down the SSL connection so it has fixed encoding.
177112623SVladimir.Kotal@Sun.COM  */
1772898Skais void
kssl_send_alert(ssl_t * ssl,SSL3AlertLevel level,SSL3AlertDescription desc)1773898Skais kssl_send_alert(ssl_t *ssl, SSL3AlertLevel level, SSL3AlertDescription desc)
1774898Skais {
1775898Skais 	mblk_t *mp;
1776898Skais 	uchar_t *buf;
1777898Skais 	KSSLCipherSpec *spec;
177812623SVladimir.Kotal@Sun.COM 	size_t len;
1779898Skais 
1780898Skais 	ASSERT(ssl != NULL);
1781898Skais 
1782898Skais 	ssl->sendalert_level = level;
1783898Skais 	ssl->sendalert_desc = desc;
1784898Skais 
1785898Skais 	if (level == alert_fatal) {
17865850Svk199839 		DTRACE_PROBE2(kssl_sending_alert,
17875850Svk199839 		    SSL3AlertLevel, level, SSL3AlertDescription, desc);
1788898Skais 		if (ssl->sid.cached == B_TRUE) {
1789898Skais 			kssl_uncache_sid(&ssl->sid, ssl->kssl_entry);
1790898Skais 		}
1791898Skais 		ssl->fatal_alert = B_TRUE;
1792898Skais 		KSSL_COUNTER(fatal_alerts, 1);
1793898Skais 	} else
1794898Skais 		KSSL_COUNTER(warning_alerts, 1);
1795898Skais 
1796898Skais 	spec = &ssl->spec[KSSL_WRITE];
1797898Skais 
1798898Skais 	ASSERT(ssl->alert_sendbuf == NULL);
1799*12696SVladimir.Kotal@Sun.COM 	if (ssl->major_version == 0x03) {
1800*12696SVladimir.Kotal@Sun.COM 		len = SSL3_HDR_LEN + SSL3_ALERT_LEN;
1801*12696SVladimir.Kotal@Sun.COM 	} else {
1802*12696SVladimir.Kotal@Sun.COM 		/* KSSL generates 5 byte SSLv2 alert messages only. */
180312623SVladimir.Kotal@Sun.COM 		len = 5;
1804*12696SVladimir.Kotal@Sun.COM 	}
180512623SVladimir.Kotal@Sun.COM 	ssl->alert_sendbuf = mp = allocb(len + spec->mac_hashsz +
1806898Skais 	    spec->cipher_bsize, BPRI_HI);
1807898Skais 	if (mp == NULL) {
1808898Skais 		KSSL_COUNTER(alloc_fails, 1);
1809898Skais 		return;
1810898Skais 	}
1811898Skais 	buf = mp->b_wptr;
1812898Skais 
181312623SVladimir.Kotal@Sun.COM 	/* SSLv3/TLS */
181412623SVladimir.Kotal@Sun.COM 	if (ssl->major_version == 0x03) {
181512623SVladimir.Kotal@Sun.COM 		/* 5 byte record header */
181612623SVladimir.Kotal@Sun.COM 		buf[0] = content_alert;
181712623SVladimir.Kotal@Sun.COM 		buf[1] = ssl->major_version;
181812623SVladimir.Kotal@Sun.COM 		buf[2] = ssl->minor_version;
181912623SVladimir.Kotal@Sun.COM 		buf[3] = 0;
182012623SVladimir.Kotal@Sun.COM 		buf[4] = 2;
182112623SVladimir.Kotal@Sun.COM 		buf += SSL3_HDR_LEN;
1822898Skais 
182312623SVladimir.Kotal@Sun.COM 		/* alert contents */
182412623SVladimir.Kotal@Sun.COM 		buf[0] = (uchar_t)level;
182512623SVladimir.Kotal@Sun.COM 		buf[1] = (uchar_t)desc;
1826*12696SVladimir.Kotal@Sun.COM 		buf += SSL3_ALERT_LEN;
182712623SVladimir.Kotal@Sun.COM 	} else {
182812623SVladimir.Kotal@Sun.COM 	/* SSLv2 has different encoding. */
182912623SVladimir.Kotal@Sun.COM 		/* 2-byte encoding of the length */
183012623SVladimir.Kotal@Sun.COM 		buf[0] = 0x80;
183112623SVladimir.Kotal@Sun.COM 		buf[1] = 0x03;
183212623SVladimir.Kotal@Sun.COM 		buf += 2;
1833898Skais 
183412623SVladimir.Kotal@Sun.COM 		/* Protocol Message Code = Error */
183512623SVladimir.Kotal@Sun.COM 		buf[0] = 0;
183612623SVladimir.Kotal@Sun.COM 		/* Error Message Code = Undefined Error */
183712623SVladimir.Kotal@Sun.COM 		buf[1] = 0;
183812623SVladimir.Kotal@Sun.COM 		buf[2] = 0;
183912623SVladimir.Kotal@Sun.COM 		buf += 3;
184012623SVladimir.Kotal@Sun.COM 	}
184112623SVladimir.Kotal@Sun.COM 
184212623SVladimir.Kotal@Sun.COM 	mp->b_wptr = buf;
1843898Skais }
1844898Skais 
1845898Skais /* Assumes RSA encryption */
1846898Skais static int
kssl_handle_client_key_exchange(ssl_t * ssl,mblk_t * mp,int msglen,kssl_callback_t cbfn,void * arg)1847898Skais kssl_handle_client_key_exchange(ssl_t *ssl, mblk_t *mp, int msglen,
1848898Skais     kssl_callback_t cbfn, void *arg)
1849898Skais {
1850898Skais 	char *buf;
1851898Skais 	uchar_t *pms;
1852898Skais 	size_t pmslen;
1853898Skais 	int allocated;
18542800Skrishna 	int err, rverr = ENOMEM;
18552800Skrishna 	kssl_entry_t *ep;
1856898Skais 	crypto_key_t *privkey;
1857898Skais 	crypto_data_t *wrapped_pms_data, *pms_data;
1858898Skais 	crypto_call_req_t creq, *creqp;
1859898Skais 
18602800Skrishna 	ep = ssl->kssl_entry;
18612800Skrishna 	privkey = ep->ke_private_key;
1862898Skais 	if (privkey == NULL) {
18632800Skrishna 		return (ENOENT);
1864898Skais 	}
1865898Skais 
1866898Skais 	ASSERT(ssl->msg.type == client_key_exchange);
1867898Skais 	ASSERT(ssl->hs_waitstate == wait_client_key);
1868898Skais 
1869898Skais 	/*
1870898Skais 	 * TLS adds an extra 2 byte length field before the data.
1871898Skais 	 */
1872898Skais 	if (IS_TLS(ssl)) {
1873898Skais 		msglen = (mp->b_rptr[0] << 8) | mp->b_rptr[1];
1874898Skais 		mp->b_rptr += 2;
1875898Skais 	}
1876898Skais 
1877898Skais 	/*
1878898Skais 	 * Allocate all we need in one shot. about 300 bytes total, for
1879898Skais 	 * 1024 bit RSA modulus.
1880898Skais 	 * The buffer layout will be: pms_data, wrapped_pms_data, the
1881898Skais 	 * value of the wrapped pms from the client, then room for the
1882898Skais 	 * resulting decrypted premaster secret.
1883898Skais 	 */
1884898Skais 	allocated = 2 * (sizeof (crypto_data_t) + msglen);
1885898Skais 	buf = kmem_alloc(allocated, KM_NOSLEEP);
1886898Skais 	if (buf == NULL) {
1887898Skais 		return (ENOMEM);
1888898Skais 	}
1889898Skais 
1890898Skais 	pms_data = (crypto_data_t *)buf;
1891898Skais 	wrapped_pms_data = &(((crypto_data_t *)buf)[1]);
1892898Skais 
1893898Skais 	wrapped_pms_data->cd_format = pms_data->cd_format = CRYPTO_DATA_RAW;
1894898Skais 	wrapped_pms_data->cd_offset = pms_data->cd_offset = 0;
1895898Skais 	wrapped_pms_data->cd_length = pms_data->cd_length = msglen;
1896898Skais 	wrapped_pms_data->cd_miscdata = pms_data->cd_miscdata = NULL;
1897898Skais 	wrapped_pms_data->cd_raw.iov_len = pms_data->cd_raw.iov_len = msglen;
1898898Skais 	wrapped_pms_data->cd_raw.iov_base = buf + 2 * sizeof (crypto_data_t);
1899898Skais 	pms_data->cd_raw.iov_base = wrapped_pms_data->cd_raw.iov_base + msglen;
1900898Skais 
1901898Skais 	bcopy(mp->b_rptr, wrapped_pms_data->cd_raw.iov_base, msglen);
1902898Skais 	mp->b_rptr += msglen;
1903898Skais 
1904898Skais 	/* Proceed synchronously if out of interrupt and configured to do so */
1905898Skais 	if ((kssl_synchronous) && (!servicing_interrupt())) {
1906898Skais 		creqp = NULL;
1907898Skais 	} else {
1908898Skais 		ssl->cke_callback_func = cbfn;
1909898Skais 		ssl->cke_callback_arg = arg;
1910898Skais 		creq.cr_flag = kssl_call_flag;
1911898Skais 		creq.cr_callback_func = kssl_cke_done;
1912898Skais 		creq.cr_callback_arg = ssl;
1913898Skais 
1914898Skais 		creqp = &creq;
1915898Skais 	}
1916898Skais 
19172800Skrishna 	if (ep->ke_is_nxkey) {
19182800Skrishna 		kssl_session_info_t *s;
19192800Skrishna 
19202800Skrishna 		s = ep->ke_sessinfo;
19212800Skrishna 		err = CRYPTO_SUCCESS;
19222800Skrishna 		if (!s->is_valid_handle) {
19232800Skrishna 			/* Reauthenticate to the provider */
19242800Skrishna 			if (s->do_reauth) {
19252800Skrishna 				err = kssl_get_obj_handle(ep);
19262800Skrishna 				if (err == CRYPTO_SUCCESS) {
19272800Skrishna 					s->is_valid_handle = B_TRUE;
19282800Skrishna 					s->do_reauth = B_FALSE;
19292800Skrishna 				}
19302800Skrishna 			} else
19312800Skrishna 				err = CRYPTO_FAILED;
19322800Skrishna 		}
19332800Skrishna 
19342800Skrishna 		if (err == CRYPTO_SUCCESS) {
19352800Skrishna 			ASSERT(s->is_valid_handle);
19362800Skrishna 			err = crypto_decrypt_prov(s->prov, s->sid,
19372800Skrishna 			    &rsa_x509_mech, wrapped_pms_data, &s->key,
19382800Skrishna 			    NULL, pms_data, creqp);
19392800Skrishna 		}
19402800Skrishna 
19412800Skrishna 		/*
19422800Skrishna 		 * Deal with session specific errors. We translate to
19432800Skrishna 		 * the closest errno.
19442800Skrishna 		 */
19452800Skrishna 		switch (err) {
19462800Skrishna 		case CRYPTO_KEY_HANDLE_INVALID:
19472800Skrishna 		case CRYPTO_SESSION_HANDLE_INVALID:
19482800Skrishna 			s->is_valid_handle = B_FALSE;
19492800Skrishna 			s->do_reauth = B_TRUE;
19502800Skrishna 			rverr = EINVAL;
19512800Skrishna 			break;
19522800Skrishna 		case CRYPTO_PIN_EXPIRED:
19532800Skrishna 		case CRYPTO_PIN_LOCKED:
19542800Skrishna 			rverr = EACCES;
19552800Skrishna 			break;
19562800Skrishna 		case CRYPTO_UNKNOWN_PROVIDER:
19572800Skrishna 			rverr = ENXIO;
19582800Skrishna 			break;
19592800Skrishna 		}
19602800Skrishna 	} else {
19612800Skrishna 		err = crypto_decrypt(&rsa_x509_mech, wrapped_pms_data,
19622800Skrishna 		    privkey, NULL, pms_data, creqp);
19632800Skrishna 	}
1964898Skais 
1965898Skais 	switch (err) {
1966898Skais 	case CRYPTO_SUCCESS:
1967898Skais 		break;
1968898Skais 
1969898Skais 	case CRYPTO_QUEUED:
1970898Skais 		/*
1971898Skais 		 * Finish the master secret then the rest of key material
1972898Skais 		 * derivation later.
1973898Skais 		 */
1974898Skais 		ssl->job.kjob = creq.cr_reqid;
1975898Skais 		ssl->job.buf = buf;
1976898Skais 		ssl->job.buflen = allocated;
1977898Skais 		ssl->hs_waitstate = wait_client_key_done;
1978898Skais 		return (0);
1979898Skais 	default:
19805850Svk199839 		DTRACE_PROBE1(kssl_err__crypto_decrypt, int, err);
1981898Skais 		kmem_free(buf, allocated);
19822800Skrishna 		return (rverr);
1983898Skais 	}
1984898Skais 
1985898Skais 	pmslen = pms_data->cd_length;
1986898Skais 	pms = kssl_rsa_unwrap((uchar_t *)pms_data->cd_raw.iov_base, &pmslen);
1987898Skais 
1988898Skais 	/* generate master key and save it in the ssl sid structure */
1989898Skais 	if (IS_TLS(ssl)) {
1990898Skais 		err = kssl_generate_tls_ms(ssl, pms, pmslen);
1991898Skais 		if (!CRYPTO_ERR(err))
1992898Skais 			err = kssl_generate_tls_keyblock(ssl);
1993898Skais 	} else {
1994898Skais 		kssl_generate_ssl_ms(ssl, pms, pmslen);
1995898Skais 		kssl_generate_keyblock(ssl);
1996898Skais 	}
1997898Skais 
1998898Skais 	if (err == CRYPTO_SUCCESS)
1999898Skais 		ssl->hs_waitstate = wait_change_cipher;
2000898Skais 
2001898Skais 	ssl->activeinput = B_FALSE;
2002898Skais 
2003898Skais 	kmem_free(buf, allocated);
2004898Skais 
2005898Skais 	return (0);
2006898Skais }
2007898Skais 
2008898Skais static int
kssl_handle_finished(ssl_t * ssl,mblk_t * mp,int msglen)2009898Skais kssl_handle_finished(ssl_t *ssl, mblk_t *mp, int msglen)
2010898Skais {
2011898Skais 	int err;
2012898Skais 	size_t finish_len;
2013898Skais 	int hashcompare;
2014898Skais 
2015898Skais 	ASSERT(ssl->msg.type == finished);
2016898Skais 	ASSERT(ssl->hs_waitstate == wait_finished);
2017898Skais 
2018898Skais 	if (IS_TLS(ssl))
2019898Skais 		finish_len = TLS_FINISHED_SIZE;
2020898Skais 	else
2021898Skais 		finish_len = KSSL_SSL3_FIN_MSGLEN;
2022898Skais 
2023898Skais 	if (msglen != finish_len) {
2024898Skais 		kssl_send_alert(ssl, alert_fatal, illegal_parameter);
2025898Skais 		return (EBADMSG);
2026898Skais 	}
2027898Skais 
2028898Skais 	if (IS_TLS(ssl)) {
2029898Skais 		hashcompare = bcmp(mp->b_rptr, ssl->hs_hashes.tlshash,
20305850Svk199839 		    finish_len);
2031898Skais 	} else {
2032898Skais 		hashcompare = bcmp(mp->b_rptr, &ssl->hs_hashes, finish_len);
2033898Skais 	}
2034898Skais 
2035898Skais 	/* The handshake hashes should be computed by now */
2036898Skais 	if (hashcompare != 0) {
2037898Skais 		kssl_send_alert(ssl, alert_fatal, handshake_failure);
2038898Skais 		return (EBADMSG);
2039898Skais 	}
2040898Skais 
2041898Skais 	mp->b_rptr += msglen;
2042898Skais 
2043898Skais 	ssl->hs_waitstate = idle_handshake;
2044898Skais 
2045898Skais 	if (ssl->resumed == B_TRUE) {
2046898Skais 		ssl->activeinput = B_FALSE;
2047898Skais 		return (0);
2048898Skais 	}
2049898Skais 
2050898Skais 	err = kssl_send_change_cipher_specs(ssl);
2051898Skais 	if (err != 0) {
2052898Skais 		return (err);
2053898Skais 	}
2054898Skais 	err = kssl_send_finished(ssl, 0);
2055898Skais 	if (err != 0) {
2056898Skais 		return (err);
2057898Skais 	}
2058898Skais 
2059898Skais 	kssl_cache_sid(&ssl->sid, ssl->kssl_entry);
2060898Skais 	ssl->activeinput = B_FALSE;
2061898Skais 
2062898Skais 	return (0);
2063898Skais }
2064898Skais 
2065898Skais #define	KSSL2_CH_MIN_RECSZ	(9)
2066898Skais 
2067898Skais /*
2068898Skais  * This method is needed to handle clients which send the
2069898Skais  * SSLv2/SSLv3 handshake for backwards compat with SSLv2 servers.
2070898Skais  * We are not really doing SSLv2 here, just handling the header
2071898Skais  * and then switching to SSLv3.
2072898Skais  */
2073898Skais int
kssl_handle_v2client_hello(ssl_t * ssl,mblk_t * mp,int recsz)2074898Skais kssl_handle_v2client_hello(ssl_t *ssl, mblk_t *mp, int recsz)
2075898Skais {
2076898Skais 	uchar_t *recend;
2077898Skais 	int err;
2078898Skais 	SSL3AlertDescription desc = illegal_parameter;
2079898Skais 	uint_t randlen;
2080898Skais 	uint_t sidlen;
208110118SBhargava.Yenduri@Sun.COM 	uint_t cslen;
2082898Skais 	uchar_t *suitesp;
2083898Skais 	uchar_t *rand;
2084898Skais 	uint_t i, j;
208512381SVladimir.Kotal@Sun.COM 	uint16_t suite, selected_suite;
2086898Skais 	int ch_recsz = KSSL2_CH_MIN_RECSZ;
208712381SVladimir.Kotal@Sun.COM 	boolean_t suite_found = B_FALSE;
2088898Skais 
2089898Skais 	ASSERT(mp->b_wptr >= mp->b_rptr + recsz);
2090898Skais 	ASSERT(ssl->hs_waitstate == wait_client_hello);
2091898Skais 	ASSERT(ssl->resumed == B_FALSE);
2092898Skais 
2093898Skais 	if (recsz < ch_recsz) {
209411984SVladimir.Kotal@Sun.COM 		DTRACE_PROBE2(kssl_err__reclen_less_than_minimum,
209511984SVladimir.Kotal@Sun.COM 		    int, recsz, int, ch_recsz);
2096898Skais 		goto falert;
2097898Skais 	}
2098898Skais 
2099898Skais 	MD5Init(&ssl->hs_md5);
2100898Skais 	SHA1Init(&ssl->hs_sha1);
2101898Skais 
2102898Skais 	kssl_update_handshake_hashes(ssl, mp->b_rptr, recsz);
2103898Skais 
2104898Skais 	recend = mp->b_rptr + recsz;
2105898Skais 
2106898Skais 	if (*mp->b_rptr != 1) {
210711984SVladimir.Kotal@Sun.COM 		DTRACE_PROBE1(kssl_err__invalid_version, uint_t, *mp->b_rptr);
2108898Skais 		goto falert;
2109898Skais 	}
2110898Skais 	mp->b_rptr += 3;
2111898Skais 
211210118SBhargava.Yenduri@Sun.COM 	cslen = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1];
2113898Skais 	sidlen = ((uint_t)mp->b_rptr[2] << 8) + (uint_t)mp->b_rptr[3];
2114898Skais 	randlen = ((uint_t)mp->b_rptr[4] << 8) + (uint_t)mp->b_rptr[5];
211510118SBhargava.Yenduri@Sun.COM 	if (cslen % 3 != 0) {
211610118SBhargava.Yenduri@Sun.COM 		DTRACE_PROBE1(kssl_err__cipher_suites_len_error, uint_t, cslen);
2117898Skais 		goto falert;
2118898Skais 	}
2119898Skais 	if (randlen < SSL_MIN_CHALLENGE_BYTES ||
2120898Skais 	    randlen > SSL_MAX_CHALLENGE_BYTES) {
21215850Svk199839 		DTRACE_PROBE1(kssl_err__randlen_out_of_range,
21225850Svk199839 		    uint_t, randlen);
2123898Skais 		goto falert;
2124898Skais 	}
2125898Skais 	mp->b_rptr += 6;
212610118SBhargava.Yenduri@Sun.COM 	ch_recsz += cslen + sidlen + randlen;
2127898Skais 	if (recsz != ch_recsz) {
212811984SVladimir.Kotal@Sun.COM 		DTRACE_PROBE2(kssl_err__invalid_message_len_sum,
212911984SVladimir.Kotal@Sun.COM 		    int, recsz, int, ch_recsz);
2130898Skais 		goto falert;
2131898Skais 	}
2132898Skais 	suitesp = mp->b_rptr;
213310118SBhargava.Yenduri@Sun.COM 	rand = suitesp + cslen + sidlen;
2134898Skais 	if (randlen < SSL3_RANDOM_LENGTH) {
2135898Skais 		bzero(ssl->client_random, SSL3_RANDOM_LENGTH);
2136898Skais 	}
2137898Skais 	bcopy(rand, &ssl->client_random[SSL3_RANDOM_LENGTH - randlen],
2138898Skais 	    randlen);
2139898Skais 
2140898Skais 	for (i = 0; i < ssl->kssl_entry->kssl_cipherSuites_nentries; i++) {
2141898Skais 		suite = ssl->kssl_entry->kssl_cipherSuites[i];
214210118SBhargava.Yenduri@Sun.COM 		for (j = 0; j < cslen; j += 3) {
214312381SVladimir.Kotal@Sun.COM 			DTRACE_PROBE2(kssl_cipher_suite_check_v2,
214412381SVladimir.Kotal@Sun.COM 			    uint16_t, suite,
214512381SVladimir.Kotal@Sun.COM 			    uint16_t,
214612381SVladimir.Kotal@Sun.COM 			    (uint16_t)((suitesp[j+1] << 8) + suitesp[j+2]));
2147898Skais 			if (suitesp[j] != 0) {
2148898Skais 				continue;
2149898Skais 			}
2150898Skais 
215112381SVladimir.Kotal@Sun.COM 			/* Check for regular (true) cipher suite. */
2152898Skais 			if (suitesp[j + 1] == ((suite >> 8) & 0xff) &&
2153898Skais 			    suitesp[j + 2] == (suite & 0xff)) {
215412381SVladimir.Kotal@Sun.COM 				DTRACE_PROBE1(kssl_cipher_suite_found,
215512381SVladimir.Kotal@Sun.COM 				    uint16_t, suite);
215612381SVladimir.Kotal@Sun.COM 				suite_found = B_TRUE;
215712381SVladimir.Kotal@Sun.COM 				selected_suite = suite;
215812381SVladimir.Kotal@Sun.COM 			}
215912381SVladimir.Kotal@Sun.COM 
216012381SVladimir.Kotal@Sun.COM 			/* Check for SCSV. */
216112381SVladimir.Kotal@Sun.COM 			if (suitesp[j + 1] ==  ((SSL_SCSV >> 8) & 0xff) &&
216212381SVladimir.Kotal@Sun.COM 			    suitesp[j + 2] == (SSL_SCSV & 0xff)) {
216312381SVladimir.Kotal@Sun.COM 				DTRACE_PROBE(kssl_scsv_found);
216412381SVladimir.Kotal@Sun.COM 				ssl->secure_renegotiation = B_TRUE;
216512381SVladimir.Kotal@Sun.COM 			}
216612381SVladimir.Kotal@Sun.COM 			/*
216712381SVladimir.Kotal@Sun.COM 			 * If we got cipher suite match and SCSV or went
216812381SVladimir.Kotal@Sun.COM 			 * through the whole list of client cipher suites
216912381SVladimir.Kotal@Sun.COM 			 * (hence we know if SCSV was present or not) we
217012381SVladimir.Kotal@Sun.COM 			 * can terminate the cycle now.
217112381SVladimir.Kotal@Sun.COM 			 */
217212381SVladimir.Kotal@Sun.COM 			if (suite_found &&
217312381SVladimir.Kotal@Sun.COM 			    (ssl->secure_renegotiation || (i > 0)))
2174898Skais 				break;
2175898Skais 		}
217612381SVladimir.Kotal@Sun.COM 		if (suite_found)
2177898Skais 			break;
2178898Skais 	}
217912381SVladimir.Kotal@Sun.COM 	if (!suite_found) {
21805850Svk199839 		DTRACE_PROBE(kssl_err__no_SSLv2_cipher_suite);
2181898Skais 		ssl->activeinput = B_FALSE;
218211984SVladimir.Kotal@Sun.COM 		/*
218311984SVladimir.Kotal@Sun.COM 		 * If there is no fallback point terminate the handshake with
218411984SVladimir.Kotal@Sun.COM 		 * SSL alert otherwise return with SSL_MISS.
218511984SVladimir.Kotal@Sun.COM 		 */
218611984SVladimir.Kotal@Sun.COM 		if (ssl->kssl_entry->ke_fallback_head == NULL) {
218711984SVladimir.Kotal@Sun.COM 			DTRACE_PROBE(kssl_no_fallback);
218811984SVladimir.Kotal@Sun.COM 			desc = handshake_failure;
218911984SVladimir.Kotal@Sun.COM 			goto falert;
219011984SVladimir.Kotal@Sun.COM 		} else {
219111984SVladimir.Kotal@Sun.COM 			return (SSL_MISS);
219211984SVladimir.Kotal@Sun.COM 		}
2193898Skais 	}
2194898Skais 
2195898Skais 	mp->b_rptr = recend;
2196898Skais 
2197898Skais 	for (i = 0; i < cipher_suite_defs_nentries; i++) {
219812381SVladimir.Kotal@Sun.COM 		if (selected_suite == cipher_suite_defs[i].suite) {
2199898Skais 			break;
2200898Skais 		}
2201898Skais 	}
2202898Skais 
2203898Skais 	ASSERT(i < cipher_suite_defs_nentries);
2204898Skais 
220512381SVladimir.Kotal@Sun.COM 	ssl->pending_cipher_suite = selected_suite;
2206898Skais 	ssl->pending_malg = cipher_suite_defs[i].malg;
2207898Skais 	ssl->pending_calg = cipher_suite_defs[i].calg;
2208898Skais 	ssl->pending_keyblksz = cipher_suite_defs[i].keyblksz;
2209898Skais 
2210898Skais 	ASSERT(ssl->sid.cached == B_FALSE);
2211898Skais 
2212898Skais 	(void) random_get_pseudo_bytes(ssl->sid.session_id,
2213898Skais 	    SSL3_SESSIONID_BYTES);
2214898Skais 	ssl->sid.client_addr = ssl->faddr;
221512381SVladimir.Kotal@Sun.COM 	ssl->sid.cipher_suite = selected_suite;
2216898Skais 
2217898Skais 	err = kssl_send_server_hello(ssl);
2218898Skais 	if (err != 0) {
2219898Skais 		return (err);
2220898Skais 	}
2221898Skais 	err = kssl_send_certificate_and_server_hello_done(ssl);
2222898Skais 	if (err != 0) {
2223898Skais 		return (err);
2224898Skais 	}
2225898Skais 	KSSL_COUNTER(full_handshakes, 1);
2226898Skais 	ssl->hs_waitstate = wait_client_key;
2227898Skais 	ssl->activeinput = B_FALSE;
2228898Skais 	return (0);
2229898Skais 
2230898Skais falert:
2231898Skais 	kssl_send_alert(ssl, alert_fatal, desc);
2232898Skais 	ssl->activeinput = B_FALSE;
2233898Skais 	return (EBADMSG);
2234898Skais }
2235898Skais 
2236898Skais /*
2237898Skais  * Call back routine for asynchronously submitted RSA decryption jobs.
223810118SBhargava.Yenduri@Sun.COM  * This routine retrieves the pre-master secret, and proceeds to generate
2239898Skais  * the remaining key materials.
2240898Skais  */
2241898Skais static void
kssl_cke_done(void * arg,int status)2242898Skais kssl_cke_done(void *arg, int status)
2243898Skais {
2244898Skais 	int ret = 0;
2245898Skais 	uchar_t *pms;
2246898Skais 	size_t pmslen;
2247898Skais 	crypto_data_t *pms_data;
2248898Skais 	kssl_cmd_t kssl_cmd = KSSL_CMD_NONE;
2249898Skais 	ssl_t *ssl = (ssl_t *)arg;
2250898Skais 	mblk_t *alertmp;
2251898Skais 	kssl_callback_t cbfn;
2252898Skais 	void *cbarg;
2253898Skais 
2254898Skais 	mutex_enter(&ssl->kssl_lock);
2255898Skais 
2256898Skais 	ASSERT(ssl->msg.type == client_key_exchange);
2257898Skais 	ASSERT(ssl->hs_waitstate == wait_client_key_done);
2258898Skais 
2259898Skais 	if (status != CRYPTO_SUCCESS) {
2260898Skais 		kssl_send_alert(ssl, alert_fatal, decrypt_error);
2261898Skais 		kssl_cmd = KSSL_CMD_SEND;
2262898Skais 		goto out;
2263898Skais 	}
2264898Skais 
2265898Skais 	pms_data = (crypto_data_t *)(ssl->job.buf);
2266898Skais 
2267898Skais 	ASSERT(pms_data != NULL);
2268898Skais 
2269898Skais 	pmslen = pms_data->cd_length;
2270898Skais 	pms = kssl_rsa_unwrap((uchar_t *)pms_data->cd_raw.iov_base, &pmslen);
2271898Skais 
2272898Skais 	/* generate master key and save it in the ssl sid structure */
2273898Skais 	if (IS_TLS(ssl)) {
2274898Skais 		ret = kssl_generate_tls_ms(ssl, pms, pmslen);
2275898Skais 		if (!CRYPTO_ERR(ret))
2276898Skais 			ret = kssl_generate_tls_keyblock(ssl);
2277898Skais 	} else {
2278898Skais 		kssl_generate_ssl_ms(ssl, pms, pmslen);
2279898Skais 		kssl_generate_keyblock(ssl);
2280898Skais 	}
2281898Skais 
2282898Skais 	if (ret == CRYPTO_SUCCESS)
2283898Skais 		ssl->hs_waitstate = wait_change_cipher;
2284898Skais 
2285898Skais out:
2286898Skais 	kmem_free(ssl->job.buf, ssl->job.buflen);
2287898Skais 
2288898Skais 	ssl->job.kjob = 0;
2289898Skais 	ssl->job.buf = NULL;
2290898Skais 	ssl->job.buflen = 0;
2291898Skais 
2292898Skais 	ssl->activeinput = B_FALSE;
2293898Skais 
2294898Skais 	cbfn = ssl->cke_callback_func;
2295898Skais 	cbarg = ssl->cke_callback_arg;
2296898Skais 	alertmp = ssl->alert_sendbuf;
2297898Skais 	ssl->alert_sendbuf = NULL;
2298898Skais 
229912644SAnders.Persson@Sun.COM 	/* dropped by callback when it has completed */
230012644SAnders.Persson@Sun.COM 	ssl->async_ops_pending++;
2301898Skais 	mutex_exit(&ssl->kssl_lock);
2302898Skais 
2303898Skais 	/* Now call the callback routine */
2304898Skais 	(*(cbfn))(cbarg, alertmp, kssl_cmd);
2305898Skais }
2306898Skais 
2307898Skais /*
2308898Skais  * Returns the first complete contiguous record out of rec_ass_head
2309898Skais  * The record is returned in a separate contiguous mblk, rec_ass_head is
2310898Skais  * left pointing to the next record in the queue.
2311898Skais  *
2312898Skais  * The output looks as follows:
2313898Skais  *
2314898Skais  * |--------|---------- .... -----|<---------->|<----------->|--- ... ---|
2315898Skais  * ^        ^                     ^  mac_size     pad_size               ^
2316898Skais  * |        |___ b_rptr  b_wptr __|                                      |
2317898Skais  * |                                                                     |
2318898Skais  * |___ db_base                                                db_lim ___|
2319898Skais  */
2320898Skais mblk_t *
kssl_get_next_record(ssl_t * ssl)2321898Skais kssl_get_next_record(ssl_t *ssl)
2322898Skais {
2323898Skais 	mblk_t *mp, *retmp;
2324898Skais 	int rhsz = SSL3_HDR_LEN;
2325898Skais 	uint16_t rec_sz;
2326898Skais 	int mpsz, total_size;
2327898Skais 	SSL3ContentType content_type;
2328898Skais 
2329898Skais 	ASSERT(MUTEX_HELD(&ssl->kssl_lock));
2330898Skais 
2331898Skais 	mp = ssl->rec_ass_head;
2332898Skais 	if (mp == NULL)
2333898Skais 		return (NULL);
2334898Skais 
2335898Skais 	/* Fast path: when mp has at least a complete record */
2336898Skais 	if (MBLKL(mp) < rhsz) {
23375850Svk199839 		DTRACE_PROBE1(kssl_mblk__incomplete_header,
23385850Svk199839 		    mblk_t *, mp);
2339898Skais 		/* Not even a complete header in there yet */
2340898Skais 		if (msgdsize(mp) < rhsz) {
2341898Skais 			return (NULL);
2342898Skais 		}
2343898Skais 
2344898Skais 		if (!pullupmsg(mp, rhsz)) {
2345898Skais 			kssl_send_alert(ssl, alert_fatal, internal_error);
2346898Skais 			freemsg(mp);
2347898Skais 			ssl->rec_ass_head = ssl->rec_ass_tail = NULL;
2348898Skais 			return (NULL);
2349898Skais 		}
2350898Skais 	}
2351898Skais 	content_type = (SSL3ContentType)mp->b_rptr[0];
2352898Skais 	if (content_type == content_handshake_v2) {
23535850Svk199839 		DTRACE_PROBE1(kssl_mblk__ssl_v2, mblk_t *, mp);
2354898Skais 		rec_sz = (uint16_t)mp->b_rptr[1];
2355898Skais 		rhsz = 2;
2356898Skais 	} else {
23575850Svk199839 		DTRACE_PROBE1(kssl_mblk__ssl_v3, mblk_t *, mp);
2358898Skais 		uint8_t *rec_sz_p = (uint8_t *)mp->b_rptr + 3;
2359898Skais 		rec_sz = BE16_TO_U16(rec_sz_p);
2360898Skais 	}
2361898Skais 
2362898Skais 	/*
2363898Skais 	 * same tests as above. Only rare very fragmented cases will
2364898Skais 	 * incur the cost of msgdsize() and msgpullup(). Well formed
2365898Skais 	 * packets will fall in the most frequent fast path.
2366898Skais 	 */
2367898Skais 	total_size = rhsz + rec_sz;
2368898Skais 
2369898Skais 	/*
2370898Skais 	 * Missing: defensive against record fabricated with longer than
2371898Skais 	 * MAX record length.
2372898Skais 	 */
2373898Skais 	if (MBLKL(mp) < total_size) {
23745850Svk199839 		DTRACE_PROBE2(kssl_mblk__smaller_than_total_size,
23755850Svk199839 		    mblk_t *, mp, int, total_size);
2376898Skais 		/* Not a complete record yet. Keep accumulating */
2377898Skais 		if (msgdsize(mp) < total_size) {
2378898Skais 			return (NULL);
2379898Skais 		}
2380898Skais 
2381898Skais 		if (!pullupmsg(mp, total_size)) {
2382898Skais 			kssl_send_alert(ssl, alert_fatal, internal_error);
2383898Skais 			freemsg(mp);
2384898Skais 			ssl->rec_ass_head = ssl->rec_ass_tail = NULL;
2385898Skais 			return (NULL);
2386898Skais 		}
2387898Skais 	}
2388898Skais 	mpsz = MBLKL(mp);	/* could've changed after the pullup */
2389898Skais 
2390898Skais 	if (mpsz > total_size) {
23915850Svk199839 		DTRACE_PROBE2(kssl_mblk__bigger_than_total_size,
23925850Svk199839 		    mblk_t *, mp, int, total_size);
2393898Skais 		/* gotta allocate a new block */
2394898Skais 		if ((retmp = dupb(mp)) == NULL) {
2395898Skais 			kssl_send_alert(ssl, alert_fatal, internal_error);
2396898Skais 			freemsg(mp);
2397898Skais 			ssl->rec_ass_head = ssl->rec_ass_tail = NULL;
2398898Skais 			return (NULL);
2399898Skais 		}
2400898Skais 
2401898Skais 		retmp->b_wptr = retmp->b_rptr + total_size;
2402898Skais 		mp->b_rptr += total_size;
2403898Skais 		ssl->rec_ass_head = mp;
2404898Skais 	} else {
24055850Svk199839 		DTRACE_PROBE2(kssl_mblk__equal_to_total_size,
24065850Svk199839 		    mblk_t *, mp, int, total_size);
2407898Skais 		ASSERT(mpsz == total_size);
2408898Skais 		ssl->rec_ass_head = mp->b_cont;
2409898Skais 		mp->b_cont = NULL;
2410898Skais 		retmp = mp;
2411898Skais 	}
2412898Skais 	/* Adjust the tail */
2413898Skais 	if ((mp = ssl->rec_ass_tail = ssl->rec_ass_head) != NULL) {
2414898Skais 		for (; mp->b_cont != NULL; mp = mp->b_cont) {
2415898Skais 			ssl->rec_ass_tail = mp->b_cont;
2416898Skais 		}
2417898Skais 	}
2418898Skais 
2419898Skais 	return (retmp);
2420898Skais }
2421898Skais 
2422898Skais 
2423898Skais static void
kssl_mblksfree(ssl_t * ssl)2424898Skais kssl_mblksfree(ssl_t *ssl)
2425898Skais {
2426898Skais 
2427898Skais 	ASSERT(ssl != NULL);
2428898Skais 
2429898Skais 	if (ssl->rec_ass_head != NULL) {
2430898Skais 		freemsg(ssl->rec_ass_head);
2431898Skais 	}
2432898Skais 	ssl->rec_ass_head = NULL;
2433898Skais 	ssl->rec_ass_tail = NULL;
2434898Skais 
2435898Skais 	if (ssl->msg.head != NULL) {
2436898Skais 		freemsg(ssl->msg.head);
2437898Skais 	}
2438898Skais 	ssl->msg.head = NULL;
2439898Skais 	ssl->msg.tail = NULL;
2440898Skais 
2441898Skais 	if (ssl->handshake_sendbuf != NULL) {
2442898Skais 		freemsg(ssl->handshake_sendbuf);
2443898Skais 		ssl->handshake_sendbuf = NULL;
2444898Skais 	}
2445898Skais 	if (ssl->alert_sendbuf != NULL) {
2446898Skais 		freemsg(ssl->alert_sendbuf);
2447898Skais 		ssl->alert_sendbuf = NULL;
2448898Skais 	}
2449898Skais }
2450898Skais 
2451898Skais static void
kssl_specsfree(ssl_t * ssl)2452898Skais kssl_specsfree(ssl_t *ssl)
2453898Skais {
2454898Skais 	KSSLCipherSpec *spec = &ssl->spec[KSSL_READ];
2455898Skais 
2456898Skais 	if (spec->cipher_ctx != NULL) {
2457898Skais 		crypto_cancel_ctx(spec->cipher_ctx);
2458898Skais 		spec->cipher_ctx = 0;
2459898Skais 	}
2460898Skais 
2461898Skais 	spec = &ssl->spec[KSSL_WRITE];
2462898Skais 
2463898Skais 	if (spec->cipher_ctx != NULL) {
2464898Skais 		crypto_cancel_ctx(spec->cipher_ctx);
2465898Skais 		spec->cipher_ctx = 0;
2466898Skais 	}
2467898Skais }
2468898Skais 
2469898Skais /*
2470898Skais  * Frees the ssl structure (aka the context of an SSL session).
2471898Skais  * Any pending crypto jobs are cancelled.
2472898Skais  * Any initiated crypto contexts are freed as well.
2473898Skais  */
2474898Skais void
kssl_free_context(ssl_t * ssl)2475898Skais kssl_free_context(ssl_t *ssl)
2476898Skais {
247712644SAnders.Persson@Sun.COM 	crypto_req_id_t reqid;
247812644SAnders.Persson@Sun.COM 
2479898Skais 	ASSERT(ssl != NULL);
2480898Skais 	if (!(MUTEX_HELD(&ssl->kssl_lock))) {
2481898Skais 		/* we're coming from an external API entry point */
2482898Skais 		mutex_enter(&ssl->kssl_lock);
2483898Skais 	}
2484898Skais 
248512644SAnders.Persson@Sun.COM 	/*
248612644SAnders.Persson@Sun.COM 	 * Cancel any active crypto request and wait for pending async
248712644SAnders.Persson@Sun.COM 	 * operations to complete. We loop here because the async thread
248812644SAnders.Persson@Sun.COM 	 * might submit a new cryto request.
248912644SAnders.Persson@Sun.COM 	 */
249012644SAnders.Persson@Sun.COM 	do {
249112644SAnders.Persson@Sun.COM 		if (ssl->job.kjob != NULL) {
249212644SAnders.Persson@Sun.COM 			/*
249312644SAnders.Persson@Sun.COM 			 * Drop the lock before canceling the request;
249412644SAnders.Persson@Sun.COM 			 * otherwise we might deadlock if the completion
249512644SAnders.Persson@Sun.COM 			 * callback is running.
249612644SAnders.Persson@Sun.COM 			 */
249712644SAnders.Persson@Sun.COM 			reqid = ssl->job.kjob;
249812644SAnders.Persson@Sun.COM 			mutex_exit(&ssl->kssl_lock);
249912644SAnders.Persson@Sun.COM 			crypto_cancel_req(reqid);
250012644SAnders.Persson@Sun.COM 			mutex_enter(&ssl->kssl_lock);
2501898Skais 
250212644SAnders.Persson@Sun.COM 			/* completion callback might have done the cleanup */
250312644SAnders.Persson@Sun.COM 			if (ssl->job.kjob != NULL) {
250412644SAnders.Persson@Sun.COM 				kmem_free(ssl->job.buf, ssl->job.buflen);
250512644SAnders.Persson@Sun.COM 				ssl->job.kjob = 0;
250612644SAnders.Persson@Sun.COM 				ssl->job.buf = NULL;
250712644SAnders.Persson@Sun.COM 				ssl->job.buflen = 0;
250812644SAnders.Persson@Sun.COM 			}
250912644SAnders.Persson@Sun.COM 		}
251012644SAnders.Persson@Sun.COM 		while (ssl->async_ops_pending > 0)
251112644SAnders.Persson@Sun.COM 			cv_wait(&ssl->async_cv, &ssl->kssl_lock);
251212644SAnders.Persson@Sun.COM 	} while (ssl->job.kjob != NULL);
2513898Skais 
2514898Skais 	kssl_mblksfree(ssl);
2515898Skais 	kssl_specsfree(ssl);
2516898Skais 
2517898Skais 	KSSL_ENTRY_REFRELE(ssl->kssl_entry);
2518898Skais 	ssl->kssl_entry = NULL;
2519898Skais 
2520898Skais 	mutex_exit(&ssl->kssl_lock);
2521898Skais 
2522898Skais 	kmem_cache_free(kssl_cache, ssl);
2523898Skais }
2524