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)¶m;
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