PSARC/2005/625 Greyhound - Solaris Kernel SSL proxy
authorkais
Sat, 12 Nov 2005 18:58:05 -0800
changeset 898 64b2a371a6bd
parent 897 8bc35ca89c2f
child 899 2d007157e61d
PSARC/2005/625 Greyhound - Solaris Kernel SSL proxy 4931229 Kernel-level SSL proxy
usr/src/cmd/cmd-inet/usr.sbin/Makefile
usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/Makefile
usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.c
usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.h
usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_create.c
usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_delete.c
usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c
usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/Makefile
usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/kssl-proxy.xml
usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c
usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.h
usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_create.c
usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_delete.c
usr/src/cmd/devfsadm/misc_link.c
usr/src/lib/libbsm/audit_event.txt
usr/src/lib/libsecdb/exec_attr.txt
usr/src/pkgdefs/SUNWckr/prototype_com
usr/src/pkgdefs/SUNWckr/prototype_i386
usr/src/pkgdefs/SUNWckr/prototype_sparc
usr/src/pkgdefs/SUNWcsr/prototype_com
usr/src/pkgdefs/SUNWcsu/prototype_com
usr/src/pkgdefs/SUNWhea/prototype_com
usr/src/pkgdefs/etc/exception_list_i386
usr/src/pkgdefs/etc/exception_list_sparc
usr/src/uts/Makefile
usr/src/uts/common/Makefile.files
usr/src/uts/common/Makefile.rules
usr/src/uts/common/c2/audit.c
usr/src/uts/common/c2/audit.h
usr/src/uts/common/c2/audit_kevents.h
usr/src/uts/common/fs/sockfs/sockssl.c
usr/src/uts/common/fs/sockfs/sockstr.c
usr/src/uts/common/fs/sockfs/socktpi.c
usr/src/uts/common/fs/sockfs/sockvnops.c
usr/src/uts/common/inet/ip.h
usr/src/uts/common/inet/kssl/Makefile
usr/src/uts/common/inet/kssl/kssl.c
usr/src/uts/common/inet/kssl/kssl.conf
usr/src/uts/common/inet/kssl/kssl.h
usr/src/uts/common/inet/kssl/ksslapi.c
usr/src/uts/common/inet/kssl/ksslapi.h
usr/src/uts/common/inet/kssl/kssldebug.h
usr/src/uts/common/inet/kssl/ksslimpl.h
usr/src/uts/common/inet/kssl/ksslioctl.c
usr/src/uts/common/inet/kssl/ksslproto.h
usr/src/uts/common/inet/kssl/ksslrec.c
usr/src/uts/common/inet/tcp.h
usr/src/uts/common/inet/tcp/tcp.c
usr/src/uts/common/inet/tcp/tcp_kssl.c
usr/src/uts/common/io/stream.c
usr/src/uts/common/io/strsun.c
usr/src/uts/common/os/streamio.c
usr/src/uts/common/os/strsubr.c
usr/src/uts/common/sys/socketvar.h
usr/src/uts/common/sys/stream.h
usr/src/uts/common/sys/strsubr.h
usr/src/uts/common/sys/strsun.h
usr/src/uts/common/sys/tihdr.h
usr/src/uts/common/syscall/sendfile.c
usr/src/uts/intel/Makefile.intel
usr/src/uts/intel/ia32/ml/modstubs.s
usr/src/uts/intel/kssl/Makefile
usr/src/uts/intel/os/minor_perm
usr/src/uts/intel/os/name_to_major
usr/src/uts/sparc/Makefile.sparc
usr/src/uts/sparc/kssl/Makefile
usr/src/uts/sparc/ml/modstubs.s
usr/src/uts/sparc/os/minor_perm
usr/src/uts/sparc/os/name_to_major
--- a/usr/src/cmd/cmd-inet/usr.sbin/Makefile	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/Makefile	Sat Nov 12 18:58:05 2005 -0800
@@ -68,12 +68,13 @@
 SRCS=		$(PROGSRCS) $(OTHERSRC)
 
 SUBDIRS=	bootconfchk htable ifconfig in.ftpd in.routed \
-		in.talkd inetadm inetconv ipqosconf mipagentconfig \
-		mipagentstat ping snoop sppptun traceroute
+		in.talkd inetadm inetconv ipqosconf kssl/kssladm \
+		kssl/ksslcfg  mipagentconfig mipagentstat ping snoop \
+		sppptun traceroute
 
 MSGSUBDIRS=	bootconfchk htable ifconfig in.ftpd in.routed in.talkd \
-		inetadm inetconv ipqosconf mipagentconfig mipagentstat \
-		sppptun snoop
+		inetadm inetconv ipqosconf kssl/ksslcfg mipagentconfig \
+		mipagentstat sppptun snoop
 
 # As programs get lint-clean, add them here and to the 'lint' target.
 # Eventually this hack should go away, and all in PROG should be
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/Makefile	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,73 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+# 
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# cmd/cmd-inet/usr.sbin/kssl/kssladm/Makefile
+#
+
+PROG= kssladm
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/lib/openssl/Makefile.openssl
+
+OBJS =	\
+    kssladm.o \
+    kssladm_create.o \
+    kssladm_delete.o \
+    openssl_util.o
+
+SRCS = $(OBJS:%.o=%.c)
+
+ROOTUSRLIBPROG = $(PROG:%=$(ROOTLIB)/%)
+
+.KEEP_STATE:
+
+CFLAGS +=	$(CCVERBOSE)
+
+CPPFLAGS += $(OPENSSL_CPPFLAGS)
+DYNFLAGS += $(OPENSSL_DYNFLAGS)
+LDFLAGS += $(OPENSSL_LDFLAGS)
+LINTFLAGS += $(OPENSSL_LDFLAGS)
+
+LDLIBS += -lnsl -lpkcs11 -lcrypto -lcryptoutil
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+	$(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(DYNFLAGS)
+	$(POST_PROCESS)
+
+install: all $(ROOTUSRLIBPROG)
+
+clean:
+	$(RM) $(OBJS)
+
+check:
+	$(CSTYLE) -pP $(SRCS)
+
+lint:	lint_SRCS
+
+include ../../../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,169 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <strings.h>
+#include <libscf.h>
+#include <sys/errno.h>
+#include <errno.h>
+#include <sys/stropts.h>
+#include "kssladm.h"
+
+
+/*
+ * kssladm(1M)
+ *
+ * Command to manage the entries in kernel SSL proxy table. This is
+ * a private command called indirectly from ksslcfg(1M).
+ */
+
+boolean_t verbose = B_FALSE;
+
+static void
+usage_all(void)
+{
+	(void) fprintf(stderr, "Usage:\n");
+	usage_create(B_FALSE);
+	usage_delete(B_FALSE);
+}
+
+int
+main(int argc, char **argv)
+{
+	int rv = SUCCESS;
+
+	if (argc < 2) {
+		usage_all();
+		return (SMF_EXIT_ERR_CONFIG);
+	}
+
+	if (strcmp(argv[1], "create") == 0) {
+		rv = do_create(argc, argv);
+	} else if (strcmp(argv[1], "delete") == 0) {
+		rv = do_delete(argc, argv);
+	} else {
+		(void) fprintf(stderr, "Unknown sub-command: %s\n", argv[1]);
+		usage_all();
+		rv = SMF_EXIT_ERR_CONFIG;
+	}
+
+	return (rv);
+}
+
+
+/*
+ * Read a passphrase from the file into the supplied buffer.
+ * A space character and the characters that follow
+ * the space character will be ignored.
+ * Return 0 when no valid passphrase was found in the file.
+ */
+static int
+read_pass_from_file(const char *filename, char *buffer, size_t bufsize)
+{
+	char *line;
+	char *p;
+	FILE *fp;
+
+	fp = fopen(filename, "r");
+	if (fp == NULL) {
+		(void) fprintf(stderr,
+		    "Unable to open password file for reading");
+		return (1);
+	}
+
+	line = fgets(buffer, bufsize, fp);
+	(void) fclose(fp);
+	if (line == NULL) {
+		return (0);
+	}
+
+	for (p = buffer; *p != '\0'; p++) {
+		if (isspace(*p)) {
+			*p = '\0';
+			break;
+		}
+	}
+
+	return (p - buffer);
+}
+
+
+int
+get_passphrase(const char *password_file, char *buf, int buf_size)
+{
+	if (password_file == NULL) {
+		char *passphrase = getpassphrase("Enter passphrase: ");
+		if (passphrase) {
+			return (strlcpy(buf, passphrase, buf_size));
+		}
+
+		return (0);
+	}
+
+	return (read_pass_from_file(password_file, buf, buf_size));
+}
+
+
+int
+kssl_send_command(char *buf, int cmd)
+{
+	int ksslfd;
+	int rv;
+
+	ksslfd = open("/dev/kssl", O_RDWR);
+	if (ksslfd < 0) {
+		perror("Cannot open /dev/kssl");
+		return (EBADF);
+	}
+
+	if ((rv = ioctl(ksslfd, cmd, buf)) < 0) {
+		switch (errno) {
+		case EEXIST:
+			(void) fprintf(stderr,
+			    "Error: Can not create a INADDR_ANY instance"
+			    " while another instance exists.\n");
+			break;
+		case EADDRINUSE:
+			(void) fprintf(stderr,
+			    "Error: Another instance with the same"
+			    " proxy port exists.\n");
+			break;
+		default:
+			perror("ioctl failure");
+			break;
+		}
+	}
+
+	(void) close(ksslfd);
+
+	return (rv);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.h	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,68 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _KSSLADM_H
+#define	_KSSLADM_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Common routines and variables used by kssladm files.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <netinet/in.h>
+#include <openssl/rsa.h>
+
+#define	SUCCESS		0
+#define	FAILURE		1
+#define	ERROR_USAGE	2
+
+extern boolean_t verbose;
+
+extern int do_create(int argc, char *argv[]);
+extern int do_delete(int argc, char *argv[]);
+extern void usage_create(boolean_t do_print);
+extern void usage_delete(boolean_t do_print);
+
+extern uchar_t *get_modulus(uchar_t *ber_buf, int buflen, int *modlen);
+extern RSA *PEM_get_rsa_key(const char *filename, char *passphrase);
+extern uchar_t *PEM_get_cert(const char *filename, char *passphrase,
+    int *cert_size);
+extern int PKCS12_get_rsa_key_cert(const char *filename, const char *password,
+    RSA **rsa, uchar_t **cert, int *cert_size);
+extern int get_passphrase(const char *password_file, char *buf, int buf_size);
+extern int kssl_send_command(char *buf, int cmd);
+extern int parse_and_set_addr(char *arg1, char *arg2, struct sockaddr_in *addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _KSSLADM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_create.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,972 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h> /* hostent */
+#include <netinet/in.h>
+#include <openssl/rsa.h>
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+#include <cryptoutil.h>
+#include <stdio.h>
+#include <strings.h>
+#include <sys/socket.h>
+#include <libscf.h>
+#include <inet/kssl/kssl.h>
+#include "kssladm.h"
+
+void
+usage_create(boolean_t do_print)
+{
+	if (do_print)
+		(void) fprintf(stderr, "Usage:\n");
+	(void) fprintf(stderr, "kssladm create"
+		" -f pkcs11 [-d softtoken_directory] -T <token_label>"
+		" -C <certificate_label> -x <proxy_port>"
+		" [options] [<server_address>] [<server_port>]\n");
+
+	(void) fprintf(stderr, "kssladm create"
+		" -f pkcs12 -i <certificate_file> -x <proxy_port>"
+		" [options] [<server_address>] [<server_port>]\n");
+
+	(void) fprintf(stderr, "kssladm create"
+		" -f pem -i <certificate_file> -x <proxy_port>"
+		" [options] [<server_address>] [<server_port>]\n");
+
+	(void) fprintf(stderr, "options are:\n"
+		"\t[-c <ciphersuites>]\n"
+		"\t[-p <password_file>]\n"
+		"\t[-t <ssl_session_cache_timeout>]\n"
+		"\t[-z <ssl_session_cache_size>]\n"
+		"\t[-v]\n");
+}
+
+static uchar_t *
+get_cert_val(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE cert_obj, int *len)
+{
+	CK_RV rv;
+	uchar_t *buf;
+	CK_ATTRIBUTE cert_attrs[] = {{CKA_VALUE, NULL, 0}};
+
+	/* the certs ... */
+	rv = C_GetAttributeValue(sess, cert_obj, cert_attrs, 1);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot get cert size."
+		    " error = %s\n", pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	buf = malloc(cert_attrs[0].ulValueLen);
+	if (buf == NULL)
+		return (NULL);
+	cert_attrs[0].pValue = buf;
+
+	rv = C_GetAttributeValue(sess, cert_obj, cert_attrs, 1);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot get cert value."
+		    " error = %s\n", pkcs11_strerror(rv));
+		free(buf);
+		return (NULL);
+	}
+
+	*len = cert_attrs[0].ulValueLen;
+	return (buf);
+}
+
+#define	REQ_ATTR_CNT	2
+#define	OPT_ATTR_CNT	6
+#define	MAX_ATTR_CNT	(REQ_ATTR_CNT + OPT_ATTR_CNT)
+
+/*
+ * Everything is allocated in one single contiguous buffer.
+ * The layout is the following:
+ * . the kssl_params_t structure
+ * . the array of sizes of the certificates, (value of sc_sizes_offset)
+ * . the array of key attribute structs, (value of ck_attrs)
+ * . the certificates values (values of sc_certs[i])
+ * . the key attributes values (values of ck_attrs[i].ck_value);
+ *
+ * The address of the certs and key attributes values are offsets
+ * from the beginning of the big buffer.
+ */
+static kssl_params_t *
+pkcs11_to_kssl(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE privkey_obj,
+    CK_OBJECT_HANDLE cert_obj, int *paramsize)
+{
+	int i;
+	CK_RV rv;
+	CK_ATTRIBUTE privkey_attrs[MAX_ATTR_CNT] = {
+		{CKA_MODULUS, NULL_PTR, 0},
+		{CKA_PRIVATE_EXPONENT, NULL_PTR, 0}
+	};
+	CK_ATTRIBUTE privkey_opt_attrs[OPT_ATTR_CNT] = {
+		{CKA_PUBLIC_EXPONENT, NULL_PTR, 0},
+		{CKA_PRIME_1, NULL_PTR, 0},
+		{CKA_PRIME_2, NULL_PTR, 0},
+		{CKA_EXPONENT_1, NULL_PTR, 0},
+		{CKA_EXPONENT_2, NULL_PTR, 0},
+		{CKA_COEFFICIENT, NULL_PTR, 0}
+	};
+	CK_ATTRIBUTE cert_attrs[] = { {CKA_VALUE, NULL, 0} };
+	kssl_object_attribute_t kssl_attrs[MAX_ATTR_CNT];
+	kssl_params_t *kssl_params;
+	kssl_key_t *key;
+	char *buf;
+	uint32_t cert_size, bufsize;
+	int attr_cnt;
+
+	/* the certs ... */
+	rv = C_GetAttributeValue(sess, cert_obj, cert_attrs, 1);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot get cert size."
+		    " error = %s\n", pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	/* Get the sizes */
+	bufsize = sizeof (kssl_params_t);
+	cert_size = (uint32_t)cert_attrs[0].ulValueLen;
+	bufsize += cert_size + sizeof (uint32_t);
+
+	/* and the required key attributes */
+	rv = C_GetAttributeValue(sess, privkey_obj, privkey_attrs,
+	    REQ_ATTR_CNT);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr,
+		    "Cannot get private key object attributes. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (NULL);
+	}
+	for (i = 0; i < REQ_ATTR_CNT; i++) {
+		bufsize += sizeof (crypto_object_attribute_t) +
+		    privkey_attrs[i].ulValueLen;
+	}
+	attr_cnt = REQ_ATTR_CNT;
+
+	/*
+	 * Get the optional key attributes. The return values could be
+	 * CKR_ATTRIBUTE_TYPE_INVALID with ulValueLen set to -1 OR
+	 * CKR_OK with ulValueLen set to 0. The latter is done by
+	 * soft token and seems dubious.
+	 */
+	rv = C_GetAttributeValue(sess, privkey_obj, privkey_opt_attrs,
+	    OPT_ATTR_CNT);
+	if (rv != CKR_OK && rv != CKR_ATTRIBUTE_TYPE_INVALID) {
+		(void) fprintf(stderr,
+		    "Cannot get private key object attributes. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (NULL);
+	}
+	for (i = 0; i < OPT_ATTR_CNT; i++) {
+		if (privkey_opt_attrs[i].ulValueLen == (CK_ULONG)-1 ||
+		    privkey_opt_attrs[i].ulValueLen == 0)
+			continue;
+		/* Structure copy */
+		privkey_attrs[attr_cnt] = privkey_opt_attrs[i];
+		bufsize += sizeof (crypto_object_attribute_t) +
+		    privkey_opt_attrs[i].ulValueLen;
+		attr_cnt++;
+	}
+
+	/* Now the big memory allocation */
+	if ((buf = calloc(bufsize, 1)) == NULL) {
+		(void) fprintf(stderr,
+			"Cannot allocate memory for the kssl_params "
+			"and values\n");
+		return (NULL);
+	}
+
+	/* LINTED */
+	kssl_params = (kssl_params_t *)buf;
+
+	buf = (char *)(kssl_params + 1);
+
+	kssl_params->kssl_certs.sc_count = 1;
+	bcopy(&cert_size, buf, sizeof (uint32_t));
+	kssl_params->kssl_certs.sc_sizes_offset = buf - (char *)kssl_params;
+	buf += sizeof (uint32_t);
+
+	/* the keys attributes structs array */
+	key = &kssl_params->kssl_privkey;
+	key->ks_format = CRYPTO_KEY_ATTR_LIST;
+	key->ks_count = attr_cnt;
+	key->ks_attrs_offset = buf - (char *)kssl_params;
+	buf += attr_cnt * sizeof (kssl_object_attribute_t);
+
+	/* now the certs values */
+	cert_attrs[0].pValue = buf;
+	kssl_params->kssl_certs.sc_certs_offset = buf - (char *)kssl_params;
+	buf += cert_attrs[0].ulValueLen;
+
+	rv = C_GetAttributeValue(sess, cert_obj, cert_attrs, 1);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot get cert value."
+		    " error = %s\n", pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	/* then the attributes values */
+	for (i = 0; i < attr_cnt; i++) {
+		privkey_attrs[i].pValue = buf;
+		/*
+		 * We assume the attribute types in the kernel are
+		 * the same as the PKCS #11 values.
+		 */
+		kssl_attrs[i].ka_type = privkey_attrs[i].type;
+		kssl_attrs[i].ka_value_offset = buf - (char *)kssl_params;
+
+		kssl_attrs[i].ka_value_len = privkey_attrs[i].ulValueLen;
+
+		buf += privkey_attrs[i].ulValueLen;
+	}
+	/* then the key attributes values */
+	rv = C_GetAttributeValue(sess, privkey_obj, privkey_attrs, attr_cnt);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr,
+		    "Cannot get private key object attributes."
+		    " error = %s\n", pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	bcopy(kssl_attrs, ((char *)kssl_params) + key->ks_attrs_offset,
+	    attr_cnt * sizeof (kssl_object_attribute_t));
+
+	*paramsize = bufsize;
+	return (kssl_params);
+}
+
+#define	max_num_cert 32
+
+kssl_params_t *
+load_from_pkcs11(const char *token_label, const char *password_file,
+	const char *certname, int *bufsize)
+{
+	static CK_BBOOL true = TRUE;
+	static CK_BBOOL false = FALSE;
+
+	CK_RV rv;
+	CK_SLOT_ID slot;
+	CK_SLOT_ID_PTR	pk11_slots;
+	CK_ULONG slotcnt = 10;
+	CK_TOKEN_INFO	token_info;
+	CK_SESSION_HANDLE sess;
+	static CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
+	static CK_CERTIFICATE_TYPE cert_type = CKC_X_509;
+	CK_ATTRIBUTE cert_tmpl[4] = {
+		{CKA_TOKEN, &true, sizeof (true)},
+		{CKA_LABEL, NULL, 0},
+		{CKA_CLASS, &cert_class, sizeof (cert_class)},
+		{CKA_CERTIFICATE_TYPE, &cert_type, sizeof (cert_type)}
+	};
+	CK_ULONG cert_tmpl_count = 4, cert_obj_count = 1;
+	CK_OBJECT_HANDLE cert_obj, privkey_obj;
+	CK_OBJECT_HANDLE cert_objs[max_num_cert];
+	static CK_OBJECT_CLASS privkey_class = CKO_PRIVATE_KEY;
+	static CK_KEY_TYPE privkey_type = CKK_RSA;
+	CK_ATTRIBUTE privkey_tmpl[] = {
+		{CKA_MODULUS, NULL, 0},
+		{CKA_TOKEN, &true, sizeof (true)},
+		{CKA_CLASS, &privkey_class, sizeof (privkey_class)},
+		{CKA_KEY_TYPE, &privkey_type, sizeof (privkey_type)}
+	};
+	CK_ULONG privkey_tmpl_count = 4, privkey_obj_count = 1;
+	static CK_BYTE modulus[1024];
+	CK_ATTRIBUTE privkey_attrs[1] = {
+		{CKA_MODULUS, modulus, sizeof (modulus)},
+	};
+	boolean_t bingo = B_FALSE;
+	int blen, mlen;
+	uchar_t *mval, *ber_buf;
+	char token_label_padded[sizeof (token_info.label) + 1];
+
+	(void) snprintf(token_label_padded, sizeof (token_label_padded),
+		"%-32s", token_label);
+
+	rv = C_Initialize(NULL_PTR);
+
+	if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
+		(void) fprintf(stderr,
+		    "Cannot initialize PKCS#11. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	/* Get slot count */
+	rv = C_GetSlotList(1, NULL_PTR, &slotcnt);
+	if (rv != CKR_OK || slotcnt == 0) {
+		(void) fprintf(stderr,
+		    "Cannot get PKCS#11 slot list. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	pk11_slots = calloc(slotcnt, sizeof (CK_SLOT_ID));
+	if (pk11_slots == NULL) {
+		(void) fprintf(stderr,
+		    "Cannot get memory for %ld slots\n", slotcnt);
+		return (NULL);
+	}
+
+	rv = C_GetSlotList(1, pk11_slots, &slotcnt);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr,
+		    "Cannot get PKCS#11 slot list. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	if (verbose)
+		(void) printf("Found %ld slots\n", slotcnt);
+
+	/* Search the token that matches the label */
+	while (slotcnt > 0) {
+		rv = C_GetTokenInfo(pk11_slots[--slotcnt], &token_info);
+		if (rv != CKR_OK)
+			continue;
+
+		if (verbose)
+			(void) printf("slot [%ld] = %s\n",
+			    slotcnt, token_info.label);
+		if (memcmp(token_label_padded, token_info.label,
+		    sizeof (token_info.label)) == 0) {
+			bingo = B_TRUE;
+			slot = pk11_slots[slotcnt];
+			break;
+		}
+		if (verbose) {
+			token_info.label[31] = '\0';
+			(void) printf("found slot [%s]\n", token_info.label);
+		}
+	}
+
+	if (!bingo) {
+		(void) fprintf(stderr, "no matching PKCS#11 token found\n");
+		return (NULL);
+	}
+
+	rv = C_OpenSession(slot, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
+		&sess);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot open session. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	cert_tmpl[1].pValue = (CK_VOID_PTR) certname;
+	cert_tmpl[1].ulValueLen = strlen(certname);
+
+	rv = C_FindObjectsInit(sess, cert_tmpl, cert_tmpl_count);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr,
+		    "Cannot intialize cert search."
+		    " error = %s\n", pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	rv = C_FindObjects(sess, cert_objs,
+		(certname == NULL ? 1 : max_num_cert), &cert_obj_count);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr,
+		    "Cannot retrieve cert object. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	/* Who cares if this fails! */
+	(void) C_FindObjectsFinal(sess);
+	if (verbose)
+		(void) printf("found %ld certificates\n", cert_obj_count);
+
+	if (cert_obj_count == 0) {
+		(void) fprintf(stderr, "\"%s\" not found.\n", certname);
+		(void) fprintf(stderr, "no certs. bye.\n");
+		return (NULL);
+	}
+
+	cert_obj = cert_objs[0];
+
+	/* Get the modulus value from the certificate */
+	ber_buf = get_cert_val(sess, cert_obj, &blen);
+	if (ber_buf == NULL) {
+		(void) fprintf(stderr,
+		    "Cannot get certificate data for \"%s\".\n", certname);
+		return (NULL);
+	}
+
+	mval = get_modulus(ber_buf, blen, &mlen);
+	if (mval == NULL) {
+		(void) fprintf(stderr,
+		    "Cannot get Modulus in certificate \"%s\".\n", certname);
+		return (NULL);
+	}
+
+	/* Now get the private key */
+
+	/* Gotta authenticate first if login is required. */
+	if (token_info.flags & CKF_LOGIN_REQUIRED) {
+		char passphrase[1024];
+		CK_ULONG ulPinLen;
+
+		ulPinLen = get_passphrase(
+		    password_file, passphrase, sizeof (passphrase));
+		if (ulPinLen == 0) {
+			(void) fprintf(stderr, "Unable to read passphrase");
+			return (NULL);
+		}
+
+		rv = C_Login(sess, CKU_USER, (CK_UTF8CHAR_PTR)passphrase,
+		    ulPinLen);
+		if (rv != CKR_OK) {
+			(void) fprintf(stderr, "Cannot login to the token."
+			    " error = %s\n", pkcs11_strerror(rv));
+		return (NULL);
+		}
+	}
+
+	privkey_tmpl[0].pValue = mval;
+	privkey_tmpl[0].ulValueLen = mlen;
+
+	rv = C_FindObjectsInit(sess, privkey_tmpl, privkey_tmpl_count);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot intialize private key search."
+		    " error = %s\n", pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	rv = C_FindObjects(sess, &privkey_obj, 1,  &privkey_obj_count);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot retrieve private key object "
+		    " error = %s\n", pkcs11_strerror(rv));
+		return (NULL);
+	}
+	/* Who cares if this fails! */
+	(void) C_FindObjectsFinal(sess);
+
+
+	(void) printf("found %ld private keys\n", privkey_obj_count);
+
+	if (privkey_obj_count == 0) {
+		(void) fprintf(stderr, "no private keys. bye.\n");
+		return (NULL);
+	}
+
+	rv = C_GetAttributeValue(sess, privkey_obj, privkey_attrs, 1);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr,
+		    "Cannot get private key object attributes."
+		    " error = %s\n", pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	if (verbose) {
+		(void) printf("private key attributes:    \n");
+		(void) printf("\tmodulus: size %ld value:",
+		    privkey_attrs[0].ulValueLen);
+	}
+
+	/* Now wrap the key, then unwrap it */
+
+	{
+	CK_BYTE	aes_key_val[16] = {
+		1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+	static CK_BYTE aes_param[16] = {
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+	CK_MECHANISM aes_cbc_pad_mech = {CKM_AES_CBC_PAD, aes_param, 16};
+	CK_OBJECT_HANDLE aes_key_obj, sess_privkey_obj;
+	CK_BYTE *wrapped_privkey;
+	CK_ULONG wrapped_privkey_len;
+
+	CK_ATTRIBUTE unwrap_tmpl[] = {
+		{CKA_TOKEN, &false, sizeof (false)},
+		{CKA_CLASS, &privkey_class, sizeof (privkey_class)},
+		{CKA_KEY_TYPE, &privkey_type, sizeof (privkey_type)},
+		{CKA_SENSITIVE, &false, sizeof (false)},
+		{CKA_PRIVATE, &false, sizeof (false)}
+	};
+
+	rv = SUNW_C_KeyToObject(sess, CKM_AES_CBC_PAD, aes_key_val, 16,
+	    &aes_key_obj);
+
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr,
+		    "Cannot create wrapping key. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	/* get the size of the wrapped key */
+	rv = C_WrapKey(sess, &aes_cbc_pad_mech, aes_key_obj, privkey_obj,
+	    NULL, &wrapped_privkey_len);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot get key size. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	wrapped_privkey = malloc(wrapped_privkey_len * sizeof (CK_BYTE));
+	if (wrapped_privkey == NULL) {
+		return (NULL);
+	}
+
+	/* do the actual key wrapping */
+	rv = C_WrapKey(sess, &aes_cbc_pad_mech, aes_key_obj, privkey_obj,
+	    wrapped_privkey, &wrapped_privkey_len);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot wrap private key. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (NULL);
+	}
+
+	(void) C_Logout(sess);
+	(void) printf("private key successfully wrapped, "
+		"wrapped blob length: %ld\n",
+		wrapped_privkey_len);
+
+	rv = C_UnwrapKey(sess, &aes_cbc_pad_mech, aes_key_obj,
+	    wrapped_privkey, wrapped_privkey_len,
+	    unwrap_tmpl, 5, &sess_privkey_obj);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot unwrap private key."
+		    " error = %s\n", pkcs11_strerror(rv));
+		return (NULL);
+	}
+	(void) printf("session private key successfully unwrapped\n");
+
+	return (pkcs11_to_kssl(sess, sess_privkey_obj, cert_obj, bufsize));
+	}
+}
+
+
+static kssl_params_t *
+openssl_to_kssl(RSA *rsa, uchar_t *cert_buf, int cert_size, int *paramsize)
+{
+	int i;
+	kssl_params_t *kssl_params;
+	kssl_key_t *key;
+	char *buf;
+	uint32_t bufsize;
+	kssl_object_attribute_t kssl_attrs[MAX_ATTR_CNT];
+	kssl_object_attribute_t kssl_tmpl_attrs[MAX_ATTR_CNT] = {
+		{SUN_CKA_MODULUS, NULL, 0},
+		{SUN_CKA_PUBLIC_EXPONENT, NULL, 0},
+		{SUN_CKA_PRIVATE_EXPONENT, NULL, 0},
+		{SUN_CKA_PRIME_1, NULL, 0},
+		{SUN_CKA_PRIME_2, NULL, 0},
+		{SUN_CKA_EXPONENT_1, NULL, 0},
+		{SUN_CKA_EXPONENT_2, NULL, 0},
+		{SUN_CKA_COEFFICIENT, NULL, 0}
+	};
+	BIGNUM *priv_key_bignums[MAX_ATTR_CNT];
+	int attr_cnt;
+
+	bufsize = sizeof (kssl_params_t);
+	bufsize += cert_size + sizeof (uint32_t);
+
+	/* and the key attributes */
+	priv_key_bignums[0] = rsa->n;		/* MODULUS */
+	priv_key_bignums[1] = rsa->e; 		/* PUBLIC_EXPONENT */
+	priv_key_bignums[2] = rsa->d; 		/* PRIVATE_EXPONENT */
+	priv_key_bignums[3] = rsa->p;		/* PRIME_1 */
+	priv_key_bignums[4] = rsa->q;		/* PRIME_2 */
+	priv_key_bignums[5] = rsa->dmp1;	/* EXPONENT_1 */
+	priv_key_bignums[6] = rsa->dmq1;	/* EXPONENT_2 */
+	priv_key_bignums[7] = rsa->iqmp;	/* COEFFICIENT */
+
+	if (rsa->n == NULL || rsa->d == NULL) {
+		(void) fprintf(stderr,
+		    "missing required attributes in private key.\n");
+		return (NULL);
+	}
+
+	attr_cnt = 0;
+	for (i = 0; i < MAX_ATTR_CNT; i++) {
+		if (priv_key_bignums[i] == NULL)
+			continue;
+		kssl_attrs[attr_cnt].ka_type = kssl_tmpl_attrs[i].ka_type;
+		kssl_attrs[attr_cnt].ka_value_len =
+		    BN_num_bytes(priv_key_bignums[i]);
+		bufsize += sizeof (crypto_object_attribute_t) +
+		    kssl_attrs[attr_cnt].ka_value_len;
+		attr_cnt++;
+	}
+
+	/* Now the big memory allocation */
+	if ((buf = calloc(bufsize, 1)) == NULL) {
+		(void) fprintf(stderr,
+		    "Cannot allocate memory for the kssl_params "
+		    "and values\n");
+		return (NULL);
+	}
+
+	/* LINTED */
+	kssl_params = (kssl_params_t *)buf;
+
+	buf = (char *)(kssl_params + 1);
+
+	kssl_params->kssl_certs.sc_count = 1;
+	bcopy(&cert_size, buf, sizeof (uint32_t));
+	kssl_params->kssl_certs.sc_sizes_offset = buf - (char *)kssl_params;
+	buf += sizeof (uint32_t);
+
+	/* the keys attributes structs array */
+	key = &kssl_params->kssl_privkey;
+	key->ks_format = CRYPTO_KEY_ATTR_LIST;
+	key->ks_count = attr_cnt;
+	key->ks_attrs_offset = buf - (char *)kssl_params;
+	buf += attr_cnt * sizeof (kssl_object_attribute_t);
+
+	/* now the certs values */
+	bcopy(cert_buf, buf, cert_size);
+	kssl_params->kssl_certs.sc_certs_offset = buf - (char *)kssl_params;
+	buf += cert_size;
+
+	attr_cnt = 0;
+	/* then the key attributes values */
+	for (i = 0; i < MAX_ATTR_CNT; i++) {
+		if (priv_key_bignums[i] == NULL)
+			continue;
+		(void) BN_bn2bin(priv_key_bignums[i], (unsigned char *)buf);
+		kssl_attrs[attr_cnt].ka_value_offset =
+		    buf - (char *)kssl_params;
+		buf += kssl_attrs[attr_cnt].ka_value_len;
+		attr_cnt++;
+	}
+
+	bcopy(kssl_attrs, ((char *)kssl_params) + key->ks_attrs_offset,
+	    attr_cnt * sizeof (kssl_object_attribute_t));
+
+	*paramsize = bufsize;
+	return (kssl_params);
+}
+
+kssl_params_t *
+load_from_pem(const char *filename, const char *password_file, int *paramsize)
+{
+	uchar_t *cert_buf;
+	int cert_size;
+	RSA *rsa;
+	kssl_params_t *kssl_params;
+
+	rsa = PEM_get_rsa_key(filename, (char *)password_file);
+	if (rsa == NULL) {
+		(void) fprintf(stderr, "cannot read the private key\n");
+		return (NULL);
+	}
+
+	if (verbose)
+		(void) printf("private key read successfully\n");
+
+	cert_buf = PEM_get_cert(filename, (char *)password_file, &cert_size);
+	if (cert_buf == NULL) {
+		RSA_free(rsa);
+		return (NULL);
+	}
+
+	if (verbose)
+		(void) printf("certificate read successfully size=%d\n",
+		    cert_size);
+
+	kssl_params = openssl_to_kssl(rsa, cert_buf, cert_size, paramsize);
+
+	free(cert_buf);
+	RSA_free(rsa);
+	return (kssl_params);
+}
+
+kssl_params_t *
+load_from_pkcs12(const char *filename, const char *password_file,
+    int *paramsize)
+{
+	uchar_t *cert_buf;
+	int cert_size;
+	RSA *rsa;
+	kssl_params_t *kssl_params;
+
+	if (PKCS12_get_rsa_key_cert(filename, password_file, &rsa, &cert_buf,
+	    &cert_size) < 0) {
+		(void) fprintf(stderr,
+		    "Unable to read cert and/or key from %s\n", filename);
+		return (NULL);
+	}
+
+	if (verbose)
+		(void) printf(
+		    "key/certificate read successfully cert_size=%d\n",
+		    cert_size);
+
+	kssl_params = openssl_to_kssl(rsa, cert_buf, cert_size, paramsize);
+
+	free(cert_buf);
+	RSA_free(rsa);
+	return (kssl_params);
+}
+
+
+int
+parse_and_set_addr(char *server_address, char *server_port,
+    struct sockaddr_in *addr)
+{
+	if (server_port == NULL) {
+		return (-1);
+	}
+
+	if (server_address == NULL) {
+		addr->sin_addr.s_addr = INADDR_ANY;
+	} else {
+		addr->sin_addr.s_addr = inet_addr(server_address);
+		if ((int)addr->sin_addr.s_addr == -1) {
+			struct hostent *hp;
+
+			if ((hp = gethostbyname(server_address)) == NULL) {
+				(void) fprintf(stderr,
+				    "Error: Unknown host: %s\n",
+				    server_address);
+				return (-1);
+			}
+
+			(void) memcpy(&addr->sin_addr.s_addr,
+			    hp->h_addr_list[0],
+			    sizeof (addr->sin_addr.s_addr));
+		}
+	}
+
+	errno = 0;
+	addr->sin_port = strtol(server_port, NULL, 10);
+	if (addr->sin_port == 0 || errno != 0) {
+		(void) fprintf(stderr, "Error: Invalid Port value: %s\n",
+		    server_port);
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * The order of the ciphers is important. It is used as the
+ * default order (when -c is not specified).
+ */
+struct csuite {
+	const char *suite;
+	uint16_t val;
+	boolean_t seen;
+} cipher_suites[CIPHER_SUITE_COUNT - 1] = {
+	{"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA, B_FALSE},
+	{"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5, B_FALSE},
+	{"rsa_3des_ede_cbc_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA, B_FALSE},
+	{"rsa_des_cbc_sha", SSL_RSA_WITH_DES_CBC_SHA, B_FALSE},
+};
+
+int
+check_suites(char *suites, uint16_t *sarray)
+{
+	int i;
+	int err = 0;
+	char *suite;
+	int sindx = 0;
+
+	if (suites != NULL) {
+		for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++)
+			sarray[i] = CIPHER_NOTSET;
+	} else {
+		for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++)
+			sarray[i] = cipher_suites[i].val;
+		return (err);
+	}
+
+	suite = strtok(suites, ",");
+	do {
+		for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++) {
+			if (strcasecmp(suite, cipher_suites[i].suite) == 0) {
+				if (!cipher_suites[i].seen) {
+					sarray[sindx++] = cipher_suites[i].val;
+					cipher_suites[i].seen = B_TRUE;
+				}
+				break;
+			}
+		}
+
+		if (i == (CIPHER_SUITE_COUNT - 1)) {
+			(void) fprintf(stderr,
+			    "Unknown Cipher suite name: %s\n", suite);
+			err++;
+		}
+	} while ((suite = strtok(NULL, ",")) != NULL);
+
+	return (err);
+}
+
+int
+do_create(int argc, char *argv[])
+{
+	const char *softtoken_dir = NULL;
+	const char *token_label = NULL;
+	const char *password_file = NULL;
+	const char *filename = NULL;
+	const char *certname = NULL;
+	char *suites = NULL;
+	uint32_t timeout = DEFAULT_SID_TIMEOUT;
+	uint32_t scache_size = DEFAULT_SID_CACHE_NENTRIES;
+	int proxy_port = -1;
+	struct sockaddr_in server_addr;
+	char *format = NULL;
+	char *port, *addr;
+	char c;
+	int pcnt;
+	kssl_params_t *kssl_params;
+	int bufsize;
+
+	argc -= 1;
+	argv += 1;
+
+	while ((c = getopt(argc, argv, "vT:d:f:i:p:c:C:t:x:z:")) != -1) {
+		switch (c) {
+		case 'd':
+			softtoken_dir = optarg;
+			break;
+		case 'c':
+			suites = optarg;
+			break;
+		case 'C':
+			certname = optarg;
+			break;
+		case 'f':
+			format = optarg;
+			break;
+		case 'i':
+			filename = optarg;
+			break;
+		case 'T':
+			token_label = optarg;
+			break;
+		case 'p':
+			password_file = optarg;
+			break;
+		case 't':
+			timeout = atoi(optarg);
+			break;
+		case 'x':
+			proxy_port = atoi(optarg);
+			break;
+		case 'v':
+			verbose = B_TRUE;
+			break;
+		case 'z':
+			scache_size = atoi(optarg);
+			break;
+		default:
+			goto err;
+		}
+	}
+
+	pcnt = argc - optind;
+	if (pcnt == 0) {
+		port = "443";	/* default SSL port */
+		addr = NULL;
+	} else if (pcnt == 1) {
+		port = argv[optind];
+		addr = NULL;
+	} else if (pcnt == 2) {
+		addr = argv[optind];
+		port = argv[optind + 1];
+	} else {
+		goto err;
+	}
+
+	if (parse_and_set_addr(addr, port, &server_addr) < 0) {
+		goto err;
+	}
+
+	if (verbose) {
+		(void) printf("addr=%s, port = %d\n",
+		    inet_ntoa(server_addr.sin_addr), server_addr.sin_port);
+	}
+
+	if (format == NULL || proxy_port == -1) {
+		goto err;
+	}
+
+	if (strcmp(format, "pkcs11") == 0) {
+		if (token_label == NULL || certname == NULL) {
+			goto err;
+		}
+		if (softtoken_dir != NULL) {
+			(void) setenv("SOFTTOKEN_DIR", softtoken_dir, 1);
+			if (verbose) {
+				(void) printf(
+				    "SOFTTOKEN_DIR=%s\n",
+				    getenv("SOFTTOKEN_DIR"));
+			}
+		}
+		kssl_params = load_from_pkcs11(
+		    token_label, password_file, certname, &bufsize);
+	} else if (strcmp(format, "pkcs12") == 0) {
+		if (filename == NULL) {
+			goto err;
+		}
+		kssl_params = load_from_pkcs12(
+		    filename, password_file, &bufsize);
+	} else if (strcmp(format, "pem") == 0) {
+		if (filename == NULL) {
+			goto err;
+		}
+		kssl_params = load_from_pem(
+		    filename, password_file, &bufsize);
+	} else {
+		(void) fprintf(stderr, "Unsupported cert format: %s\n", format);
+		goto err;
+	}
+
+	if (kssl_params == NULL) {
+		return (FAILURE);
+	}
+
+	if (check_suites(suites, kssl_params->kssl_suites) != 0)
+		goto err;
+
+	kssl_params->kssl_params_size = bufsize;
+	kssl_params->kssl_addr = server_addr;
+	kssl_params->kssl_session_cache_timeout = timeout;
+	kssl_params->kssl_proxy_port = proxy_port;
+	kssl_params->kssl_session_cache_size = scache_size;
+
+	if (kssl_send_command((char *)kssl_params, KSSL_ADD_ENTRY) < 0) {
+		(void) fprintf(stderr, "Error loading cert and key");
+		return (FAILURE);
+	}
+
+	if (verbose)
+		(void) printf("Successfully loaded cert and key\n");
+
+	free(kssl_params);
+	return (SUCCESS);
+
+err:
+	usage_create(B_TRUE);
+	return (SMF_EXIT_ERR_CONFIG);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_delete.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,98 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <netinet/in.h> /* struct sockaddr_in */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <libscf.h>
+#include <inet/kssl/kssl.h>
+#include "kssladm.h"
+
+void
+usage_delete(boolean_t do_print)
+{
+	if (do_print)
+		(void) fprintf(stderr, "Usage:\n");
+	(void) fprintf(stderr,
+	    "kssladm delete [-v] [<server_address>] <server_port>\n");
+}
+
+int
+do_delete(int argc, char *argv[])
+{
+	struct sockaddr_in server_addr;
+	char c;
+	char *port, *addr;
+	int pcnt;
+
+	if (argc < 3) {
+		goto err;
+	}
+
+	argc -= 1;
+	argv += 1;
+
+	while ((c = getopt(argc, argv, "v")) != -1) {
+		switch (c) {
+		case 'v':
+			verbose = B_TRUE;
+			break;
+		default:
+			goto err;
+		}
+	}
+
+	pcnt = argc - optind;
+	if (pcnt == 1) {
+		port = argv[optind];
+		addr = NULL;
+	} else if (pcnt == 2) {
+		addr = argv[optind];
+		port = argv[optind + 1];
+	}
+
+	if (parse_and_set_addr(addr, port, &server_addr) < 0) {
+		goto err;
+	}
+
+	if (kssl_send_command((char *)&server_addr, KSSL_DELETE_ENTRY) < 0) {
+		perror("Error deleting entry");
+		return (FAILURE);
+	}
+
+	if (verbose)
+		(void) printf("Successfully loaded cert and key\n");
+
+	return (SUCCESS);
+
+err:
+	usage_delete(B_TRUE);
+	return (SMF_EXIT_ERR_CONFIG);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,265 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <assert.h>
+#include <strings.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+#include "kssladm.h"
+
+static void
+print_crypto_error(void)
+{
+	ERR_load_crypto_strings();
+	ERR_print_errors_fp(stderr);
+}
+
+/* ARGSUSED */
+static int
+pem_password_callback(char *buf, int size, int rwflag, void *userdata)
+{
+	return (get_passphrase((const char *)userdata, buf, size));
+}
+
+
+static STACK_OF(X509_INFO) *
+PEM_get_x509_info_stack(const char *filename, char *passphrase)
+{
+	FILE *fp;
+	STACK_OF(X509_INFO) *x509_info_stack;
+
+	fp = fopen(filename, "r");
+	if (fp == NULL) {
+		perror("Unable to open pem file for reading");
+		return (NULL);
+	}
+	if (verbose)
+		(void) printf("In PEM_get_x509_info_stack: %s opened\n",
+		    filename);
+
+	OpenSSL_add_all_algorithms();
+
+	x509_info_stack = PEM_X509_INFO_read(
+	    fp, NULL, pem_password_callback, passphrase);
+	(void) fclose(fp);
+
+	if (x509_info_stack == NULL) {
+		print_crypto_error();
+	}
+
+	return (x509_info_stack);
+}
+
+
+RSA *
+PEM_get_rsa_key(const char *filename, char *passphrase)
+{
+	FILE *fp;
+	RSA *rsa_key;
+
+	fp = fopen(filename, "r");
+	if (fp == NULL) {
+		perror("Unable to open pem file for reading");
+		return (NULL);
+	}
+	if (verbose)
+		(void) printf("In PEM_get_rsa_key: %s opened\n", filename);
+
+	OpenSSL_add_all_algorithms();
+
+	rsa_key = PEM_read_RSAPrivateKey(
+	    fp, NULL, pem_password_callback, passphrase);
+	(void) fclose(fp);
+
+	if (rsa_key == NULL) {
+		print_crypto_error();
+	}
+
+	return (rsa_key);
+}
+
+uchar_t *
+get_modulus(uchar_t *ber_buf, int buflen, int *modlen)
+{
+	int i, j, v;
+	X509 *x;
+	EVP_PKEY *pkey;
+	BIGNUM *bn;
+	uchar_t *m = NULL, *mptr;
+
+	x = d2i_X509(NULL, &ber_buf, buflen);
+	if (x != NULL) {
+		pkey = X509_get_pubkey(x);
+		if (pkey == NULL) {
+			X509_free(x);
+			return (NULL);
+		}
+
+		bn = pkey->pkey.rsa->n;
+		mptr = m = malloc(bn->top * BN_BYTES);
+		for (i = bn->top - 1; i >= 0; i--) {
+			for (j = BN_BITS2 - 8; j >= 0; j -= 8) {
+				v = ((int)(bn->d[i] >> (long)j)) & 0xff;
+				*m = v;
+				m++;
+			}
+		}
+		*modlen = bn->top * BN_BYTES;
+		EVP_PKEY_free(pkey);
+		X509_free(x);
+	}
+
+	return (mptr);
+}
+
+static uchar_t *
+X509_to_bytes(X509 *cert, int *cert_size)
+{
+	uchar_t *cert_buf = NULL;
+	int size;
+
+	size = i2d_X509(cert, &cert_buf);
+	if (size < 0)  {
+		perror("Invalid cert\n");
+		return (NULL);
+	}
+
+	*cert_size = size;
+	return (cert_buf);
+}
+
+
+/* Returns DER encoded cert */
+uchar_t *
+PEM_get_cert(const char *filename, char *passphrase, int *cert_size)
+{
+	STACK_OF(X509_INFO) *x509_info_stack;
+	uchar_t *cert_buf;
+	X509_INFO *info;
+
+	x509_info_stack = PEM_get_x509_info_stack(filename, passphrase);
+	if (x509_info_stack == NULL) {
+		return (NULL);
+	}
+
+	/* LINTED */
+	info = sk_X509_INFO_pop(x509_info_stack);
+	if (info == NULL || info->x509 == NULL) {
+		(void) fprintf(stderr, "No cert found\n");
+		return (NULL);
+	}
+
+	cert_buf = X509_to_bytes(info->x509, cert_size);
+	X509_INFO_free(info);
+	return (cert_buf);
+}
+
+#include <openssl/pkcs12.h>
+static PKCS12 *
+PKCS12_load(const char *filename)
+{
+	FILE *fp;
+	PKCS12 *p12;
+
+	fp = fopen(filename, "r");
+	if (fp == NULL) {
+		perror("Unnable to open file for reading");
+		return (NULL);
+	}
+
+	OpenSSL_add_all_algorithms();
+
+	p12 = d2i_PKCS12_fp(fp, NULL);
+	(void) fclose(fp);
+	if (p12 == NULL) {
+		ERR_load_PKCS12_strings();
+		ERR_print_errors_fp(stderr);
+		(void) fprintf(stderr, "Unable to load from %s\n", filename);
+		return (NULL);
+	}
+
+	return (p12);
+}
+
+int
+PKCS12_get_rsa_key_cert(const char *filename, const char *password_file,
+	RSA **rsa, uchar_t **cert, int *cert_size)
+{
+	int rv = -1;
+	EVP_PKEY *pkey = NULL;
+	X509 *x509 = NULL;
+	char *password = NULL;
+	char password_buf[1024];
+	PKCS12 *p12;
+
+	p12 = PKCS12_load(filename);
+	if (p12 == NULL) {
+		goto out0;
+	}
+
+	if (! PKCS12_verify_mac(p12, NULL, 0)) {
+		if (get_passphrase(
+		    password_file, password_buf, sizeof (password_buf)) <= 0) {
+			perror("Unnable to read passphrase");
+			goto out0;
+		}
+
+		password = password_buf;
+	}
+
+	(void) PKCS12_parse(p12, password, &pkey, &x509, NULL);
+
+	PKCS12_free(p12);
+	if (pkey == NULL) {
+		(void) fprintf(stderr, "No key returned\n");
+		goto out0;
+	}
+	if (x509 == NULL) {
+		(void) fprintf(stderr, "No cert returned\n");
+		goto out1;
+	}
+
+	*rsa = EVP_PKEY_get1_RSA(pkey);
+	if (*rsa == NULL) {
+		goto out2;
+	}
+
+	*cert = X509_to_bytes(x509, cert_size);
+
+	if (*cert != NULL) {
+		rv = 0;
+	}
+
+out2:
+	X509_free(x509);
+out1:
+	EVP_PKEY_free(pkey);
+out0:
+	return (rv);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/Makefile	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,87 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+# 
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# cmd/cmd-inet/usr.sbin/kssl/kssladm/Makefile
+#
+
+PROG= ksslcfg
+MANIFEST= kssl-proxy.xml
+
+include $(SRC)/cmd/Makefile.cmd
+
+OBJS =	\
+    ksslcfg.o \
+    ksslcfg_create.o \
+    ksslcfg_delete.o
+
+POFILES = $(OBJS:%.o=%.po)
+POFILE = $(PROG)_all.po
+
+SRCS = $(OBJS:%.o=%.c)
+
+ROOTMANIFESTDIR= $(ROOTSVCNETWORK)/ssl
+$(ROOTMANIFEST):= FILEMODE= 444
+
+$(ROOTMANIFESTDIR)/%: %
+	$(INS.file)
+
+.KEEP_STATE:
+
+CFLAGS +=	$(CCVERBOSE)
+
+LDLIBS += -lscf -lnsl
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+	$(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(DYNFLAGS)
+	$(POST_PROCESS)
+
+$(POFILE): $(POFILES)
+	$(RM) $@; cat $(POFILES) > $@
+
+install: all $(ROOTUSRSBINPROG) $(ROOTMANIFEST)
+
+clean:
+	$(RM) $(OBJS)
+
+check: $(CHKMANIFEST)
+	$(CSTYLE) -pP $(SRCS)
+
+lint:	lint_SRCS
+
+$(ROOTUSRSBINPROG): $(ROOTUSRSBIN)
+
+$(ROOTUSRSBIN):
+	$(MKDIR) -p $@
+
+$(ROOTMANIFEST): $(ROOTSVCNETWORK)/ssl
+
+$(ROOTSVCNETWORK)/ssl:
+	$(MKDIR) -p $@
+
+include ../../../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/kssl-proxy.xml	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+	Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+	Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License").  You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+	ident	"%Z%%M%	%I%	%E% SMI"
+
+	NOTE:  This service manifest is not editable; its contents will
+	be overwritten by package or patch operations, including
+	operating system upgrade.  Make customizations in a different
+	file.
+-->
+
+<service_bundle type='manifest' name='SUNWcsr:kssl-proxy'>
+
+<service
+	name='network/ssl/proxy'
+	type='service'
+	version='1'>
+
+	<dependency
+	    name='cryptosvc'
+	    grouping='require_all'
+	    restart_on='none'
+	    type='service'>
+		<service_fmri value='svc:/system/cryptosvc' />
+	</dependency>
+
+	<dependency
+	    name='name-services'
+	    grouping='require_all'
+	    restart_on='none'
+	    type='service'>
+		<service_fmri value='svc:/milestone/name-services' />
+	</dependency>
+
+	<property_group name='startd' type='framework'>
+		<propval name='duration' type='astring' value='transient' />
+	</property_group>
+
+	<stability value='Unstable' />
+
+	<template>
+		<common_name>
+			<loctext xml:lang='C'>
+			kernel ssl proxy configuration
+			</loctext>
+		</common_name>
+		<documentation>
+			<manpage title='ksslcfg' section='1M'
+			    manpath='/usr/share/man' />
+		</documentation>
+	</template>
+
+</service>
+
+</service_bundle>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,246 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <arpa/inet.h> /* inet_addr() */
+#include <ctype.h>
+#include <libscf.h>
+#include <netdb.h> /* hostent */
+#include <netinet/in.h> /* ip_addr_t */
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <strings.h>
+#include <sys/varargs.h>
+#include "ksslcfg.h"
+
+/*
+ * ksslcfg(1M)
+ *
+ * ksslcfg manages smf(5) instances for the Kernel SSL proxy module.
+ * It makes use of kssladm(1M) which does the grunt work.
+ */
+
+#define	KSSLCFG_VERSION "1.0"
+
+boolean_t verbose = B_FALSE;
+const char *SERVICE_NAME = "network/ssl/proxy";
+
+void
+KSSL_DEBUG(const char *format, ...)
+{
+	va_list ap;
+
+	if (verbose) {
+		va_start(ap, format);
+		(void) vprintf(format, ap);
+		va_end(ap);
+	}
+}
+
+int
+get_portnum(const char *s, ushort_t *rport)
+{
+	unsigned long port;
+
+	errno = 0;
+	port = strtoul(s, NULL, 10);
+	if (port > USHRT_MAX || port == 0 || errno != 0) {
+		return (0);
+	}
+
+	if (rport != NULL)
+		*rport = (ushort_t)port;
+	return (1);
+}
+
+#define	ANY_ADDR	"INADDR_ANY"
+
+/*
+ * An instance name is formed using either the host name in the fully
+ * qualified domain name form (FQDN) which should map to a specific IP address
+ * or using INADDR_ANY which means all IP addresses.
+ *
+ * We do a lookup or reverse lookup to get the host name. It is assumed that
+ * the returned name is in the FQDN form. i.e. DNS is used.
+ */
+char *
+create_instance_name(const char *arg, char **inaddr_any_name,
+    boolean_t is_create)
+{
+	int len;
+	uint16_t port;
+	char *cname;
+	in_addr_t addr;
+	char *instance_name;
+	const char *prefix = "kssl-";
+	char *first_space = strchr(arg, ' ');
+
+	if (first_space == NULL) {
+		if (get_portnum(arg, &port) == 0) {
+			(void) fprintf(stderr,
+			    gettext("Error: Invalid port value -- %s\n"),
+			    arg);
+			return (NULL);
+		}
+		KSSL_DEBUG("port=%d\n", port);
+		if ((cname = strdup(ANY_ADDR)) == NULL)
+			return (NULL);
+	} else {
+		char *temp_str;
+		char *ptr;
+		struct hostent *hp;
+		boolean_t do_warn;
+
+		if (get_portnum(first_space + 1, &port) == 0) {
+			(void) fprintf(stderr,
+			    gettext("Error: Invalid port value -- %s\n"),
+			    first_space + 1);
+			return (NULL);
+		}
+		KSSL_DEBUG("port=%d\n", port);
+
+		if ((temp_str = strdup(arg)) == NULL)
+			return (NULL);
+		*(strchr(temp_str, ' ')) = '\0';
+
+		if ((int)(addr = inet_addr(temp_str)) == -1) {
+			if ((hp = gethostbyname(temp_str)) == NULL) {
+				(void) fprintf(stderr,
+				    gettext("Error: Unknown host -- %s\n"),
+				    temp_str);
+				free(temp_str);
+				return (NULL);
+			}
+		} else {
+			/* This is an IP address. Do a reverse lookup. */
+			if ((hp = gethostbyaddr((char *)&addr, 4, AF_INET))
+			    == NULL) {
+				(void) fprintf(stderr,
+				    gettext("Error: Unknown host -- %s\n"),
+				    temp_str);
+				free(temp_str);
+				return (NULL);
+			}
+		}
+
+		if ((ptr = cname = strdup(hp->h_name)) == NULL) {
+			free(temp_str);
+			return (NULL);
+		}
+		do_warn = B_TRUE;
+		/* "s/./-/g" */
+		while ((ptr = strchr(ptr, '.')) != NULL) {
+			if (do_warn)
+				do_warn = B_FALSE;
+			*ptr = '-';
+			ptr++;
+		}
+
+		if (do_warn && is_create) {
+			(void) fprintf(stderr,
+			    gettext("Warning: %s does not appear to have a"
+			    " registered DNS name.\n"), temp_str);
+		}
+
+		free(temp_str);
+	}
+
+	KSSL_DEBUG("Cannonical host name =%s\n", cname);
+
+	len = strlen(prefix) + strlen(cname) + 10;
+	if ((instance_name = malloc(len)) == NULL) {
+		(void) fprintf(stderr,
+		    gettext("Error: memory allocation failure.\n"));
+		return (NULL);
+	}
+	(void) snprintf(instance_name, len, "%s%s-%d", prefix, cname, port);
+
+	if (is_create) {
+		len = strlen(prefix) + strlen(ANY_ADDR) + 10;
+		if ((*inaddr_any_name = malloc(len)) == NULL) {
+			(void) fprintf(stderr,
+			    gettext("Error: memory allocation failure.\n"));
+			free(cname);
+			return (NULL);
+		}
+
+		(void) snprintf(*inaddr_any_name, len,
+		    "%s%s-%d", prefix, ANY_ADDR, port);
+	}
+
+	free(cname);
+	KSSL_DEBUG("instance_name=%s\n", instance_name);
+	return (instance_name);
+}
+
+static void
+usage_all(void)
+{
+	(void) fprintf(stderr, gettext("Usage:\n"));
+	usage_create(B_FALSE);
+	usage_delete(B_FALSE);
+	(void) fprintf(stderr, "ksslcfg -V\n");
+	(void) fprintf(stderr, "ksslcfg -?\n");
+}
+
+
+int
+main(int argc, char **argv)
+{
+	int rv = SUCCESS;
+
+	(void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
+#define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
+#endif
+	(void) textdomain(TEXT_DOMAIN);
+
+	if (argc < 2) {
+		usage_all();
+		return (ERROR_USAGE);
+	}
+
+	if (strcmp(argv[1], "create") == 0) {
+		rv = do_create(argc, argv);
+	} else if (strcmp(argv[1], "delete") == 0) {
+		rv = do_delete(argc, argv);
+	} else if (strcmp(argv[1], "-V") == 0) {
+		(void) printf("%s\n", KSSLCFG_VERSION);
+	} else if (strcmp(argv[1], "-?") == 0) {
+		usage_all();
+	} else {
+		(void) fprintf(stderr,
+		    gettext("Error: Unknown subcommand -- %s\n"), argv[1]);
+		usage_all();
+		rv = ERROR_USAGE;
+	}
+
+	return (rv);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.h	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,69 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _KSSLCFG_H
+#define	_KSSLCFG_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Common routines and variables used by ksslcfg files.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <libintl.h>
+#include <locale.h>
+
+#define	MAX_ADRPORT_LEN	128 /* sufficient for host name/IP address + port */
+
+#define	SUCCESS			0
+#define	FAILURE			1
+#define	ERROR_USAGE		2
+#define	INSTANCE_ANY_EXISTS	3
+#define	INSTANCE_OTHER_EXISTS	4
+
+extern const char *SERVICE_NAME;
+extern boolean_t verbose;
+
+extern char *create_instance_name(const char *arg, char **inaddr_any_name,
+    boolean_t is_create);
+int get_portnum(const char *, ushort_t *);
+extern void KSSL_DEBUG(const char *format, ...);
+extern int do_create(int argc, char *argv[]);
+extern int do_delete(int argc, char *argv[]);
+extern int delete_instance(const char *instance_name);
+extern void usage_create(boolean_t do_print);
+extern void usage_delete(boolean_t do_print);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _KSSLCFG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_create.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,665 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+
+#include <libscf.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/types.h>
+#include "ksslcfg.h"
+
+void
+usage_create(boolean_t do_print)
+{
+	if (do_print)
+		(void) fprintf(stderr, gettext("Usage:\n"));
+	(void) fprintf(stderr, "ksslcfg create"
+		" -f pkcs11 [-d softtoken_directory] -T <token_label>"
+		" -C <certificate_subject> -x <proxy_port>"
+		" [options] [<server_address>] <server_port>\n");
+
+	(void) fprintf(stderr, "ksslcfg create"
+		" -f pkcs12 -i <certificate_file> -x <proxy_port>"
+		" [options] [<server_address>] <server_port>\n");
+
+	(void) fprintf(stderr, "ksslcfg create"
+		" -f pem -i <certificate_file> -x <proxy_port>"
+		" [options] [<server_address>] <server_port>\n");
+
+	(void) fprintf(stderr, gettext("options are:\n"));
+	(void) fprintf(stderr, "\t[-c <ciphersuites>]\n"
+		"\t[-p <password_file>]\n"
+		"\t[-t <ssl_session_cache_timeout>]\n"
+		"\t[-u <username>]\n"
+		"\t[-z <ssl_session_cache_size>]\n"
+		"\t[-v]\n");
+}
+
+static scf_propertygroup_t *
+add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance,
+    const char *pg_name, const char *pg_type)
+{
+	scf_propertygroup_t *pg;
+
+	pg = scf_pg_create(handle);
+	if (pg == NULL) {
+		KSSL_DEBUG("scf_pg_create failed: %s\n",
+		    scf_strerror(scf_error()));
+		(void) fprintf(stderr, gettext(
+		    "Unexpected fatal libscf error: %s. Exiting.\n"),
+		    scf_strerror(scf_error()));
+		return (NULL);
+	}
+
+	if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) {
+		KSSL_DEBUG("ERROR: scf_instance_add_pg failed: %s\n",
+		    scf_strerror(scf_error()));
+		if (scf_error() == SCF_ERROR_EXISTS)
+			(void) fprintf(stderr, gettext(
+			    "Error: another process is modifying this instance."
+			    " Exiting.\n"));
+		else
+			(void) fprintf(stderr, gettext(
+			    "Unexpected fatal libscf error: %s. Exiting.\n"),
+			    scf_strerror(scf_error()));
+		scf_pg_destroy(pg);
+		return (NULL);
+	} else {
+		KSSL_DEBUG("property group created\n");
+	}
+
+	return (pg);
+}
+
+static int
+add_new_property(scf_handle_t *handle, const char *prop_name,
+    scf_type_t type, const char *val, scf_transaction_t *tx)
+{
+	scf_value_t *value = NULL;
+	scf_transaction_entry_t *entry = NULL;
+	int status = FAILURE;
+
+	entry = scf_entry_create(handle);
+	if (entry == NULL) {
+		KSSL_DEBUG("scf_entry_create failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out;
+	}
+	KSSL_DEBUG("scf_entry_create succeeded\n");
+
+	value = scf_value_create(handle);
+	if (value == NULL) {
+		goto out;
+	}
+	KSSL_DEBUG("scf_value_create succeeded\n");
+
+	if (scf_transaction_property_new(tx, entry, prop_name, type) != 0) {
+		goto out;
+	}
+	KSSL_DEBUG("scf_transaction_property_new succeeded\n");
+
+	if (scf_value_set_from_string(value, type, val) != 0) {
+		goto out;
+	}
+	KSSL_DEBUG("scf_value_set_from_string \'%s\' succeeded\n", val);
+
+	if (scf_entry_add_value(entry, value) != 0) {
+		KSSL_DEBUG(
+		    "scf_entry_add_value failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out;
+	}
+	KSSL_DEBUG("scf_entry_add_value succeeded\n");
+
+	status = SUCCESS;
+
+out:
+	if (status != SUCCESS)
+		(void) fprintf(stderr, gettext(
+		    "Unexpected fatal libscf error: %s. Exiting.\n"),
+		    scf_strerror(scf_error()));
+	return (status);
+}
+
+static int
+set_method_context(scf_handle_t *handle, scf_transaction_t *tran,
+    const char *value_str)
+{
+	if ((add_new_property(handle, SCF_PROPERTY_USE_PROFILE,
+		SCF_TYPE_BOOLEAN, "false", tran) != SUCCESS) ||
+	    (add_new_property(handle, SCF_PROPERTY_USER, SCF_TYPE_ASTRING,
+		value_str, tran) != SUCCESS) ||
+	    (add_new_property(handle, SCF_PROPERTY_GROUP, SCF_TYPE_ASTRING,
+		":default", tran) != SUCCESS) ||
+	    (add_new_property(handle, SCF_PROPERTY_LIMIT_PRIVILEGES,
+		SCF_TYPE_ASTRING, ":default", tran) != SUCCESS) ||
+	    (add_new_property(handle, SCF_PROPERTY_WORKING_DIRECTORY,
+		SCF_TYPE_ASTRING, ":default", tran) != SUCCESS) ||
+	    (add_new_property(handle, SCF_PROPERTY_SUPP_GROUPS,
+		SCF_TYPE_ASTRING, ":default", tran) != SUCCESS) ||
+	    (add_new_property(handle, SCF_PROPERTY_RESOURCE_POOL,
+		SCF_TYPE_ASTRING, ":default", tran) != SUCCESS) ||
+	    (add_new_property(handle, SCF_PROPERTY_PROJECT, SCF_TYPE_ASTRING,
+		":default", tran) != SUCCESS) ||
+	    (add_new_property(handle, SCF_PROPERTY_PRIVILEGES,
+		SCF_TYPE_ASTRING, "basic,sys_net_config", tran) != SUCCESS))
+		return (FAILURE);
+
+	return (SUCCESS);
+}
+
+static int
+add_pg_method(scf_handle_t *handle, scf_instance_t *instance,
+    const char *kssl_entry, const char *pg_name, const char *flags,
+    const char *value_str)
+{
+	int len, rv;
+	char *command;
+	const char *base_command;
+	int status = FAILURE;
+	boolean_t errflag = B_FALSE;
+	scf_transaction_t *tran;
+	scf_propertygroup_t *pg;
+
+	pg = add_property_group_to_instance(handle, instance,
+	    pg_name, SCF_GROUP_METHOD);
+	if (pg == NULL) {
+		/* flag is false to suppress duplicate error messages */
+		errflag = B_FALSE;
+		goto out0;
+	}
+	KSSL_DEBUG("%s method added\n", pg_name);
+
+	tran = scf_transaction_create(handle);
+	if (tran == NULL) {
+		KSSL_DEBUG("scf_transaction_create failed: %s\n",
+		    scf_strerror(scf_error()));
+		errflag = B_TRUE;
+		goto out0;
+	}
+	KSSL_DEBUG("scf_transaction_create succeeded\n");
+
+	do {
+		if (scf_transaction_start(tran, pg) != 0) {
+			KSSL_DEBUG("scf_transaction_start failed: %s\n",
+			    scf_strerror(scf_error()));
+			if (scf_error() == SCF_ERROR_PERMISSION_DENIED) {
+				(void) fprintf(stderr, gettext(
+				    "Error: Permission denied.\n"));
+				errflag = B_FALSE;
+			} else if (scf_error() ==  SCF_ERROR_DELETED) {
+				(void) fprintf(stderr, gettext(
+				    "Error: property group %s has"
+				    " been deleted.\n"), pg_name);
+				errflag = B_FALSE;
+			} else
+				errflag = B_TRUE;
+			goto out1;
+		}
+		KSSL_DEBUG("scf_transaction_start succeeded\n");
+
+		if (strcmp(pg_name, "stop") == 0)
+			base_command = "/usr/lib/kssladm delete";
+		else
+			base_command = "/usr/lib/kssladm create";
+
+		len = strlen(base_command) + strlen(flags) +
+		    strlen(kssl_entry) + 3;
+
+		command = malloc(len);
+		if (command == NULL) {
+			goto out2;
+		}
+
+		(void) snprintf(command, len, "%s %s %s",
+		    base_command, flags, kssl_entry);
+		KSSL_DEBUG("command=%s\n", command);
+
+		if (add_new_property(handle, SCF_PROPERTY_EXEC,
+		    SCF_TYPE_ASTRING, command, tran) != SUCCESS) {
+			free(command);
+			goto out2;
+		}
+		free(command);
+
+		if (add_new_property(handle, SCF_PROPERTY_TIMEOUT,
+		    SCF_TYPE_COUNT, "60", tran) != SUCCESS)
+			goto out2;
+
+		if (set_method_context(handle, tran, value_str) != SUCCESS)
+			goto out2;
+
+		rv = scf_transaction_commit(tran);
+		switch (rv) {
+		case 1:
+			KSSL_DEBUG("scf_transaction_commit succeeded\n");
+			status = SUCCESS;
+			goto out2;
+		case 0:
+			scf_transaction_reset(tran);
+			if (scf_pg_update(pg) == -1) {
+				goto out2;
+			}
+			break;
+		case -1:
+		default:
+			KSSL_DEBUG("ERROR: scf_transaction_commit failed: %s\n",
+			    scf_strerror(scf_error()));
+			if (scf_error() == SCF_ERROR_PERMISSION_DENIED) {
+				(void) fprintf(stderr, gettext(
+				    "Error: Permission denied.\n"));
+				errflag = B_FALSE;
+			} else {
+				errflag = B_TRUE;
+			}
+			goto out2;
+		}
+	} while (rv == 0);
+
+out2:
+	scf_transaction_reset(tran);
+out1:
+	scf_transaction_destroy_children(tran);
+	scf_transaction_destroy(tran);
+out0:
+	if (pg != NULL)
+		scf_pg_destroy(pg);
+	if (errflag)
+		(void) fprintf(stderr, gettext(
+		    "Unexpected fatal libscf error: %s. Exiting.\n"),
+		    scf_strerror(scf_error()));
+	return (status);
+}
+
+static int
+create_instance(scf_handle_t *handle, scf_service_t *svc,
+    const char *instance_name, const char *kssl_entry, const char *command,
+    const char *username, char *inaddr_any_name)
+{
+	int status = FAILURE;
+	char *buf;
+	boolean_t errflag = B_FALSE;
+	ssize_t max_fmri_len;
+	scf_instance_t *instance;
+
+	instance = scf_instance_create(handle);
+	if (instance == NULL) {
+		errflag = B_TRUE;
+		KSSL_DEBUG("scf_instance_create failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out;
+	}
+	KSSL_DEBUG("scf_instance_create succeeded\n");
+
+	if (scf_service_get_instance(svc, inaddr_any_name, instance) == 0) {
+		/* Let the caller deal with the duplicate instance */
+		status = INSTANCE_ANY_EXISTS;
+		goto out;
+	}
+
+	if (scf_service_add_instance(svc, instance_name, instance) != 0) {
+		if (scf_error() == SCF_ERROR_EXISTS) {
+			/* Let the caller deal with the duplicate instance */
+			status = INSTANCE_OTHER_EXISTS;
+			goto out;
+		}
+
+		errflag = B_TRUE;
+		KSSL_DEBUG("scf_service_add_instance failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out;
+	}
+	KSSL_DEBUG("scf_service_add_instance succeeded\n");
+
+	if ((add_pg_method(handle, instance, kssl_entry, "start",
+		command, username) != SUCCESS) ||
+	    (add_pg_method(handle, instance, kssl_entry, "refresh",
+		command, username) != SUCCESS) ||
+	    (add_pg_method(handle, instance, kssl_entry, "stop",
+		"", username) != SUCCESS)) {
+		scf_instance_destroy(instance);
+		return (status);
+	}
+
+	/* enabling the instance */
+	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
+	if ((buf = malloc(max_fmri_len + 1)) == NULL)
+		goto out;
+
+	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
+		KSSL_DEBUG("instance_fmri=%s\n", buf);
+		if (smf_enable_instance(buf, 0) != 0) {
+			errflag = B_TRUE;
+			KSSL_DEBUG(
+			    "smf_enable_instance failed: %s\n",
+			    scf_strerror(scf_error()));
+			goto out;
+		}
+		status = SUCCESS;
+	}
+
+out:
+	if (instance != NULL)
+		scf_instance_destroy(instance);
+	if (errflag)
+		(void) fprintf(stderr, gettext(
+		    "Unexpected fatal libscf error: %s. Exiting.\n"),
+		    scf_strerror(scf_error()));
+	return (status);
+}
+
+static int
+create_service(const char *instance_name, const char *kssl_entry,
+    const char *command, const char *username, char *inaddr_any_name)
+{
+	int status = FAILURE;
+	scf_scope_t *scope;
+	scf_service_t *svc;
+	scf_handle_t *handle;
+	boolean_t errflag = B_TRUE;
+
+	handle = scf_handle_create(SCF_VERSION);
+	if (handle == NULL) {
+		KSSL_DEBUG("scf_handle_create failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out1;
+	}
+	KSSL_DEBUG("scf_handle_create succeeded\n");
+
+	if (scf_handle_bind(handle) == -1) {
+		KSSL_DEBUG("scf_handle_bind failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out1;
+	}
+	KSSL_DEBUG("scf_handle_bind succeeded\n");
+
+	if ((scope = scf_scope_create(handle)) == NULL) {
+		KSSL_DEBUG("scf_scope_create failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out2;
+	}
+	KSSL_DEBUG("scf_scope_create succeeded\n");
+
+	if ((svc = scf_service_create(handle)) == NULL) {
+		KSSL_DEBUG("scf_service_create failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out3;
+	}
+	KSSL_DEBUG("scf_service_create succeeded\n");
+
+	if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc,
+	    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) {
+		KSSL_DEBUG("scf_handle_decode_fmri failed: %s\n",
+		    scf_strerror(scf_error()));
+		if (scf_error() == SCF_ERROR_NOT_FOUND) {
+			(void) fprintf(stderr, gettext(
+			    "service %s not found in the repository."
+			    " Exiting.\n"), SERVICE_NAME);
+			errflag = B_FALSE;
+		}
+		goto out4;
+	}
+
+	status = create_instance(handle, svc, instance_name, kssl_entry,
+	    command, username, inaddr_any_name);
+
+out4:
+	scf_service_destroy(svc);
+out3:
+	scf_scope_destroy(scope);
+out2:
+	(void) scf_handle_unbind(handle);
+out1:
+	if (handle != NULL)
+		scf_handle_destroy(handle);
+
+	if (status != SUCCESS && status != INSTANCE_OTHER_EXISTS &&
+	    status != INSTANCE_ANY_EXISTS && errflag)
+		(void) fprintf(stderr, gettext(
+		    "Unexpected fatal libscf error: %s. Exiting.\n"),
+		    scf_strerror(scf_error()));
+	return (status);
+}
+
+int
+do_create(int argc, char *argv[])
+{
+	char c;
+	char *buf, *ptr, *instance_name;
+	char *inaddr_any_name = NULL;
+	int i, status, len, pcnt;
+	const char *token_label = NULL;
+	const char *filename = NULL;
+	const char *certname = NULL;
+	const char *username = NULL;
+	const char *proxy_port = NULL;
+	char *format = NULL;
+	boolean_t quote_next;
+	char address_port[MAX_ADRPORT_LEN + 1];
+
+	argc -= 1;
+	argv += 1;
+
+	/*
+	 * Many of these arguments are passed on to kssladm command
+	 * in the start method of the SMF instance created. So, we do only
+	 * the basic usage checks here and let kssladm check the validity
+	 * of the arguments. This is the reason we ignore optarg
+	 * for some of the cases below.
+	 */
+	while ((c = getopt(argc, argv, "vT:d:f:i:p:c:C:t:u:x:z:")) != -1) {
+		switch (c) {
+		case 'd':
+			break;
+		case 'c':
+			break;
+		case 'C':
+			certname = optarg;
+			break;
+		case 'f':
+			format = optarg;
+			break;
+		case 'i':
+			filename = optarg;
+			break;
+		case 'T':
+			token_label = optarg;
+			break;
+		case 'p':
+			break;
+		case 't':
+			break;
+		case 'u':
+			username = optarg;
+			break;
+		case 'x':
+			proxy_port = optarg;
+			break;
+		case 'v':
+			verbose = B_TRUE;
+			break;
+		case 'z':
+			break;
+		default:
+			goto err;
+		}
+	}
+
+	if (format == NULL || proxy_port == NULL) {
+		goto err;
+	}
+
+	if (get_portnum(proxy_port, NULL) == 0) {
+		(void) fprintf(stderr,
+		    gettext("Error: Invalid proxy port value %s\n"),
+		    proxy_port);
+		goto err;
+	}
+
+	if (strcmp(format, "pkcs11") == 0) {
+		if (token_label == NULL || certname == NULL) {
+			goto err;
+		}
+	} else if (strcmp(format, "pkcs12") == 0 ||
+	    strcmp(format, "pem") == 0) {
+		if (filename == NULL) {
+			goto err;
+		}
+	} else {
+		goto err;
+	}
+
+	pcnt = argc - optind;
+	if (pcnt == 1) {
+		if (strlen(argv[optind]) < MAX_ADRPORT_LEN) {
+			(void) strcpy(address_port, argv[optind]);
+		} else {
+			(void) fprintf(stderr, gettext(
+			    "argument too long -- %s\n"),
+			    argv[optind]);
+			return (FAILURE);
+		}
+	} else if (pcnt == 2) {
+		if ((len = strlen(argv[optind])) +
+		    (strlen(argv[optind + 1])) < MAX_ADRPORT_LEN) {
+			(void) strcpy(address_port, argv[optind]);
+			address_port[len] = ' ';
+			(void) strcpy(address_port + len + 1, argv[optind + 1]);
+		} else {
+			(void) fprintf(stderr, gettext(
+			    "arguments too long -- %s %s\n"),
+			    argv[optind], argv[optind + 1]);
+			return (FAILURE);
+		}
+	} else {
+		goto err;
+	}
+
+	/*
+	 * We need to create the kssladm command line in
+	 * the SMF instance from the current arguments.
+	 *
+	 * Construct a buffer with all the arguments except
+	 * the -u argument. We have to quote the string arguments,
+	 * -T and -C, as they can contain white space.
+	 */
+	len = 0;
+	for (i = 1; i < optind; i++) {
+		len += strlen(argv[i]) + 3;
+	}
+
+	if ((buf = malloc(len)) == NULL) {
+		return (FAILURE);
+	}
+
+	ptr = buf;
+	quote_next = B_FALSE;
+	for (i = 1; i < optind; i++) {
+		int arglen =  strlen(argv[i]) + 1;
+
+		if (strncmp(argv[i], "-u", 2) == 0) {
+			i++;
+			continue;
+		}
+
+		if (quote_next) {
+			(void) snprintf(ptr, len, "\"%s\" ", argv[i]);
+			quote_next = B_FALSE;
+			arglen += 2;
+		} else {
+			(void) snprintf(ptr, len, "%s ", argv[i]);
+		}
+
+		quote_next = (strncmp(argv[i], "-T", 2) == 0 ||
+		    strncmp(argv[i], "-C", 2) == 0);
+
+		ptr += arglen;
+		len -= arglen;
+	}
+	KSSL_DEBUG("buf=%s\n", buf);
+
+	instance_name = create_instance_name(address_port,
+	    &inaddr_any_name, B_TRUE);
+	if (instance_name == NULL || inaddr_any_name == NULL) {
+		free(buf);
+		return (FAILURE);
+	}
+	KSSL_DEBUG("instance_name=%s\n", instance_name);
+	KSSL_DEBUG("inaddr_any_name=%s\n", inaddr_any_name);
+
+	if (username == NULL)
+		username = "root";
+	status = create_service(instance_name, address_port,
+	    buf, username, inaddr_any_name);
+	if (status == INSTANCE_OTHER_EXISTS || status == INSTANCE_ANY_EXISTS) {
+		if (status == INSTANCE_ANY_EXISTS &&
+		    (strcmp(instance_name, inaddr_any_name) != SUCCESS)) {
+			/*
+			 * The following could result in a misconfiguration.
+			 * Better bail out with an error.
+			 */
+			(void) fprintf(stderr,
+			    gettext("Error: INADDR_ANY instance exists."
+			    " Can not create a new instance %s.\n"),
+			    instance_name);
+			free(instance_name);
+			free(inaddr_any_name);
+			free(buf);
+			return (status);
+		}
+
+		/*
+		 * Delete the existing instance and create a new instance
+		 * with the supplied arguments.
+		 */
+		KSSL_DEBUG("Deleting duplicate instance\n");
+		if (delete_instance(instance_name) != SUCCESS) {
+			(void) fprintf(stderr,
+			    gettext(
+			    "Error: Can not delete existing instance %s.\n"),
+			    instance_name);
+		} else {
+			(void) fprintf(stdout, gettext(
+			    "Note: reconfiguring the existing instance %s.\n"),
+			    instance_name);
+			status = create_service(instance_name, address_port,
+			    buf, username, inaddr_any_name);
+		}
+	}
+
+	free(instance_name);
+	free(inaddr_any_name);
+	free(buf);
+	return (status);
+
+err:
+	usage_create(B_TRUE);
+	return (ERROR_USAGE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_delete.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,296 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <libscf.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/types.h>
+#include "ksslcfg.h"
+
+void
+usage_delete(boolean_t do_print)
+{
+	if (do_print)
+		(void) fprintf(stderr, gettext("Usage:\n"));
+	(void) fprintf(stderr,
+	    "ksslcfg delete [-v] [<server_address>] <server_port>\n");
+}
+
+#define	DEFAULT_TIMEOUT	60000000
+#define	INIT_WAIT_USECS	50000
+
+void
+wait_till_to(char *fmri)
+{
+	char *state;
+	useconds_t max;
+	useconds_t usecs;
+	uint64_t *cp = NULL;
+	scf_simple_prop_t *sp = NULL;
+
+	max = DEFAULT_TIMEOUT;
+
+	if (((sp = scf_simple_prop_get(NULL, fmri, "stop",
+	    SCF_PROPERTY_TIMEOUT)) != NULL) &&
+	    ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0))
+		max = (*cp) * 1000000;	/* convert to usecs */
+
+	if (sp != NULL)
+		scf_simple_prop_free(sp);
+
+	for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) {
+		/* incremental wait */
+		usecs *= 2;
+		usecs = (usecs > max) ? max : usecs;
+
+		(void) usleep(usecs);
+
+		/* Check state after the wait */
+		if ((state = smf_get_state(fmri)) != NULL) {
+			if (strcmp(state, "disabled") == 0)
+				return;
+		}
+	}
+
+	(void) fprintf(stderr, gettext("Warning: delete %s timed out.\n"),
+	    fmri);
+}
+
+int
+delete_instance(const char *instance_name)
+{
+	int status = FAILURE;
+	char *buf;
+	boolean_t errflag = B_FALSE;
+	ssize_t max_fmri_len;
+	scf_scope_t *scope;
+	scf_service_t *svc;
+	scf_handle_t *handle;
+	scf_instance_t *instance;
+
+	handle = scf_handle_create(SCF_VERSION);
+	if (handle == NULL) {
+		errflag = B_TRUE;
+		KSSL_DEBUG("scf_handle_create failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out1;
+	}
+	KSSL_DEBUG("scf_handle_create succeeded\n");
+
+	if (scf_handle_bind(handle) == -1) {
+		errflag = B_TRUE;
+		KSSL_DEBUG("scf_handle_bind failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out1;
+	}
+	KSSL_DEBUG("scf_handle_bind succeeded\n");
+
+	if ((scope = scf_scope_create(handle)) == NULL) {
+		errflag = B_TRUE;
+		KSSL_DEBUG("scf_scope_create failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out2;
+	}
+	KSSL_DEBUG("scf_scope_create succeeded\n");
+
+	if ((svc = scf_service_create(handle)) == NULL) {
+		errflag = B_TRUE;
+		KSSL_DEBUG("scf_service_create failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out3;
+	}
+	KSSL_DEBUG("scf_service_create succeeded\n");
+
+	if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1) {
+		errflag = B_TRUE;
+		KSSL_DEBUG("scf_handle_get_scope failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out4;
+	}
+	KSSL_DEBUG("scf_handle_get_scope succeeded\n");
+
+	if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0) {
+		scf_error_t scf_errnum = scf_error();
+
+		if (scf_errnum != SCF_ERROR_NOT_FOUND) {
+			errflag = B_TRUE;
+			KSSL_DEBUG(
+			    "ERROR scf_scope_get_service failed: %s\n",
+			    scf_strerror(scf_errnum));
+		}
+		goto out4;
+	} else {
+		KSSL_DEBUG("scf_scope_get_service succeeded\n");
+	}
+
+	instance = scf_instance_create(handle);
+	if (instance == NULL) {
+		errflag = B_TRUE;
+		KSSL_DEBUG("scf_instance_create failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out4;
+	}
+
+	if (scf_service_get_instance(svc, instance_name, instance) != 0) {
+		scf_error_t scf_errnum = scf_error();
+
+		if (scf_errnum == SCF_ERROR_NOT_FOUND) {
+			status = SUCCESS;
+		} else {
+			errflag = B_TRUE;
+			KSSL_DEBUG(
+			    "ERROR scf_scope_get_service failed: %s\n",
+			    scf_strerror(scf_errnum));
+		}
+		scf_instance_destroy(instance);
+		goto out4;
+	}
+
+	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
+	if ((buf = malloc(max_fmri_len + 1)) == NULL)
+		goto out4;
+
+	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
+		char *state;
+
+		KSSL_DEBUG("instance_fmri=%s\n", buf);
+		state = smf_get_state(buf);
+		if (state)
+			KSSL_DEBUG("state=%s\n", state);
+		if (state && strcmp(state, "online") == 0) {
+			if (smf_disable_instance(buf, 0) != 0) {
+				errflag = B_TRUE;
+				KSSL_DEBUG(
+				    "smf_disable_instance failed: %s\n",
+				    scf_strerror(scf_error()));
+			} else {
+				/*
+				 * Wait for some time till timeout to avoid
+				 * a race with scf_instance_delete() below.
+				 */
+				wait_till_to(buf);
+			}
+		}
+	}
+
+	if (scf_instance_delete(instance) != 0) {
+		errflag = B_TRUE;
+		KSSL_DEBUG(
+		    "ERROR scf_instance_delete failed: %s\n",
+		    scf_strerror(scf_error()));
+		goto out4;
+	} else {
+		KSSL_DEBUG("deleted %s\n", instance_name);
+	}
+
+	status = SUCCESS;
+
+out4:
+	scf_service_destroy(svc);
+out3:
+	scf_scope_destroy(scope);
+out2:
+	(void) scf_handle_unbind(handle);
+out1:
+	if (handle != NULL)
+		scf_handle_destroy(handle);
+	if (errflag)
+		(void) fprintf(stderr, gettext(
+		    "Unexpected fatal libscf error: %s.  Exiting.\n"),
+		    scf_strerror(scf_error()));
+	return (status);
+}
+
+int
+do_delete(int argc, char *argv[])
+{
+	char c;
+	int status, len, pcnt;
+	char address_port[MAX_ADRPORT_LEN + 1];
+	char *instance_name;
+
+	if (argc < 3) {
+		goto err;
+	}
+
+	argc -= 1;
+	argv += 1;
+
+	while ((c = getopt(argc, argv, "v")) != -1) {
+		switch (c) {
+		case 'v':
+			verbose = B_TRUE;
+			break;
+		default:
+			goto err;
+		}
+	}
+
+	pcnt = argc - optind;
+	if (pcnt == 1) {
+		if (strlen(argv[optind]) < MAX_ADRPORT_LEN) {
+			(void) strcpy(address_port, argv[optind]);
+		} else {
+			(void) fprintf(stderr, gettext(
+			    "argument too long -- %s\n"),
+			    argv[optind]);
+			return (FAILURE);
+		}
+	} else if (pcnt == 2) {
+		if ((len = strlen(argv[optind])) +
+		    (strlen(argv[optind + 1])) < MAX_ADRPORT_LEN) {
+			(void) strcpy(address_port, argv[optind]);
+			address_port[len] = ' ';
+			(void) strcpy(address_port + len + 1, argv[optind + 1]);
+		} else {
+			(void) fprintf(stderr, gettext(
+			    "arguments too long -- %s %s\n"),
+			    argv[optind], argv[optind + 1]);
+			return (FAILURE);
+		}
+	} else {
+		goto err;
+	}
+
+	instance_name = create_instance_name(address_port, NULL, B_FALSE);
+	if (instance_name == NULL) {
+		return (FAILURE);
+	}
+
+	KSSL_DEBUG("instance_name=%s\n", instance_name);
+	status = delete_instance(instance_name);
+	free(instance_name);
+
+	return (status);
+
+err:
+	usage_delete(B_TRUE);
+	return (ERROR_USAGE);
+}
--- a/usr/src/cmd/devfsadm/misc_link.c	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/cmd/devfsadm/misc_link.c	Sat Nov 12 18:58:05 2005 -0800
@@ -95,7 +95,7 @@
 	    "(^eeprom$)|(^ptsl$)|(^mm$)|(^wc$)|(^dump$)|(^cn$)|(^lo$)|(^ptm$)|"
 	    "(^ptc$)|(^openeepr$)|(^poll$)|(^sysmsg$)|(^random$)|(^trapstat$)|"
 	    "(^cryptoadm$)|(^crypto$)|(^pool$)|(^poolctl$)|(^bl$)|(^kmdb$)|"
-	    "(^sysevent$)",
+	    "(^sysevent$)|(^kssl$)",
 	    TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name
 	},
 	{ "pseudo", "ddi_pseudo",
--- a/usr/src/lib/libbsm/audit_event.txt	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/lib/libbsm/audit_event.txt	Sat Nov 12 18:58:05 2005 -0800
@@ -326,6 +326,7 @@
 290:AUE_MODDEVPLCY:modctl(2) - configure device policy:as
 291:AUE_MODADDPRIV:modctl(2) - configure additional privilege:as
 292:AUE_CRYPTOADM:kernel cryptographic framework:as
+293:AUE_CONFIGSSL:configure kernel SSL:as
 #
 # user level audit events
 #
--- a/usr/src/lib/libsecdb/exec_attr.txt	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/lib/libsecdb/exec_attr.txt	Sat Nov 12 18:58:05 2005 -0800
@@ -198,6 +198,7 @@
 Network Security:solaris:cmd:::/usr/sbin/ipsecconf:privs=sys_net_config
 Network Security:solaris:cmd:::/usr/sbin/ipseckey:privs=sys_net_config
 Network Security:solaris:cmd:::/usr/sbin/ipsecalgs:privs=sys_net_config
+Network Security:solaris:cmd:::/usr/sbin/ksslcfg:euid=0
 Network Security:suser:cmd:::/usr/bin/ssh-keygen:uid=0;gid=sys
 Network Security:suser:cmd:::/usr/lib/inet/certdb:euid=0
 Network Security:suser:cmd:::/usr/lib/inet/certlocal:euid=0
--- a/usr/src/pkgdefs/SUNWckr/prototype_com	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/pkgdefs/SUNWckr/prototype_com	Sat Nov 12 18:58:05 2005 -0800
@@ -85,6 +85,7 @@
 f none kernel/drv/iwscn.conf 644 root sys
 f none kernel/drv/keysock.conf 644 root sys
 f none kernel/drv/kmdb.conf 644 root sys
+f none kernel/drv/kssl.conf 644 root sys
 f none kernel/drv/llc1.conf 644 root sys
 f none kernel/drv/lofi.conf 644 root sys
 e preserve kernel/drv/log.conf 644 root sys
--- a/usr/src/pkgdefs/SUNWckr/prototype_i386	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/pkgdefs/SUNWckr/prototype_i386	Sat Nov 12 18:58:05 2005 -0800
@@ -84,6 +84,7 @@
 f none kernel/drv/iwscn 755 root sys
 f none kernel/drv/keysock 755 root sys
 f none kernel/drv/kmdb 755 root sys
+f none kernel/drv/kssl 755 root sys
 f none kernel/drv/llc1 755 root sys
 f none kernel/drv/lofi 755 root sys
 f none kernel/drv/log 755 root sys
@@ -252,6 +253,7 @@
 f none kernel/drv/amd64/iwscn 755 root sys
 f none kernel/drv/amd64/keysock 755 root sys
 f none kernel/drv/amd64/kmdb 755 root sys
+f none kernel/drv/amd64/kssl 755 root sys
 f none kernel/drv/amd64/llc1 755 root sys
 f none kernel/drv/amd64/lofi 755 root sys
 f none kernel/drv/amd64/log 755 root sys
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc	Sat Nov 12 18:58:05 2005 -0800
@@ -91,6 +91,7 @@
 f none kernel/drv/sparcv9/kb8042 755 root sys
 f none kernel/drv/sparcv9/keysock 755 root sys
 f none kernel/drv/sparcv9/kmdb 755 root sys
+f none kernel/drv/sparcv9/kssl 755 root sys
 f none kernel/drv/sparcv9/llc1 755 root sys
 f none kernel/drv/sparcv9/lofi 755 root sys
 f none kernel/drv/sparcv9/log 755 root sys
--- a/usr/src/pkgdefs/SUNWcsr/prototype_com	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/pkgdefs/SUNWcsr/prototype_com	Sat Nov 12 18:58:05 2005 -0800
@@ -474,6 +474,8 @@
 f manifest var/svc/manifest/network/dns/client.xml 0444 root sys
 d none var/svc/manifest/network/ldap 0755 root sys
 f manifest var/svc/manifest/network/ldap/client.xml 0444 root sys
+d none var/svc/manifest/network/ssl 0755 root sys
+f manifest var/svc/manifest/network/ssl/kssl-proxy.xml 0444 root sys
 d none var/svc/manifest/platform 755 root sys
 d none var/svc/manifest/site 755 root sys
 d none var/svc/manifest/system 755 root sys
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com	Sat Nov 12 18:58:05 2005 -0800
@@ -548,6 +548,7 @@
 f none usr/lib/inet/inetd 555 root bin
 f none usr/lib/intrd 555 root bin
 f none usr/lib/isaexec 555 root bin
+f none usr/lib/kssladm 555 root bin
 s none usr/lib/ld.so.1=../../lib/ld.so.1
 d none usr/lib/locale 755 root bin
 d none usr/lib/locale/C 755 root bin
@@ -755,6 +756,7 @@
 f none usr/sbin/install 555 root bin
 f none usr/sbin/keyserv 555 root sys
 f none usr/sbin/killall 555 root bin
+f none usr/sbin/ksslcfg 555 root bin
 s none usr/sbin/labelit=./clri
 f none usr/sbin/link 555 root bin
 s none usr/sbin/lockfs=../lib/fs/ufs/lockfs
--- a/usr/src/pkgdefs/SUNWhea/prototype_com	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com	Sat Nov 12 18:58:05 2005 -0800
@@ -149,6 +149,8 @@
 f none usr/include/inet/snmpcom.h 644 root bin
 f none usr/include/inet/tcp.h 644 root bin
 f none usr/include/inet/tcp_sack.h 644 root bin
+d none usr/include/inet/kssl 755 root bin
+f none usr/include/inet/kssl/ksslapi.h 644 root bin
 f none usr/include/inttypes.h 644 root bin
 f none usr/include/ipmp.h 644 root bin
 f none usr/include/ipmp_mpathd.h 644 root bin
--- a/usr/src/pkgdefs/etc/exception_list_i386	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/pkgdefs/etc/exception_list_i386	Sat Nov 12 18:58:05 2005 -0800
@@ -524,6 +524,11 @@
 usr/include/inet/nca/ncandd.h		i386
 usr/include/inet/nca/ncaio.h		i386
 #
+usr/include/inet/kssl			i386
+usr/include/inet/kssl/kssl.h		i386
+usr/include/inet/kssl/ksslimpl.h	i386
+usr/include/inet/kssl/ksslproto.h	i386
+#
 # other contents (packages removed in source product)
 usr/bin/des				i386
 usr/include/des/desdata.h		i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Sat Nov 12 18:58:05 2005 -0800
@@ -531,6 +531,10 @@
 usr/include/inet/nca/ncalogd.h		sparc
 usr/include/inet/nca/ncandd.h		sparc
 usr/include/inet/nca/ncaio.h		sparc
+usr/include/inet/kssl			sparc
+usr/include/inet/kssl/kssl.h		sparc
+usr/include/inet/kssl/ksslimpl.h	sparc
+usr/include/inet/kssl/ksslproto.h	sparc
 #
 # other contents (packages removed in source product)
 usr/bin/des				sparc
--- a/usr/src/uts/Makefile	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/Makefile	Sat Nov 12 18:58:05 2005 -0800
@@ -92,8 +92,8 @@
 #
 COMMON_HDRDIRS= common/des common/fs common/gssapi common/inet common/net \
 	common/netinet common/nfs common/rpc common/sys common/vm \
-	common/c2 common/pcmcia/sys common/rpcsvc common/inet/nca \
-	common/ipp
+	common/c2 common/pcmcia/sys common/rpcsvc common/inet/kssl \
+	common/inet/nca common/ipp
 
 sparc_HDRDIRS= sun/sys
 i386_HDRDIRS= i86pc/vm
--- a/usr/src/uts/common/Makefile.files	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/Makefile.files	Sat Nov 12 18:58:05 2005 -0800
@@ -417,7 +417,8 @@
 
 RTS_OBJS +=	rtsddi.o rts.o rts_opt_data.o
 
-IP_TCP_OBJS =	tcp.o tcp_trace.o tcp_opt_data.o tcp_sack.o tcp_fusion.o
+IP_TCP_OBJS =	tcp.o tcp_fusion.o tcp_kssl.o tcp_opt_data.o tcp_sack.o \
+		tcp_trace.o
 IP_UDP_OBJS =	udp.o udp_opt_data.o
 IP_SCTP_OBJS =	sctp_crc32.o sctp.o sctp_opt_data.o sctp_output.o \
 		sctp_init.o sctp_input.o sctp_cookie.o \
@@ -805,8 +806,9 @@
 
 SOCK_OBJS +=	socksubr.o	sockvfsops.o	sockvnops.o	\
 		socksyscalls.o	socktpi.o	sockstr.o	ncafs.o \
-		socksctp.o	socksctpsubr.o	socksctpvnops.o	nl7c.o \
-		nl7curi.o	nl7chttp.o	nl7clogd.o	nl7cnca.o
+		socksctp.o	socksctpsubr.o	socksctpvnops.o	sockssl.o \
+		nl7c.o		nl7curi.o	nl7chttp.o	nl7clogd.o \
+		nl7cnca.o
 
 TMPFS_OBJS +=	tmp_dir.o	tmp_subr.o	tmp_tnode.o	tmp_vfsops.o \
 		tmp_vnops.o
@@ -1040,6 +1042,11 @@
 SWRANDPROV_OBJS += swrand.o
 
 #
+#			kernel SSL
+#
+KSSL_OBJS +=	kssl.o ksslioctl.o ksslapi.o ksslrec.o
+
+#
 #			misc. modules
 #
 AMSRC1_OBJS +=	am_src1.o
--- a/usr/src/uts/common/Makefile.rules	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/Makefile.rules	Sat Nov 12 18:58:05 2005 -0800
@@ -349,6 +349,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/inet/kssl/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/inet/sctp/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -1136,6 +1140,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/inet/ipf/%.c
 	@($(LHEAD) $(LINT.c) $(IPFFLAG2) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/inet/kssl/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/inet/udp/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- a/usr/src/uts/common/c2/audit.c	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/c2/audit.c	Sat Nov 12 18:58:05 2005 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -63,6 +63,7 @@
 #include <sys/disp.h>		/* for servicing_interrupt() */
 #include <sys/devpolicy.h>
 #include <sys/crypto/ioctladmin.h>
+#include <inet/kssl/kssl.h>
 
 static void add_return_token(caddr_t *, unsigned int scid, int err, int rval);
 
@@ -2274,3 +2275,77 @@
 
 	au_close(kctx, (caddr_t *)&ad, AU_OK, AUE_CRYPTOADM, 0);
 }
+
+/*
+ * Audit the kernel SSL administration command. The address and the
+ * port number for the SSL instance, and the proxy port are put in the
+ * audit trail.
+ */
+void
+audit_kssl(int cmd, void *params, int error)
+{
+	cred_t			*cr = CRED();
+	t_audit_data_t		*tad;
+	token_t			*ad = NULL;
+	const auditinfo_addr_t	*ainfo = crgetauinfo(cr);
+	au_kcontext_t		*kctx = SET_KCTX_PZ;
+
+	ASSERT(kctx != NULL);
+	tad = U2A(u);
+
+	if (ainfo == NULL)
+		return;
+
+	tad->tad_event = AUE_CONFIGKSSL;
+
+	if (audit_success(kctx, tad, error) != AU_OK)
+		return;
+
+	/* Add a subject token */
+	AUDIT_SETSUBJ((caddr_t *)&ad, cr, ainfo);
+
+	/* add an optional group token */
+	AUDIT_SETGROUP((caddr_t *)&ad, cr, kctx);
+
+	switch (cmd) {
+	case KSSL_ADD_ENTRY: {
+		char buf[32];
+		kssl_params_t *kp = (kssl_params_t *)params;
+		struct sockaddr_in *saddr = &(kp->kssl_addr);
+
+		au_write((caddr_t *)&ad, au_to_text("op=KSSL_ADD_ENTRY"));
+		au_write((caddr_t *)&ad, au_to_in_addr(&(saddr->sin_addr)));
+		(void) snprintf(buf, sizeof (buf), "SSL port=%d",
+		    saddr->sin_port);
+		au_write((caddr_t *)&ad, au_to_text(buf));
+
+		(void) snprintf(buf, sizeof (buf), "proxy port=%d",
+		    kp->kssl_proxy_port);
+		au_write((caddr_t *)&ad, au_to_text(buf));
+		break;
+	}
+
+	case KSSL_DELETE_ENTRY: {
+		char buf[32];
+		struct sockaddr_in *saddr = (struct sockaddr_in *)params;
+
+		au_write((caddr_t *)&ad, au_to_text("op=KSSL_DELETE_ENTRY"));
+		au_write((caddr_t *)&ad, au_to_in_addr(&(saddr->sin_addr)));
+		(void) snprintf(buf, sizeof (buf), "SSL port=%d",
+		    saddr->sin_port);
+		au_write((caddr_t *)&ad, au_to_text(buf));
+		break;
+	}
+
+	default:
+		return;
+	}
+
+	/* add a return token */
+	add_return_token((caddr_t *)&ad, tad->tad_scid, error, 0);
+
+	AS_INC(as_generated, 1, kctx);
+	AS_INC(as_kernel, 1, kctx);
+
+	au_close(kctx, (caddr_t *)&ad, AU_OK, AUE_CONFIGKSSL, 0);
+}
--- a/usr/src/uts/common/c2/audit.h	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/c2/audit.h	Sat Nov 12 18:58:05 2005 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -579,6 +579,7 @@
 void	audit_setppriv(int, int, const struct priv_set *, const cred_t *);
 void	audit_devpolicy(int, const struct devplcysys *);
 void	audit_update_context(proc_t *, cred_t *);
+void	audit_kssl(int, void *, int);
 
 #endif
 
--- a/usr/src/uts/common/c2/audit_kevents.h	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/c2/audit_kevents.h	Sat Nov 12 18:58:05 2005 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -333,6 +333,7 @@
 #define	AUE_MODDEVPLCY		290	/* =ad modctl(2) */
 #define	AUE_MODADDPRIV		291	/* =ad modctl(2) */
 #define	AUE_CRYPTOADM		292	/* =as kernel cryptographic framework */
+#define	AUE_CONFIGKSSL		293	/* =as kernel SSL */
 
 /*
  * Maximum number of kernel events in the event to class table
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/sockfs/sockssl.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,116 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/sysmacros.h>
+#include <sys/vnode.h>
+#include <sys/debug.h>
+#include <sys/errno.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/vtrace.h>
+#include <sys/strsun.h>
+#include <sys/cmn_err.h>
+
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/socketvar.h>
+
+#include <inet/kssl/ksslapi.h>
+
+
+/*
+ * This routine is registered with the stream head to be called by kstrgetmsg()
+ * with every packet received on the read queue, and before copying its
+ * content to user buffers. kstrgetmsg() calls only once with the same
+ * message.
+ * If the message is successfully procssed, then it is returned.
+ * A failed message will be freed.
+ */
+/* ARGSUSED */
+mblk_t *
+strsock_kssl_input(vnode_t *vp, mblk_t *mp,
+		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
+		strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
+{
+	struct sonode *so = VTOSO(vp);
+	kssl_ctx_t kssl_ctx = so->so_kssl_ctx;
+	kssl_cmd_t kssl_cmd;
+	mblk_t *out;
+
+	dprintso(so, 1, ("strsock_kssl_input(%p, %p)\n", vp, mp));
+
+	ASSERT(!(DB_FLAGS(mp) & DBLK_COOKED));
+
+	kssl_cmd = kssl_handle_record(kssl_ctx, &mp, &out);
+
+	switch (kssl_cmd) {
+	case KSSL_CMD_NONE:
+		return (NULL);
+
+	case KSSL_CMD_DELIVER_PROXY:
+		return (mp);
+
+	case KSSL_CMD_SEND: {
+		ASSERT(out != NULL);
+
+		putnext(vp->v_stream->sd_wrq, out);
+	}
+	/* FALLTHU */
+	default:
+		/* transient error. */
+		return (NULL);
+	}
+}
+
+/*
+ * This routine is registered with the stream head be called by
+ * kstrmakedata() with every packet sent downstreams.
+ * If the message is successfully procssed, then it is returned.
+ */
+/* ARGSUSED */
+mblk_t *
+strsock_kssl_output(vnode_t *vp, mblk_t *mp,
+		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
+		strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
+{
+	struct sonode *so = VTOSO(vp);
+	kssl_ctx_t kssl_ctx = so->so_kssl_ctx;
+	mblk_t *recmp;
+
+	dprintso(so, 1, ("strsock_kssl_output(%p, %p)\n", vp, mp));
+
+	if ((recmp = kssl_build_record(kssl_ctx, mp)) == NULL) {
+		/* The caller will free the bogus message */
+		return (NULL);
+	}
+	return (recmp);
+}
--- a/usr/src/uts/common/fs/sockfs/sockstr.c	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/fs/sockfs/sockstr.c	Sat Nov 12 18:58:05 2005 -0800
@@ -65,6 +65,8 @@
 #define	_SUN_TPI_VERSION	2
 #include <sys/tihdr.h>
 
+#include <inet/kssl/ksslapi.h>
+
 #include <c2/audit.h>
 
 int so_default_version = SOV_SOCKSTREAM;
@@ -1202,6 +1204,20 @@
 			}
 			so->so_error = ECONNABORTED;
 			mutex_exit(&so->so_lock);
+
+			/*
+			 * T_KSSL_PROXY_CONN_IND may carry a handle for
+			 * an SSL context, and needs to be released.
+			 */
+			if ((tci->PRIM_type == T_SSL_PROXY_CONN_IND) &&
+			    (mp->b_cont != NULL)) {
+				kssl_ctx_t kssl_ctx;
+
+				ASSERT(MBLKL(mp->b_cont) ==
+				    sizeof (kssl_ctx_t));
+				kssl_ctx = *((kssl_ctx_t *)mp->b_cont->b_rptr);
+				kssl_release_ctx(kssl_ctx);
+			}
 			freemsg(mp);
 			return (0);
 		}
@@ -2148,6 +2164,11 @@
 		return (NULL);
 	}
 
+	/*
+	 * Extra processing in case of an SSL proxy, before queuing or
+	 * forwarding to the fallback endpoint
+	 */
+	case T_SSL_PROXY_CONN_IND:
 	case T_CONN_IND:
 		/*
 		 * Verify the min size and queue the message on
@@ -2171,6 +2192,28 @@
 			freemsg(mp);
 			return (NULL);
 		}
+
+		if (tpr->type == T_SSL_PROXY_CONN_IND && mp->b_cont == NULL) {
+			/* No context: need to fall back */
+			struct sonode *fbso;
+			stdata_t *fbstp;
+
+			tpr->type = T_CONN_IND;
+
+			fbso = kssl_find_fallback(so->so_kssl_ent);
+
+			/*
+			 * No fallback: the remote will timeout and
+			 * disconnect.
+			 */
+			if (fbso == NULL) {
+				freemsg(mp);
+				return (NULL);
+			}
+			fbstp = SOTOV(fbso)->v_stream;
+			qreply(fbstp->sd_wrq->q_next, mp);
+			return (NULL);
+		}
 		soqueueconnind(so, mp);
 		*allmsgsigs = S_INPUT | S_RDNORM;
 		*pollwakeups = POLLIN | POLLRDNORM;
--- a/usr/src/uts/common/fs/sockfs/socktpi.c	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/fs/sockfs/socktpi.c	Sat Nov 12 18:58:05 2005 -0800
@@ -78,6 +78,8 @@
 #include <fs/sockfs/nl7c.h>
 #include <sys/zone.h>
 
+#include <inet/kssl/ksslapi.h>
+
 /*
  * Possible failures when memory can't be allocated. The documented behavior:
  *
@@ -174,6 +176,12 @@
 extern	void *nl7c_add_addr(void *, t_uscalar_t);
 extern	void nl7c_listener_addr(void *, queue_t *);
 
+/* Sockets acting as an in-kernel SSL proxy */
+extern mblk_t	*strsock_kssl_input(vnode_t *, mblk_t *, strwakeup_t *,
+		    strsigset_t *, strsigset_t *, strpollset_t *);
+extern mblk_t	*strsock_kssl_output(vnode_t *, mblk_t *, strwakeup_t *,
+		    strsigset_t *, strsigset_t *, strpollset_t *);
+
 static int	sotpi_unbind(struct sonode *, int);
 
 /* TPI sockfs sonode operations */
@@ -289,6 +297,12 @@
 		version = so_default_version;
 
 	so->so_version = (short)version;
+
+	/* Initialize the kernel SSL proxy fields */
+	so->so_kssl_type = KSSL_NO_PROXY;
+	so->so_kssl_ent = NULL;
+	so->so_kssl_ctx = NULL;
+
 	return (so);
 }
 
@@ -773,9 +787,37 @@
 	mp = soallocproto2(&bind_req, sizeof (bind_req),
 				addr, addrlen, 0, _ALLOC_SLEEP);
 	so->so_state &= ~SS_LADDR_VALID;
+
 	/* Done using so_laddr_sa - can drop the lock */
 	mutex_exit(&so->so_lock);
 
+	/*
+	 * Intercept the bind_req message here to check if this <address/port>
+	 * was configured as an SSL proxy server, or if another endpoint was
+	 * already configured to act as a proxy for us.
+	 */
+	if ((so->so_family == AF_INET || so->so_family == AF_INET6) &&
+	    so->so_type == SOCK_STREAM) {
+
+		if (so->so_kssl_ent != NULL) {
+			kssl_release_ent(so->so_kssl_ent, so, so->so_kssl_type);
+			so->so_kssl_ent = NULL;
+		}
+
+		so->so_kssl_type = kssl_check_proxy(mp, so, &so->so_kssl_ent);
+		switch (so->so_kssl_type) {
+		case KSSL_NO_PROXY:
+			break;
+
+		case KSSL_HAS_PROXY:
+			mutex_enter(&so->so_lock);
+			goto skip_transport;
+
+		case KSSL_IS_PROXY:
+			break;
+		}
+	}
+
 	error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0,
 			MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0);
 	if (error) {
@@ -791,6 +833,7 @@
 		eprintsoline(so, error);
 		goto done;
 	}
+skip_transport:
 	ASSERT(mp);
 	/*
 	 * Even if some TPI message (e.g. T_DISCON_IND) was received in
@@ -1155,7 +1198,18 @@
 		vnode_t *vp;
 
 		if ((vp = so->so_ux_bound_vp) != NULL) {
-			ASSERT(vp->v_stream);
+
+			/* Undo any SSL proxy setup */
+			if ((so->so_family == AF_INET ||
+			    so->so_family == AF_INET6) &&
+			    (so->so_type == SOCK_STREAM) &&
+			    (so->so_kssl_ent != NULL)) {
+				kssl_release_ent(so->so_kssl_ent, so,
+				    so->so_kssl_type);
+				so->so_kssl_ent = NULL;
+				so->so_kssl_type = KSSL_NO_PROXY;
+			}
+
 			so->so_ux_bound_vp = NULL;
 			vn_rele_stream(vp);
 		}
@@ -1164,6 +1218,7 @@
 	}
 	so->so_state &= ~(SS_ISBOUND|SS_ACCEPTCONN|SS_LADDR_VALID);
 done:
+
 	/* If the caller held the lock don't release it here */
 	ASSERT(MUTEX_HELD(&so->so_lock));
 	ASSERT(so->so_flag & SOLOCKED);
@@ -1356,7 +1411,7 @@
 	struct T_conn_ind	*conn_ind;
 	struct T_conn_res	*conn_res;
 	int			error = 0;
-	mblk_t			*mp;
+	mblk_t			*mp, *ctxmp;
 	struct sonode		*nso;
 	vnode_t			*nvp;
 	void			*src;
@@ -1384,6 +1439,8 @@
 
 	ASSERT(mp);
 	conn_ind = (struct T_conn_ind *)mp->b_rptr;
+	ctxmp = mp->b_cont;
+
 	/*
 	 * Save SEQ_number for error paths.
 	 */
@@ -1476,6 +1533,23 @@
 	}
 	nvp = SOTOV(nso);
 
+	/*
+	 * If the transport sent up an SSL connection context, then attach
+	 * it the new socket, and set the (sd_wputdatafunc)() and
+	 * (sd_rputdatafunc)() stream head hooks to intercept and process
+	 * SSL records.
+	 */
+	if (ctxmp != NULL) {
+		/*
+		 * This kssl_ctx_t is already held for us by the transport.
+		 * So, we don't need to do a kssl_hold_ctx() here.
+		 */
+		nso->so_kssl_ctx = *((kssl_ctx_t *)ctxmp->b_rptr);
+		freemsg(ctxmp);
+		mp->b_cont = NULL;
+		strsetrwputdatahooks(nvp, strsock_kssl_input,
+		    strsock_kssl_output);
+	}
 #ifdef DEBUG
 	/*
 	 * SO_DEBUG is used to trigger the dprint* and eprint* macros thus
@@ -4288,6 +4362,7 @@
 	struct stdata *stp = SOTOV(so)->v_stream;
 	ssize_t iosize, rmax, maxblk;
 	queue_t *tcp_wq = stp->sd_wrq->q_next;
+	mblk_t *newmp;
 	int error = 0, wflag = 0;
 
 	ASSERT(so->so_mode & SM_BYTESTREAM);
@@ -4305,6 +4380,15 @@
 		 * data to tcp.
 		 */
 		ASSERT(mp != NULL);
+		if (stp->sd_wputdatafunc != NULL) {
+			newmp = (stp->sd_wputdatafunc)(SOTOV(so), mp, NULL,
+			    NULL, NULL, NULL);
+			if (newmp == NULL) {
+				/* The caller will free mp */
+				return (ECOMM);
+			}
+			mp = newmp;
+		}
 		tcp_wput(tcp_wq, mp);
 		return (0);
 	}
@@ -4347,6 +4431,15 @@
 		 * to tcp and let the rest be handled in strwrite().
 		 */
 		ASSERT(error == 0 || error == ENOMEM);
+		if (stp->sd_wputdatafunc != NULL) {
+			newmp = (stp->sd_wputdatafunc)(SOTOV(so), mp, NULL,
+			    NULL, NULL, NULL);
+			if (newmp == NULL) {
+				/* The caller will free mp */
+				return (ECOMM);
+			}
+			mp = newmp;
+		}
 		tcp_wput(tcp_wq, mp);
 
 		wflag |= NOINTR;
--- a/usr/src/uts/common/fs/sockfs/sockvnops.c	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/fs/sockfs/sockvnops.c	Sat Nov 12 18:58:05 2005 -0800
@@ -91,6 +91,8 @@
 #include <inet/udp_impl.h>
 #include <inet/tcp_impl.h>
 
+#include <inet/kssl/ksslapi.h>
+
 static int socktpi_close(struct vnode *, int, int, offset_t, struct cred *);
 static int socktpi_read(struct vnode *, struct uio *, int, struct cred *,
 	struct caller_context *);
@@ -370,6 +372,19 @@
 			so->so_ux_bound_vp = NULL;
 			vn_rele_stream(ux_vp);
 		}
+		if (so->so_family == AF_INET || so->so_family == AF_INET6) {
+			strsetrwputdatahooks(SOTOV(so), NULL, NULL);
+			if (so->so_kssl_ent != NULL) {
+				kssl_release_ent(so->so_kssl_ent, so,
+				    so->so_kssl_type);
+				so->so_kssl_ent = NULL;
+			}
+			if (so->so_kssl_ctx != NULL) {
+				kssl_release_ctx(so->so_kssl_ctx);
+				so->so_kssl_ctx = NULL;
+			}
+			so->so_kssl_type = KSSL_NO_PROXY;
+		}
 		error = strclose(vp, flag, cr);
 		vp->v_stream = NULL;
 		mutex_enter(&so->so_lock);
--- a/usr/src/uts/common/inet/ip.h	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/inet/ip.h	Sat Nov 12 18:58:05 2005 -0800
@@ -3068,6 +3068,7 @@
 #define	SQTAG_UDP_INPUT			33
 #define	SQTAG_UDP_WPUT			34
 #define	SQTAG_UDP_OUTPUT		35
+#define	SQTAG_TCP_KSSL_INPUT		36
 
 #endif	/* _KERNEL */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/kssl/Makefile	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,53 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# uts/common/inet/kssl/Makefile
+#
+# include global definitions
+include ../../../../Makefile.master
+
+HDRS= kssl.h ksslapi.h ksslimpl.h ksslproto.h
+
+ROOTDIRS= $(ROOT)/usr/include/inet/kssl
+
+ROOTHDRS= $(HDRS:%=$(ROOT)/usr/include/inet/kssl/%)
+
+CHECKHDRS= $(HDRS:%.h=%.check)
+
+$(ROOTDIRS)/%: %
+	$(INS.file)
+
+.KEEP_STATE:
+
+.PARALLEL: $(CHECKHDRS)
+
+install_h: $(ROOTDIRS) $(ROOTHDRS)
+
+$(ROOTDIRS):
+	$(INS.dir)
+
+check:	$(CHECKHDRS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/kssl/kssl.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,580 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * The system call and DDI interface for the kernel SSL module
+ */
+
+#include <sys/types.h>
+#include <sys/modctl.h>
+#include <sys/conf.h>
+#include <sys/stat.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/kmem.h>
+#include <sys/errno.h>
+#include <sys/ksynch.h>
+#include <sys/file.h>
+#include <sys/open.h>
+#include <sys/cred.h>
+#include <sys/proc.h>
+#include <sys/task.h>
+#include <sys/mkdev.h>
+#include <sys/model.h>
+#include <sys/sysmacros.h>
+#include <sys/policy.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/api.h>
+#include <c2/audit.h>
+#include <sys/kstat.h>
+
+#include "kssl.h"
+#include "ksslimpl.h"
+
+/*
+ * DDI entry points.
+ */
+static int kssl_attach(dev_info_t *, ddi_attach_cmd_t);
+static int kssl_detach(dev_info_t *, ddi_detach_cmd_t);
+static int kssl_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int kssl_open(dev_t *, int, int, cred_t *);
+static int kssl_close(dev_t, int, int, cred_t *);
+static int kssl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+
+static int kssl_constructor(void *buf, void *arg, int kmflags);
+static void kssl_destructor(void *buf, void *arg);
+
+/*
+ * Module linkage.
+ */
+static struct cb_ops cbops = {
+	kssl_open,		/* cb_open */
+	kssl_close,		/* cb_close */
+	nodev,			/* cb_strategy */
+	nodev,			/* cb_print */
+	nodev,			/* cb_dump */
+	nodev,			/* cb_read */
+	nodev,			/* cb_write */
+	kssl_ioctl,		/* cb_ioctl */
+	nodev,			/* cb_devmap */
+	nodev,			/* cb_mmap */
+	nodev,			/* cb_segmap */
+	nochpoll,		/* cb_chpoll */
+	ddi_prop_op,		/* cb_prop_op */
+	NULL,			/* cb_streamtab */
+	D_MP,			/* cb_flag */
+	CB_REV,			/* cb_rev */
+	nodev,			/* cb_aread */
+	nodev,			/* cb_awrite */
+};
+
+static struct dev_ops devops = {
+	DEVO_REV,		/* devo_rev */
+	0,			/* devo_refcnt */
+	kssl_getinfo,		/* devo_getinfo */
+	nulldev,		/* devo_identify */
+	nulldev,		/* devo_probe */
+	kssl_attach,		/* devo_attach */
+	kssl_detach,		/* devo_detach */
+	nodev,			/* devo_reset */
+	&cbops,			/* devo_cb_ops */
+	NULL,			/* devo_bus_ops */
+	NULL,			/* devo_power */
+};
+
+static struct modldrv modldrv = {
+	&mod_driverops,			/* drv_modops */
+	"Kernel SSL Interface v%I%",	/* drv_linkinfo */
+	&devops,
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,		/* ml_rev */
+	&modldrv,		/* ml_linkage */
+	NULL
+};
+
+static dev_info_t *kssl_dip = NULL;
+
+crypto_mechanism_t rsa_x509_mech = {CRYPTO_MECH_INVALID, NULL, 0};
+crypto_mechanism_t hmac_md5_mech = {CRYPTO_MECH_INVALID, NULL, 0};
+crypto_mechanism_t hmac_sha1_mech = {CRYPTO_MECH_INVALID, NULL, 0};
+crypto_call_flag_t kssl_call_flag = CRYPTO_ALWAYS_QUEUE;
+
+KSSLCipherDef cipher_defs[] = { /* indexed by SSL3BulkCipher */
+	/* type bsize keysz crypto_mech_type_t */
+
+	{type_stream, 0, 0, CRYPTO_MECH_INVALID},
+
+	/* mech_type to be initialized with CKM_RC4's */
+	{type_stream, 0, 16, CRYPTO_MECH_INVALID},
+
+	/* mech_type to be initialized with CKM_DES_CBC's */
+	{type_block, 8, 8, CRYPTO_MECH_INVALID},
+
+	/* mech_type to be initialized with CKM_DES3_CBC's */
+	{type_block, 8, 24, CRYPTO_MECH_INVALID},
+};
+
+int kssl_enabled = 1;
+struct kmem_cache *kssl_cache;
+
+static void kssl_global_init();
+static void kssl_init_mechs();
+static void kssl_event_callback(uint32_t, void *);
+
+/*
+ * DDI entry points.
+ */
+int
+_init(void)
+{
+	return (mod_install(&modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+/* ARGSUSED */
+static int
+kssl_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+	switch (cmd) {
+	case DDI_INFO_DEVT2DEVINFO:
+		*result = kssl_dip;
+		return (DDI_SUCCESS);
+
+	case DDI_INFO_DEVT2INSTANCE:
+		*result = (void *)0;
+		return (DDI_SUCCESS);
+	}
+	return (DDI_FAILURE);
+}
+
+static int
+kssl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	if (cmd != DDI_ATTACH) {
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_get_instance(dip) != 0) {
+		/* we only allow instance 0 to attach */
+		return (DDI_FAILURE);
+	}
+
+	/* create the minor node */
+	if (ddi_create_minor_node(dip, "kssl", S_IFCHR, 0, DDI_PSEUDO, 0) !=
+	    DDI_SUCCESS) {
+		cmn_err(CE_WARN, "kssl_attach: failed creating minor node");
+		ddi_remove_minor_node(dip, NULL);
+		return (DDI_FAILURE);
+	}
+
+	kssl_dip = dip;
+
+	kssl_global_init();
+
+	return (DDI_SUCCESS);
+}
+
+static int
+kssl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	if (cmd != DDI_DETACH)
+		return (DDI_FAILURE);
+
+	if (kssl_entry_tab_nentries != 0)
+		return (DDI_FAILURE);
+
+	mutex_destroy(&kssl_tab_mutex);
+	kssl_dip = NULL;
+
+	if (kssl_cache != NULL) {
+		kmem_cache_destroy(kssl_cache);
+	}
+
+	ddi_remove_minor_node(dip, NULL);
+
+	return (DDI_SUCCESS);
+}
+
+static crypto_notify_handle_t prov_update_handle = NULL;
+
+/* ARGSUSED */
+static int
+kssl_open(dev_t *devp, int flag, int otyp, cred_t *credp)
+{
+	if (otyp != OTYP_CHR)
+		return (ENXIO);
+
+	if (kssl_dip == NULL)
+		return (ENXIO);
+
+	/* first time here? initialize everything */
+	if (rsa_x509_mech.cm_type == CRYPTO_MECH_INVALID) {
+		kssl_init_mechs();
+		prov_update_handle = crypto_notify_events(
+		    kssl_event_callback, CRYPTO_EVENT_PROVIDERS_CHANGE);
+	}
+
+	/* exclusive opens are not supported */
+	if (flag & FEXCL)
+		return (ENOTSUP);
+
+	return (0);
+}
+
+/* ARGSUSED */
+static int
+kssl_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+	return (0);
+}
+
+#define	KSSL_MAX_KEYANDCERTS	80000	/* max 64K plus a little margin */
+
+/* ARGSUSED */
+static int
+kssl_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *c,
+    int *rval)
+{
+	int error = EINVAL;
+
+#define	ARG	((caddr_t)arg)
+
+	if (secpolicy_net_config(c, B_FALSE) != 0) {
+		return (EPERM);
+	}
+
+	switch (cmd) {
+	case KSSL_ADD_ENTRY: {
+		kssl_params_t kssl_params_s, *kssl_params = &kssl_params_s;
+		uint64_t len;
+
+		if (copyin(ARG, kssl_params, sizeof (kssl_params_s)) != 0) {
+			return (EFAULT);
+		}
+
+		len = kssl_params->kssl_params_size;
+		if (len < sizeof (kssl_params_t) ||
+		    len > KSSL_MAX_KEYANDCERTS) {
+			return (EINVAL);
+		}
+
+		kssl_params = kmem_alloc(len, KM_SLEEP);
+
+		/* Get the whole structure and parameters in one move */
+		if (copyin(ARG, kssl_params, len) != 0) {
+			kmem_free(kssl_params, len);
+			return (EFAULT);
+		}
+		error = kssl_add_entry(kssl_params);
+#ifdef C2_AUDIT
+	if (audit_active)
+		audit_kssl(KSSL_ADD_ENTRY, kssl_params, error);
+#endif
+		kmem_free(kssl_params, len);
+		break;
+	}
+	case KSSL_DELETE_ENTRY: {
+		struct sockaddr_in server_addr;
+
+		if (copyin(ARG, &server_addr, sizeof (server_addr)) != 0) {
+			return (EFAULT);
+		}
+
+		error = kssl_delete_entry(&server_addr);
+#ifdef C2_AUDIT
+	if (audit_active)
+		audit_kssl(KSSL_DELETE_ENTRY, &server_addr, error);
+#endif
+		break;
+	}
+	}
+
+	return (error);
+}
+
+#define	NUM_MECHS	6
+mech_to_cipher_t mech_to_cipher_tab[NUM_MECHS] = {
+	{CRYPTO_MECH_INVALID, SUN_CKM_RSA_X_509,
+	    {SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA,
+	    SSL_RSA_WITH_DES_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA,
+	    SSL_RSA_WITH_NULL_SHA}},
+	{CRYPTO_MECH_INVALID, SUN_CKM_MD5_HMAC, {SSL_RSA_WITH_RC4_128_MD5}},
+	{CRYPTO_MECH_INVALID, SUN_CKM_SHA1_HMAC,
+	    {SSL_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_DES_CBC_SHA,
+	    SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_NULL_SHA}},
+	{CRYPTO_MECH_INVALID, SUN_CKM_RC4,
+	    {SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA}},
+	{CRYPTO_MECH_INVALID, SUN_CKM_DES_CBC, {SSL_RSA_WITH_DES_CBC_SHA}},
+	{CRYPTO_MECH_INVALID, SUN_CKM_DES3_CBC,
+	    {SSL_RSA_WITH_3DES_EDE_CBC_SHA}}
+};
+
+static void
+kssl_init_mechs()
+{
+	mech_to_cipher_tab[0].mech = rsa_x509_mech.cm_type =
+	    crypto_mech2id(SUN_CKM_RSA_X_509);
+	mech_to_cipher_tab[1].mech = hmac_md5_mech.cm_type =
+	    crypto_mech2id(SUN_CKM_MD5_HMAC);
+	mech_to_cipher_tab[2].mech = hmac_sha1_mech.cm_type =
+	    crypto_mech2id(SUN_CKM_SHA1_HMAC);
+
+	mech_to_cipher_tab[3].mech = cipher_defs[cipher_rc4].mech_type =
+	    crypto_mech2id(SUN_CKM_RC4);
+	mech_to_cipher_tab[4].mech = cipher_defs[cipher_des].mech_type =
+	    crypto_mech2id(SUN_CKM_DES_CBC);
+	mech_to_cipher_tab[5].mech = cipher_defs[cipher_3des].mech_type =
+	    crypto_mech2id(SUN_CKM_DES3_CBC);
+}
+
+static int
+is_in_suites(uint16_t s, uint16_t *sarray)
+{
+	int i;
+
+	for (i = 0; i < CIPHER_SUITE_COUNT; i++) {
+		if (s == sarray[i])
+			return (1);
+	}
+
+	return (0);
+}
+
+static int
+is_in_mechlist(char *name, crypto_mech_name_t *mechs, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (strncmp(name, mechs[i], CRYPTO_MAX_MECH_NAME) == 0)
+			return (1);
+	}
+
+	return (0);
+}
+
+/*
+ * Callback function invoked by the crypto framework when a provider's
+ * mechanism is available/unavailable. This callback updates entries in the
+ * kssl_entry_tab[] to make changes to the cipher suites of an entry
+ * which are affected by the mechansim.
+ */
+static void
+kssl_event_callback(uint32_t event, void *event_arg)
+{
+	int i, j;
+	int cnt, rcnt;
+	uint16_t s;
+	boolean_t changed;
+	crypto_mech_name_t *mechs;
+	uint_t mech_count;
+	mech_to_cipher_t *mc;
+	kssl_entry_t *old;
+	kssl_entry_t *new;
+	uint16_t tmp_suites[CIPHER_SUITE_COUNT];
+	uint16_t dis_list[CIPHER_SUITE_COUNT];
+	crypto_notify_event_change_t *prov_change =
+	    (crypto_notify_event_change_t *)event_arg;
+
+	/* ignore events for which we didn't register */
+	if (event != CRYPTO_EVENT_PROVIDERS_CHANGE) {
+		return;
+	}
+
+	for (i = 0; i < NUM_MECHS; i++) {
+		mc = &(mech_to_cipher_tab[i]);
+		if (mc->mech == CRYPTO_MECH_INVALID)
+			continue;
+
+		/*
+		 * Check if this crypto framework provider mechanism being
+		 * added or removed affects us.
+		 */
+		if (strncmp(mc->name, prov_change->ec_mech_name,
+		    CRYPTO_MAX_MECH_NAME) == 0)
+			break;
+	}
+
+	if (i == NUM_MECHS)
+		return;
+
+	mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
+	if (mechs == NULL)
+		return;
+
+	mutex_enter(&kssl_tab_mutex);
+
+	for (i = 0; i < kssl_entry_tab_size; i++) {
+		if ((old = kssl_entry_tab[i]) == NULL)
+			continue;
+
+		cnt = 0;
+		rcnt = 0;
+		changed = B_FALSE;
+		for (j = 0; j < CIPHER_SUITE_COUNT; j++) {
+			tmp_suites[j] = CIPHER_NOTSET;
+			dis_list[j] = CIPHER_NOTSET;
+		}
+
+		/*
+		 * We start with the saved cipher suite list for the new entry.
+		 * If a mechanism is disabled, resulting in a cipher suite being
+		 * disabled now, we take it out from the list for the new entry.
+		 * If a mechanism is enabled, resulting in a cipher suite being
+		 * enabled now, we don't need to do any thing.
+		 */
+		if (!is_in_mechlist(mc->name, mechs, mech_count)) {
+			for (j = 0; j < CIPHER_SUITE_COUNT; j++) {
+				s = mc->kssl_suites[j];
+				if (s == 0)
+					break;
+				if (is_in_suites(s, old->kssl_saved_Suites)) {
+					/* Disable this cipher suite */
+					if (!is_in_suites(s, dis_list))
+						dis_list[cnt++] = s;
+				}
+			}
+		}
+
+		for (j = 0; j < CIPHER_SUITE_COUNT; j++) {
+			s = old->kssl_saved_Suites[j];
+			if (!is_in_suites(s, dis_list))
+				tmp_suites[rcnt] = s;
+
+			if (!changed &&
+			    (tmp_suites[rcnt] != old->kssl_cipherSuites[rcnt]))
+				changed = B_TRUE;
+			rcnt++;
+		}
+
+		if (changed) {
+			new = kmem_zalloc(sizeof (kssl_entry_t), KM_NOSLEEP);
+			if (new == NULL)
+				continue;
+
+			*new = *old;		/* Structure copy */
+			old->ke_no_freeall = B_TRUE;
+			new->ke_refcnt = 0;
+			new->kssl_cipherSuites_nentries = rcnt;
+			for (j = 0; j < CIPHER_SUITE_COUNT; j++)
+				new->kssl_cipherSuites[j] = tmp_suites[j];
+
+			KSSL_ENTRY_REFHOLD(new);
+			kssl_entry_tab[i] = new;
+			KSSL_ENTRY_REFRELE(old);
+		}
+	}
+
+	mutex_exit(&kssl_tab_mutex);
+	crypto_free_mech_list(mechs, mech_count);
+}
+
+
+kssl_stats_t *kssl_statp;
+
+static void
+kssl_global_init()
+{
+	kstat_t *ksp;
+
+	mutex_init(&kssl_tab_mutex, NULL, MUTEX_DRIVER, NULL);
+
+	kssl_cache = kmem_cache_create("kssl_cache", sizeof (ssl_t),
+	    0, kssl_constructor, kssl_destructor, NULL, NULL, NULL, 0);
+
+	if ((ksp = kstat_create("kssl", 0, "kssl_stats", "crypto",
+	    KSTAT_TYPE_NAMED, sizeof (kssl_stats_t) / sizeof (kstat_named_t),
+	    KSTAT_FLAG_PERSISTENT)) != NULL) {
+		kssl_statp = ksp->ks_data;
+
+		kstat_named_init(&kssl_statp->sid_cache_lookups,
+		    "kssl_sid_cache_lookups", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->sid_cache_hits,
+		    "kssl_sid_cache_hits", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->sid_uncached,
+		    "kssl_sid_uncached", KSTAT_DATA_UINT64);
+
+		kstat_named_init(&kssl_statp->full_handshakes,
+		    "kssl_full_handshakes", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->resumed_sessions,
+		    "kssl_resumed_sessions", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->fallback_connections,
+		    "kssl_fallback_connections", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->proxy_fallback_failed,
+		    "kssl_proxy_fallback_failed", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->appdata_record_ins,
+		    "kssl_appdata_record_ins", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->appdata_record_outs,
+		    "kssl_appdata_record_outs", KSTAT_DATA_UINT64);
+
+		kstat_named_init(&kssl_statp->alloc_fails, "kssl_alloc_fails",
+		    KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->fatal_alerts,
+		    "kssl_fatal_alerts", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->warning_alerts,
+		    "kssl_warning_alerts", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->no_suite_found,
+		    "kssl_no_suite_found", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->compute_mac_failure,
+		    "kssl_compute_mac_failure", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->verify_mac_failure,
+		    "kssl_verify_mac_failure", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->record_decrypt_failure,
+		    "kssl_record_decrypt_failure", KSTAT_DATA_UINT64);
+		kstat_named_init(&kssl_statp->bad_pre_master_secret,
+		    "kssl_bad_pre_master_secret", KSTAT_DATA_UINT64);
+
+		kstat_install(ksp);
+	};
+}
+
+/*ARGSUSED*/
+static int
+kssl_constructor(void *buf, void *arg, int kmflags)
+{
+	ssl_t *ssl = buf;
+
+	mutex_init(&ssl->kssl_lock, NULL, MUTEX_DEFAULT, NULL);
+
+	return (0);
+}
+
+/*ARGSUSED*/
+static void
+kssl_destructor(void *buf, void *arg)
+{
+	ssl_t *ssl = buf;
+	mutex_destroy(&ssl->kssl_lock);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/kssl/kssl.conf	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+
+name="kssl" parent="pseudo" instance=0;
+ddi-forceattach=1;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/kssl/kssl.h	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,111 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_INET_KSSL_KSSL_H
+#define	_INET_KSSL_KSSL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/crypto/common.h>
+
+/* These are re-definition from <crypto/ioctl.h>  */
+typedef struct kssl_object_attribute {
+	uint64_t	ka_type;		/* attribute type */
+	uint32_t	ka_value_offset;	/* offset to attribute value */
+	uint32_t	ka_value_len;		/* length of attribute value */
+} kssl_object_attribute_t;
+
+
+typedef struct kssl_key {
+	crypto_key_format_t ks_format;	/* format identifier */
+	uint32_t ks_count;		/* number of attributes */
+	uint32_t ks_attrs_offset;	/* offset to the attributes */
+} kssl_key_t;
+
+
+typedef struct kssl_certs_s {
+	uint32_t sc_count;		/* number of certificates */
+	uint32_t sc_sizes_offset;	/* offset to certificates sizes array */
+	uint32_t sc_certs_offset;	/* offset to certificates array */
+} kssl_certs_t;
+
+
+#define	SSL_RSA_WITH_NULL_SHA		0x0002
+#define	SSL_RSA_WITH_RC4_128_MD5	0x0004
+#define	SSL_RSA_WITH_RC4_128_SHA	0x0005
+#define	SSL_RSA_WITH_DES_CBC_SHA	0x0009
+#define	SSL_RSA_WITH_3DES_EDE_CBC_SHA	0x000a
+#define	CIPHER_SUITE_COUNT		5
+#define	CIPHER_NOTSET			0xffff
+
+#define	DEFAULT_SID_TIMEOUT		86400	/* 24 hours in seconds */
+#define	DEFAULT_SID_CACHE_NENTRIES	5000
+
+typedef struct kssl_params_s {
+	uint64_t		kssl_params_size; /* total params buf len */
+	/* address and port number */
+	struct sockaddr_in	kssl_addr;
+	uint16_t		kssl_proxy_port;
+
+	uint32_t		kssl_session_cache_timeout;	/* In seconds */
+	uint32_t		kssl_session_cache_size;
+
+	/*
+	 * Contains ordered list of cipher suites. We do not include
+	 * the one suite with no encryption. Hence the -1.
+	 */
+	uint16_t		kssl_suites[CIPHER_SUITE_COUNT - 1];
+
+	/* certificates */
+	kssl_certs_t		kssl_certs;
+
+	/* private key */
+	kssl_key_t		kssl_privkey;
+} kssl_params_t;
+
+/* The ioctls to /dev/kssl */
+#define	KSSL_IOC(x)		(('k' << 8) | (x))
+#define	KSSL_ADD_ENTRY		KSSL_IOC(1)
+#define	KSSL_DELETE_ENTRY	KSSL_IOC(2)
+
+#ifdef	_KERNEL
+
+extern int kssl_add_entry(kssl_params_t *);
+extern int kssl_delete_entry(struct sockaddr_in *);
+
+#endif	/* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _INET_KSSL_KSSL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/kssl/ksslapi.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,1185 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/cpuvar.h>
+#include <sys/atomic.h>
+#include <sys/sysmacros.h>
+
+#include <inet/common.h>
+#include <inet/ip.h>
+#include <inet/ip6.h>
+
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/tihdr.h>
+
+#include "ksslimpl.h"
+#include "ksslproto.h"
+#include "ksslapi.h"
+
+static kssl_cmd_t kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp,
+    mblk_t **decrmp, kssl_callback_t cbfn, void *arg);
+static boolean_t kssl_enqueue(kssl_chain_t **head, void *item);
+static void kssl_dequeue(kssl_chain_t **head, void *item);
+static kssl_status_t kssl_build_single_record(ssl_t *ssl, mblk_t *mp);
+
+/*
+ * The socket T_bind_req message is intercepted and re-routed here
+ * to see is there is SSL relevant job to do, based on the kssl config
+ * in the kssl_entry_tab.
+ * Looks up the kernel SSL proxy table, to find an entry that matches the
+ * same serveraddr, and has one of the following two criteria:
+ * 1. in_port is an ssl_port. This endpoint can be used later as a fallback
+ *    to complete connections that cannot be handled by the SSL kernel proxy
+ *    (typically non supported ciphersuite). The cookie for the calling client
+ *    is saved with the kssl_entry to be retrieved for the fallback.
+ *    The function returns KSSL_HAS_PROXY.
+ *
+ * 2. in_port is a proxy port for another ssl port. The ssl port is then
+ *    substituted to the in_port in the bind_req TPI structure, so that
+ *    the bind falls through to the SSL port. At the end of this operation,
+ *    all the packets arriving to the SSL port will be delivered to an
+ *    accepted endpoint child of this bound socket.
+ *    The  kssl_entry_t is returned in *ksslent, for later use by the
+ *    lower modules' SSL hooks that handle the Handshake messages.
+ *    The function returns KSSL_IS_PROXY.
+ *
+ * The function returns KSSL_NO_PROXY otherwise. We do not suppport
+ * IPv6 addresses.
+ */
+
+kssl_endpt_type_t
+kssl_check_proxy(mblk_t *bindmp, void *cookie, kssl_ent_t *ksslent)
+{
+	int i;
+	kssl_endpt_type_t ret;
+	kssl_entry_t *ep;
+	sin_t *sin;
+	struct T_bind_req *tbr;
+	ipaddr_t v4addr;
+	in_port_t in_port;
+
+	if (kssl_enabled == 0) {
+		return (KSSL_NO_PROXY);
+	}
+
+	tbr = (struct T_bind_req *)bindmp->b_rptr;
+
+	ret = KSSL_NO_PROXY;
+
+
+	switch (tbr->ADDR_length) {
+	case sizeof (sin_t):
+		sin = (sin_t *)(bindmp->b_rptr + tbr->ADDR_length);
+		in_port = ntohs(sin->sin_port);
+		v4addr = sin->sin_addr.s_addr;
+		break;
+
+	case sizeof (sin6_t):
+		/* Future support of IPv6 goes here */
+	default:
+		/* Should ASSERT() here? */
+		return (ret);
+	}
+
+	mutex_enter(&kssl_tab_mutex);
+
+	for (i = 0; i < kssl_entry_tab_size; i++) {
+		if ((ep = kssl_entry_tab[i]) == NULL)
+			continue;
+
+		if ((ep->ke_laddr == v4addr) || (ep->ke_laddr == INADDR_ANY)) {
+
+			/* This is an SSL port to fallback to */
+			if (ep->ke_ssl_port == in_port) {
+
+				/*
+				 * Let's see first if there's at least
+				 * an endpoint for a proxy server.
+				 * If there's none, then we return as we have
+				 * no proxy, so that the bind() to the
+				 * transport layer goes through.
+				 * The calling module will ask for this
+				 * cookie if it wants to fall back to it,
+				 * so add this one to the list of fallback
+				 * clients.
+				 */
+				if (!kssl_enqueue((kssl_chain_t **)
+				    &(ep->ke_fallback_head), cookie)) {
+					break;
+				}
+
+				/*
+				 * Now transform the T_BIND_REQ into
+				 * a T_BIND_ACK.
+				 */
+				tbr->PRIM_type = T_BIND_ACK;
+				bindmp->b_datap->db_type = M_PCPROTO;
+
+				KSSL_ENTRY_REFHOLD(ep);
+				*ksslent = (kssl_ent_t)ep;
+
+				ret = KSSL_HAS_PROXY;
+				break;
+			}
+
+			/* This is a proxy port. */
+			if (ep->ke_proxy_port == in_port) {
+				mblk_t *entmp;
+
+				/* Append this entry to the bind_req mblk */
+
+				entmp = allocb(sizeof (kssl_entry_t),
+				    BPRI_MED);
+				if (entmp == NULL)
+					break;
+				*((kssl_entry_t **)entmp->b_rptr) = ep;
+
+				entmp->b_wptr = entmp->b_rptr +
+				    sizeof (kssl_entry_t);
+
+				bindmp->b_cont = entmp;
+
+				/* Add the caller's cookie to proxies list */
+
+				if (!kssl_enqueue((kssl_chain_t **)
+				    &(ep->ke_proxy_head), cookie)) {
+					freeb(bindmp->b_cont);
+					bindmp->b_cont = NULL;
+					break;
+				}
+
+				/*
+				 * Make this look  like the SSL port to the
+				 * transport below
+				 */
+				sin->sin_port = htons(ep->ke_ssl_port);
+
+				tbr->PRIM_type = T_SSL_PROXY_BIND_REQ;
+
+				KSSL_ENTRY_REFHOLD(ep);
+				*ksslent = (kssl_ent_t)ep;
+
+				ret = KSSL_IS_PROXY;
+				break;
+			}
+		}
+	}
+
+	mutex_exit(&kssl_tab_mutex);
+	return (ret);
+}
+
+/*
+ * Retrieved an endpoint "bound" to the SSL entry.
+ * Such endpoint has previously called kssl_check_proxy(), got itself
+ * linked to the kssl_entry's ke_fallback_head list.
+ * This routine returns the cookie from that SSL entry ke_fallback_head list.
+ */
+void *
+kssl_find_fallback(kssl_ent_t ksslent)
+{
+	kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent;
+
+	if (kssl_entry->ke_fallback_head != NULL)
+		return (kssl_entry->ke_fallback_head->fallback_bound);
+
+	KSSL_COUNTER(proxy_fallback_failed, 1);
+
+	return (NULL);
+}
+
+/*
+ * Re-usable code for adding and removing an element to/from a chain that
+ * matches "item"
+ * The chain is simple-linked and NULL ended.
+ */
+
+/*
+ * This routine returns TRUE if the item was either successfully added to
+ * the chain, or is already there. It returns FALSE otherwise.
+ */
+static boolean_t
+kssl_enqueue(kssl_chain_t **head, void *item)
+{
+	kssl_chain_t *newchain, *cur;
+
+	/* Lookup the existing entries to avoid duplicates */
+	cur = *head;
+	while (cur != NULL) {
+		if (cur->item == item) {
+			return (B_TRUE);
+		}
+		cur = cur->next;
+	}
+
+	newchain = kmem_alloc(sizeof (kssl_chain_t), KM_NOSLEEP);
+	if (newchain == NULL) {
+		return (B_FALSE);
+	}
+
+	newchain->item = item;
+	newchain->next = *head;
+	*head = newchain;
+	return (B_TRUE);
+}
+
+static void
+kssl_dequeue(kssl_chain_t **head, void *item)
+{
+	kssl_chain_t *prev, *cur;
+
+	prev = cur = *head;
+	while (cur != NULL) {
+		if (cur->item == item) {
+			if (cur == *head)
+				*head = (*head)->next;
+			else
+				prev->next = cur->next;
+			kmem_free(cur, sizeof (kssl_chain_t));
+			return;
+		}
+		prev = cur;
+		cur = cur->next;
+	}
+}
+
+/*
+ * Holds the kssl_entry
+ */
+void
+kssl_hold_ent(kssl_ent_t ksslent)
+{
+	KSSL_ENTRY_REFHOLD((kssl_entry_t *)ksslent);
+}
+
+/*
+ * Releases the kssl_entry
+ * If the caller passes a cookie, then it should be removed from both
+ * proxies and fallbacks chains.
+ */
+void
+kssl_release_ent(kssl_ent_t ksslent, void *cookie, kssl_endpt_type_t endpt_type)
+{
+	kssl_entry_t *kssl_entry = (kssl_entry_t *)ksslent;
+
+	if (cookie != NULL) {
+		if (endpt_type == KSSL_IS_PROXY)
+			ASSERT(kssl_entry->ke_proxy_head != NULL);
+			kssl_dequeue(
+			    (kssl_chain_t **)&kssl_entry->ke_proxy_head,
+			    cookie);
+		if (endpt_type == KSSL_HAS_PROXY)
+			ASSERT(kssl_entry->ke_fallback_head != NULL);
+			kssl_dequeue(
+			    (kssl_chain_t **)&kssl_entry->ke_fallback_head,
+			    cookie);
+	}
+	KSSL_ENTRY_REFRELE(kssl_entry);
+}
+
+/*
+ * Holds the kssl context
+ */
+void
+kssl_hold_ctx(kssl_ctx_t ksslctx)
+{
+	ssl_t *ssl = (ssl_t *)ksslctx;
+
+	KSSL_SSL_REFHOLD(ssl);
+}
+
+/*
+ * Releases the kssl_context
+ */
+void
+kssl_release_ctx(kssl_ctx_t ksslctx)
+{
+	KSSL_SSL_REFRELE((ssl_t *)ksslctx);
+}
+
+/*
+ * Packets are accumulated here, if there are packets already queued,
+ * or if the context is active.
+ * The context is active when an incoming record processing function
+ * is already executing on a different thread.
+ * Queued packets are handled either when an mblk arrived and completes
+ * a record, or, when the active context processor finishes the task at
+ * hand.
+ * The caller has to keep calling this routine in a loop until it returns
+ * B_FALSE in *more. The reason for this is SSL3: The protocol
+ * allows the client to send its first application_data message right
+ * after it had sent its Finished message, and not wait for the server
+ * ChangeCipherSpec and Finished. This overlap means we can't batch up
+ * a returned Handshake message to be sent on the wire
+ * with a decrypted application_data to be delivered to the application.
+ */
+kssl_cmd_t
+kssl_input(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp, boolean_t *more,
+    kssl_callback_t cbfn, void *arg)
+{
+	mblk_t *recmp, *outmp = NULL;
+	kssl_cmd_t kssl_cmd;
+	ssl_t *ssl;
+	uint8_t *rec_sz_p;
+	int mplen;
+	SSL3ContentType content_type;
+	uint16_t rec_sz;
+
+	ASSERT(ctx != NULL);
+
+	if (mp != NULL) {
+		ASSERT(mp->b_prev == NULL && mp->b_next == NULL);
+	}
+
+	ssl = (ssl_t *)(ctx);
+
+	*decrmp = NULL;
+	*more = B_FALSE;
+
+	mutex_enter(&ssl->kssl_lock);
+
+	if (ssl->close_notify == B_TRUE) {
+		goto sendnewalert;
+	}
+
+	/* Whomever is currently processing this connection will get to this */
+	if (ssl->activeinput) {
+		if (mp != NULL) {
+			KSSL_ENQUEUE_MP(ssl, mp);
+		}
+		mutex_exit(&ssl->kssl_lock);
+		return (KSSL_CMD_NONE);
+	}
+
+	/*
+	 * Fast path for complete incoming application_data records on an empty
+	 * queue.
+	 * This is by far the most frequently encountered case
+	 */
+
+	if ((!ssl->activeinput) && (ssl->rec_ass_head == NULL) &&
+	    ((mp != NULL) && (mplen = MBLKL(mp)) > SSL3_HDR_LEN)) {
+
+		content_type = (SSL3ContentType)mp->b_rptr[0];
+
+		if ((content_type == content_application_data) &&
+		    (ssl->hs_waitstate == idle_handshake)) {
+			rec_sz_p = SSL3_REC_SIZE(mp);
+			rec_sz = BE16_TO_U16(rec_sz_p);
+
+			if ((mp->b_cont == NULL) && (mplen == rec_sz)) {
+
+				mp->b_flag &= ~DBLK_COOKED;
+				*decrmp = mp;
+				mutex_exit(&ssl->kssl_lock);
+				return (KSSL_CMD_DELIVER_PROXY);
+			}
+		}
+	}
+
+	ssl->activeinput = B_TRUE;
+	/* Accumulate at least one record */
+	if (mp != NULL) {
+		KSSL_ENQUEUE_MP(ssl, mp);
+		mp = NULL;
+	}
+	recmp = kssl_get_next_record(ssl);
+
+	if (recmp == NULL) {
+		ssl->activeinput = B_FALSE;
+		if (ssl->alert_sendbuf != NULL) {
+			goto sendalert;
+		}
+		/* Not even a complete header yet. wait for the rest */
+		mutex_exit(&ssl->kssl_lock);
+		return (KSSL_CMD_NONE);
+	}
+
+	do {
+		if ((SSL3ContentType)recmp->b_rptr[0] ==
+		    content_application_data) {
+			/*
+			 * application_data records are decrypted and
+			 * MAC-verified by the stream head, and in the context
+			 * a read()'ing thread. This avoids unfairly charging
+			 * the cost of handling this record on the whole system,
+			 * and prevents doing it while in the shared IP
+			 * perimeter.
+			 */
+			ssl->activeinput = B_FALSE;
+			if (ssl->hs_waitstate != idle_handshake) {
+				goto sendnewalert;
+			}
+			outmp = recmp;
+			kssl_cmd = KSSL_CMD_DELIVER_PROXY;
+		} else {
+			/*
+			 * If we're past the initial handshake, start letting
+			 * the stream head process all records, in particular
+			 * the close_notify.
+			 * This is needed to avoid processing them out of
+			 * sequence when previous application data packets are
+			 * waiting to be decrypted/MAC'ed and delivered.
+			 */
+			if (ssl->hs_waitstate == idle_handshake) {
+				ssl->activeinput = B_FALSE;
+				outmp = recmp;
+				kssl_cmd = KSSL_CMD_DELIVER_PROXY;
+			} else {
+				kssl_cmd = kssl_handle_any_record(ssl, recmp,
+				    &outmp, cbfn, arg);
+			}
+		}
+
+		/* Priority to Alert messages */
+		if (ssl->alert_sendbuf != NULL) {
+			goto sendalert;
+		}
+
+		/* Then handshake messages */
+		if (ssl->handshake_sendbuf) {
+			if (*decrmp != NULL) {
+				linkb(*decrmp, ssl->handshake_sendbuf);
+			} else {
+				*decrmp = ssl->handshake_sendbuf;
+			}
+			ssl->handshake_sendbuf = NULL;
+
+			*more = ((ssl->rec_ass_head != NULL) &&
+			    (!ssl->activeinput));
+			mutex_exit(&ssl->kssl_lock);
+			return (kssl_cmd);
+		}
+
+		if (ssl->hs_waitstate == idle_handshake) {
+			*more = ((ssl->rec_ass_head != NULL) &&
+			    (!ssl->activeinput));
+		}
+
+		if (outmp != NULL) {
+			*decrmp = outmp;
+			/*
+			 * Don't process any packet after an application_data.
+			 * We could well receive the close_notify which should
+			 * be handled separately.
+			 */
+			mutex_exit(&ssl->kssl_lock);
+			return (kssl_cmd);
+		}
+		/*
+		 * The current record isn't done yet. Don't start the next one
+		 */
+		if (ssl->activeinput) {
+			mutex_exit(&ssl->kssl_lock);
+			return (kssl_cmd);
+		}
+	} while ((recmp = kssl_get_next_record(ssl)) != NULL);
+
+	mutex_exit(&ssl->kssl_lock);
+	return (kssl_cmd);
+
+sendnewalert:
+	kssl_send_alert(ssl, alert_fatal, unexpected_message);
+	if (mp != NULL) {
+		freeb(mp);
+	}
+
+sendalert:
+	*decrmp = ssl->alert_sendbuf;
+	ssl->alert_sendbuf = NULL;
+	mutex_exit(&ssl->kssl_lock);
+	return (KSSL_CMD_SEND);
+}
+
+/*
+ * Decrypt and verify the MAC of an incoming chain of application_data record.
+ * Each block has exactly one SSL record.
+ * This routine recycles its incoming mblk, and flags it as DBLK_COOKED
+ */
+kssl_cmd_t
+kssl_handle_record(kssl_ctx_t ctx, mblk_t **mpp, mblk_t **outmp)
+{
+	uchar_t *recend, *rec_sz_p;
+	uchar_t *real_recend;
+	mblk_t *prevmp = NULL, *nextmp, *mp = *mpp, *copybp;
+	int mac_sz;
+	uchar_t version[2];
+	uint16_t rec_sz;
+	SSL3AlertDescription desc;
+	SSL3ContentType content_type;
+	ssl_t *ssl;
+	KSSLCipherSpec *spec;
+	int error = 0, ret;
+	kssl_cmd_t kssl_cmd = KSSL_CMD_DELIVER_PROXY;
+	boolean_t deliverit = B_FALSE;
+	crypto_data_t cipher_data;
+
+	ASSERT(ctx != NULL);
+
+	ssl = (ssl_t *)(ctx);
+
+	*outmp = NULL;
+
+more:
+
+	while (mp != NULL) {
+
+		if (DB_REF(mp) > 1) {
+			/*
+			 * Fortunately copyb() preserves the offset,
+			 * tail space and alignement so the copy is
+			 * ready to be made an SSL record.
+			 */
+			if ((copybp = copyb(mp)) == NULL)
+				return (NULL);
+
+			copybp->b_cont = mp->b_cont;
+			if (mp == *mpp) {
+				*mpp = copybp;
+			} else {
+				prevmp->b_cont = copybp;
+			}
+			freeb(mp);
+			mp = copybp;
+		}
+
+		content_type = (SSL3ContentType)mp->b_rptr[0];
+
+		if (content_type != content_application_data) {
+			nextmp = mp->b_cont;
+
+			/* Remove this message */
+			if (prevmp != NULL) {
+				prevmp->b_cont = nextmp;
+
+				/*
+				 * If we had processed blocks that need to
+				 * be delivered, then remember that error code
+				 */
+				if (kssl_cmd == KSSL_CMD_DELIVER_PROXY)
+					deliverit = B_TRUE;
+			}
+
+			mutex_enter(&ssl->kssl_lock);
+			kssl_cmd = kssl_handle_any_record(ssl, mp, outmp,
+			    NULL, NULL);
+
+			if (ssl->alert_sendbuf != NULL) {
+				goto sendalert;
+			}
+			mutex_exit(&ssl->kssl_lock);
+
+			if (deliverit) {
+				kssl_cmd = KSSL_CMD_DELIVER_PROXY;
+			}
+
+			mp = nextmp;
+			continue;
+		}
+
+		version[0] = mp->b_rptr[1];
+		version[1] = mp->b_rptr[2];
+		rec_sz_p = SSL3_REC_SIZE(mp);
+		rec_sz = BE16_TO_U16(rec_sz_p);
+
+		mp->b_rptr += SSL3_HDR_LEN;
+		recend = mp->b_rptr + rec_sz;
+		real_recend = recend;
+
+		spec = &ssl->spec[KSSL_READ];
+		mac_sz = spec->mac_hashsz;
+		if (spec->cipher_ctx != 0) {
+			cipher_data.cd_format = CRYPTO_DATA_RAW;
+			cipher_data.cd_offset = 0;
+			cipher_data.cd_length = rec_sz;
+			cipher_data.cd_miscdata = NULL;
+			cipher_data.cd_raw.iov_base = (char *)mp->b_rptr;
+			cipher_data.cd_raw.iov_len = rec_sz;
+			error = crypto_decrypt_update(spec->cipher_ctx,
+			    &cipher_data, NULL, NULL);
+			if (CRYPTO_ERR(error)) {
+#ifdef	DEBUG
+				cmn_err(CE_WARN, "kssl_handle_record: "
+				    "crypto_decrypt_update failed: 0x%02X",
+				    error);
+#endif	/* DEBUG */
+				KSSL_COUNTER(record_decrypt_failure, 1);
+				mp->b_rptr = recend;
+				desc = decrypt_error;
+				goto makealert;
+			}
+		}
+		if (spec->cipher_type == type_block) {
+			uint_t pad_sz = recend[-1];
+			pad_sz++;
+			if (pad_sz + mac_sz > rec_sz) {
+				mp->b_rptr = recend;
+				desc = bad_record_mac;
+				goto makealert;
+			}
+			rec_sz -= pad_sz;
+			recend -= pad_sz;
+		}
+		if (mac_sz != 0) {
+			uchar_t hash[MAX_HASH_LEN];
+			if (rec_sz < mac_sz) {
+				mp->b_rptr = real_recend;
+				desc = bad_record_mac;
+				goto makealert;
+			}
+			rec_sz -= mac_sz;
+			recend -= mac_sz;
+			ret = kssl_compute_record_mac(ssl, KSSL_READ,
+				ssl->seq_num[KSSL_READ], content_type,
+				version, mp->b_rptr, rec_sz, hash);
+			if (ret != CRYPTO_SUCCESS ||
+			    bcmp(hash, recend, mac_sz)) {
+				mp->b_rptr = real_recend;
+				desc = bad_record_mac;
+#ifdef	DEBUG
+				cmn_err(CE_WARN, "kssl_handle_record: "
+					"msg MAC mismatch");
+#endif	/* DEBUG */
+				KSSL_COUNTER(verify_mac_failure, 1);
+				goto makealert;
+			}
+			ssl->seq_num[KSSL_READ]++;
+		}
+
+		if (ssl->hs_waitstate != idle_handshake) {
+			mp->b_rptr = real_recend;
+			desc = unexpected_message;
+			goto makealert;
+		}
+		mp->b_wptr = recend;
+
+		prevmp = mp;
+		mp = mp->b_cont;
+	}
+
+	KSSL_COUNTER(appdata_record_ins, 1);
+	return (kssl_cmd);
+
+makealert:
+	nextmp = mp->b_cont;
+	freeb(mp);
+	mp = nextmp;
+	mutex_enter(&ssl->kssl_lock);
+	kssl_send_alert(ssl, alert_fatal, desc);
+
+	if (ssl->alert_sendbuf == NULL) {
+		/* internal memory allocation failure. just return. */
+#ifdef	DEBUG
+		cmn_err(CE_WARN, "kssl_handle_record: "
+		    "alert message allocation failed");
+#endif	/* DEBUG */
+		mutex_exit(&ssl->kssl_lock);
+
+		if (mp) {
+			prevmp = NULL;
+			goto more;
+		}
+
+		return (KSSL_CMD_NONE);
+	}
+	kssl_cmd = KSSL_CMD_SEND;
+sendalert:
+	if (*outmp == NULL) {
+		*outmp = ssl->alert_sendbuf;
+	} else {
+		linkb(*outmp, ssl->alert_sendbuf);
+	}
+	ssl->alert_sendbuf = NULL;
+	mutex_exit(&ssl->kssl_lock);
+
+	if (mp) {
+		prevmp = NULL;
+		goto more;
+	}
+
+	return (kssl_cmd);
+}
+/*
+ * This is the routine that handles incoming SSL records.
+ * When called the first time, with a NULL context, this routine expects
+ * a ClientHello SSL Handshake packet and shall allocate a context
+ * of a new SSL connection.
+ * During the rest of the handshake packets, the routine adjusts the
+ * state of the context according to the record received.
+ * After the ChangeCipherSpec message is received, the routine first
+ * decrypts/authenticated the packet using the key materials in the
+ * connection's context.
+ * The return code tells the caller what to do with the returned packet.
+ */
+static kssl_cmd_t
+kssl_handle_any_record(kssl_ctx_t ctx, mblk_t *mp, mblk_t **decrmp,
+    kssl_callback_t cbfn, void *arg)
+{
+	uchar_t *recend, *rec_sz_p;
+	uchar_t version[2];
+	uchar_t *real_recend, *save_rptr, *save_wptr;
+	int rhsz = SSL3_HDR_LEN;
+	uint16_t rec_sz;
+	int sz;
+	int mac_sz;
+	SSL3AlertDescription desc;
+	SSL3AlertLevel level;
+	SSL3ContentType content_type;
+	ssl_t *ssl;
+	KSSLCipherSpec *spec;
+	int error = 0, ret;
+
+	ASSERT(ctx != NULL);
+
+	ssl = (ssl_t *)(ctx);
+
+	*decrmp = NULL;
+
+	save_rptr = mp->b_rptr;
+	save_wptr = mp->b_wptr;
+
+	ASSERT(MUTEX_HELD(&ssl->kssl_lock));
+
+	content_type = (SSL3ContentType)mp->b_rptr[0];
+	if (content_type == content_handshake_v2) {
+		if (ssl->hs_waitstate == wait_client_hello) {
+			/* V2 compatible ClientHello */
+			if (mp->b_rptr[3] == 0x03 &&
+			    (mp->b_rptr[4] == 0x01 ||
+				mp->b_rptr[4] == 0x00)) {
+				ssl->major_version = version[0] = mp->b_rptr[3];
+				ssl->minor_version = version[1] = mp->b_rptr[4];
+			} else {
+			/* We don't support "pure" SSLv2 */
+				desc = protocol_version;
+				goto sendalert;
+			}
+		}
+		rec_sz = (uint16_t)mp->b_rptr[1];
+		rhsz = 2;
+	} else {
+		ssl->major_version = version[0] = mp->b_rptr[1];
+		ssl->minor_version = version[1] = mp->b_rptr[2];
+		rec_sz_p = SSL3_REC_SIZE(mp);
+		rec_sz = BE16_TO_U16(rec_sz_p);
+	}
+
+	mp->b_rptr += rhsz;
+	recend = mp->b_rptr + rec_sz;
+	real_recend = recend;
+
+	spec = &ssl->spec[KSSL_READ];
+	mac_sz = spec->mac_hashsz;
+	if (spec->cipher_ctx != 0) {
+		spec->cipher_data.cd_length = rec_sz;
+		spec->cipher_data.cd_raw.iov_base = (char *)mp->b_rptr;
+		spec->cipher_data.cd_raw.iov_len = rec_sz;
+		error = crypto_decrypt_update(spec->cipher_ctx,
+		    &spec->cipher_data, NULL, NULL);
+		if (CRYPTO_ERR(error)) {
+#ifdef	DEBUG
+			cmn_err(CE_WARN,
+				"kssl_handle_any_record: crypto_decrypt_update "
+				"failed: 0x%02X", error);
+#endif	/* DEBUG */
+			KSSL_COUNTER(record_decrypt_failure, 1);
+			mp->b_rptr = recend;
+			desc = decrypt_error;
+			goto sendalert;
+		}
+	}
+	if (spec->cipher_type == type_block) {
+		uint_t pad_sz = recend[-1];
+		pad_sz++;
+		if (pad_sz + mac_sz > rec_sz) {
+			mp->b_rptr = recend;
+			desc = bad_record_mac;
+			goto sendalert;
+		}
+		rec_sz -= pad_sz;
+		recend -= pad_sz;
+	}
+	if (mac_sz != 0) {
+		uchar_t hash[MAX_HASH_LEN];
+		if (rec_sz < mac_sz) {
+			mp->b_rptr = real_recend;
+			desc = bad_record_mac;
+			goto sendalert;
+		}
+		rec_sz -= mac_sz;
+		recend -= mac_sz;
+		ret = kssl_compute_record_mac(ssl, KSSL_READ,
+			ssl->seq_num[KSSL_READ], content_type,
+			version, mp->b_rptr, rec_sz, hash);
+		if (ret != CRYPTO_SUCCESS ||
+		    bcmp(hash, recend, mac_sz)) {
+			mp->b_rptr = real_recend;
+			desc = bad_record_mac;
+#ifdef	DEBUG
+			cmn_err(CE_WARN, "kssl_handle_any_record: "
+				"msg MAC mismatch");
+#endif	/* DEBUG */
+			KSSL_COUNTER(verify_mac_failure, 1);
+			goto sendalert;
+		}
+		ssl->seq_num[KSSL_READ]++;
+	}
+
+	switch (content_type) {
+	case content_handshake:
+		do {
+			if (error != 0 ||
+			    /* ignore client renegotiation for now */
+			    ssl->hs_waitstate == idle_handshake) {
+				mp->b_rptr = recend;
+			}
+			if (mp->b_rptr == recend) {
+				mp->b_rptr = real_recend;
+				if (error != 0) {
+					goto error;
+				}
+				freeb(mp);
+
+				if (ssl->hs_waitstate == wait_client_key_done)
+					return (KSSL_CMD_QUEUED);
+
+				return ((ssl->handshake_sendbuf != NULL) ?
+				    KSSL_CMD_SEND : KSSL_CMD_NONE);
+			}
+			if (ssl->msg.state < MSG_BODY) {
+				if (ssl->msg.state == MSG_INIT) {
+					ssl->msg.type =
+					    (SSL3HandshakeType)*mp->b_rptr++;
+					ssl->msg.state = MSG_INIT_LEN;
+				}
+				if (ssl->msg.state == MSG_INIT_LEN) {
+					int msglenb =
+					    ssl->msg.msglen_bytes;
+					int msglen = ssl->msg.msglen;
+					while (mp->b_rptr < recend &&
+					    msglenb < 3) {
+						msglen = (msglen << 8) +
+						    (uint_t)(*mp->b_rptr++);
+						msglenb++;
+					}
+					ssl->msg.msglen_bytes = msglenb;
+					ssl->msg.msglen = msglen;
+					if (msglenb == 3) {
+						ssl->msg.state = MSG_BODY;
+					}
+				}
+				if (mp->b_rptr == recend) {
+					mp->b_rptr = real_recend;
+					freeb(mp);
+					return (KSSL_CMD_NONE);
+				}
+			}
+			ASSERT(ssl->msg.state == MSG_BODY);
+
+			sz = recend - mp->b_rptr;
+
+			if (ssl->msg.head == NULL &&
+			    ssl->msg.msglen <= sz) {
+				continue;
+			}
+			if (ssl->msg.head != NULL) {
+				sz += msgdsize(ssl->msg.head);
+				if (ssl->msg.msglen <= sz) {
+					ssl->msg.tail->b_cont = mp;
+					mp = ssl->msg.head;
+					ssl->sslcnt = 100;
+					ssl->msg.head = NULL;
+					ssl->msg.tail = NULL;
+					if (pullupmsg(mp, -1)) {
+						recend = mp->b_rptr + sz;
+						ASSERT(recend <= mp->b_wptr);
+						continue;
+					}
+					mp->b_rptr = real_recend;
+					error = ENOMEM;
+					KSSL_COUNTER(alloc_fails, 1);
+					goto error;
+				}
+			}
+
+			mp->b_wptr = recend;
+
+			if (ssl->msg.head == NULL) {
+				ssl->msg.head = mp;
+				ssl->msg.tail = mp;
+				return (KSSL_CMD_NONE);
+			} else {
+				ssl->msg.tail->b_cont = mp;
+				ssl->msg.tail = mp;
+				return (KSSL_CMD_NONE);
+			}
+		} while (kssl_handle_handshake_message(ssl, mp, &error, cbfn,
+		    arg));
+		if (error == SSL_MISS) {
+			mp->b_rptr = save_rptr;
+			mp->b_wptr = save_wptr;
+			KSSL_COUNTER(fallback_connections, 1);
+			return (KSSL_CMD_NOT_SUPPORTED);
+		}
+		if (ssl->hs_waitstate == wait_client_key_done) {
+			return (KSSL_CMD_QUEUED);
+		} else {
+			return (KSSL_CMD_NONE);
+		}
+	case content_alert:
+		if (rec_sz != 2) {
+			mp->b_rptr = real_recend;
+			desc = illegal_parameter;
+			goto sendalert;
+		} else {
+			level = *mp->b_rptr++;
+			desc = *mp->b_rptr++;
+			mp->b_rptr = real_recend;
+			if (level != alert_warning || desc != close_notify) {
+				if (ssl->sid.cached == B_TRUE) {
+					kssl_uncache_sid(&ssl->sid,
+					    ssl->kssl_entry);
+					ssl->sid.cached = B_FALSE;
+				}
+				ssl->fatal_alert = B_TRUE;
+				error = EBADMSG;
+				goto error;
+			} else {
+				ssl->close_notify = B_TRUE;
+				ssl->activeinput = B_FALSE;
+				freeb(mp);
+				return (KSSL_CMD_NONE);
+			}
+		}
+	case content_change_cipher_spec:
+		if (ssl->hs_waitstate != wait_change_cipher) {
+			desc = unexpected_message;
+		} else if (rec_sz != 1 || *mp->b_rptr != 1) {
+			desc = illegal_parameter;
+		} else {
+			mp->b_rptr = real_recend;
+			ssl->hs_waitstate = wait_finished;
+			ssl->seq_num[KSSL_READ] = 0;
+			if ((error = kssl_spec_init(ssl, KSSL_READ)) != 0) {
+#ifdef	DEBUG
+				cmn_err(CE_WARN,
+					"kssl_spec_init returned error "
+					"0x%02X", error);
+#endif	/* DEBUG */
+				goto error;
+			}
+			ssl->activeinput = B_FALSE;
+			freeb(mp);
+			return (KSSL_CMD_NONE);
+		}
+		mp->b_rptr = real_recend;
+		goto sendalert;
+
+	case content_application_data:
+		if (ssl->hs_waitstate != idle_handshake) {
+			mp->b_rptr = real_recend;
+			desc = unexpected_message;
+			goto sendalert;
+		}
+		mp->b_wptr = recend;
+		*decrmp = mp;
+		ssl->activeinput = B_FALSE;
+		return (KSSL_CMD_DELIVER_PROXY);
+
+	case content_handshake_v2:
+		error = kssl_handle_v2client_hello(ssl, mp, rec_sz);
+		if (error == SSL_MISS) {
+			mp->b_rptr = save_rptr;
+			mp->b_wptr = save_wptr;
+			KSSL_COUNTER(fallback_connections, 1);
+			return (KSSL_CMD_NOT_SUPPORTED);
+		} else if (error != 0) {
+			goto error;
+		}
+		freeb(mp);
+		return (KSSL_CMD_SEND);
+	default:
+		mp->b_rptr = real_recend;
+		desc = unexpected_message;
+		break;
+	}
+
+sendalert:
+	kssl_send_alert(ssl, alert_fatal, desc);
+	*decrmp = ssl->alert_sendbuf;
+	ssl->alert_sendbuf = NULL;
+	freeb(mp);
+	return ((*decrmp != NULL) ? KSSL_CMD_SEND : KSSL_CMD_NONE);
+error:
+	freeb(mp);
+	return (KSSL_CMD_NONE);
+}
+
+/*
+ * Initialize the context of an SSL connection, coming to the specified
+ * address.
+ * the ssl structure returned is held.
+ */
+kssl_status_t
+kssl_init_context(kssl_ent_t kssl_ent, ipaddr_t faddr, int mss,
+    kssl_ctx_t *kssl_ctxp)
+{
+	ssl_t *ssl = kmem_cache_alloc(kssl_cache, KM_NOSLEEP);
+
+	if (ssl == NULL) {
+		return (KSSL_STS_ERR);
+	}
+
+	kssl_cache_count++;
+
+	bzero(ssl, sizeof (ssl_t));
+
+	ssl->kssl_entry = (kssl_entry_t *)kssl_ent;
+	KSSL_ENTRY_REFHOLD(ssl->kssl_entry);
+
+	ssl->faddr = faddr;
+	ssl->tcp_mss = mss;
+	ssl->sendalert_level = alert_warning;
+	ssl->sendalert_desc = close_notify;
+	ssl->sid.cached = B_FALSE;
+
+	*kssl_ctxp = (kssl_ctx_t)ssl;
+	KSSL_SSL_REFHOLD(ssl);
+	return (KSSL_STS_OK);
+}
+
+/*
+ * Builds SSL records out of the chain of mblks, and returns it.
+ * Taked a copy of the message before encypting it if it has another
+ * reference.
+ * In case of failure, NULL is returned, and the message will be
+ * freed by the caller.
+ * A NULL mp means a close_notify is requested.
+ */
+mblk_t *
+kssl_build_record(kssl_ctx_t ctx, mblk_t *mp)
+{
+	ssl_t *ssl = (ssl_t *)ctx;
+	mblk_t *retmp = mp, *bp = mp, *prevbp = mp, *copybp;
+
+	ASSERT(ssl != NULL);
+	ASSERT(mp != NULL);
+
+	do {
+		if (DB_REF(bp) > 1) {
+			/*
+			 * Fortunately copyb() preserves the offset,
+			 * tail space and alignement so the copy is
+			 * ready to be made an SSL record.
+			 */
+			if ((copybp = copyb(bp)) == NULL)
+				return (NULL);
+
+			copybp->b_cont = bp->b_cont;
+			if (bp == mp) {
+				retmp = copybp;
+			} else {
+				prevbp->b_cont = copybp;
+			}
+			freeb(bp);
+			bp = copybp;
+		}
+
+		if (kssl_build_single_record(ssl, bp) != KSSL_STS_OK)
+			return (NULL);
+
+		prevbp = bp;
+		bp = bp->b_cont;
+	} while (bp != NULL);
+
+	return (retmp);
+}
+
+/*
+ * Builds a single SSL record
+ * In-line encryption of the record.
+ */
+static kssl_status_t
+kssl_build_single_record(ssl_t *ssl, mblk_t *mp)
+{
+	int len;
+	int reclen = 0;
+	uchar_t *recstart, *versionp;
+	KSSLCipherSpec *spec;
+	int mac_sz;
+	int pad_sz = 0;
+
+
+	spec = &ssl->spec[KSSL_WRITE];
+	mac_sz = spec->mac_hashsz;
+
+
+	ASSERT(DB_REF(mp) == 1);
+	ASSERT((mp->b_rptr - mp->b_datap->db_base >= SSL3_HDR_LEN) &&
+	    (mp->b_datap->db_lim - mp->b_wptr >= mac_sz + spec->cipher_bsize));
+
+	len = MBLKL(mp);
+
+	ASSERT(len > 0);
+
+	mutex_enter(&ssl->kssl_lock);
+
+	recstart = mp->b_rptr = mp->b_rptr - SSL3_HDR_LEN;
+	recstart[0] = content_application_data;
+	recstart[1] = ssl->major_version;
+	recstart[2] = ssl->minor_version;
+	versionp = &recstart[1];
+
+	reclen = len + mac_sz;
+	if (spec->cipher_type == type_block) {
+		pad_sz = spec->cipher_bsize -
+		    (reclen & (spec->cipher_bsize - 1));
+		ASSERT(reclen + pad_sz <=
+		    SSL3_MAX_RECORD_LENGTH);
+		reclen += pad_sz;
+	}
+	recstart[3] = (reclen >> 8) & 0xff;
+	recstart[4] = reclen & 0xff;
+
+	if (kssl_mac_encrypt_record(ssl, content_application_data, versionp,
+	    recstart, mp) != 0) {
+		/* Do we need an internal_error Alert here? */
+		mutex_exit(&ssl->kssl_lock);
+		return (KSSL_STS_ERR);
+	}
+
+	KSSL_COUNTER(appdata_record_outs, 1);
+	mutex_exit(&ssl->kssl_lock);
+	return (KSSL_STS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/kssl/ksslapi.h	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,109 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_INET_KSSL_KSSLAPI_H
+#define	_INET_KSSL_KSSLAPI_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * The kernel SSL proxy interface
+ */
+
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include	<sys/socket.h>
+#include	<netinet/in.h>
+
+/* return status for the kssl API functions */
+
+typedef enum {
+	KSSL_STS_OK,	/* No further processing required */
+	KSSL_STS_ERR	/* bogus argument  ... */
+} kssl_status_t;
+
+/* Endpoint type */
+typedef	enum {
+	KSSL_NO_PROXY = 0,	/* Not configured for use with KSSL */
+	KSSL_IS_PROXY,		/* Acts as a proxy for someone else */
+	KSSL_HAS_PROXY		/* A proxy is handling its work */
+} kssl_endpt_type_t;
+
+/* Return codes/commands from kssl_handle_record */
+typedef enum {
+	KSSL_CMD_NOT_SUPPORTED,	/* Not supported */
+	KSSL_CMD_SEND,		/* send this packet out on the wire */
+	KSSL_CMD_DELIVER_PROXY,	/* deliver this packet to proxy listener */
+	KSSL_CMD_DELIVER_SSL,	/* Deliver to the SSL listener */
+	KSSL_CMD_NONE,		/* consider it consumed. (ACK it, ... */
+	KSSL_CMD_QUEUED		/* Queued, a call back will finish it */
+} kssl_cmd_t;
+
+typedef enum {
+	KSSL_EVENT_CLOSE	/* close this context */
+} kssl_event_t;
+
+/* Un opaque context of an SSL connection */
+typedef void *kssl_ctx_t;
+
+/* Un opaque handle for an SSL map entry */
+typedef	void *kssl_ent_t;
+
+#define	SSL3_HDR_LEN		5
+#define	SSL3_WROFFSET		7	/* 5 hdr + 2 byte-alignment */
+#define	SSL3_MAX_TAIL_LEN	36	/* 16 AES blocks +  20 SHA1 digest */
+#define	SSL3_MAX_RECORD_LEN	16384 - 1 - SSL3_HDR_LEN - SSL3_MAX_TAIL_LEN
+
+
+kssl_endpt_type_t kssl_check_proxy(mblk_t *, void *, kssl_ent_t *);
+
+kssl_status_t kssl_init_context(kssl_ent_t, uint32_t, int, kssl_ctx_t *);
+
+void kssl_hold_ent(kssl_ent_t);
+void kssl_release_ent(kssl_ent_t, void *, kssl_endpt_type_t);
+void *kssl_find_fallback(kssl_ent_t);
+
+void kssl_hold_ctx(kssl_ctx_t);
+void kssl_release_ctx(kssl_ctx_t);
+
+typedef void (*kssl_callback_t)(void *arg, mblk_t *mp, kssl_cmd_t cmd);
+
+kssl_cmd_t kssl_input(kssl_ctx_t, mblk_t *, mblk_t **, boolean_t *,
+    kssl_callback_t cbfn, void *arg);
+
+kssl_cmd_t kssl_handle_record(kssl_ctx_t, mblk_t **, mblk_t **);
+
+mblk_t *kssl_build_record(kssl_ctx_t, mblk_t *);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _INET_KSSL_KSSLAPI_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/kssl/kssldebug.h	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,111 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_INET_KSSL_KSSLDEBUG_H
+#define	_INET_KSSL_KSSLDEBUG_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* BEGIN CSTYLED */
+#ifdef DEBUG
+extern int kssl_debug;
+
+#define	KSSL_DEBUG1(a1)			cmn_err(CE_CONT, (a1))
+#define	KSSL_DEBUG2(a1,a2)		cmn_err(CE_CONT, (a1),(a2))
+#define	KSSL_DEBUG3(a1,a2,a3)		cmn_err(CE_CONT, (a1),(a2),(a3))
+#define	KSSL_DEBUG4(a1,a2,a3,a4)		cmn_err(CE_CONT, (a1),(a2),(a3),(a4))
+#define	KSSL_DEBUG5(a1,a2,a3,a4,a5)		\
+    cmn_err(CE_CONT,(a1),(a2),(a3),(a4),(a5))
+#define	KSSL_DEBUG6(a1,a2,a3,a4,a5,a6)		\
+    cmn_err(CE_CONT,(a1),(a2),(a3),(a4),(a5),(a6))
+#define	KSSL_DEBUG7(a1,a2,a3,a4,a5,a6,a7)	\
+    cmn_err(CE_CONT,(a1),(a2),(a3),(a4),(a5),(a6),(a7))
+#define	KSSL_DEBUG8(a1,a2,a3,a4,a5,a6,a7,a8)	\
+    cmn_err(CE_CONT,(a1),(a2),(a3),(a4),(a5),(a6),(a7),(a8))
+#define	KSSL_DEBUG9(a1,a2,a3,a4,a5,a6,a7,a8,a9)	\
+    cmn_err(CE_CONT,(a1),(a2),(a3),(a4),(a5),(a6),(a7),(a8),(a9))
+
+#define	KSSL_DEBUG12(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) \
+    cmn_err(CE_CONT,(a1),(a2),(a3),(a4),(a5),(a6),(a7),(a8),(a9),(a10),(a11), \
+	(a12))
+#define	KSSL_DEBUG14(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14) \
+    cmn_err(CE_CONT,(a1),(a2),(a3),(a4),(a5),(a6),(a7),(a8),(a9),(a10),(a11), \
+	(a12),(a13),(a14))
+#define	KSSL_DEBUG15(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \
+    cmn_err(CE_CONT,(a1),(a2),(a3),(a4),(a5),(a6),(a7),(a8),(a9),(a10),(a11), \
+	(a12),(a13),(a14),(a15))
+
+#define	KSSL_DEBUG1_IF(c,a1)			\
+	{ if (c) KSSL_DEBUG1((a1)); }
+#define	KSSL_DEBUG2_IF(c,a1,a2)			\
+	{ if (c) KSSL_DEBUG2((a1),(a2)); }
+#define	KSSL_DEBUG3_IF(c,a1,a2,a3)		\
+	{ if (c) KSSL_DEBUG3((a1),(a2),(a3)); }
+#define	KSSL_DEBUG4_IF(c,a1,a2,a3,a4)		\
+	{ if (c) KSSL_DEBUG4((a1),(a2),(a3),(a4)); }
+#define	KSSL_DEBUG5_IF(c,a1,a2,a3,a4,a5)		\
+	{ if (c) KSSL_DEBUG5((a1),(a2),(a3),(a4),(a5)); }
+#define	KSSL_DEBUG6_IF(c,a1,a2,a3,a4,a5,a6)	\
+	{ if (c) KSSL_DEBUG6((a1),(a2),(a3),(a4),(a5),(a6)); }
+#define	KSSL_DEBUG7_IF(c,a1,a2,a3,a4,a5,a6,a7)	\
+	{ if (c) KSSL_DEBUG7((a1),(a2),(a3),(a4),(a5),(a6),(a7)); }
+
+#else	/* !DEBUG */
+
+#define	KSSL_DEBUG1(a1)				/* empty */
+#define	KSSL_DEBUG2(a1,a2)			/* empty */
+#define	KSSL_DEBUG3(a1,a2,a3)			/* empty */
+#define	KSSL_DEBUG4(a1,a2,a3,a4)			/* empty */
+#define	KSSL_DEBUG5(a1,a2,a3,a4,a5)		/* empty */
+#define	KSSL_DEBUG6(a1,a2,a3,a4,a5,a6)		/* empty */
+#define	KSSL_DEBUG7(a1,a2,a3,a4,a5,a6,a7)	/* empty */
+#define	KSSL_DEBUG8(a1,a2,a3,a4,a5,a6,a7,a8)	/* empty */
+#define	KSSL_DEBUG9(a1,a2,a3,a4,a5,a6,a7,a8,a9)	/* empty */
+
+#define	KSSL_DEBUG12(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)	/* empty */
+#define	KSSL_DEBUG14(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)
+#define	KSSL_DEBUG15(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)
+
+#define	KSSL_DEBUG1_IF(c,a1)			/* empty */
+#define	KSSL_DEBUG2_IF(c,a1,a2) 			/* empty */
+#define	KSSL_DEBUG3_IF(c,a1,a2,a3)		/* empty */
+#define	KSSL_DEBUG4_IF(c,a1,a2,a3,a4)		/* empty */
+#define	KSSL_DEBUG5_IF(c,a1,a2,a3,a4,a5)		/* empty */
+#define	KSSL_DEBUG6_IF(c,a1,a2,a3,a4,a5,a6)	/* empty */
+#define	KSSL_DEBUG7_IF(c,a1,a2,a3,a4,a5,a6,a7)	/* empty */
+
+#endif	/* DEBUG */
+/* END CSTYLED */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _INET_KSSL_KSSLDEBUG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/kssl/ksslimpl.h	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,208 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_INET_KSSL_KSSLIMPL_H
+#define	_INET_KSSL_KSSLIMPL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/atomic.h>
+#include <sys/mutex.h>
+#include <sys/crypto/common.h>
+#include <sys/kstat.h>
+#include <inet/kssl/ksslapi.h>
+#include <inet/kssl/ksslproto.h>
+
+/*
+ * Certificate structure. The msg field is the BER data of the
+ * certificate.
+ */
+typedef struct Certificate {
+    uchar_t *msg;
+    int len;
+} Certificate_t;
+
+/* Generic linked chain type */
+typedef struct kssl_chain_s {
+	struct kssl_chain_s	*next;
+	void			*item;
+} kssl_chain_t;
+
+/* Proxies chain. follows the generic kssl_chain_t layout */
+typedef struct kssl_proxy_s {
+	struct kssl_proxy_s	*next;
+	void			*proxy_bound;
+} kssl_proxy_t;
+
+/* Fallback endpoints chain. Ditto. */
+typedef struct kssl_fallback_s {
+	struct kssl_fallback_s	*next;
+	void			*fallback_bound;
+} kssl_fallback_t;
+
+/* kssl_entry_t structure. */
+
+typedef struct kssl_entry_s {
+	uint_t			ke_refcnt;	/* for hold/release */
+	boolean_t		ke_no_freeall;
+	kmutex_t		ke_mutex;
+
+	ipaddr_t		ke_laddr;	/* Only IPv4 is supported */
+	in_port_t		ke_ssl_port;	/* SSL port */
+	in_port_t		ke_proxy_port;	/* SSL proxy port */
+
+	uint32_t		sid_cache_timeout; /* In seconds */
+	uint32_t		sid_cache_nentries;
+	kssl_sid_ent_t		*sid_cache;
+
+	uint16_t		kssl_cipherSuites[CIPHER_SUITE_COUNT];
+	int			kssl_cipherSuites_nentries;
+	uint16_t		kssl_saved_Suites[CIPHER_SUITE_COUNT];
+
+	crypto_key_t		*ke_private_key; /* instance's private key */
+	Certificate_t		*ke_server_certificate;
+
+	Certificate_t		**ke_cacert_chain;
+
+	kssl_proxy_t	*ke_proxy_head;		/* Proxies chain */
+	kssl_fallback_t	*ke_fallback_head;	/* Fall-back endpoints chain */
+
+} kssl_entry_t;
+
+typedef struct mech_to_cipher_s {
+	crypto_mech_type_t mech;
+	char *name;
+	uint16_t kssl_suites[CIPHER_SUITE_COUNT];
+} mech_to_cipher_t;
+
+#define	KSSL_ENTRY_REFHOLD(kssl_entry) {				\
+	atomic_add_32(&(kssl_entry)->ke_refcnt, 1);			\
+	ASSERT((kssl_entry)->ke_refcnt != 0);				\
+}
+
+#define	KSSL_ENTRY_REFRELE(kssl_entry) {				\
+	ASSERT((kssl_entry)->ke_refcnt != 0);				\
+	membar_exit();							\
+	if (atomic_add_32_nv(&(kssl_entry)->ke_refcnt, -1) == 0) {	\
+		kssl_free_entry((kssl_entry));				\
+	}								\
+}
+
+#define	KSSL_SSL_REFHOLD(ssl) {						\
+	atomic_add_32(&(ssl)->kssl_refcnt, 1);				\
+	ASSERT((ssl)->kssl_refcnt != 0);				\
+	ASSERT((ssl)->kssl_refcnt < 100000);				\
+}
+
+#define	KSSL_SSL_REFRELE(ssl) {						\
+	ASSERT((ssl)->kssl_refcnt != 0);				\
+	ASSERT((ssl)->kssl_refcnt < 100000);				\
+	membar_exit();							\
+	if (atomic_add_32_nv(&(ssl)->kssl_refcnt, -1) == 0) {		\
+		kssl_free_context((ssl));				\
+	}								\
+}
+
+#define	CRYPTO_ERR(r) ((r) != CRYPTO_SUCCESS && (r) != CRYPTO_QUEUED)
+
+#define	KSSL_ENQUEUE_MP(ssl, mp)					\
+	if ((ssl)->rec_ass_tail == NULL) {				\
+		(ssl)->rec_ass_head = (mp);				\
+		(ssl)->rec_ass_tail = (mp);				\
+	} else {							\
+		(ssl)->rec_ass_tail->b_cont = (mp);			\
+		(ssl)->rec_ass_tail = (mp);				\
+	}
+
+#define	SSL_MISS	123	/* Internal SSL error */
+
+extern crypto_mechanism_t rsa_x509_mech;
+extern crypto_mechanism_t hmac_md5_mech;
+extern crypto_mechanism_t hmac_sha1_mech;
+extern crypto_call_flag_t kssl_call_flag;
+extern KSSLCipherDef cipher_defs[];
+
+extern int kssl_enabled;
+extern int kssl_cache_count;
+extern struct kmem_cache *kssl_cache;
+
+#define	KSSL_TAB_INITSIZE	32
+extern kssl_entry_t **kssl_entry_tab;
+extern int kssl_entry_tab_size;
+extern int kssl_entry_tab_nentries;
+extern kmutex_t kssl_tab_mutex;
+
+typedef struct kssl_stats {
+	kstat_named_t sid_cache_lookups;
+	kstat_named_t sid_cache_hits;
+	kstat_named_t sid_uncached;
+	kstat_named_t full_handshakes;
+	kstat_named_t resumed_sessions;
+	kstat_named_t fallback_connections;
+	kstat_named_t proxy_fallback_failed;
+	kstat_named_t appdata_record_ins;
+	kstat_named_t appdata_record_outs;
+	kstat_named_t alloc_fails;
+	kstat_named_t fatal_alerts;
+	kstat_named_t warning_alerts;
+	kstat_named_t no_suite_found;
+	kstat_named_t compute_mac_failure;
+	kstat_named_t verify_mac_failure;
+	kstat_named_t record_decrypt_failure;
+	kstat_named_t bad_pre_master_secret;
+} kssl_stats_t;
+
+extern kssl_stats_t *kssl_statp;
+
+#define	KSSL_COUNTER(p, v)	 atomic_add_64(&kssl_statp->p.value.ui64, v)
+
+#define	IS_SSL_PORT	1
+#define	IS_PROXY_PORT	2
+
+extern void kssl_free_entry(kssl_entry_t *);
+extern void kssl_free_context(ssl_t *);
+extern int kssl_compute_record_mac(ssl_t *, int, uint64_t, SSL3ContentType,
+    uchar_t *, uchar_t *, int, uchar_t *);
+extern int kssl_handle_handshake_message(ssl_t *, mblk_t *, int *,
+    kssl_callback_t, void *);
+extern int kssl_handle_v2client_hello(ssl_t *, mblk_t *, int);
+extern void kssl_uncache_sid(sslSessionID *, kssl_entry_t *);
+extern int kssl_mac_encrypt_record(ssl_t *, SSL3ContentType, uchar_t *,
+    uchar_t *, mblk_t *);
+extern mblk_t *kssl_get_next_record(ssl_t *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _INET_KSSL_KSSLIMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/kssl/ksslioctl.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,599 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * The kernel SSL module ioctls.
+ */
+
+#include <sys/types.h>
+#include <sys/modctl.h>
+#include <sys/conf.h>
+#include <sys/stat.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/kmem.h>
+#include <sys/errno.h>
+#include <sys/ksynch.h>
+#include <sys/file.h>
+#include <sys/open.h>
+#include <sys/cred.h>
+#include <sys/proc.h>
+#include <sys/task.h>
+#include <sys/mkdev.h>
+#include <sys/model.h>
+#include <sys/sysmacros.h>
+#include <sys/policy.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/api.h>
+#include <inet/common.h>
+#include <inet/ip.h>
+#include <inet/ip6.h>
+
+#include "ksslimpl.h"
+#include "kssl.h"
+#include "ksslproto.h"
+
+kssl_entry_t **kssl_entry_tab;
+int kssl_entry_tab_size;
+int kssl_entry_tab_nentries;
+kmutex_t kssl_tab_mutex;
+
+
+static void
+certificate_free(Certificate_t *cert)
+{
+	kmem_free(cert->msg, cert->len);
+	kmem_free(cert, sizeof (struct Certificate));
+}
+
+static void
+privateKey_free(crypto_key_t *privkey)
+{
+	crypto_object_attribute_t *attrs = privkey->ck_attrs;
+	size_t attrs_size
+		= privkey->ck_count * sizeof (crypto_object_attribute_t);
+
+	int i;
+
+	for (i = 0; i < privkey->ck_count; i++) {
+		bzero(attrs[i].oa_value, attrs[i].oa_value_len);
+		kmem_free(attrs[i].oa_value, attrs[i].oa_value_len);
+	}
+	kmem_free(attrs, attrs_size);
+	kmem_free(privkey, sizeof (crypto_key_t));
+}
+
+/*
+ * Frees the space for the entry and the keys and certs
+ * it carries.
+ */
+void
+kssl_free_entry(kssl_entry_t *kssl_entry)
+{
+	int i;
+	Certificate_t *cert;
+	crypto_key_t *privkey;
+
+	if (kssl_entry->ke_no_freeall) {
+		kmem_free(kssl_entry, sizeof (kssl_entry_t));
+		return;
+	}
+
+	if ((cert = kssl_entry->ke_server_certificate) != NULL) {
+		certificate_free(cert);
+	}
+
+	if ((privkey = kssl_entry->ke_private_key) != NULL) {
+		privateKey_free(privkey);
+	};
+
+	for (i = 0; i < kssl_entry->sid_cache_nentries; i++)
+		mutex_destroy(&(kssl_entry->sid_cache[i].se_lock));
+
+	kmem_free(kssl_entry->sid_cache,
+	    kssl_entry->sid_cache_nentries * sizeof (kssl_sid_ent_t));
+
+	ASSERT(kssl_entry->ke_proxy_head == NULL);
+	ASSERT(kssl_entry->ke_fallback_head == NULL);
+
+	kmem_free(kssl_entry, sizeof (kssl_entry_t));
+}
+
+/*
+ * Returns the index of the entry in kssl_entry_tab[] that matches
+ * the address and port.  Returns -1 if no match is found.
+ */
+static int
+kssl_find_entry(ipaddr_t laddr, in_port_t port, int type,
+    boolean_t wild_card_match)
+{
+	int i;
+	kssl_entry_t *ep;
+
+	ASSERT(MUTEX_HELD(&kssl_tab_mutex));
+
+	for (i = 0; i < kssl_entry_tab_size; i++) {
+		ep = kssl_entry_tab[i];
+		if (ep == NULL)
+			continue;
+
+		if (!((type == IS_SSL_PORT && ep->ke_ssl_port == port) ||
+		    (type == IS_PROXY_PORT && ep->ke_proxy_port == port)))
+			continue;
+
+		if ((ep->ke_laddr == laddr) || (wild_card_match &&
+		    ((laddr == INADDR_ANY) || (ep->ke_laddr == INADDR_ANY))))
+			break;
+	}
+
+	if (i == kssl_entry_tab_size)
+		return (-1);
+
+	return (i);
+}
+
+static void
+copy_int_to_bytearray(int x, uchar_t *buf)
+{
+	buf[0] = (x >> 16) & 0xff;
+	buf[1] = (x >> 8) & 0xff;
+	buf[2] = (x) & 0xff;
+}
+
+static int
+extract_certificate(kssl_params_t *kssl_params, Certificate_t **certpp)
+{
+	int i, len;
+	uint64_t in_size;
+	uchar_t *end_pos;
+	uint32_t ncert;
+	uint32_t *cert_sizes;
+	Certificate_t *cert;
+	char *begin = (char *)kssl_params;
+	uchar_t *cert_buf;
+	int cert_buf_len;
+	uchar_t *cert_from, *cert_to;
+
+	ASSERT(kssl_params);
+
+	in_size = kssl_params->kssl_params_size;
+	end_pos = (uchar_t *)kssl_params + in_size;
+
+	/*
+	 * Get the certs array. First the array of sizes, then the actual
+	 * certs.
+	 */
+	ncert = kssl_params->kssl_certs.sc_count;
+
+	if (ncert == 0) {
+		/* no certs in here! why did ya call? */
+		return (EINVAL);
+	}
+	if (in_size < (sizeof (kssl_params_t) + ncert * sizeof (uint32_t))) {
+		return (EINVAL);
+	}
+
+	/* Trusting that the system call preserved the 4-byte aligment */
+	cert_sizes = (uint32_t *)(begin +
+	    kssl_params->kssl_certs.sc_sizes_offset);
+
+	/* should this be an ASSERT()? */
+	if (!IS_P2ALIGNED(cert_sizes, sizeof (uint32_t))) {
+		return (EINVAL);
+	}
+
+	len = 0;
+	for (i = 0; i < ncert; i++) {
+		if (cert_sizes[i] < 1) {
+			return (EINVAL);
+		}
+		len += cert_sizes[i] + 3;
+	}
+
+	len += 3;	/* length of certificate message without msg header */
+
+	cert_buf_len = len + 4 + 4;	/* add space for msg headers */
+
+	cert_buf = kmem_alloc(cert_buf_len, KM_SLEEP);
+
+	cert_buf[0] = (uchar_t)certificate;
+	copy_int_to_bytearray(len, & cert_buf[1]);
+	copy_int_to_bytearray(len - 3, & cert_buf[4]);
+
+	cert_from = (uchar_t *)(begin +
+	    kssl_params->kssl_certs.sc_certs_offset);
+	cert_to = &cert_buf[7];
+
+	for (i = 0; i < ncert; i++) {
+		copy_int_to_bytearray(cert_sizes[i], cert_to);
+		cert_to += 3;
+
+		if (cert_from + cert_sizes[i] > end_pos) {
+			kmem_free(cert_buf, cert_buf_len);
+			return (EINVAL);
+		}
+
+		bcopy(cert_from, cert_to, cert_sizes[i]);
+		cert_from += cert_sizes[i];
+		cert_to += cert_sizes[i];
+	}
+
+	len += 4;
+	cert_buf[len] = (uchar_t)server_hello_done;
+	copy_int_to_bytearray(0, & cert_buf[len + 1]);
+
+	cert = kmem_alloc(sizeof (Certificate_t), KM_SLEEP);
+	cert->msg = cert_buf;
+	cert->len = cert_buf_len;
+
+	*certpp = cert;
+
+	return (0);
+}
+
+static int
+extract_private_key(kssl_params_t *kssl_params, crypto_key_t **privkey)
+{
+	char *begin = (char *)kssl_params;
+	char *end_pos;
+	int i, j, rv;
+	size_t attrs_size;
+	crypto_object_attribute_t *newattrs = NULL;
+	char *mp_attrs;
+	kssl_object_attribute_t att;
+	char *attval;
+	uint32_t attlen;
+	crypto_key_t *kssl_privkey;
+
+	end_pos = (char *)kssl_params + kssl_params->kssl_params_size;
+
+	kssl_privkey = kmem_alloc(sizeof (crypto_key_t), KM_SLEEP);
+
+	kssl_privkey->ck_format = kssl_params->kssl_privkey.ks_format;
+	kssl_privkey->ck_count = kssl_params->kssl_privkey.ks_count;
+
+	switch (kssl_privkey->ck_format) {
+		case CRYPTO_KEY_ATTR_LIST:
+			break;
+		case CRYPTO_KEY_RAW:
+		case CRYPTO_KEY_REFERENCE:
+		default:
+			rv = EINVAL;
+			goto err1;
+	}
+
+	/* allocate the attributes */
+	attrs_size = kssl_privkey->ck_count *
+	    sizeof (crypto_object_attribute_t);
+
+	newattrs = kmem_alloc(attrs_size, KM_NOSLEEP);
+	if (newattrs == NULL) {
+		rv = ENOMEM;
+		goto err1;
+	}
+
+	mp_attrs = begin + kssl_params->kssl_privkey.ks_attrs_offset;
+	if (mp_attrs + attrs_size > end_pos) {
+		rv = EINVAL;
+		goto err1;
+	}
+
+	/* Now the individual attributes */
+	for (i = 0; i < kssl_privkey->ck_count; i++) {
+
+		bcopy(mp_attrs, &att, sizeof (kssl_object_attribute_t));
+
+		mp_attrs += sizeof (kssl_object_attribute_t);
+
+		attval = begin + att.ka_value_offset;
+		attlen = att.ka_value_len;
+
+		if (attval + attlen > end_pos) {
+			rv = EINVAL;
+			goto err2;
+		}
+
+		newattrs[i].oa_type = att.ka_type;
+		newattrs[i].oa_value_len = attlen;
+		newattrs[i].oa_value = kmem_alloc(attlen, KM_NOSLEEP);
+		if (newattrs[i].oa_value == NULL) {
+			rv = ENOMEM;
+			goto err2;
+		}
+
+		bcopy(attval, newattrs[i].oa_value, attlen);
+	}
+
+	kssl_privkey->ck_attrs = newattrs;
+
+	*privkey = kssl_privkey;
+
+	return (0);
+
+err2:
+	for (j = 0; j < i; j++) {
+		kmem_free(newattrs[j].oa_value, newattrs[j].oa_value_len);
+	}
+	kmem_free(newattrs, attrs_size);
+err1:
+	kmem_free(kssl_privkey, sizeof (crypto_key_t));
+	return (rv);
+}
+
+static kssl_entry_t *
+create_kssl_entry(kssl_params_t *kssl_params, Certificate_t *cert,
+    crypto_key_t *privkey)
+{
+	int i;
+	uint16_t s;
+	kssl_entry_t *kssl_entry;
+	uint_t cnt, mech_count;
+	crypto_mech_name_t *mechs;
+	boolean_t got_rsa, got_md5, got_sha1, got_rc4, got_des, got_3des;
+
+	kssl_entry = kmem_zalloc(sizeof (kssl_entry_t), KM_SLEEP);
+
+	kssl_entry->ke_laddr = kssl_params->kssl_addr.sin_addr.s_addr;
+	kssl_entry->ke_ssl_port = kssl_params->kssl_addr.sin_port;
+	kssl_entry->ke_proxy_port = kssl_params->kssl_proxy_port;
+	if (kssl_params->kssl_session_cache_timeout == 0)
+		kssl_entry->sid_cache_timeout = DEFAULT_SID_TIMEOUT;
+	else
+		kssl_entry->sid_cache_timeout =
+		    kssl_params->kssl_session_cache_timeout;
+	if (kssl_params->kssl_session_cache_size == 0)
+		kssl_entry->sid_cache_nentries = DEFAULT_SID_CACHE_NENTRIES;
+	else
+		kssl_entry->sid_cache_nentries =
+		    kssl_params->kssl_session_cache_size;
+	kssl_entry->ke_private_key = privkey;
+	kssl_entry->ke_server_certificate = cert;
+
+	mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
+	if (mechs != NULL) {
+		got_rsa = got_md5 = got_sha1 = got_rc4 =
+		    got_des = got_3des = B_FALSE;
+		for (i = 0; i < mech_count; i++) {
+			if (strncmp(SUN_CKM_RSA_X_509, mechs[i],
+			    CRYPTO_MAX_MECH_NAME) == 0)
+				got_rsa = B_TRUE;
+			else if (strncmp(SUN_CKM_MD5_HMAC, mechs[i],
+			    CRYPTO_MAX_MECH_NAME) == 0)
+				got_md5 = B_TRUE;
+			else if (strncmp(SUN_CKM_SHA1_HMAC, mechs[i],
+			    CRYPTO_MAX_MECH_NAME) == 0)
+				got_sha1 = B_TRUE;
+			else if (strncmp(SUN_CKM_RC4, mechs[i],
+			    CRYPTO_MAX_MECH_NAME) == 0)
+				got_rc4 = B_TRUE;
+			else if (strncmp(SUN_CKM_DES_CBC, mechs[i],
+			    CRYPTO_MAX_MECH_NAME) == 0)
+				got_des = B_TRUE;
+			else if (strncmp(SUN_CKM_DES3_CBC, mechs[i],
+			    CRYPTO_MAX_MECH_NAME) == 0)
+				got_3des = B_TRUE;
+		}
+
+		cnt = 0;
+		for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++) {
+			switch (s = kssl_params->kssl_suites[i]) {
+			case SSL_RSA_WITH_RC4_128_MD5:
+				if (got_rsa && got_rc4 && got_md5)
+				    kssl_entry->kssl_cipherSuites[cnt++] = s;
+				break;
+			case SSL_RSA_WITH_RC4_128_SHA:
+				if (got_rsa && got_rc4 && got_sha1)
+				    kssl_entry->kssl_cipherSuites[cnt++] = s;
+				break;
+			case SSL_RSA_WITH_DES_CBC_SHA:
+				if (got_rsa && got_des && got_sha1)
+				    kssl_entry->kssl_cipherSuites[cnt++] = s;
+				break;
+			case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
+				if (got_rsa && got_3des && got_sha1)
+				    kssl_entry->kssl_cipherSuites[cnt++] = s;
+				break;
+			case CIPHER_NOTSET:
+			default:
+				break;
+			}
+		}
+
+		crypto_free_mech_list(mechs, mech_count);
+	}
+
+	/* Add the no encryption suite to the end */
+	kssl_entry->kssl_cipherSuites[cnt++] = SSL_RSA_WITH_NULL_SHA;
+	kssl_entry->kssl_cipherSuites_nentries = cnt;
+	for (i = 0; i < cnt; i++)
+		kssl_entry->kssl_saved_Suites[i] =
+		    kssl_entry->kssl_cipherSuites[i];
+
+	kssl_entry->sid_cache = kmem_alloc(
+	    kssl_entry->sid_cache_nentries * sizeof (kssl_sid_ent_t), KM_SLEEP);
+
+	for (i = 0; i < kssl_entry->sid_cache_nentries; i++) {
+		mutex_init(&(kssl_entry->sid_cache[i].se_lock), NULL,
+		    MUTEX_DEFAULT, NULL);
+		kssl_entry->sid_cache[i].se_used = 0;
+		kssl_entry->sid_cache[i].se_sid.cached = B_FALSE;
+	}
+
+	KSSL_ENTRY_REFHOLD(kssl_entry);
+
+	return (kssl_entry);
+}
+
+int
+kssl_add_entry(kssl_params_t *kssl_params)
+{
+	int rv, index, i;
+	Certificate_t *cert;
+	crypto_key_t *privkey;
+	kssl_entry_t *kssl_entry;
+	ipaddr_t laddr;
+
+	if ((rv = extract_certificate(kssl_params, &cert)) != 0) {
+		return (rv);
+	}
+
+	if ((rv = extract_private_key(kssl_params, &privkey)) != 0) {
+		certificate_free(cert);
+		return (rv);
+	}
+
+	kssl_entry = create_kssl_entry(kssl_params, cert, privkey);
+
+	/* Revisit here for IPv6 support */
+	laddr = kssl_params->kssl_addr.sin_addr.s_addr;
+
+retry:
+	mutex_enter(&kssl_tab_mutex);
+	/* Allocate the array first time here */
+	if (kssl_entry_tab == NULL) {
+		size_t allocsize;
+		kssl_entry_t **tmp_tab;
+		int tmp_size;
+
+		tmp_size = KSSL_TAB_INITSIZE;
+		allocsize = tmp_size * sizeof (kssl_entry_t *);
+		mutex_exit(&kssl_tab_mutex);
+		tmp_tab = kmem_zalloc(allocsize, KM_SLEEP);
+		mutex_enter(&kssl_tab_mutex);
+		if (kssl_entry_tab != NULL) {
+			mutex_exit(&kssl_tab_mutex);
+			kmem_free(tmp_tab, allocsize);
+			goto retry;
+		}
+		kssl_entry_tab_size = tmp_size;
+		kssl_entry_tab = tmp_tab;
+		index = 0;
+	} else {
+		/* Check if a matching entry exists already */
+		index = kssl_find_entry(laddr,
+		    kssl_params->kssl_addr.sin_port, IS_SSL_PORT, B_TRUE);
+
+		if (index == -1) {
+			/* Check if an entry with the same proxy port exists */
+			if (kssl_find_entry(laddr, kssl_params->kssl_proxy_port,
+			    IS_PROXY_PORT, B_TRUE) != -1) {
+				mutex_exit(&kssl_tab_mutex);
+				kssl_free_entry(kssl_entry);
+				return (EADDRINUSE);
+			}
+
+			/* No matching entry, find an empty spot */
+			for (i = 0; i < kssl_entry_tab_size; i++) {
+				if (kssl_entry_tab[i] == NULL)
+					break;
+			}
+			/* Table full. Gotta grow it */
+			if (i == kssl_entry_tab_size) {
+				kssl_entry_t **new_tab, **old_tab;
+				size_t allocsize;
+				size_t oldtabsize = kssl_entry_tab_size *
+				    sizeof (kssl_entry_t *);
+				int tmp_size, old_size;
+
+				tmp_size = old_size = kssl_entry_tab_size;
+				tmp_size += KSSL_TAB_INITSIZE;
+				allocsize = tmp_size * sizeof (kssl_entry_t *);
+				mutex_exit(&kssl_tab_mutex);
+				new_tab = kmem_zalloc(allocsize, KM_SLEEP);
+				mutex_enter(&kssl_tab_mutex);
+				if (kssl_entry_tab_size > old_size) {
+					mutex_exit(&kssl_tab_mutex);
+					kmem_free(new_tab, allocsize);
+					goto retry;
+				}
+
+				kssl_entry_tab_size = tmp_size;
+				bcopy(kssl_entry_tab, new_tab, oldtabsize);
+
+				old_tab = kssl_entry_tab;
+				kssl_entry_tab = new_tab;
+
+				kmem_free(old_tab, oldtabsize);
+			}
+			index = i;
+		} else {
+			/*
+			 * We do not want an entry with a specific address and
+			 * an entry with IN_ADDR_ANY to coexist. We could
+			 * replace the existing entry. But, most likely this
+			 * is misconfiguration. Better bail out with an error.
+			 */
+			if ((laddr == INADDR_ANY &&
+			    (kssl_entry_tab[index]->ke_laddr != INADDR_ANY)) ||
+			    (laddr != INADDR_ANY &&
+			    (kssl_entry_tab[index]->ke_laddr == INADDR_ANY))) {
+				mutex_exit(&kssl_tab_mutex);
+				kssl_free_entry(kssl_entry);
+				return (EEXIST);
+			}
+
+			/* Replace the existing entry */
+			KSSL_ENTRY_REFRELE(kssl_entry_tab[index]);
+			kssl_entry_tab[index] = NULL;
+			kssl_entry_tab_nentries--;
+		}
+	}
+
+	kssl_entry_tab[index] = kssl_entry;
+	kssl_entry_tab_nentries++;
+	mutex_exit(&kssl_tab_mutex);
+
+	return (0);
+}
+
+int
+kssl_delete_entry(struct sockaddr_in *kssl_addr)
+{
+	ipaddr_t laddr;
+	int index;
+
+	/* Revisit here for IPv6 support */
+	laddr = kssl_addr->sin_addr.s_addr;
+
+	mutex_enter(&kssl_tab_mutex);
+	index = kssl_find_entry(laddr, kssl_addr->sin_port,
+	    IS_SSL_PORT, B_FALSE);
+
+	if (index == -1) {
+		mutex_exit(&kssl_tab_mutex);
+		return (ENOENT);
+	}
+
+	KSSL_ENTRY_REFRELE(kssl_entry_tab[index]);
+	kssl_entry_tab[index] = NULL;
+	kssl_entry_tab_nentries--;
+
+	mutex_exit(&kssl_tab_mutex);
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/kssl/ksslproto.h	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,355 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_INET_KSSL_KSSLPROTO_H
+#define	_INET_KSSL_KSSLPROTO_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/md5.h>
+#include <sys/sha1.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/api.h>
+#include <inet/kssl/kssl.h>	/* Cipher suite definitions */
+#include <inet/kssl/ksslapi.h>
+#include <inet/kssl/ksslimpl.h>
+
+#define	SSL3_RANDOM_LENGTH		32
+#define	SSL3_SESSIONID_BYTES		32
+#define	SSL3_HDR_LEN			5
+#define	SSL3_MAX_RECORD_LENGTH		16384
+#define	SSL3_PRE_MASTER_SECRET_LEN	48
+#define	SSL3_MASTER_SECRET_LEN		48
+#define	SSL3_MD5_PAD_LEN		48
+#define	SSL3_SHA1_PAD_LEN		40
+
+#define	SSL_MIN_CHALLENGE_BYTES		16
+#define	SSL_MAX_CHALLENGE_BYTES		32
+
+#define	SHA1_HASH_LEN			20
+#define	MD5_HASH_LEN			16
+#define	MAX_HASH_LEN			SHA1_HASH_LEN
+
+#define	KSSL_READ			0
+#define	KSSL_WRITE			1
+
+#define	KSSL_ENCRYPT			0
+#define	KSSL_DECRYPT			1
+
+#define	MSG_INIT			0
+#define	MSG_INIT_LEN			1
+#define	MSG_BODY			2
+
+#define	MAX_KEYBLOCK_LENGTH		112
+
+#define	TLS_MASTER_SECRET_LABEL		"master secret"
+#define	TLS_CLIENT_WRITE_KEY_LABEL	"client write key"
+#define	TLS_SERVER_WRITE_KEY_LABEL	"server write key"
+#define	TLS_CLIENT_FINISHED_LABEL	"client finished"
+#define	TLS_SERVER_FINISHED_LABEL	"server finished"
+#define	TLS_KEY_EXPANSION_LABEL		"key expansion"
+#define	TLS_IV_BLOCK_LABEL		"IV block"
+#define	TLS_MAX_LABEL_SIZE		24
+
+#define	TLS_FINISHED_SIZE		12
+
+/*
+ * The following constants try to insure an input buffer is optimally aligned
+ * for MAC hash computation.  SHA1/MD5 code prefers 4 byte alignment of each
+ * 64byte input block to avoid a copy. Our goal is to reach 4 byte alignment
+ * starting form the 3rd MAC block (input buffer starts in the 3rd block). The
+ * 3rd block includes the first 53 (MD5 SSL3 MAC) or 57 (SHA1 SSL3 MAC) bytes
+ * of the input buffer. This means input buffer should start at offset 3
+ * within a 4 byte word so that its next block is 4 byte aligned. Since the
+ * SSL3 record header is 5 bytes long it should start at at offset 2 within a
+ * 4 byte word. To insure the next record (for buffers that don't fit into 1
+ * SSL3 record) also starts at offset 2 within a 4 byte word the previous
+ * record length should be 3 mod 8 since 5 + 3 mod 8 is 0 i.e. the next record
+ * starts at the same offset within a 4 byte word as the the previous record.
+ */
+#define	SSL3_MAX_OPTIMAL_RECORD_LENGTH	(SSL3_MAX_RECORD_LENGTH - 1)
+#define	SSL3_OPTIMAL_RECORD_ALIGNMENT	2
+
+/* session state */
+typedef struct sslSessionIDStr {
+	uchar_t	session_id[SSL3_SESSIONID_BYTES];
+	uchar_t master_secret[SSL3_MASTER_SECRET_LEN];
+	clock_t time;
+	ipaddr_t client_addr;
+	boolean_t cached;
+	uint16_t cipher_suite;
+} sslSessionID;
+
+/* An element of the session cache */
+typedef struct kssl_sid_ent {
+	kmutex_t se_lock;
+	uint64_t se_used;	/* Counter to check hash distribution */
+	sslSessionID se_sid;
+	uchar_t  pad[2 * 64 - sizeof (kmutex_t) - sizeof (uint64_t) \
+	    - sizeof (sslSessionID)];
+} kssl_sid_ent_t;
+
+typedef struct RC4ContextStr {
+	uchar_t i;
+	uchar_t j;
+	uchar_t S[256];
+} RC4Context;
+
+typedef enum {
+    content_change_cipher_spec	= 20,
+    content_alert		= 21,
+    content_handshake		= 22,
+    content_application_data	= 23,
+    content_handshake_v2	= 128
+} SSL3ContentType;
+
+typedef enum {
+    hello_request	= 0,
+    client_hello	= 1,
+    server_hello	= 2,
+    certificate		= 11,
+    server_key_exchange	= 12,
+    certificate_request	= 13,
+    server_hello_done	= 14,
+    certificate_verify	= 15,
+    client_key_exchange	= 16,
+    finished		= 20
+} SSL3HandshakeType;
+
+typedef struct SSL3HandshakeMsgStr {
+	int state;
+	SSL3HandshakeType type;
+	int msglen;
+	int msglen_bytes;
+	mblk_t *head;
+	mblk_t *tail;
+} SSL3HandshakeMsg;
+
+typedef struct KSSLJOBStr {
+	struct ssl_s	*ssl;
+	crypto_req_id_t	kjob;
+	char		*buf;
+	size_t		buflen;
+	int		status;
+} KSSLJOB;
+
+typedef struct KSSLMACJOBStr {
+	struct ssl_s *ssl;
+	buf_t *in;
+	buf_t *out;
+	uchar_t *rstart;
+	int rlen;
+	uint64_t seq;
+	SSL3ContentType ct;
+	uchar_t *digest;
+	int dir;
+} KSSLMACJOB;
+
+
+typedef struct {
+	uchar_t md5[MD5_HASH_LEN];
+	uchar_t sha1[SHA1_HASH_LEN];
+	uchar_t tlshash[TLS_FINISHED_SIZE];
+} SSL3Hashes;
+
+typedef enum {
+	close_notify		= 0,
+	unexpected_message	= 10,
+	bad_record_mac		= 20,
+	decompression_failure	= 30,
+	handshake_failure	= 40,
+	no_certificate		= 41,
+	bad_certificate		= 42,
+	unsupported_certificate	= 43,
+	certificate_revoked	= 44,
+	certificate_expired	= 45,
+	certificate_unknown	= 46,
+	illegal_parameter	= 47,
+	unknown_ca		= 48,
+	access_denied		= 49,
+	decode_error		= 50,
+	decrypt_error		= 51,
+	export_restriction	= 60,
+	protocol_version	= 70,
+	insufficient_security	= 71,
+	internal_error		= 80,
+	user_canceled		= 90,
+	no_renegotiation	= 100
+} SSL3AlertDescription;
+
+typedef enum {
+	alert_warning = 1,
+	alert_fatal = 2
+} SSL3AlertLevel;
+
+typedef enum {
+	wait_client_hello = 0,
+	wait_client_key = 1,
+	wait_client_key_done = 2,
+	wait_change_cipher = 3,
+	wait_finished = 4,
+	idle_handshake = 5
+} SSL3WaitState;
+
+typedef enum {
+    sender_client = 0x434c4e54,
+    sender_server = 0x53525652
+} SSL3Sender;
+
+typedef enum {
+    mac_md5	= 0,
+    mac_sha	= 1
+} SSL3MACAlgorithm;
+
+/* The SSL bulk cipher definition */
+typedef enum {
+    cipher_null = 0,
+    cipher_rc4 = 1,
+    cipher_des = 2,
+    cipher_3des = 3
+} SSL3BulkCipher;
+
+typedef enum { type_stream = 0, type_block = 1 } CipherType;
+
+typedef struct ssl3CipherSuiteDefStr {
+	uint16_t		suite;
+	SSL3BulkCipher		calg;
+	SSL3MACAlgorithm	malg;
+	int			keyblksz;
+} ssl3CipherSuiteDef;
+
+typedef void (*hashinit_func_t)(void *);
+typedef void (*hashupdate_func_t)(void *, uchar_t *, uint32_t);
+typedef void (*hashfinal_func_t)(uchar_t *, void *);
+
+typedef struct KSSLMACDefStr {
+	int			hashsz;
+	int			padsz;
+	hashinit_func_t		HashInit;
+	hashupdate_func_t	HashUpdate;
+	hashfinal_func_t	HashFinal;
+} KSSLMACDef;
+
+typedef struct KSSLCipherDefStr {
+	CipherType		type;
+	int			bsize;
+	int			keysz;
+	crypto_mech_type_t	mech_type;
+} KSSLCipherDef;
+
+typedef union KSSL_HASHCTXUnion {
+	SHA1_CTX	sha;
+	MD5_CTX		md5;
+} KSSL_HASHCTX;
+
+typedef struct KSSLCipherSpecStr {
+	int		mac_hashsz;
+	int		mac_padsz;
+	void		(*MAC_HashInit)(void *);
+	void		(*MAC_HashUpdate)(void *, uchar_t *, uint32_t);
+	void		(*MAC_HashFinal)(uchar_t *, void *);
+
+	CipherType	cipher_type;
+	int		cipher_bsize;
+	int		cipher_keysz;
+
+	crypto_mechanism_t	cipher_mech;
+	crypto_mechanism_t	hmac_mech;	/* for TLS */
+	crypto_key_t		cipher_key;
+	crypto_key_t		hmac_key;	/* for TLS */
+
+	crypto_context_t	cipher_ctx;
+	crypto_data_t		cipher_data;
+
+} KSSLCipherSpec;
+
+/*
+ * SSL connection state. This one hangs off of a tcp_t structure.
+ */
+typedef struct ssl_s {
+	kmutex_t		kssl_lock;
+	struct kssl_entry_s	*kssl_entry;
+	mblk_t			*rec_ass_head;
+	mblk_t			*rec_ass_tail;
+	uint_t			kssl_refcnt;
+	ipaddr_t		faddr;
+	uint32_t		tcp_mss;
+	SSL3WaitState		hs_waitstate;
+	boolean_t		resumed;
+	boolean_t		close_notify;
+	boolean_t		fatal_alert;
+	boolean_t		fatal_error;
+	boolean_t		alert_sent;
+	boolean_t		appdata_sent;
+	boolean_t		activeinput;
+	SSL3AlertLevel		sendalert_level;
+	SSL3AlertDescription	sendalert_desc;
+	mblk_t			*handshake_sendbuf;
+	mblk_t			*alert_sendbuf;
+	kssl_callback_t		cke_callback_func;
+	void			*cke_callback_arg;
+	uint32_t		macjobs_todo;
+	uint32_t		macjobs_done;
+	uint16_t		pending_cipher_suite;
+	SSL3MACAlgorithm	pending_malg;
+	SSL3BulkCipher		pending_calg;
+	int			pending_keyblksz;
+	uint64_t		seq_num[2];
+	SSL3HandshakeMsg	msg;
+	KSSLJOB			job;
+	KSSLCipherSpec		spec[2];
+	uchar_t			pending_keyblock[MAX_KEYBLOCK_LENGTH];
+	uchar_t			mac_secret[2][MAX_HASH_LEN];
+	KSSL_HASHCTX		mac_ctx[2][2];	/* inner 'n outer per dir */
+	sslSessionID		sid;
+	SHA1_CTX		hs_sha1;
+	MD5_CTX			hs_md5;
+	SSL3Hashes		hs_hashes;
+	uchar_t			client_random[SSL3_RANDOM_LENGTH];
+	uchar_t			server_random[SSL3_RANDOM_LENGTH];
+	int			sslcnt;
+	uchar_t			major_version;
+	uchar_t			minor_version;
+} ssl_t;
+
+#define	IS_TLS(s) (s->major_version == 3 && s->minor_version == 1)
+
+#define	SSL3_REC_SIZE(mp)	(uint8_t *)(mp)->b_rptr + 3
+
+extern int kssl_spec_init(ssl_t *, int);
+extern void kssl_send_alert(ssl_t *, SSL3AlertLevel, SSL3AlertDescription);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _INET_KSSL_KSSLPROTO_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/kssl/ksslrec.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,2077 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/stropts.h>
+#include <sys/strsun.h>
+#define	_SUN_TPI_VERSION 2
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+#include <sys/vtrace.h>
+#include <sys/kmem.h>
+#include <sys/cpuvar.h>
+#include <sys/atomic.h>
+#include <sys/sysmacros.h>
+
+#include <sys/errno.h>
+#include <sys/isa_defs.h>
+#include <sys/md5.h>
+#include <sys/sha1.h>
+#include <sys/random.h>
+#include <inet/common.h>
+#include <netinet/in.h>
+
+#include <sys/systm.h>
+#include <sys/param.h>
+
+#include "ksslimpl.h"
+#include "ksslapi.h"
+#include "ksslproto.h"
+#include "kssldebug.h"
+
+static ssl3CipherSuiteDef cipher_suite_defs[] = {
+	{SSL_RSA_WITH_RC4_128_SHA,	cipher_rc4,	mac_sha,	72},
+	{SSL_RSA_WITH_RC4_128_MD5,	cipher_rc4,	mac_md5,	64},
+	{SSL_RSA_WITH_DES_CBC_SHA,	cipher_des,	mac_sha,	72},
+	{SSL_RSA_WITH_3DES_EDE_CBC_SHA,	cipher_3des,	mac_sha,	104},
+	{SSL_RSA_WITH_NULL_SHA,		cipher_null,	mac_sha,	40}
+};
+
+static int cipher_suite_defs_nentries =
+    sizeof (cipher_suite_defs) / sizeof (cipher_suite_defs[0]);
+
+static KSSLMACDef mac_defs[] = { /* indexed by SSL3MACAlgorithm */
+	/* macsz padsz HashInit HashUpdate HashFinal */
+
+	{MD5_HASH_LEN, SSL3_MD5_PAD_LEN,
+	    (hashinit_func_t)MD5Init, (hashupdate_func_t)MD5Update,
+	    (hashfinal_func_t)MD5Final},
+
+	{SHA1_HASH_LEN, SSL3_SHA1_PAD_LEN,
+	    (hashinit_func_t)SHA1Init, (hashupdate_func_t)SHA1Update,
+	    (hashfinal_func_t)SHA1Final},
+};
+
+static uchar_t kssl_pad_1[60] = {
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36
+};
+static uchar_t kssl_pad_2[60] = {
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+    0x5c, 0x5c, 0x5c, 0x5c
+};
+
+int kssl_debug;
+int kssl_cache_count;
+static boolean_t kssl_synchronous = B_FALSE;
+
+static void kssl_update_handshake_hashes(ssl_t *, uchar_t *, uint_t);
+static int kssl_compute_handshake_hashes(ssl_t *, SSL3Hashes *, uint32_t);
+static int kssl_handle_client_hello(ssl_t *, mblk_t *, int);
+static int kssl_handle_client_key_exchange(ssl_t *, mblk_t *, int,
+    kssl_callback_t, void *);
+static int kssl_send_server_hello(ssl_t *);
+static int kssl_send_certificate_and_server_hello_done(ssl_t *);
+static int kssl_send_change_cipher_specs(ssl_t *);
+static int kssl_send_finished(ssl_t *, int);
+static int kssl_handle_finished(ssl_t *, mblk_t *, int);
+static void kssl_get_hello_random(uchar_t *);
+static uchar_t *kssl_rsa_unwrap(uchar_t *, size_t *);
+static void kssl_cache_sid(sslSessionID *, kssl_entry_t *);
+static void kssl_lookup_sid(sslSessionID *, uchar_t *, ipaddr_t,
+    kssl_entry_t *);
+static int kssl_generate_tls_ms(ssl_t *, uchar_t *, size_t);
+static void kssl_generate_ssl_ms(ssl_t *, uchar_t *, size_t);
+static int kssl_generate_tls_keyblock(ssl_t *);
+static void kssl_generate_keyblock(ssl_t *);
+static void kssl_ssl3_key_material_derive_step(ssl_t *, uchar_t *, size_t,
+    int, uchar_t *, int);
+static int kssl_tls_PRF(ssl_t *, uchar_t *, size_t,
+    uchar_t *, size_t, uchar_t *, size_t, uchar_t *, size_t);
+static int kssl_tls_P_hash(crypto_mechanism_t *, crypto_key_t *,
+    size_t, uchar_t *, size_t, uchar_t *, size_t, uchar_t *, size_t);
+static void kssl_cke_done(void *, int);
+
+#define	MAX_TLS_KEYBLOCK_SIZE 160 /* more than enough for largest TLS key */
+
+#define	HMAC_INIT(m, k, c) \
+	rv = crypto_mac_init(m, k, NULL, c, NULL); if (CRYPTO_ERR(rv)) goto end;
+
+#define	HMAC_UPDATE(c, d, l) \
+	dd.cd_raw.iov_base = (char *)d; \
+	dd.cd_length = dd.cd_raw.iov_len = l; \
+	rv = crypto_mac_update(c, &dd, NULL); if (CRYPTO_ERR(rv)) goto end;
+
+#define	HMAC_FINAL(c, d, l) \
+	mac.cd_raw.iov_base = (char *)d; \
+	mac.cd_length = mac.cd_raw.iov_len = l; \
+	rv = crypto_mac_final(c, &mac, NULL); if (CRYPTO_ERR(rv)) goto end;
+
+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)
+{
+	KSSL_HASHCTX mac_ctx;
+	KSSL_HASHCTX *ctx = &mac_ctx;
+	uchar_t temp[16], *p;
+	KSSLCipherSpec *spec;
+	int rv = 0;
+
+	spec = &ssl->spec[direction];
+
+	if (spec->mac_hashsz == 0) {
+		return (1);
+	}
+
+	/* mac_secret = ssl->mac_secret[direction]; */
+
+	p = temp;
+
+	*p++ = (seq_num >> 56) & 0xff;
+	*p++ = (seq_num >> 48) & 0xff;
+	*p++ = (seq_num >> 40) & 0xff;
+	*p++ = (seq_num >> 32) & 0xff;
+	*p++ = (seq_num >> 24) & 0xff;
+	*p++ = (seq_num >> 16) & 0xff;
+	*p++ = (seq_num >> 8) & 0xff;
+	*p++ = (seq_num) & 0xff;
+	*p++ = (uchar_t)ct;
+	if (IS_TLS(ssl)) {
+		*p++ = versionp[0];
+		*p++ = versionp[1];
+	}
+	*p++ = (len >> 8) & 0xff;
+	*p++ = (len) & 0xff;
+
+	if (IS_TLS(ssl)) {
+		crypto_data_t dd, mac;
+		crypto_context_t ctx;
+
+		dd.cd_format = CRYPTO_DATA_RAW;
+		dd.cd_offset = 0;
+		mac.cd_format = CRYPTO_DATA_RAW;
+		mac.cd_offset = 0;
+
+		HMAC_INIT(&spec->hmac_mech, &spec->hmac_key, &ctx);
+		HMAC_UPDATE(ctx, temp, p - temp);
+		HMAC_UPDATE(ctx, buf, len);
+		HMAC_FINAL(ctx, digest, spec->mac_hashsz);
+end:
+		if (CRYPTO_ERR(rv)) {
+#ifdef	DEBUG
+			cmn_err(CE_WARN,
+				"kssl_compute_record_mac - crypto_mac error "
+				"0x%0x", rv);
+#endif	/* DEBUG */
+			KSSL_COUNTER(compute_mac_failure, 1);
+		}
+	} else {
+		bcopy(&(ssl->mac_ctx[direction][0]), ctx,
+			sizeof (KSSL_HASHCTX));
+		spec->MAC_HashUpdate((void *)ctx, temp, p - temp);
+		spec->MAC_HashUpdate((void *)ctx, buf, len);
+		spec->MAC_HashFinal(digest, (void *)ctx);
+
+		bcopy(&(ssl->mac_ctx[direction][1]), ctx,
+			sizeof (KSSL_HASHCTX));
+		spec->MAC_HashUpdate((void *)ctx, digest, spec->mac_hashsz);
+		spec->MAC_HashFinal(digest, (void *)ctx);
+	}
+
+	return (rv);
+}
+
+/*
+ * Handles handshake messages.
+ * Messages to be replied are returned in handshake_sendbuf.
+ */
+int
+kssl_handle_handshake_message(ssl_t *ssl, mblk_t *mp, int *err,
+    kssl_callback_t cbfn, void *arg)
+{
+	uint32_t msglen;
+	uchar_t msghdr[4];
+
+	ASSERT(ssl->msg.state == MSG_BODY);
+	ASSERT(ssl->msg.msglen_bytes == 3);
+	ASSERT(mp->b_wptr >= mp->b_rptr + ssl->msg.msglen);
+
+	ssl->sslcnt++;
+	msglen = ssl->msg.msglen;
+
+	if (ssl->msg.type == client_hello) {
+		MD5Init(&ssl->hs_md5);
+		SHA1Init(&ssl->hs_sha1);
+	}
+
+	if (ssl->msg.type == finished && ssl->resumed == B_FALSE) {
+		if (kssl_compute_handshake_hashes(ssl, &ssl->hs_hashes,
+		    sender_client) != 0) {
+			*err = SSL_MISS;
+			return (0);
+		}
+	}
+
+	if (ssl->msg.type != finished || ssl->resumed == B_FALSE) {
+		msghdr[0] = (uchar_t)ssl->msg.type;
+
+		msghdr[1] = (uchar_t)(msglen >> 16);
+		msghdr[2] = (uchar_t)(msglen >> 8);
+		msghdr[3] = (uchar_t)(msglen);
+		kssl_update_handshake_hashes(ssl, msghdr, 4);
+		kssl_update_handshake_hashes(ssl, mp->b_rptr, msglen);
+	}
+
+	ssl->msg.state = MSG_INIT;
+	ssl->msg.msglen = 0;
+	ssl->msg.msglen_bytes = 0;
+
+	switch (ssl->msg.type) {
+	case client_hello:
+		if (ssl->hs_waitstate != wait_client_hello) {
+			kssl_send_alert(ssl, alert_fatal,
+			    unexpected_message);
+			*err = EBADMSG;
+			ssl->activeinput = B_FALSE;
+			return (1);
+		}
+		*err = kssl_handle_client_hello(ssl, mp, msglen);
+		if (*err == SSL_MISS) {
+			ssl->activeinput = B_FALSE;
+			return (0);
+		}
+		return (1);
+	case client_key_exchange:
+		if (ssl->hs_waitstate != wait_client_key) {
+			kssl_send_alert(ssl, alert_fatal,
+			    unexpected_message);
+			*err = EBADMSG;
+			ssl->activeinput = B_FALSE;
+			return (1);
+		}
+		*err = kssl_handle_client_key_exchange(ssl, mp,
+		    msglen, cbfn, arg);
+		return (1);
+	case finished:
+		if (ssl->hs_waitstate != wait_finished) {
+			kssl_send_alert(ssl, alert_fatal,
+				unexpected_message);
+			*err = EBADMSG;
+			ssl->activeinput = B_FALSE;
+			return (1);
+		}
+		*err = kssl_handle_finished(ssl, mp, msglen);
+		return (1);
+	default:
+		kssl_send_alert(ssl, alert_fatal, unexpected_message);
+		ssl->activeinput = B_FALSE;
+		*err = EBADMSG;
+		return (1);
+	}
+}
+
+static void
+kssl_update_handshake_hashes(ssl_t *ssl, uchar_t *buf, uint_t len)
+{
+	MD5Update(&ssl->hs_md5, buf, len);
+	SHA1Update(&ssl->hs_sha1, buf, len);
+}
+
+static int
+kssl_compute_handshake_hashes(
+	ssl_t *ssl,
+	SSL3Hashes *hashes,
+	uint32_t sender)
+{
+	MD5_CTX md5 = ssl->hs_md5;	/* clone md5 context */
+	SHA1_CTX sha1 = ssl->hs_sha1;	/* clone sha1 context */
+	MD5_CTX *md5ctx = &md5;
+	SHA1_CTX *sha1ctx = &sha1;
+
+	if (IS_TLS(ssl)) {
+		uchar_t seed[MD5_HASH_LEN + SHA1_HASH_LEN];
+		char *label;
+
+		/*
+		 * Do not take another hash step here.
+		 * Just complete the operation.
+		 */
+		MD5Final(hashes->md5, md5ctx);
+		SHA1Final(hashes->sha1, sha1ctx);
+
+		bcopy(hashes->md5, seed, MD5_HASH_LEN);
+		bcopy(hashes->sha1, seed + MD5_HASH_LEN, SHA1_HASH_LEN);
+
+		if (sender == sender_client)
+			label = TLS_CLIENT_FINISHED_LABEL;
+		else
+			label = TLS_SERVER_FINISHED_LABEL;
+
+		return (kssl_tls_PRF(ssl,
+			ssl->sid.master_secret, (size_t)SSL3_MASTER_SECRET_LEN,
+			(uchar_t *)label, strlen(label),
+			seed, (size_t)(MD5_HASH_LEN + SHA1_HASH_LEN),
+			hashes->tlshash, (size_t)TLS_FINISHED_SIZE));
+	} else {
+		uchar_t s[4];
+		s[0] = (sender >> 24) & 0xff;
+		s[1] = (sender >> 16) & 0xff;
+		s[2] = (sender >> 8) & 0xff;
+		s[3] = (sender) & 0xff;
+
+		MD5Update(md5ctx, s, 4);
+		MD5Update(md5ctx, ssl->sid.master_secret,
+		    SSL3_MASTER_SECRET_LEN);
+		MD5Update(md5ctx, kssl_pad_1, SSL3_MD5_PAD_LEN);
+		MD5Final(hashes->md5, md5ctx);
+
+		MD5Init(md5ctx);
+		MD5Update(md5ctx, ssl->sid.master_secret,
+		    SSL3_MASTER_SECRET_LEN);
+		MD5Update(md5ctx, kssl_pad_2, SSL3_MD5_PAD_LEN);
+		MD5Update(md5ctx, hashes->md5, MD5_HASH_LEN);
+		MD5Final(hashes->md5, md5ctx);
+
+		SHA1Update(sha1ctx, s, 4);
+		SHA1Update(sha1ctx, ssl->sid.master_secret,
+		    SSL3_MASTER_SECRET_LEN);
+		SHA1Update(sha1ctx, kssl_pad_1, SSL3_SHA1_PAD_LEN);
+		SHA1Final(hashes->sha1, sha1ctx);
+
+		SHA1Init(sha1ctx);
+		SHA1Update(sha1ctx, ssl->sid.master_secret,
+		    SSL3_MASTER_SECRET_LEN);
+		SHA1Update(sha1ctx, kssl_pad_2, SSL3_SHA1_PAD_LEN);
+		SHA1Update(sha1ctx, hashes->sha1, SHA1_HASH_LEN);
+		SHA1Final(hashes->sha1, sha1ctx);
+		return (0);
+	}
+}
+
+
+#define	KSSL_SSL3_CH_MIN_MSGLEN	(39)
+
+static int
+kssl_handle_client_hello(ssl_t *ssl, mblk_t *mp, int msglen)
+{
+	uchar_t *msgend;
+	int err;
+	SSL3AlertDescription desc = illegal_parameter;
+	uint_t sidlen;
+	uint_t nsuites;
+	uchar_t *suitesp;
+	uint_t i, j;
+	uint16_t suite;
+	int ch_msglen = KSSL_SSL3_CH_MIN_MSGLEN;
+
+	ASSERT(mp->b_wptr >= mp->b_rptr + msglen);
+	ASSERT(ssl->msg.type == client_hello);
+	ASSERT(ssl->hs_waitstate == wait_client_hello);
+	ASSERT(ssl->resumed == B_FALSE);
+
+	if (msglen < ch_msglen) {
+		goto falert;
+	}
+
+	msgend = mp->b_rptr + msglen;
+
+	/* Support SSLv3 (version == 3.0) or TLS (version == 3.1) */
+	if (ssl->major_version != 3 || (ssl->major_version == 3 &&
+		ssl->minor_version != 0 && ssl->minor_version != 1)) {
+		KSSL_DEBUG3_IF(kssl_debug,
+			"HandleClientHello: handshake failure - "
+			"SSL version not supported (%d %d)",
+			ssl->major_version, ssl->minor_version);
+		desc = handshake_failure;
+		goto falert;
+	}
+	mp->b_rptr += 2; /* skip the version bytes */
+
+	bcopy(mp->b_rptr, ssl->client_random, SSL3_RANDOM_LENGTH);
+	mp->b_rptr += SSL3_RANDOM_LENGTH;
+
+	ASSERT(ssl->sid.cached == B_FALSE);
+	sidlen = *mp->b_rptr++;
+	ch_msglen += sidlen;
+	if (msglen < ch_msglen) {
+		goto falert;
+	}
+	if (sidlen != SSL3_SESSIONID_BYTES) {
+		mp->b_rptr += sidlen;
+	} else {
+		kssl_lookup_sid(&ssl->sid, mp->b_rptr, ssl->faddr,
+		    ssl->kssl_entry);
+		mp->b_rptr += SSL3_SESSIONID_BYTES;
+	}
+
+	nsuites = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1];
+	mp->b_rptr += 2;
+	ch_msglen += nsuites;
+	if (msglen != ch_msglen) {
+		goto falert;
+	}
+	if (nsuites & 0x1) {
+		goto falert;
+	}
+	suitesp = mp->b_rptr;
+	if (ssl->sid.cached == B_TRUE) {
+		suite = ssl->sid.cipher_suite;
+		for (j = 0; j < nsuites; j += 2) {
+			if (suitesp[j] == ((suite >> 8) & 0xff) &&
+			    suitesp[j + 1] == (suite & 0xff)) {
+				break;
+			}
+		}
+		if (j < nsuites) {
+			goto suite_found;
+		}
+		kssl_uncache_sid(&ssl->sid, ssl->kssl_entry);
+		ssl->sid.cached = B_FALSE;
+	}
+
+	/* Check if this server is capable of the cipher suite */
+	for (i = 0; i < ssl->kssl_entry->kssl_cipherSuites_nentries; i++) {
+		suite = ssl->kssl_entry->kssl_cipherSuites[i];
+		for (j = 0; j < nsuites; j += 2) {
+			if (suitesp[j] == ((suite >> 8) & 0xff) &&
+			    suitesp[j + 1] == (suite & 0xff)) {
+				break;
+			}
+		}
+		if (j < nsuites) {
+			break;
+		}
+	}
+	if (i == ssl->kssl_entry->kssl_cipherSuites_nentries) {
+		if (ssl->sslcnt == 1) {
+			KSSL_COUNTER(no_suite_found, 1);
+			return (SSL_MISS);
+		}
+		desc = handshake_failure;
+		KSSL_DEBUG1_IF(kssl_debug,
+			"kssl_handle_client_hello: no cipher suites found");
+		goto falert;
+	}
+
+suite_found:
+
+	mp->b_rptr += nsuites;
+	if (*mp->b_rptr++ != 1 || *mp->b_rptr++ != 0) {
+		desc = handshake_failure;
+		KSSL_DEBUG1_IF(kssl_debug,
+			"kssl_handle_client_hello: handshake failure");
+		goto falert;
+	}
+
+	mp->b_rptr = msgend;
+
+	for (i = 0; i < cipher_suite_defs_nentries; i++) {
+		if (suite == cipher_suite_defs[i].suite) {
+			break;
+		}
+	}
+
+	ASSERT(i < cipher_suite_defs_nentries);
+
+	ssl->pending_cipher_suite = suite;
+	ssl->pending_malg = cipher_suite_defs[i].malg;
+	ssl->pending_calg = cipher_suite_defs[i].calg;
+	ssl->pending_keyblksz = cipher_suite_defs[i].keyblksz;
+
+	if (ssl->sid.cached == B_TRUE) {
+		err = kssl_send_server_hello(ssl);
+		if (err != 0) {
+			return (err);
+		}
+		if (IS_TLS(ssl))
+			err = kssl_generate_tls_keyblock(ssl);
+		else
+			kssl_generate_keyblock(ssl);
+
+		err = kssl_send_change_cipher_specs(ssl);
+		if (err != 0) {
+			return (err);
+		}
+
+		err = kssl_send_finished(ssl, 1);
+		if (err != 0)
+			return (err);
+
+		err = kssl_compute_handshake_hashes(ssl, &ssl->hs_hashes,
+			sender_client);
+		if (err != 0)
+			return (err);
+
+		ssl->hs_waitstate = wait_change_cipher;
+		ssl->resumed = B_TRUE;
+		ssl->activeinput = B_FALSE;
+		KSSL_COUNTER(resumed_sessions, 1);
+		return (0);
+	}
+
+	(void) random_get_pseudo_bytes(ssl->sid.session_id,
+	    SSL3_SESSIONID_BYTES);
+	ssl->sid.client_addr = ssl->faddr;
+	ssl->sid.cipher_suite = suite;
+
+	err = kssl_send_server_hello(ssl);
+	if (err != 0) {
+		return (err);
+	}
+	err = kssl_send_certificate_and_server_hello_done(ssl);
+	if (err != 0) {
+		return (err);
+	}
+	KSSL_COUNTER(full_handshakes, 1);
+	ssl->hs_waitstate = wait_client_key;
+	ssl->activeinput = B_FALSE;
+	return (0);
+
+falert:
+	kssl_send_alert(ssl, alert_fatal, desc);
+	return (EBADMSG);
+}
+
+static void
+kssl_cache_sid(sslSessionID *sid, kssl_entry_t *kssl_entry)
+{
+	uint_t index;
+	uchar_t *s = sid->session_id;
+	int l = SSL3_SESSIONID_BYTES - 1;
+	kmutex_t *lock;
+
+	ASSERT(sid->cached == B_TRUE);
+
+	index = (int)sid->client_addr ^ (((int)s[0] << 24) | ((int)s[1] << 16) |
+	    ((int)s[2] << 8) | (int)s[l]);
+
+	index %= kssl_entry->sid_cache_nentries;
+
+	sid->time = lbolt;
+
+	lock = &(kssl_entry->sid_cache[index].se_lock);
+	mutex_enter(lock);
+	kssl_entry->sid_cache[index].se_used++;
+	bcopy(sid, &(kssl_entry->sid_cache[index].se_sid), sizeof (*sid));
+	mutex_exit(lock);
+}
+
+static void
+kssl_lookup_sid(sslSessionID *sid, uchar_t *s, ipaddr_t faddr,
+    kssl_entry_t *kssl_entry)
+{
+	uint_t index;
+	int l = SSL3_SESSIONID_BYTES - 1;
+	kmutex_t *lock;
+	sslSessionID *csid;
+
+	ASSERT(sid->cached == B_FALSE);
+
+	KSSL_COUNTER(sid_cache_lookups, 1);
+
+	index = (int)faddr ^ (((int)s[0] << 24) | ((int)s[1] << 16) |
+	    ((int)s[2] << 8) | (int)s[l]);
+
+	index %= kssl_entry->sid_cache_nentries;
+
+	lock = &(kssl_entry->sid_cache[index].se_lock);
+	mutex_enter(lock);
+	csid = &(kssl_entry->sid_cache[index].se_sid);
+	if (csid->cached == B_FALSE || csid->client_addr != faddr ||
+	    bcmp(csid->session_id, s, SSL3_SESSIONID_BYTES)) {
+		mutex_exit(lock);
+		return;
+	}
+
+	if (TICK_TO_SEC(lbolt - csid->time) > kssl_entry->sid_cache_timeout) {
+		csid->cached = B_FALSE;
+		mutex_exit(lock);
+		return;
+	}
+
+	bcopy(csid, sid, sizeof (*sid));
+	mutex_exit(lock);
+	ASSERT(sid->cached == B_TRUE);
+
+	KSSL_COUNTER(sid_cache_hits, 1);
+}
+
+static uchar_t *
+kssl_rsa_unwrap(uchar_t *buf, size_t *lenp)
+{
+	size_t len = *lenp;
+	int i = 2;
+
+	if (buf[0] != 0 || buf[1] != 2) {
+		return (NULL);
+	}
+
+	while (i < len) {
+		if (buf[i++] == 0) {
+			*lenp = len - i;
+			break;
+		}
+	}
+
+	if (i == len) {
+		return (NULL);
+	}
+
+	return (buf + i);
+}
+
+void
+kssl_uncache_sid(sslSessionID *sid, kssl_entry_t *kssl_entry)
+{
+	uint_t index;
+	uchar_t *s = sid->session_id;
+	int l = SSL3_SESSIONID_BYTES - 1;
+	sslSessionID *csid;
+	kmutex_t *lock;
+
+	ASSERT(sid->cached == B_TRUE);
+
+	KSSL_COUNTER(sid_uncached, 1);
+
+	index = (int)sid->client_addr ^ (((int)s[0] << 24) | ((int)s[1] << 16) |
+	    ((int)s[2] << 8) | (int)s[l]);
+
+	index %= kssl_entry->sid_cache_nentries;
+
+	lock = &(kssl_entry->sid_cache[index].se_lock);
+	mutex_enter(lock);
+	csid = &(kssl_entry->sid_cache[index].se_sid);
+	if (csid->client_addr != sid->client_addr ||
+	    bcmp(csid->session_id, s, SSL3_SESSIONID_BYTES)) {
+		mutex_exit(lock);
+		return;
+	}
+	csid->cached = B_FALSE;
+	mutex_exit(lock);
+}
+
+
+#define	KSSL_SSL3_SH_RECLEN	(74)
+#define	KSSL_SSL3_FIN_MSGLEN	(36)
+
+#define	KSSL_SSL3_MAX_CCP_FIN_MSGLEN	(128)	/* comfortable upper bound */
+
+static int
+kssl_send_server_hello(ssl_t *ssl)
+{
+	mblk_t *mp;
+	uchar_t *buf;
+	uchar_t *msgstart;
+
+	mp = allocb(ssl->tcp_mss, BPRI_HI);
+	if (mp == NULL) {
+		KSSL_COUNTER(alloc_fails, 1);
+		return (ENOMEM);
+	}
+	ssl->handshake_sendbuf = mp;
+	buf = mp->b_wptr;
+
+	/* 5 byte record header */
+	buf[0] = content_handshake;
+	buf[1] = ssl->major_version;
+	buf[2] = ssl->minor_version;
+	buf[3] = KSSL_SSL3_SH_RECLEN >> 8;
+	buf[4] = KSSL_SSL3_SH_RECLEN & 0xff;
+	buf += SSL3_HDR_LEN;
+
+	msgstart = buf;
+
+	/* 6 byte message header */
+	buf[0] = (uchar_t)server_hello;			/* message type */
+	buf[1] = 0;					/* message len byte 0 */
+	buf[2] = ((KSSL_SSL3_SH_RECLEN - 4) >> 8) &
+	    0xff;					/* message len byte 1 */
+	buf[3] = (KSSL_SSL3_SH_RECLEN - 4) & 0xff;	/* message len byte 2 */
+
+	buf[4] = ssl->major_version;	/* version byte 0 */
+	buf[5] = ssl->minor_version;	/* version byte 1 */
+
+	buf += 6;
+
+	kssl_get_hello_random(ssl->server_random);
+	bcopy(ssl->server_random, buf, SSL3_RANDOM_LENGTH);
+	buf += SSL3_RANDOM_LENGTH;
+
+	buf[0] = SSL3_SESSIONID_BYTES;
+	bcopy(ssl->sid.session_id, buf + 1, SSL3_SESSIONID_BYTES);
+	buf += SSL3_SESSIONID_BYTES + 1;
+
+	buf[0] = (ssl->pending_cipher_suite >> 8) & 0xff;
+	buf[1] = ssl->pending_cipher_suite & 0xff;
+
+	buf[2] = 0;	/* No compression */
+
+	mp->b_wptr = buf + 3;
+	ASSERT(mp->b_wptr < mp->b_datap->db_lim);
+
+	kssl_update_handshake_hashes(ssl, msgstart, KSSL_SSL3_SH_RECLEN);
+	return (0);
+}
+
+static void
+kssl_get_hello_random(uchar_t *buf)
+{
+	timestruc_t ts;
+	time_t sec;
+
+	gethrestime(&ts);
+	sec = ts.tv_sec;
+
+	buf[0] = (sec >> 24) & 0xff;
+	buf[1] = (sec >> 16) & 0xff;
+	buf[2] = (sec >> 8) & 0xff;
+	buf[3] = (sec) & 0xff;
+
+	(void) random_get_pseudo_bytes(&buf[4], SSL3_RANDOM_LENGTH - 4);
+
+	/* Should this be caching? */
+}
+
+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)
+{
+	int rv = 0;
+	uchar_t A1[MAX_HASH_LEN], result[MAX_HASH_LEN];
+	int bytes_left = datalen;
+	crypto_data_t dd, mac;
+	crypto_context_t ctx;
+
+	dd.cd_format = CRYPTO_DATA_RAW;
+	dd.cd_offset = 0;
+	mac.cd_format = CRYPTO_DATA_RAW;
+	mac.cd_offset = 0;
+
+	/*
+	 * A(i) = HMAC_hash(secred, seed + A(i-1));
+	 * A(0) = seed;
+	 *
+	 * Compute A(1):
+	 * A(1) = HMAC_hash(secret, label + seed)
+	 *
+	 */
+	HMAC_INIT(mech, key, &ctx);
+	HMAC_UPDATE(ctx, label, label_len);
+	HMAC_UPDATE(ctx, seed, seedlen);
+	HMAC_FINAL(ctx, A1, hashlen);
+
+	/* Compute A(2) ... A(n) */
+	while (bytes_left > 0) {
+		HMAC_INIT(mech, key, &ctx);
+		HMAC_UPDATE(ctx, A1, hashlen);
+		HMAC_UPDATE(ctx, label, label_len);
+		HMAC_UPDATE(ctx, seed, seedlen);
+		HMAC_FINAL(ctx, result, hashlen);
+
+		/*
+		 * The A(i) value is stored in "result".
+		 * Save the results of the MAC so it can be input to next
+		 * iteration.
+		 */
+		if (bytes_left > hashlen) {
+			/* Store the chunk result */
+			bcopy(result, data, hashlen);
+			data += hashlen;
+
+			bytes_left -= hashlen;
+
+			/* Update A1 for next iteration */
+			HMAC_INIT(mech, key, &ctx);
+			HMAC_UPDATE(ctx, A1, hashlen);
+			HMAC_FINAL(ctx, A1, hashlen);
+
+		} else {
+			bcopy(result, data, bytes_left);
+			data += bytes_left;
+			bytes_left = 0;
+		}
+	}
+end:
+	if (CRYPTO_ERR(rv)) {
+#ifdef	DEBUG
+		cmn_err(CE_WARN, "kssl_P_hash: crypto_mac error 0x%02X", rv);
+#endif	/* DEBUG */
+		KSSL_COUNTER(compute_mac_failure, 1);
+	}
+	return (rv);
+}
+
+/* ARGSUSED */
+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)
+{
+	/*
+	 * RFC 2246:
+	 *  PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
+	 *				P_SHA1(S2, label + seed);
+	 * S1 = 1st half of secret.
+	 * S1 = 2nd half of secret.
+	 *
+	 */
+
+	int rv = 0, i;
+	uchar_t psha1[MAX_TLS_KEYBLOCK_SIZE];
+	crypto_key_t S1, S2;
+
+	/* length of secret keys is ceil(length/2) */
+	size_t slen = roundup(secret_len, 2) / 2;
+
+	if (prfresult_len > MAX_TLS_KEYBLOCK_SIZE) {
+		KSSL_DEBUG2_IF(kssl_debug, "kssl_tls_PRF: unexpected keyblock "
+			"size (%lu)", prfresult_len);
+		return (CRYPTO_ARGUMENTS_BAD);
+	}
+
+	ASSERT(prfresult != NULL);
+	ASSERT(label != NULL);
+	ASSERT(seed != NULL);
+
+	S1.ck_data   = secret;
+	S1.ck_length = slen * 8; /* bits */
+	S1.ck_format = CRYPTO_KEY_RAW;
+
+	S2.ck_data   = secret + slen;
+	S2.ck_length = slen * 8; /* bits */
+	S2.ck_format = CRYPTO_KEY_RAW;
+
+	rv = kssl_tls_P_hash(&hmac_md5_mech, &S1, MD5_HASH_LEN,
+			label, label_len,
+			seed, seed_len,
+			prfresult, prfresult_len);
+	if (CRYPTO_ERR(rv))
+		goto end;
+
+	rv = kssl_tls_P_hash(&hmac_sha1_mech, &S2, SHA1_HASH_LEN,
+			label, label_len,
+			seed, seed_len,
+			psha1, prfresult_len);
+	if (CRYPTO_ERR(rv))
+		goto end;
+
+	for (i = 0; i < prfresult_len; i++)
+		prfresult[i] ^= psha1[i];
+
+end:
+	if (CRYPTO_ERR(rv))
+		bzero(prfresult, prfresult_len);
+
+	return (rv);
+}
+
+static int
+kssl_generate_tls_ms(ssl_t *ssl, uchar_t *pms, size_t pmslen)
+{
+	uchar_t seed[SSL3_RANDOM_LENGTH * 2];
+
+	/*
+	 * Computing the master secret:
+	 * ----------------------------
+	 * master_secret = PRF (pms, "master secret",
+	 *		ClientHello.random + ServerHello.random);
+	 */
+	bcopy(ssl->client_random, seed, SSL3_RANDOM_LENGTH);
+	bcopy(ssl->server_random, seed + SSL3_RANDOM_LENGTH,
+		SSL3_RANDOM_LENGTH);
+
+	return (kssl_tls_PRF(ssl,
+		pms, pmslen,
+		(uchar_t *)TLS_MASTER_SECRET_LABEL,
+		(size_t)strlen(TLS_MASTER_SECRET_LABEL),
+		seed, sizeof (seed),
+		ssl->sid.master_secret,
+		(size_t)sizeof (ssl->sid.master_secret)));
+}
+
+static void
+kssl_generate_ssl_ms(ssl_t *ssl, uchar_t *pms, size_t pmslen)
+{
+	uchar_t buf[SSL3_PRE_MASTER_SECRET_LEN];
+	uchar_t *ms;
+	int hlen = MD5_HASH_LEN;
+
+	ms = ssl->sid.master_secret;
+
+	/* if pms is bad fake it to thwart Bleichenbacher attack */
+	if (pms == NULL || pmslen != SSL3_PRE_MASTER_SECRET_LEN ||
+	    pms[0] != ssl->major_version || pms[1] != ssl->minor_version) {
+#ifdef	DEBUG
+		cmn_err(CE_WARN, "Under Bleichenbacher attack");
+#endif	/* DEBUG */
+		KSSL_COUNTER(bad_pre_master_secret, 1);
+		pms = buf;
+		pmslen = SSL3_PRE_MASTER_SECRET_LEN;
+		pms[0] = ssl->major_version;
+		pms[1] = ssl->minor_version;
+		(void) random_get_pseudo_bytes(&buf[2], pmslen - 2);
+	}
+	kssl_ssl3_key_material_derive_step(ssl, pms, pmslen, 1, ms, 0);
+	kssl_ssl3_key_material_derive_step(ssl, pms, pmslen, 2, ms + hlen, 0);
+	kssl_ssl3_key_material_derive_step(ssl, pms, pmslen, 3, ms + 2 * hlen,
+	    0);
+}
+
+static int
+kssl_generate_tls_keyblock(ssl_t *ssl)
+{
+	uchar_t seed[2 * SSL3_RANDOM_LENGTH];
+
+	bcopy(ssl->server_random, seed, SSL3_RANDOM_LENGTH);
+	bcopy(ssl->client_random, seed + SSL3_RANDOM_LENGTH,
+		SSL3_RANDOM_LENGTH);
+
+	return (kssl_tls_PRF(ssl, ssl->sid.master_secret,
+		(size_t)SSL3_MASTER_SECRET_LEN,
+		(uchar_t *)TLS_KEY_EXPANSION_LABEL,
+		(size_t)strlen(TLS_KEY_EXPANSION_LABEL),
+		seed, (size_t)sizeof (seed),
+		ssl->pending_keyblock,
+		(size_t)ssl->pending_keyblksz));
+
+}
+
+static void
+kssl_generate_keyblock(ssl_t *ssl)
+{
+	uchar_t *ms;
+	size_t mslen = SSL3_MASTER_SECRET_LEN;
+	int hlen = MD5_HASH_LEN;
+	uchar_t *keys = ssl->pending_keyblock;
+	int steps = howmany(ssl->pending_keyblksz, hlen);
+	int i;
+
+	ms = ssl->sid.master_secret;
+
+	ASSERT(hlen * steps <= MAX_KEYBLOCK_LENGTH);
+
+	for (i = 1; i <= steps; i++) {
+		kssl_ssl3_key_material_derive_step(ssl, ms, mslen, i, keys, 1);
+		keys += hlen;
+	}
+}
+
+static char *ssl3_key_derive_seeds[8] = {"A", "BB", "CCC", "DDDD", "EEEEE",
+					    "FFFFFF", "GGGGGGG", "HHHHHHHH"};
+
+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)
+{
+	SHA1_CTX sha1, *sha1ctx;
+	MD5_CTX md5, *md5ctx;
+	uchar_t sha1_hash[SHA1_HASH_LEN];
+
+	sha1ctx = &sha1;
+	md5ctx = &md5;
+
+	ASSERT(step <=
+	    sizeof (ssl3_key_derive_seeds) /
+	    sizeof (ssl3_key_derive_seeds[0]));
+	step--;
+
+	SHA1Init(sha1ctx);
+	SHA1Update(sha1ctx, (uchar_t *)ssl3_key_derive_seeds[step],
+	    step + 1);
+	SHA1Update(sha1ctx, secret, secretlen);
+	if (sr_first) {
+		SHA1Update(sha1ctx, ssl->server_random, SSL3_RANDOM_LENGTH);
+		SHA1Update(sha1ctx, ssl->client_random, SSL3_RANDOM_LENGTH);
+	} else {
+		SHA1Update(sha1ctx, ssl->client_random, SSL3_RANDOM_LENGTH);
+		SHA1Update(sha1ctx, ssl->server_random, SSL3_RANDOM_LENGTH);
+	}
+	SHA1Final(sha1_hash, sha1ctx);
+
+	MD5Init(md5ctx);
+	MD5Update(md5ctx, secret, secretlen);
+	MD5Update(md5ctx, sha1_hash, SHA1_HASH_LEN);
+	MD5Final(dst, md5ctx);
+}
+
+static int
+kssl_send_certificate_and_server_hello_done(ssl_t *ssl)
+{
+	int cur_reclen;
+	int mss;
+	int len, copylen;
+	mblk_t *mp;
+	uchar_t *cert_buf;
+	int cert_len;
+	uchar_t *msgbuf;
+	Certificate_t *cert;
+
+	cert = ssl->kssl_entry->ke_server_certificate;
+	if (cert == NULL) {
+	    return (ENOENT);
+	}
+	cert_buf = cert->msg;
+	cert_len = cert->len;
+
+	mp = ssl->handshake_sendbuf;
+	mss = ssl->tcp_mss;
+	ASSERT(mp != NULL);
+	cur_reclen = mp->b_wptr - mp->b_rptr - SSL3_HDR_LEN;
+	ASSERT(cur_reclen == KSSL_SSL3_SH_RECLEN);
+	/* Assume MSS is at least 80 bytes */
+	ASSERT(mss > cur_reclen + SSL3_HDR_LEN);
+	ASSERT(cur_reclen < SSL3_MAX_RECORD_LENGTH); /* XXX */
+
+	copylen = mss - (cur_reclen + SSL3_HDR_LEN);
+	len = cert_len;
+	copylen = MIN(copylen, len);
+	copylen = MIN(copylen, SSL3_MAX_RECORD_LENGTH - cur_reclen);
+
+	/* new record always starts in a new mblk for simplicity */
+	msgbuf = cert_buf;
+	for (;;) {
+		ASSERT(mp->b_wptr + copylen <= mp->b_datap->db_lim);
+		bcopy(msgbuf, mp->b_wptr, copylen);
+		msgbuf += copylen;
+		mp->b_wptr += copylen;
+		cur_reclen += copylen;
+		len -= copylen;
+		if (len == 0) {
+			break;
+		}
+		if (cur_reclen == SSL3_MAX_RECORD_LENGTH) {
+			cur_reclen = 0;
+		}
+		copylen = MIN(len, mss);
+		copylen = MIN(copylen, SSL3_MAX_RECORD_LENGTH - cur_reclen);
+		mp->b_cont = allocb(copylen, BPRI_HI);
+		if (mp->b_cont == NULL) {
+			KSSL_COUNTER(alloc_fails, 1);
+			freemsg(ssl->handshake_sendbuf);
+			ssl->handshake_sendbuf = NULL;
+			return (ENOMEM);
+		}
+		mp = mp->b_cont;
+		if (cur_reclen == 0) {
+			mp->b_wptr[0] = content_handshake;
+			mp->b_wptr[1] = ssl->major_version;
+			mp->b_wptr[2] = ssl->minor_version;
+			cur_reclen = MIN(len, SSL3_MAX_RECORD_LENGTH);
+			mp->b_wptr[3] = (cur_reclen >> 8) & 0xff;
+			mp->b_wptr[4] = (cur_reclen) & 0xff;
+			mp->b_wptr += SSL3_HDR_LEN;
+			cur_reclen = 0;
+			copylen = MIN(copylen, mss - SSL3_HDR_LEN);
+		}
+	}
+
+	/* adjust the record length field for the first record */
+	mp = ssl->handshake_sendbuf;
+	cur_reclen = MIN(KSSL_SSL3_SH_RECLEN + cert_len,
+	    SSL3_MAX_RECORD_LENGTH);
+	mp->b_rptr[3] = (cur_reclen >> 8) & 0xff;
+	mp->b_rptr[4] = (cur_reclen) & 0xff;
+
+	kssl_update_handshake_hashes(ssl, cert_buf, cert_len);
+
+	return (0);
+}
+
+static int
+kssl_send_change_cipher_specs(ssl_t *ssl)
+{
+	mblk_t *mp, *newmp;
+	uchar_t *buf;
+
+	mp = ssl->handshake_sendbuf;
+
+	/* We're most likely to hit the fast path for resumed sessions */
+	if ((mp != NULL) &&
+	    (mp->b_datap->db_lim - mp->b_wptr > KSSL_SSL3_MAX_CCP_FIN_MSGLEN)) {
+		buf = mp->b_wptr;
+	} else {
+		newmp = allocb(KSSL_SSL3_MAX_CCP_FIN_MSGLEN, BPRI_HI);
+
+		if (newmp == NULL)
+			return (ENOMEM);	/* need to do better job! */
+
+		if (mp == NULL) {
+			ssl->handshake_sendbuf = newmp;
+		} else {
+			linkb(ssl->handshake_sendbuf, newmp);
+		}
+		mp = newmp;
+		buf = mp->b_rptr;
+	}
+
+	/* 5 byte record header */
+	buf[0] = content_change_cipher_spec;
+	buf[1] = ssl->major_version;
+	buf[2] = ssl->minor_version;
+	buf[3] = 0;
+	buf[4] = 1;
+	buf += SSL3_HDR_LEN;
+
+	buf[0] = 1;
+
+	mp->b_wptr = buf + 1;
+	ASSERT(mp->b_wptr < mp->b_datap->db_lim);
+
+	ssl->seq_num[KSSL_WRITE] = 0;
+	return (kssl_spec_init(ssl, KSSL_WRITE));
+}
+
+int
+kssl_spec_init(ssl_t *ssl, int dir)
+{
+	KSSL_HASHCTX *ctx;
+	KSSLCipherSpec *spec = &ssl->spec[dir];
+	int ret = 0;
+
+	spec->mac_hashsz = mac_defs[ssl->pending_malg].hashsz;
+	spec->mac_padsz = mac_defs[ssl->pending_malg].padsz;
+
+	spec->MAC_HashInit = mac_defs[ssl->pending_malg].HashInit;
+	spec->MAC_HashUpdate = mac_defs[ssl->pending_malg].HashUpdate;
+	spec->MAC_HashFinal = mac_defs[ssl->pending_malg].HashFinal;
+
+	if (dir == KSSL_READ) {
+		bcopy(ssl->pending_keyblock, ssl->mac_secret[dir],
+		    spec->mac_hashsz);
+	} else {
+		bcopy(&(ssl->pending_keyblock[spec->mac_hashsz]),
+		    ssl->mac_secret[dir], spec->mac_hashsz);
+	}
+
+	/* Pre-compute these here. will save cycles on each record later */
+	if (!IS_TLS(ssl)) {
+		ctx = &ssl->mac_ctx[dir][0];
+		spec->MAC_HashInit((void *)ctx);
+		spec->MAC_HashUpdate((void *)ctx, ssl->mac_secret[dir],
+		    spec->mac_hashsz);
+		spec->MAC_HashUpdate((void *)ctx, kssl_pad_1,
+			spec->mac_padsz);
+
+		ctx = &ssl->mac_ctx[dir][1];
+		spec->MAC_HashInit((void *)ctx);
+		spec->MAC_HashUpdate((void *)ctx, ssl->mac_secret[dir],
+		    spec->mac_hashsz);
+		spec->MAC_HashUpdate((void *)ctx, kssl_pad_2,
+			spec->mac_padsz);
+	}
+
+	spec->cipher_type = cipher_defs[ssl->pending_calg].type;
+	spec->cipher_mech.cm_type = cipher_defs[ssl->pending_calg].mech_type;
+	spec->cipher_bsize = cipher_defs[ssl->pending_calg].bsize;
+	spec->cipher_keysz = cipher_defs[ssl->pending_calg].keysz;
+
+	if (spec->cipher_ctx != NULL) {
+		crypto_cancel_ctx(spec->cipher_ctx);
+		spec->cipher_ctx = 0;
+	}
+
+	/*
+	 * Initialize HMAC keys for TLS.
+	 */
+	if (IS_TLS(ssl)) {
+		if (ssl->pending_malg == mac_md5) {
+			spec->hmac_mech = hmac_md5_mech;
+		} else if (ssl->pending_malg == mac_sha) {
+			spec->hmac_mech = hmac_sha1_mech;
+		}
+
+		spec->hmac_key.ck_format = CRYPTO_KEY_RAW;
+		spec->hmac_key.ck_data = ssl->mac_secret[dir];
+		spec->hmac_key.ck_length = spec->mac_hashsz * 8;
+	}
+
+	/* We're done if this is the nil cipher */
+	if (spec->cipher_keysz == 0) {
+		return (0);
+	}
+
+	/* Initialize the key and the active context */
+	spec->cipher_key.ck_format = CRYPTO_KEY_RAW;
+	spec->cipher_key.ck_length = 8 * spec->cipher_keysz; /* in bits */
+
+	if (cipher_defs[ssl->pending_calg].bsize > 0) {
+		/* client_write_IV */
+		spec->cipher_mech.cm_param =
+		    (caddr_t)&(ssl->pending_keyblock[2 * spec->mac_hashsz +
+		    2 * spec->cipher_keysz]);
+		spec->cipher_mech.cm_param_len = spec->cipher_bsize;
+	}
+	spec->cipher_data.cd_format = CRYPTO_DATA_RAW;
+	if (dir == KSSL_READ) {
+		spec->cipher_mech.cm_param_len =
+		    cipher_defs[ssl->pending_calg].bsize;
+
+		/* cilent_write_key */
+		spec->cipher_key.ck_data =
+		    &(ssl->pending_keyblock[2 * spec->mac_hashsz]);
+
+		ret = crypto_decrypt_init(&(spec->cipher_mech),
+			&(spec->cipher_key), NULL, &spec->cipher_ctx, NULL);
+#ifdef	DEBUG
+		if (CRYPTO_ERR(ret)) {
+			cmn_err(CE_WARN, "kssl_spec_init: "
+				"crypto_decrypt_init error 0x%02X", ret);
+		}
+#endif	/* DEBUG */
+	} else {
+		if (cipher_defs[ssl->pending_calg].bsize > 0) {
+			spec->cipher_mech.cm_param += spec->cipher_bsize;
+		}
+		/* server_write_key */
+		spec->cipher_key.ck_data =
+		    &(ssl->pending_keyblock[2 * spec->mac_hashsz +
+		    spec->cipher_keysz]);
+
+		ret = crypto_encrypt_init(&(spec->cipher_mech),
+			&(spec->cipher_key), NULL, &spec->cipher_ctx, NULL);
+#ifdef	DEBUG
+		if (CRYPTO_ERR(ret))
+			cmn_err(CE_WARN, "kssl_spec_init: "
+				"crypto_encrypt_init error 0x%02X", ret);
+#endif	/* DEBUG */
+	}
+	return (ret);
+}
+
+static int
+kssl_send_finished(ssl_t *ssl, int update_hsh)
+{
+	mblk_t *mp;
+	uchar_t *buf;
+	uchar_t *rstart;
+	uchar_t *versionp;
+	SSL3Hashes ssl3hashes;
+	size_t finish_len;
+	int ret = 0;
+
+	mp = ssl->handshake_sendbuf;
+	ASSERT(mp != NULL);
+	buf = mp->b_wptr;
+	ASSERT(buf - mp->b_rptr == SSL3_HDR_LEN + KSSL_SSL3_SH_RECLEN +
+	    SSL3_HDR_LEN + 1 || buf - mp->b_rptr == SSL3_HDR_LEN + 1);
+
+	rstart = buf;
+
+	if (IS_TLS(ssl))
+		finish_len = TLS_FINISHED_SIZE;
+	else
+		finish_len = KSSL_SSL3_FIN_MSGLEN;
+
+	/* 5 byte record header */
+	buf[0] = content_handshake;
+	buf[1] = ssl->major_version;
+	buf[2] = ssl->minor_version;
+	buf[3] = 0;
+	buf[4] = 4 + finish_len;
+
+	versionp = &buf[1];
+
+	buf += SSL3_HDR_LEN;
+
+	/* 4 byte message header */
+	buf[0] = (uchar_t)finished;	/* message type */
+	buf[1] = 0;			/* message len byte 0 */
+	buf[2] = 0;			/* message len byte 1 */
+	buf[3] = finish_len;	/* message len byte 2 */
+	buf += 4;
+
+	if (IS_TLS(ssl)) {
+		bcopy(ssl->hs_hashes.md5, ssl3hashes.md5,
+			sizeof (ssl3hashes.md5));
+		bcopy(ssl->hs_hashes.sha1, ssl3hashes.sha1,
+			sizeof (ssl3hashes.sha1));
+	}
+
+	/* Compute hashes for the SENDER side */
+	ret = kssl_compute_handshake_hashes(ssl, &ssl3hashes, sender_server);
+	if (ret != 0)
+		return (ret);
+
+	if (IS_TLS(ssl)) {
+		bcopy(ssl3hashes.tlshash, buf, sizeof (ssl3hashes.tlshash));
+	} else {
+		bcopy(ssl3hashes.md5, buf, MD5_HASH_LEN);
+		bcopy(ssl3hashes.sha1, buf + MD5_HASH_LEN, SHA1_HASH_LEN);
+	}
+
+	if (update_hsh) {
+		kssl_update_handshake_hashes(ssl, buf - 4, finish_len + 4);
+	}
+
+	mp->b_wptr = buf + finish_len;
+
+	ret = kssl_mac_encrypt_record(ssl, content_handshake, versionp,
+	    rstart, mp);
+	ASSERT(mp->b_wptr <= mp->b_datap->db_lim);
+
+	return (ret);
+}
+
+int
+kssl_mac_encrypt_record(ssl_t *ssl,
+	SSL3ContentType ct,
+	uchar_t *versionp,
+	uchar_t *rstart,
+	mblk_t *mp)
+{
+	KSSLCipherSpec *spec;
+	int mac_sz;
+	int ret = 0;
+	uint16_t rec_sz;
+	int pad_sz;
+	int i;
+
+	ASSERT(ssl != NULL);
+	ASSERT(rstart >= mp->b_rptr);
+	ASSERT(rstart < mp->b_wptr);
+
+	spec = &ssl->spec[KSSL_WRITE];
+	mac_sz = spec->mac_hashsz;
+
+	rec_sz = (mp->b_wptr - rstart) - SSL3_HDR_LEN;
+	ASSERT(rec_sz > 0);
+
+	if (mac_sz != 0) {
+		ASSERT(mp->b_wptr + mac_sz <= mp->b_datap->db_lim);
+		ret = kssl_compute_record_mac(ssl, KSSL_WRITE,
+		    ssl->seq_num[KSSL_WRITE], ct, versionp,
+		    rstart + SSL3_HDR_LEN, rec_sz, mp->b_wptr);
+		if (ret == CRYPTO_SUCCESS) {
+			ssl->seq_num[KSSL_WRITE]++;
+			mp->b_wptr += mac_sz;
+			rec_sz += mac_sz;
+		} else {
+			return (ret);
+		}
+	}
+
+	if (spec->cipher_type == type_block) {
+		pad_sz = spec->cipher_bsize -
+		    (rec_sz & (spec->cipher_bsize - 1));
+		ASSERT(mp->b_wptr + pad_sz <= mp->b_datap->db_lim);
+		for (i = 0; i < pad_sz; i++) {
+			mp->b_wptr[i] = pad_sz - 1;
+		}
+		mp->b_wptr += pad_sz;
+		rec_sz += pad_sz;
+	}
+
+	ASSERT(rec_sz <= SSL3_MAX_RECORD_LENGTH);
+
+	U16_TO_BE16(rec_sz, rstart + 3);
+
+	if (spec->cipher_ctx == 0)
+		return (ret);
+
+	spec->cipher_data.cd_length = rec_sz;
+	spec->cipher_data.cd_raw.iov_base = (char *)(rstart + SSL3_HDR_LEN);
+	spec->cipher_data.cd_raw.iov_len = rec_sz;
+	/* One record at a time. Otherwise, gotta allocate the crypt_data_t */
+	ret = crypto_encrypt_update(spec->cipher_ctx, &spec->cipher_data,
+	    NULL, NULL);
+#ifdef	DEBUG
+	if (CRYPTO_ERR(ret)) {
+		cmn_err(CE_WARN,
+			"kssl_mac_encrypt_record: crypto_encrypt_update "
+			"error 0x%02X", ret);
+	}
+#endif	/* DEBUG */
+	return (ret);
+}
+
+void
+kssl_send_alert(ssl_t *ssl, SSL3AlertLevel level, SSL3AlertDescription desc)
+{
+	mblk_t *mp;
+	uchar_t *buf;
+	KSSLCipherSpec *spec;
+
+	ASSERT(ssl != NULL);
+
+	ssl->sendalert_level = level;
+	ssl->sendalert_desc = desc;
+
+	if (level == alert_fatal) {
+#ifdef	DEBUG
+		cmn_err(CE_WARN, "sending an alert %d %d from %p\n", level,
+		    desc, (void *)caller());
+#endif	/* DEBUG */
+		if (ssl->sid.cached == B_TRUE) {
+			kssl_uncache_sid(&ssl->sid, ssl->kssl_entry);
+			ssl->sid.cached = B_FALSE;
+		}
+		ssl->fatal_alert = B_TRUE;
+		KSSL_COUNTER(fatal_alerts, 1);
+	} else
+		KSSL_COUNTER(warning_alerts, 1);
+
+	spec = &ssl->spec[KSSL_WRITE];
+
+	ASSERT(ssl->alert_sendbuf == NULL);
+	ssl->alert_sendbuf = mp = allocb(7 + spec->mac_hashsz +
+	    spec->cipher_bsize, BPRI_HI);
+	if (mp == NULL) {
+		KSSL_COUNTER(alloc_fails, 1);
+		return;
+	}
+	buf = mp->b_wptr;
+
+	/* 5 byte record header */
+	buf[0] = content_alert;
+	buf[1] = ssl->major_version;
+	buf[2] = ssl->minor_version;
+	buf[3] = 0;
+	buf[4] = 2;
+	buf += SSL3_HDR_LEN;
+
+	/* alert contents */
+	buf[0] = (uchar_t)level;
+	buf[1] = (uchar_t)desc;
+
+	mp->b_wptr = buf + 2;
+}
+
+/* Assumes RSA encryption */
+static int
+kssl_handle_client_key_exchange(ssl_t *ssl, mblk_t *mp, int msglen,
+    kssl_callback_t cbfn, void *arg)
+{
+	char *buf;
+	uchar_t *pms;
+	size_t pmslen;
+	int allocated;
+	int err;
+	crypto_key_t *privkey;
+	crypto_data_t *wrapped_pms_data, *pms_data;
+	crypto_call_req_t creq, *creqp;
+
+	privkey = ssl->kssl_entry->ke_private_key;
+	if (privkey == NULL) {
+	    return (ENOENT);
+	}
+
+	ASSERT(ssl->msg.type == client_key_exchange);
+	ASSERT(ssl->hs_waitstate == wait_client_key);
+
+	/*
+	 * TLS adds an extra 2 byte length field before the data.
+	 */
+	if (IS_TLS(ssl)) {
+		msglen = (mp->b_rptr[0] << 8) | mp->b_rptr[1];
+		mp->b_rptr += 2;
+	}
+
+	/*
+	 * Allocate all we need in one shot. about 300 bytes total, for
+	 * 1024 bit RSA modulus.
+	 * The buffer layout will be: pms_data, wrapped_pms_data, the
+	 * value of the wrapped pms from the client, then room for the
+	 * resulting decrypted premaster secret.
+	 */
+	allocated = 2 * (sizeof (crypto_data_t) + msglen);
+	buf = kmem_alloc(allocated, KM_NOSLEEP);
+	if (buf == NULL) {
+		return (ENOMEM);
+	}
+
+	pms_data = (crypto_data_t *)buf;
+	wrapped_pms_data = &(((crypto_data_t *)buf)[1]);
+
+	wrapped_pms_data->cd_format = pms_data->cd_format = CRYPTO_DATA_RAW;
+	wrapped_pms_data->cd_offset = pms_data->cd_offset = 0;
+	wrapped_pms_data->cd_length = pms_data->cd_length = msglen;
+	wrapped_pms_data->cd_miscdata = pms_data->cd_miscdata = NULL;
+	wrapped_pms_data->cd_raw.iov_len = pms_data->cd_raw.iov_len = msglen;
+	wrapped_pms_data->cd_raw.iov_base = buf + 2 * sizeof (crypto_data_t);
+	pms_data->cd_raw.iov_base = wrapped_pms_data->cd_raw.iov_base + msglen;
+
+	bcopy(mp->b_rptr, wrapped_pms_data->cd_raw.iov_base, msglen);
+	mp->b_rptr += msglen;
+
+	/* Proceed synchronously if out of interrupt and configured to do so */
+	if ((kssl_synchronous) && (!servicing_interrupt())) {
+		creqp = NULL;
+	} else {
+		ssl->cke_callback_func = cbfn;
+		ssl->cke_callback_arg = arg;
+		creq.cr_flag = kssl_call_flag;
+		creq.cr_callback_func = kssl_cke_done;
+		creq.cr_callback_arg = ssl;
+
+		/* The callback routine will release this one */
+		KSSL_SSL_REFHOLD(ssl);
+
+		creqp = &creq;
+	}
+
+	err = crypto_decrypt(&rsa_x509_mech, wrapped_pms_data,
+		privkey, NULL, pms_data, creqp);
+
+	switch (err) {
+	case CRYPTO_SUCCESS:
+		break;
+
+	case CRYPTO_QUEUED:
+		/*
+		 * Finish the master secret then the rest of key material
+		 * derivation later.
+		 */
+		ssl->job.kjob = creq.cr_reqid;
+		ssl->job.buf = buf;
+		ssl->job.buflen = allocated;
+		ssl->hs_waitstate = wait_client_key_done;
+		return (0);
+	default:
+#ifdef	DEBUG
+		cmn_err(CE_WARN, "kssl_handle_client_key_exchange: "
+			"crypto_decrypt error 0x%02X", err);
+#endif	/* DEBUG */
+		kmem_free(buf, allocated);
+		return (ENOMEM);
+	}
+
+	pmslen = pms_data->cd_length;
+	pms = kssl_rsa_unwrap((uchar_t *)pms_data->cd_raw.iov_base, &pmslen);
+
+	/* generate master key and save it in the ssl sid structure */
+	if (IS_TLS(ssl)) {
+		err = kssl_generate_tls_ms(ssl, pms, pmslen);
+		if (!CRYPTO_ERR(err))
+			err = kssl_generate_tls_keyblock(ssl);
+	} else {
+		kssl_generate_ssl_ms(ssl, pms, pmslen);
+		kssl_generate_keyblock(ssl);
+	}
+
+	if (err == CRYPTO_SUCCESS)
+		ssl->hs_waitstate = wait_change_cipher;
+
+	ssl->activeinput = B_FALSE;
+
+	kmem_free(buf, allocated);
+
+	return (0);
+}
+
+static int
+kssl_handle_finished(ssl_t *ssl, mblk_t *mp, int msglen)
+{
+	int err;
+	size_t finish_len;
+	int hashcompare;
+
+	ASSERT(ssl->msg.type == finished);
+	ASSERT(ssl->hs_waitstate == wait_finished);
+
+	if (IS_TLS(ssl))
+		finish_len = TLS_FINISHED_SIZE;
+	else
+		finish_len = KSSL_SSL3_FIN_MSGLEN;
+
+	if (msglen != finish_len) {
+		kssl_send_alert(ssl, alert_fatal, illegal_parameter);
+		return (EBADMSG);
+	}
+
+	if (IS_TLS(ssl)) {
+		hashcompare = bcmp(mp->b_rptr, ssl->hs_hashes.tlshash,
+			finish_len);
+	} else {
+		hashcompare = bcmp(mp->b_rptr, &ssl->hs_hashes, finish_len);
+	}
+
+	/* The handshake hashes should be computed by now */
+	if (hashcompare != 0) {
+		kssl_send_alert(ssl, alert_fatal, handshake_failure);
+		return (EBADMSG);
+	}
+
+	mp->b_rptr += msglen;
+
+	ssl->hs_waitstate = idle_handshake;
+
+	if (ssl->resumed == B_TRUE) {
+		ssl->activeinput = B_FALSE;
+		return (0);
+	}
+
+	err = kssl_send_change_cipher_specs(ssl);
+	if (err != 0) {
+		return (err);
+	}
+	err = kssl_send_finished(ssl, 0);
+	if (err != 0) {
+		return (err);
+	}
+
+	ASSERT(ssl->sid.cached == B_FALSE);
+	ssl->sid.cached = B_TRUE;
+	kssl_cache_sid(&ssl->sid, ssl->kssl_entry);
+	ssl->activeinput = B_FALSE;
+
+	return (0);
+}
+
+#define	KSSL2_CH_MIN_RECSZ	(9)
+
+/*
+ * This method is needed to handle clients which send the
+ * SSLv2/SSLv3 handshake for backwards compat with SSLv2 servers.
+ * We are not really doing SSLv2 here, just handling the header
+ * and then switching to SSLv3.
+ */
+int
+kssl_handle_v2client_hello(ssl_t *ssl, mblk_t *mp, int recsz)
+{
+	uchar_t *recend;
+	int err;
+	SSL3AlertDescription desc = illegal_parameter;
+	uint_t randlen;
+	uint_t sidlen;
+	uint_t nsuites;
+	uchar_t *suitesp;
+	uchar_t *rand;
+	uint_t i, j;
+	uint16_t suite;
+	int ch_recsz = KSSL2_CH_MIN_RECSZ;
+
+	ASSERT(mp->b_wptr >= mp->b_rptr + recsz);
+	ASSERT(ssl->hs_waitstate == wait_client_hello);
+	ASSERT(ssl->resumed == B_FALSE);
+
+	if (recsz < ch_recsz) {
+		goto falert;
+	}
+
+	MD5Init(&ssl->hs_md5);
+	SHA1Init(&ssl->hs_sha1);
+
+	kssl_update_handshake_hashes(ssl, mp->b_rptr, recsz);
+
+	recend = mp->b_rptr + recsz;
+
+	if (*mp->b_rptr != 1) {
+		goto falert;
+	}
+	mp->b_rptr += 3;
+
+	nsuites = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1];
+	sidlen = ((uint_t)mp->b_rptr[2] << 8) + (uint_t)mp->b_rptr[3];
+	randlen = ((uint_t)mp->b_rptr[4] << 8) + (uint_t)mp->b_rptr[5];
+	if (nsuites % 3 != 0) {
+		KSSL_DEBUG2_IF(kssl_debug,
+			"kssl_handle_v2client_hello nsuites = %d, error.",
+			nsuites);
+		goto falert;
+	}
+	if (randlen < SSL_MIN_CHALLENGE_BYTES ||
+	    randlen > SSL_MAX_CHALLENGE_BYTES) {
+		KSSL_DEBUG2_IF(kssl_debug,
+			"kssl_handle_v2client_hello randlen out of range: %d",
+			randlen);
+		goto falert;
+	}
+	mp->b_rptr += 6;
+	ch_recsz += nsuites + sidlen + randlen;
+	if (recsz != ch_recsz) {
+		goto falert;
+	}
+	suitesp = mp->b_rptr;
+	rand = suitesp + nsuites + sidlen;
+	if (randlen < SSL3_RANDOM_LENGTH) {
+		bzero(ssl->client_random, SSL3_RANDOM_LENGTH);
+	}
+	bcopy(rand, &ssl->client_random[SSL3_RANDOM_LENGTH - randlen],
+	    randlen);
+
+	for (i = 0; i < ssl->kssl_entry->kssl_cipherSuites_nentries; i++) {
+		suite = ssl->kssl_entry->kssl_cipherSuites[i];
+		for (j = 0; j < nsuites; j += 3) {
+			if (suitesp[j] != 0) {
+				continue;
+			}
+
+			if (suitesp[j + 1] == ((suite >> 8) & 0xff) &&
+			    suitesp[j + 2] == (suite & 0xff)) {
+				break;
+			}
+		}
+		if (j < nsuites) {
+			break;
+		}
+	}
+	if (i == ssl->kssl_entry->kssl_cipherSuites_nentries) {
+		KSSL_DEBUG1_IF(kssl_debug, "kssl_handle_v2client_hello - "
+			"cannot find SSLv2 cipher suite");
+		ssl->activeinput = B_FALSE;
+		return (SSL_MISS);
+	}
+
+	mp->b_rptr = recend;
+
+	for (i = 0; i < cipher_suite_defs_nentries; i++) {
+		if (suite == cipher_suite_defs[i].suite) {
+			break;
+		}
+	}
+
+	ASSERT(i < cipher_suite_defs_nentries);
+
+	ssl->pending_cipher_suite = suite;
+	ssl->pending_malg = cipher_suite_defs[i].malg;
+	ssl->pending_calg = cipher_suite_defs[i].calg;
+	ssl->pending_keyblksz = cipher_suite_defs[i].keyblksz;
+
+	ASSERT(ssl->sid.cached == B_FALSE);
+
+	(void) random_get_pseudo_bytes(ssl->sid.session_id,
+	    SSL3_SESSIONID_BYTES);
+	ssl->sid.client_addr = ssl->faddr;
+	ssl->sid.cipher_suite = suite;
+
+	err = kssl_send_server_hello(ssl);
+	if (err != 0) {
+		return (err);
+	}
+	err = kssl_send_certificate_and_server_hello_done(ssl);
+	if (err != 0) {
+		return (err);
+	}
+	KSSL_COUNTER(full_handshakes, 1);
+	ssl->hs_waitstate = wait_client_key;
+	ssl->activeinput = B_FALSE;
+	return (0);
+
+falert:
+	kssl_send_alert(ssl, alert_fatal, desc);
+	ssl->activeinput = B_FALSE;
+	return (EBADMSG);
+}
+
+/*
+ * Call back routine for asynchronously submitted RSA decryption jobs.
+ * The routine retreived the pre-master secret, and proceeds to generate
+ * the remaining key materials.
+ */
+static void
+kssl_cke_done(void *arg, int status)
+{
+	int ret = 0;
+	uchar_t *pms;
+	size_t pmslen;
+	crypto_data_t *pms_data;
+	kssl_cmd_t kssl_cmd = KSSL_CMD_NONE;
+	ssl_t *ssl = (ssl_t *)arg;
+	mblk_t *alertmp;
+	kssl_callback_t cbfn;
+	void *cbarg;
+
+	mutex_enter(&ssl->kssl_lock);
+
+	ASSERT(ssl->msg.type == client_key_exchange);
+	ASSERT(ssl->hs_waitstate == wait_client_key_done);
+
+	if (status != CRYPTO_SUCCESS) {
+		kssl_send_alert(ssl, alert_fatal, decrypt_error);
+		kssl_cmd = KSSL_CMD_SEND;
+		goto out;
+	}
+
+	pms_data = (crypto_data_t *)(ssl->job.buf);
+
+	ASSERT(pms_data != NULL);
+
+	pmslen = pms_data->cd_length;
+	pms = kssl_rsa_unwrap((uchar_t *)pms_data->cd_raw.iov_base, &pmslen);
+
+	/* generate master key and save it in the ssl sid structure */
+	if (IS_TLS(ssl)) {
+		ret = kssl_generate_tls_ms(ssl, pms, pmslen);
+		if (!CRYPTO_ERR(ret))
+			ret = kssl_generate_tls_keyblock(ssl);
+	} else {
+		kssl_generate_ssl_ms(ssl, pms, pmslen);
+		kssl_generate_keyblock(ssl);
+	}
+
+	if (ret == CRYPTO_SUCCESS)
+		ssl->hs_waitstate = wait_change_cipher;
+
+out:
+	kmem_free(ssl->job.buf, ssl->job.buflen);
+
+	ssl->job.kjob = 0;
+	ssl->job.buf = NULL;
+	ssl->job.buflen = 0;
+
+	ssl->activeinput = B_FALSE;
+
+	/* If we're the only ones left, then we won't callback */
+	if (ssl->kssl_refcnt == 1) {
+		mutex_exit(&ssl->kssl_lock);
+		KSSL_SSL_REFRELE(ssl);
+		return;
+	}
+
+	cbfn = ssl->cke_callback_func;
+	cbarg = ssl->cke_callback_arg;
+	alertmp = ssl->alert_sendbuf;
+	ssl->alert_sendbuf = NULL;
+
+	mutex_exit(&ssl->kssl_lock);
+
+	KSSL_SSL_REFRELE(ssl);
+
+	/* Now call the callback routine */
+	(*(cbfn))(cbarg, alertmp, kssl_cmd);
+}
+
+/*
+ * Returns the first complete contiguous record out of rec_ass_head
+ * The record is returned in a separate contiguous mblk, rec_ass_head is
+ * left pointing to the next record in the queue.
+ *
+ * The output looks as follows:
+ *
+ * |--------|---------- .... -----|<---------->|<----------->|--- ... ---|
+ * ^        ^                     ^  mac_size     pad_size               ^
+ * |        |___ b_rptr  b_wptr __|                                      |
+ * |                                                                     |
+ * |___ db_base                                                db_lim ___|
+ */
+mblk_t *
+kssl_get_next_record(ssl_t *ssl)
+{
+	mblk_t *mp, *retmp;
+	int rhsz = SSL3_HDR_LEN;
+	uint16_t rec_sz;
+	int mpsz, total_size;
+	SSL3ContentType content_type;
+
+	ASSERT(MUTEX_HELD(&ssl->kssl_lock));
+
+	mp = ssl->rec_ass_head;
+	if (mp == NULL)
+		return (NULL);
+
+	/* Fast path: when mp has at least a complete record */
+	if (MBLKL(mp) < rhsz) {
+		/* Not even a complete header in there yet */
+		if (msgdsize(mp) < rhsz) {
+			return (NULL);
+		}
+
+		if (!pullupmsg(mp, rhsz)) {
+			kssl_send_alert(ssl, alert_fatal, internal_error);
+			freemsg(mp);
+			ssl->rec_ass_head = ssl->rec_ass_tail = NULL;
+			return (NULL);
+		}
+	}
+	content_type = (SSL3ContentType)mp->b_rptr[0];
+	if (content_type == content_handshake_v2) {
+		rec_sz = (uint16_t)mp->b_rptr[1];
+		rhsz = 2;
+	} else {
+		uint8_t *rec_sz_p = (uint8_t *)mp->b_rptr + 3;
+		rec_sz = BE16_TO_U16(rec_sz_p);
+	}
+
+	/*
+	 * same tests as above. Only rare very fragmented cases will
+	 * incur the cost of msgdsize() and msgpullup(). Well formed
+	 * packets will fall in the most frequent fast path.
+	 */
+	total_size = rhsz + rec_sz;
+
+	/*
+	 * Missing: defensive against record fabricated with longer than
+	 * MAX record length.
+	 */
+	if (MBLKL(mp) < total_size) {
+		/* Not a complete record yet. Keep accumulating */
+		if (msgdsize(mp) < total_size) {
+			return (NULL);
+		}
+
+		if (!pullupmsg(mp, total_size)) {
+			kssl_send_alert(ssl, alert_fatal, internal_error);
+			freemsg(mp);
+			ssl->rec_ass_head = ssl->rec_ass_tail = NULL;
+			return (NULL);
+		}
+	}
+	mpsz = MBLKL(mp);	/* could've changed after the pullup */
+
+	if (mpsz > total_size) {
+		/* gotta allocate a new block */
+		if ((retmp = dupb(mp)) == NULL) {
+			kssl_send_alert(ssl, alert_fatal, internal_error);
+			freemsg(mp);
+			ssl->rec_ass_head = ssl->rec_ass_tail = NULL;
+			return (NULL);
+		}
+
+		retmp->b_wptr = retmp->b_rptr + total_size;
+		mp->b_rptr += total_size;
+		ssl->rec_ass_head = mp;
+	} else {
+		ASSERT(mpsz == total_size);
+		ssl->rec_ass_head = mp->b_cont;
+		mp->b_cont = NULL;
+		retmp = mp;
+	}
+	/* Adjust the tail */
+	if ((mp = ssl->rec_ass_tail = ssl->rec_ass_head) != NULL) {
+		for (; mp->b_cont != NULL; mp = mp->b_cont) {
+			ssl->rec_ass_tail = mp->b_cont;
+		}
+	}
+
+	return (retmp);
+}
+
+
+static void
+kssl_mblksfree(ssl_t *ssl)
+{
+
+	ASSERT(ssl != NULL);
+
+	if (ssl->rec_ass_head != NULL) {
+		freemsg(ssl->rec_ass_head);
+	}
+	ssl->rec_ass_head = NULL;
+	ssl->rec_ass_tail = NULL;
+
+	if (ssl->msg.head != NULL) {
+		freemsg(ssl->msg.head);
+	}
+	ssl->msg.head = NULL;
+	ssl->msg.tail = NULL;
+
+	if (ssl->handshake_sendbuf != NULL) {
+		freemsg(ssl->handshake_sendbuf);
+		ssl->handshake_sendbuf = NULL;
+	}
+	if (ssl->alert_sendbuf != NULL) {
+		freemsg(ssl->alert_sendbuf);
+		ssl->alert_sendbuf = NULL;
+	}
+}
+
+static void
+kssl_specsfree(ssl_t *ssl)
+{
+	KSSLCipherSpec *spec = &ssl->spec[KSSL_READ];
+
+	if (spec->cipher_ctx != NULL) {
+		crypto_cancel_ctx(spec->cipher_ctx);
+		spec->cipher_ctx = 0;
+	}
+
+	spec = &ssl->spec[KSSL_WRITE];
+
+	if (spec->cipher_ctx != NULL) {
+		crypto_cancel_ctx(spec->cipher_ctx);
+		spec->cipher_ctx = 0;
+	}
+}
+
+/*
+ * Frees the ssl structure (aka the context of an SSL session).
+ * Any pending crypto jobs are cancelled.
+ * Any initiated crypto contexts are freed as well.
+ */
+void
+kssl_free_context(ssl_t *ssl)
+{
+	ASSERT(ssl != NULL);
+	if (!(MUTEX_HELD(&ssl->kssl_lock))) {
+		/* we're coming from an external API entry point */
+		mutex_enter(&ssl->kssl_lock);
+	}
+
+	if (ssl->job.kjob != NULL) {
+		crypto_cancel_req(ssl->job.kjob);
+		kmem_free(ssl->job.buf, ssl->job.buflen);
+
+		ssl->job.kjob = 0;
+		ssl->job.buf = NULL;
+		ssl->job.buflen = 0;
+	}
+
+	kssl_mblksfree(ssl);
+	kssl_specsfree(ssl);
+
+	KSSL_ENTRY_REFRELE(ssl->kssl_entry);
+	ssl->kssl_entry = NULL;
+
+	mutex_exit(&ssl->kssl_lock);
+
+	kmem_cache_free(kssl_cache, ssl);
+	kssl_cache_count--;
+}
--- a/usr/src/uts/common/inet/tcp.h	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/inet/tcp.h	Sat Nov 12 18:58:05 2005 -0800
@@ -40,6 +40,7 @@
 #include <inet/tcp_sack.h>
 #include <sys/socket.h>
 #include <sys/multidata.h>
+#include <inet/kssl/ksslapi.h>
 
 /*
  * Private (and possibly temporary) ioctl used by configuration code
@@ -543,6 +544,13 @@
 	boolean_t	tcp_issocket;	/* this is a socket tcp */
 
 	uint32_t	tcp_squeue_bytes;
+	/*
+	 * Kernel SSL session information
+	 */
+	boolean_t		tcp_kssl_pending; /* waiting for 1st SSL rec. */
+	boolean_t		tcp_kssl_inhandshake; /* during SSL handshake */
+	kssl_ent_t		tcp_kssl_ent;	/* SSL table entry */
+	kssl_ctx_t		tcp_kssl_ctx;	/* SSL session */
 } tcp_t;
 
 extern void 	tcp_free(tcp_t *tcp);
--- a/usr/src/uts/common/inet/tcp/tcp.c	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/inet/tcp/tcp.c	Sat Nov 12 18:58:05 2005 -0800
@@ -94,6 +94,7 @@
 #include <inet/ip_if.h>
 #include <inet/ipp_common.h>
 #include <sys/squeue.h>
+#include <inet/kssl/ksslapi.h>
 
 /*
  * TCP Notes: aka FireEngine Phase I (PSARC 2002/433)
@@ -759,7 +760,7 @@
 void 		tcp_input(void *arg, mblk_t *mp, void *arg2);
 void		tcp_rput_data(void *arg, mblk_t *mp, void *arg2);
 static void	tcp_close_output(void *arg, mblk_t *mp, void *arg2);
-static void	tcp_output(void *arg, mblk_t *mp, void *arg2);
+void		tcp_output(void *arg, mblk_t *mp, void *arg2);
 static void	tcp_rsrv_input(void *arg, mblk_t *mp, void *arg2);
 static void	tcp_timer_handler(void *arg, mblk_t *mp, void *arg2);
 
@@ -980,6 +981,8 @@
 static mblk_t	*tcp_zcopy_backoff(tcp_t *, mblk_t *, int);
 static void	tcp_ire_ill_check(tcp_t *, ire_t *, ill_t *, boolean_t);
 
+extern void	tcp_kssl_input(tcp_t *, mblk_t *);
+
 /*
  * Routines related to the TCP_IOC_ABORT_CONN ioctl command.
  *
@@ -1111,7 +1114,7 @@
 
 
 /* TCP bind hash list - all tcp_t with state >= BOUND. */
-static tf_t	tcp_bind_fanout[TCP_BIND_FANOUT_SIZE];
+tf_t	tcp_bind_fanout[TCP_BIND_FANOUT_SIZE];
 
 /* TCP queue hash list - all tcp_t in case they will be an acceptor. */
 static tf_t	tcp_acceptor_fanout[TCP_FANOUT_SIZE];
@@ -1676,6 +1679,18 @@
 	tcp_bind_hash_remove(tcp);
 	tcp_free(tcp);
 
+	/* Release any SSL context */
+	if (tcp->tcp_kssl_ent != NULL) {
+		kssl_release_ent(tcp->tcp_kssl_ent, NULL, KSSL_NO_PROXY);
+		tcp->tcp_kssl_ent = NULL;
+	}
+
+	if (tcp->tcp_kssl_ctx != NULL) {
+		kssl_release_ctx(tcp->tcp_kssl_ctx);
+		tcp->tcp_kssl_ctx = NULL;
+	}
+	tcp->tcp_kssl_pending = B_FALSE;
+
 	conn_delete_ire(connp, NULL);
 	if (connp->conn_flags & IPCL_TCPCONN) {
 		if (connp->conn_latch != NULL)
@@ -3713,6 +3728,7 @@
 	    tcp_close_output, connp, SQTAG_IP_TCP_CLOSE);
 
 	mutex_enter(&tcp->tcp_closelock);
+
 	while (!tcp->tcp_closed)
 		cv_wait(&tcp->tcp_closecv, &tcp->tcp_closelock);
 	mutex_exit(&tcp->tcp_closelock);
@@ -3996,6 +4012,7 @@
 		tcp->tcp_rq = tcp_g_q;
 		tcp->tcp_wq = WR(tcp_g_q);
 	}
+
 	/* Signal tcp_close() to finish closing. */
 	tcp->tcp_closed = 1;
 	cv_signal(&tcp->tcp_closecv);
@@ -4086,6 +4103,7 @@
 	tcp->tcp_ibsegs = 0;
 	UPDATE_MIB(&tcp_mib, tcpOutSegs, tcp->tcp_obsegs);
 	tcp->tcp_obsegs = 0;
+
 	/*
 	 * If we are an eager connection hanging off a listener that
 	 * hasn't formally accepted the connection yet, get off his
@@ -4164,6 +4182,17 @@
 	ASSERT(tcp->tcp_time_wait_prev == NULL);
 	ASSERT(tcp->tcp_time_wait_expire == 0);
 	tcp->tcp_state = TCPS_CLOSED;
+
+	/* Release any SSL context */
+	if (tcp->tcp_kssl_ent != NULL) {
+		kssl_release_ent(tcp->tcp_kssl_ent, NULL, KSSL_NO_PROXY);
+		tcp->tcp_kssl_ent = NULL;
+	}
+	if (tcp->tcp_kssl_ctx != NULL) {
+		kssl_release_ctx(tcp->tcp_kssl_ctx);
+		tcp->tcp_kssl_ctx = NULL;
+	}
+	tcp->tcp_kssl_pending = B_FALSE;
 }
 
 /*
@@ -4691,6 +4720,13 @@
 	}
 	tcp->tcp_conn.tcp_eager_conn_ind = tpi_mp;
 
+	/* Inherit the listener's SSL protection state */
+
+	if ((tcp->tcp_kssl_ent = ltcp->tcp_kssl_ent) != NULL) {
+		kssl_hold_ent(tcp->tcp_kssl_ent);
+		tcp->tcp_kssl_pending = B_TRUE;
+	}
+
 	return (0);
 }
 
@@ -4806,6 +4842,12 @@
 	}
 	tcp->tcp_conn.tcp_eager_conn_ind = tpi_mp;
 
+	/* Inherit the listener's SSL protection state */
+	if ((tcp->tcp_kssl_ent = ltcp->tcp_kssl_ent) != NULL) {
+		kssl_hold_ent(tcp->tcp_kssl_ent);
+		tcp->tcp_kssl_pending = B_TRUE;
+	}
+
 	return (0);
 }
 
@@ -7170,6 +7212,20 @@
 	ASSERT(tcp->tcp_time_wait_prev == NULL);
 	ASSERT(tcp->tcp_time_wait_expire == 0);
 
+	if (tcp->tcp_kssl_pending) {
+		tcp->tcp_kssl_pending = B_FALSE;
+
+		/* Don't reset if the initialized by bind. */
+		if (tcp->tcp_kssl_ent != NULL) {
+			kssl_release_ent(tcp->tcp_kssl_ent, NULL,
+			    KSSL_NO_PROXY);
+		}
+	}
+	if (tcp->tcp_kssl_ctx != NULL) {
+		kssl_release_ctx(tcp->tcp_kssl_ctx);
+		tcp->tcp_kssl_ctx = NULL;
+	}
+
 	/*
 	 * Reset/preserve other values
 	 */
@@ -7528,6 +7584,10 @@
 
 	PRESERVE(tcp->tcp_squeue_bytes);
 
+	ASSERT(tcp->tcp_kssl_ctx == NULL);
+	ASSERT(!tcp->tcp_kssl_pending);
+	PRESERVE(tcp->tcp_kssl_ent);
+
 #undef	DONTCARE
 #undef	PRESERVE
 }
@@ -8663,7 +8723,10 @@
 		 * chunks.  We round up the buffer size to the nearest SMSS.
 		 */
 		maxpsz = MSS_ROUNDUP(tcp->tcp_xmit_hiwater, mss);
-		mss = INFPSZ;
+		if (tcp->tcp_kssl_ctx == NULL)
+			mss = INFPSZ;
+		else
+			mss = SSL3_MAX_RECORD_LEN;
 	} else {
 		/*
 		 * Set sd_qn_maxpsz to approx half the (receivers) buffer
@@ -11003,6 +11066,11 @@
 #ifdef DEBUG
 		cnt += msgdsize(mp);
 #endif
+		/* Does this need SSL processing first? */
+		if ((tcp->tcp_kssl_ctx  != NULL) && (DB_TYPE(mp) == M_DATA)) {
+			tcp_kssl_input(tcp, mp);
+			continue;
+		}
 		putnext(q, mp);
 	}
 	ASSERT(cnt == tcp->tcp_rcv_cnt);
@@ -12532,7 +12600,22 @@
 		BUMP_MIB(&tcp_mib, tcpInClosed);
 		TCP_RECORD_TRACE(tcp,
 		    mp, TCP_TRACE_RECV_PKT);
+
 		freemsg(mp);
+		/*
+		 * This could be an SSL closure alert. We're detached so just
+		 * acknowledge it this last time.
+		 */
+		if (tcp->tcp_kssl_ctx != NULL) {
+			kssl_release_ctx(tcp->tcp_kssl_ctx);
+			tcp->tcp_kssl_ctx = NULL;
+
+			tcp->tcp_rnxt += seg_len;
+			U32_TO_ABE32(tcp->tcp_rnxt, tcp->tcp_tcph->th_ack);
+			flags |= TH_ACK_NEEDED;
+			goto ack_check;
+		}
+
 		tcp_xmit_ctl("new data when detached", tcp,
 		    tcp->tcp_snxt, 0, TH_RST);
 		(void) tcp_clean_death(tcp, EPROTO, 12);
@@ -13241,7 +13324,8 @@
 	if (tcp->tcp_ipversion == IPV6_VERSION && bytes_acked > 0)
 		tcp->tcp_ip_forward_progress = B_TRUE;
 	if (tcp->tcp_state == TCPS_SYN_RCVD) {
-		if (tcp->tcp_conn.tcp_eager_conn_ind != NULL) {
+		if ((tcp->tcp_conn.tcp_eager_conn_ind != NULL) &&
+		    ((tcp->tcp_kssl_ent == NULL) || !tcp->tcp_kssl_pending)) {
 			/* 3-way handshake complete - pass up the T_CONN_IND */
 			tcp_t	*listener = tcp->tcp_listener;
 			mblk_t	*mp = tcp->tcp_conn.tcp_eager_conn_ind;
@@ -13968,6 +14052,7 @@
 	}
 est:
 	if (tcp->tcp_state > TCPS_ESTABLISHED) {
+
 		switch (tcp->tcp_state) {
 		case TCPS_FIN_WAIT_1:
 			if (tcp->tcp_fin_acked) {
@@ -14170,7 +14255,12 @@
 		 *	Removing tcp_listener check for TH_URG
 		 *	Making M_PCPROTO and MARK messages skip the eager case
 		 */
-		tcp_rcv_enqueue(tcp, mp, seg_len);
+
+		if (tcp->tcp_kssl_pending) {
+			tcp_kssl_input(tcp, mp);
+		} else {
+			tcp_rcv_enqueue(tcp, mp, seg_len);
+		}
 	} else {
 		if (mp->b_datap->db_type != M_DATA ||
 		    (flags & TH_MARKNEXT_NEEDED)) {
@@ -14189,9 +14279,16 @@
 				mp->b_flag |= MSGMARKNEXT;
 				flags &= ~TH_MARKNEXT_NEEDED;
 			}
-			putnext(tcp->tcp_rq, mp);
-			if (!canputnext(tcp->tcp_rq))
-				tcp->tcp_rwnd -= seg_len;
+
+			/* Does this need SSL processing first? */
+			if ((tcp->tcp_kssl_ctx  != NULL) &&
+			    (DB_TYPE(mp) == M_DATA)) {
+				tcp_kssl_input(tcp, mp);
+			} else {
+				putnext(tcp->tcp_rq, mp);
+				if (!canputnext(tcp->tcp_rq))
+					tcp->tcp_rwnd -= seg_len;
+			}
 		} else if (((flags & (TH_PUSH|TH_FIN)) ||
 		    tcp->tcp_rcv_cnt + seg_len >= tcp->tcp_rq->q_hiwat >> 3) &&
 		    (sqp != NULL)) {
@@ -14212,9 +14309,15 @@
 				tcp_rcv_enqueue(tcp, mp, seg_len);
 				flags |= tcp_rcv_drain(tcp->tcp_rq, tcp);
 			} else {
-				putnext(tcp->tcp_rq, mp);
-				if (!canputnext(tcp->tcp_rq))
-					tcp->tcp_rwnd -= seg_len;
+				/* Does this need SSL processing first? */
+				if ((tcp->tcp_kssl_ctx  != NULL) &&
+				    (DB_TYPE(mp) == M_DATA)) {
+					tcp_kssl_input(tcp, mp);
+				} else {
+					putnext(tcp->tcp_rq, mp);
+					if (!canputnext(tcp->tcp_rq))
+						tcp->tcp_rwnd -= seg_len;
+				}
 			}
 		} else {
 			/*
@@ -16561,7 +16664,7 @@
  * NOTE: the logic of the fast path is duplicated from tcp_wput_data()
  */
 /* ARGSUSED */
-static void
+void
 tcp_output(void *arg, mblk_t *mp, void *arg2)
 {
 	int		len;
@@ -17024,6 +17127,26 @@
 		    tcp_wroff_xtra);
 	}
 
+	/*
+	 * If this is endpoint is handling SSL, then reserve extra
+	 * offset and space at the end.
+	 * Also have the stream head allocate SSL3_MAX_RECORD_LEN packets,
+	 * overriding the previous setting. The extra cost of signing and
+	 * encrypting multiple MSS-size records (12 of them with Ethernet),
+	 * instead of a single contiguous one by the stream head
+	 * largely outweighs the statistical reduction of ACKs, when
+	 * applicable. The peer will also save on decyption and verification
+	 * costs.
+	 */
+	if (tcp->tcp_kssl_ctx != NULL) {
+		stropt->so_wroff += SSL3_WROFFSET;
+
+		stropt->so_flags |= SO_TAIL;
+		stropt->so_tail = SSL3_MAX_TAIL_LEN;
+
+		stropt->so_maxblk = SSL3_MAX_RECORD_LEN;
+	}
+
 	/* Send the options up */
 	putnext(q, stropt_mp);
 
@@ -17335,12 +17458,16 @@
 			 * order as how the 3WHS is completed.
 			 */
 			while (tcp != listener) {
-				if (!tcp->tcp_eager_prev_q0->tcp_conn_def_q0)
+				if (!tcp->tcp_eager_prev_q0->tcp_conn_def_q0 &&
+				    !tcp->tcp_kssl_pending)
 					break;
 				else
 					tcp = tcp->tcp_eager_prev_q0;
 			}
-			ASSERT(tcp != listener);
+			/* None of the pending eagers can be sent up now */
+			if (tcp == listener)
+				goto no_more_eagers;
+
 			mp1 = tcp->tcp_conn.tcp_eager_conn_ind;
 			tcp->tcp_conn.tcp_eager_conn_ind = NULL;
 			/* Move from q0 to q */
@@ -17376,6 +17503,7 @@
 			    tcp_send_pending, listener->tcp_connp,
 			    SQTAG_TCP_SEND_PENDING);
 		}
+no_more_eagers:
 		tcp_eager_unlink(eager);
 		mutex_exit(&listener->tcp_eager_lock);
 
@@ -20577,6 +20705,28 @@
 non_urgent_data:
 
 	switch ((int)tprim->type) {
+	case T_SSL_PROXY_BIND_REQ:	/* an SSL proxy endpoint bind request */
+		/*
+		 * save the kssl_ent_t from the next block, and convert this
+		 * back to a normal bind_req.
+		 */
+		if (mp->b_cont != NULL) {
+		    ASSERT(MBLKL(mp->b_cont) >= sizeof (kssl_ent_t));
+
+			if (tcp->tcp_kssl_ent != NULL) {
+				kssl_release_ent(tcp->tcp_kssl_ent, NULL,
+				    KSSL_NO_PROXY);
+				tcp->tcp_kssl_ent = NULL;
+			}
+			bcopy(mp->b_cont->b_rptr, &tcp->tcp_kssl_ent,
+			    sizeof (kssl_ent_t));
+			kssl_hold_ent(tcp->tcp_kssl_ent);
+			freemsg(mp->b_cont);
+			mp->b_cont = NULL;
+		}
+		tprim->type = T_BIND_REQ;
+
+	/* FALLTHROUGH */
 	case O_T_BIND_REQ:	/* bind request */
 	case T_BIND_REQ:	/* new semantics bind request */
 		tcp_bind(tcp, mp);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/tcp/tcp_kssl.c	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,404 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/strsubr.h>
+#include <sys/stropts.h>
+#include <sys/strlog.h>
+#include <sys/strsun.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+#include <sys/vtrace.h>
+#include <sys/kmem.h>
+#include <sys/zone.h>
+#include <sys/tihdr.h>
+
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <inet/common.h>
+#include <inet/ipclassifier.h>
+#include <inet/ip.h>
+#include <inet/ip6.h>
+#include <inet/mi.h>
+#include <inet/mib2.h>
+#include <inet/tcp.h>
+#include <inet/ipdrop.h>
+#include <inet/tcp_trace.h>
+#include <inet/tcp_impl.h>
+
+#include <sys/squeue.h>
+#include <inet/kssl/ksslapi.h>
+
+/*
+ * For the Kernel SSL proxy
+ *
+ * Routines in this file are called on tcp's incoming path,
+ * tcp_rput_data() mainly, and right before the message is
+ * to be putnext()'ed upstreams.
+ */
+
+static void	tcp_kssl_input_callback(void *, mblk_t *, kssl_cmd_t);
+static void	tcp_kssl_input_asynch(void *, mblk_t *, void *);
+
+extern void	tcp_output(void *, mblk_t *, void *);
+extern void	tcp_send_conn_ind(void *, mblk_t *, void *);
+
+extern squeue_func_t tcp_squeue_wput_proc;
+
+/*
+ * tcp_rput_data() calls this routine for all packet destined to a
+ * connection to the SSL port, when the SSL kernel proxy is configured
+ * to intercept and process those packets.
+ * A packet may carry multiple SSL records, so the function
+ * calls kssl_input() in a loop, until all records are
+ * handled.
+ * As long as this conection is in handshake, that is until the first
+ * time kssl_input() returns a record to be delivered ustreams,
+ * we maintain the tcp_kssl_inhandshake, and keep an extra reference on
+ * the tcp/connp across the call to kssl_input(). The reason is, that
+ * function may return KSSL_CMD_QUEUED after scheduling an asynchronous
+ * request and cause tcp_kssl_callback() to be called on adifferent CPU,
+ * which could decrement the conn/tcp reference before we get to increment it.
+ */
+void
+tcp_kssl_input(tcp_t *tcp, mblk_t *mp)
+{
+	struct conn_s	*connp = tcp->tcp_connp;
+	tcp_t		*listener;
+	mblk_t		*ind_mp;
+	kssl_cmd_t	kssl_cmd;
+	mblk_t		*outmp;
+	struct		T_conn_ind *tci;
+	boolean_t	more = B_FALSE;
+	boolean_t	conn_held = B_FALSE;
+
+	/* First time here, allocate the SSL context */
+	if (tcp->tcp_kssl_ctx == NULL) {
+		ASSERT(tcp->tcp_kssl_pending);
+
+		if (kssl_init_context(tcp->tcp_kssl_ent,
+		    tcp->tcp_ipha->ipha_dst, tcp->tcp_mss,
+		    &(tcp->tcp_kssl_ctx)) != KSSL_STS_OK) {
+			tcp->tcp_kssl_pending = B_FALSE;
+			kssl_release_ent(tcp->tcp_kssl_ent, NULL,
+			    KSSL_NO_PROXY);
+			tcp->tcp_kssl_ent = NULL;
+			goto no_can_do;
+		}
+		tcp->tcp_kssl_inhandshake = B_TRUE;
+
+		/* we won't be needing this one after now */
+		kssl_release_ent(tcp->tcp_kssl_ent, NULL, KSSL_NO_PROXY);
+		tcp->tcp_kssl_ent = NULL;
+
+	}
+
+	if (tcp->tcp_kssl_inhandshake) {
+		CONN_INC_REF(connp);
+		conn_held = B_TRUE;
+	}
+	do {
+		kssl_cmd = kssl_input(tcp->tcp_kssl_ctx, mp, &outmp,
+		    &more, tcp_kssl_input_callback, (void *)tcp);
+
+		switch (kssl_cmd) {
+		case KSSL_CMD_SEND:
+			/*
+			 * We need to increment tcp_squeue_bytes to account
+			 * for the extra bytes internally injected to the
+			 * outgoing flow. tcp_output() will decrement it
+			 * as they are sent out.
+			 */
+			ASSERT(!MUTEX_HELD(&connp->conn_lock));
+			mutex_enter(&connp->conn_lock);
+			tcp->tcp_squeue_bytes += msgdsize(outmp);
+			mutex_exit(&connp->conn_lock);
+			tcp_output(connp, outmp, NULL);
+
+		/* FALLTHROUGH */
+		case KSSL_CMD_NONE:
+			if (tcp->tcp_kssl_pending) {
+				mblk_t *ctxmp;
+
+				/*
+				 * SSL handshake successfully started -
+				 * pass up the T_CONN_IND
+				 */
+
+				mp = NULL;
+
+				listener = tcp->tcp_listener;
+				tcp->tcp_kssl_pending = B_FALSE;
+
+				ind_mp = tcp->tcp_conn.tcp_eager_conn_ind;
+				ASSERT(ind_mp != NULL);
+
+				ctxmp = allocb(sizeof (kssl_ctx_t), BPRI_MED);
+
+				/*
+				 * Give this session a chance to fall back to
+				 * userland SSL
+				 */
+				if (ctxmp == NULL)
+					goto no_can_do;
+
+				/*
+				 * attach the kssl_ctx to the conn_ind and
+				 * transform it to a T_SSL_PROXY_CONN_IND.
+				 * Hold it so that it stays valid till it
+				 * reaches the stream head.
+				 */
+				kssl_hold_ctx(tcp->tcp_kssl_ctx);
+				*((kssl_ctx_t *)ctxmp->b_rptr) =
+					tcp->tcp_kssl_ctx;
+				ctxmp->b_wptr = ctxmp->b_rptr +
+				    sizeof (kssl_ctx_t);
+
+				ind_mp->b_cont = ctxmp;
+
+				tci = (struct T_conn_ind *)ind_mp->b_rptr;
+				tci->PRIM_type = T_SSL_PROXY_CONN_IND;
+
+				/*
+				 * The code below is copied from tcp_rput_data()
+				 * delivering the T_CONN_IND on a TCPS_SYN_RCVD,
+				 * and all conn ref cnt comments apply.
+				 */
+				tcp->tcp_conn.tcp_eager_conn_ind = NULL;
+
+				CONN_INC_REF(connp);
+
+				CONN_INC_REF(listener->tcp_connp);
+				if (listener->tcp_connp->conn_sqp ==
+				    connp->conn_sqp) {
+					tcp_send_conn_ind(listener->tcp_connp,
+					    ind_mp,
+					    listener->tcp_connp->conn_sqp);
+					CONN_DEC_REF(listener->tcp_connp);
+				} else {
+					squeue_fill(
+					    listener->tcp_connp->conn_sqp,
+					    ind_mp, tcp_send_conn_ind,
+					    listener->tcp_connp,
+					    SQTAG_TCP_CONN_IND);
+				}
+			}
+			break;
+
+		case KSSL_CMD_QUEUED:
+			/*
+			 * We hold the conn_t here because an asynchronous
+			 * request have been queued and
+			 * tcp_kssl_input_callback() will be called later.
+			 * It will release the conn_t
+			 */
+			CONN_INC_REF(connp);
+			break;
+
+		case KSSL_CMD_DELIVER_PROXY:
+		case KSSL_CMD_DELIVER_SSL:
+			/*
+			 * Keep accumulating if not yet accepted.
+			 */
+			if (tcp->tcp_listener != NULL) {
+				tcp_rcv_enqueue(tcp, outmp, msgdsize(outmp));
+			} else {
+				putnext(tcp->tcp_rq, outmp);
+			}
+			/*
+			 * We're at a phase where records are sent upstreams,
+			 * past the handshake
+			 */
+			tcp->tcp_kssl_inhandshake = B_FALSE;
+			break;
+
+		case KSSL_CMD_NOT_SUPPORTED:
+			/*
+			 * Stop the SSL processing by the proxy, and
+			 * switch to the userland SSL
+			 */
+			if (tcp->tcp_kssl_pending) {
+
+				tcp->tcp_kssl_pending = B_FALSE;
+
+no_can_do:
+				listener = tcp->tcp_listener;
+				ind_mp = tcp->tcp_conn.tcp_eager_conn_ind;
+				ASSERT(ind_mp != NULL);
+
+				if (tcp->tcp_kssl_ctx != NULL) {
+					kssl_release_ctx(tcp->tcp_kssl_ctx);
+					tcp->tcp_kssl_ctx = NULL;
+				}
+
+				/*
+				 * Make this a T_SSL_PROXY_CONN_IND, for the
+				 * stream head to deliver it to the SSL
+				 * fall-back listener
+				 */
+				tci = (struct T_conn_ind *)ind_mp->b_rptr;
+				tci->PRIM_type = T_SSL_PROXY_CONN_IND;
+
+				/*
+				 * The code below is copied from tcp_rput_data()
+				 * delivering the T_CONN_IND on a TCPS_SYN_RCVD,
+				 * and all conn ref cnt comments apply.
+				 */
+				tcp->tcp_conn.tcp_eager_conn_ind = NULL;
+
+				CONN_INC_REF(connp);
+
+				CONN_INC_REF(listener->tcp_connp);
+				if (listener->tcp_connp->conn_sqp ==
+				    connp->conn_sqp) {
+					tcp_send_conn_ind(listener->tcp_connp,
+					    ind_mp,
+					    listener->tcp_connp->conn_sqp);
+					CONN_DEC_REF(listener->tcp_connp);
+				} else {
+					squeue_fill(
+					    listener->tcp_connp->conn_sqp,
+					    ind_mp, tcp_send_conn_ind,
+					    listener->tcp_connp,
+					    SQTAG_TCP_CONN_IND);
+				}
+			}
+			if (mp != NULL)
+				tcp_rcv_enqueue(tcp, mp, msgdsize(mp));
+			break;
+		}
+		mp = NULL;
+	} while (more);
+	if (conn_held) {
+		CONN_DEC_REF(connp);
+	}
+}
+
+/*
+ * Callback function for the cases kssl_input() had to submit an asynchronous
+ * job and need to come back when done to carry on the input processing.
+ * This routine follows the conentions of timeout and interrupt handlers.
+ * (no blocking, ...)
+ */
+static void
+tcp_kssl_input_callback(void *arg, mblk_t *mp, kssl_cmd_t kssl_cmd)
+{
+	tcp_t	*tcp = (tcp_t *)arg;
+	conn_t	*connp;
+	mblk_t	*sqmp;
+
+	ASSERT(tcp != NULL);
+
+	connp = tcp->tcp_connp;
+
+	ASSERT(connp != NULL);
+
+	switch (kssl_cmd) {
+	case KSSL_CMD_SEND:
+		/* I'm coming from an outside perimeter */
+		if (mp != NULL) {
+			/*
+			 * See comment in tcp_kssl_input() call to tcp_output()
+			 */
+			ASSERT(!MUTEX_HELD(&connp->conn_lock));
+			mutex_enter(&connp->conn_lock);
+			CONN_INC_REF_LOCKED(connp);
+			tcp->tcp_squeue_bytes += msgdsize(mp);
+			mutex_exit(&connp->conn_lock);
+		} else {
+			CONN_INC_REF(connp);
+		}
+		(*tcp_squeue_wput_proc)(connp->conn_sqp, mp,
+		    tcp_output, connp, SQTAG_TCP_OUTPUT);
+
+	/* FALLTHROUGH */
+	case KSSL_CMD_NONE:
+		break;
+
+	case KSSL_CMD_DELIVER_PROXY:
+	case KSSL_CMD_DELIVER_SSL:
+		/*
+		 * Keep accumulating if not yet accepted.
+		 */
+		if (tcp->tcp_listener != NULL) {
+			tcp_rcv_enqueue(tcp, mp, msgdsize(mp));
+		} else {
+			putnext(tcp->tcp_rq, mp);
+		}
+		break;
+
+	case KSSL_CMD_NOT_SUPPORTED:
+		/* Stop the SSL processing */
+		kssl_release_ctx(tcp->tcp_kssl_ctx);
+		tcp->tcp_kssl_ctx = NULL;
+	}
+	/*
+	 * Process any input that may have accumulated while we're waiting for
+	 * the call-back.
+	 * We need to re-enter the squeue for this connp, and a new mp is
+	 * necessary.
+	 */
+	if ((sqmp = allocb(1, BPRI_MED)) != NULL) {
+		CONN_INC_REF(connp);
+		squeue_fill(connp->conn_sqp, sqmp, tcp_kssl_input_asynch,
+		    connp, SQTAG_TCP_KSSL_INPUT);
+	}
+#ifdef	DEBUG
+	else {
+		cmn_err(CE_WARN, "tcp_kssl_input_callback: alloc failure");
+	}
+#endif	/* DEBUG */
+	CONN_DEC_REF(connp);
+}
+
+/*
+ * Needed by tcp_kssl_input_callback() to continue processing the incoming
+ * flow on a tcp_t after an asynchronous callback call.
+ */
+/* ARGSUSED */
+void
+tcp_kssl_input_asynch(void *arg, mblk_t *mp, void *arg2)
+{
+	conn_t	*connp = (conn_t *)arg;
+	tcp_t *tcp = connp->conn_tcp;
+
+	ASSERT(connp != NULL);
+	freemsg(mp);
+
+	/*
+	 * NULL tcp_kssl_ctx means this connection is getting/was closed
+	 * while we're away
+	 */
+	if (tcp->tcp_kssl_ctx != NULL) {
+		tcp_kssl_input(tcp, NULL);
+	}
+}
--- a/usr/src/uts/common/io/stream.c	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/io/stream.c	Sat Nov 12 18:58:05 2005 -0800
@@ -542,6 +542,9 @@
 	dbp->db_struioflag = 0;
 	dbp->db_struioun.cksum.flags = 0;
 
+	/* and the COOKED flag */
+	dbp->db_flags &= ~DBLK_COOKED;
+
 	kmem_cache_free(dbp->db_cache, dbp);
 }
 
--- a/usr/src/uts/common/io/strsun.c	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/io/strsun.c	Sat Nov 12 18:58:05 2005 -0800
@@ -253,6 +253,7 @@
 {
 	mblk_t	*head = NULL, **tail = &head;
 	size_t	offset = stp->sd_wroff;
+	size_t tail_len = stp->sd_tail;
 
 	if (iosize == INFPSZ || iosize > uiop->uio_resid)
 		iosize = uiop->uio_resid;
@@ -279,7 +280,8 @@
 
 		blocksize = MIN(iosize, maxblk);
 		ASSERT(blocksize >= 0);
-		if ((mp = allocb_cred(offset + blocksize, CRED())) == NULL) {
+		if ((mp = allocb_cred(offset + blocksize + tail_len,
+		    CRED())) == NULL) {
 			*errorp = ENOMEM;
 			return (head);
 		}
--- a/usr/src/uts/common/os/streamio.c	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/os/streamio.c	Sat Nov 12 18:58:05 2005 -0800
@@ -370,6 +370,7 @@
 	stp->sd_rerror = 0;
 	stp->sd_werror = 0;
 	stp->sd_wroff = 0;
+	stp->sd_tail = 0;
 	stp->sd_iocblk = NULL;
 	stp->sd_pushcnt = 0;
 	stp->sd_qn_minpsz = 0;
@@ -2269,6 +2270,8 @@
 		}
 		if (sop->so_flags & SO_WROFF)
 			stp->sd_wroff = sop->so_wroff;
+		if (sop->so_flags & SO_TAIL)
+			stp->sd_tail = sop->so_tail;
 		if (sop->so_flags & SO_MINPSZ)
 			q->q_minpsz = sop->so_minpsz;
 		if (sop->so_flags & SO_MAXPSZ)
@@ -5884,7 +5887,7 @@
 	/*
 	 * Timed wait for acknowledgment.  The wait time is limited by the
 	 * timeout value, which must be a positive integer (number of
-	 * milliseconds to wait, or 0 (use default value of STRTIMOUT
+	 * milliseconds) to wait, or 0 (use default value of STRTIMOUT
 	 * milliseconds), or -1 (wait forever).  This will be awakened
 	 * either by an ACK/NAK message arriving, the timer expiring, or
 	 * the timer expiring on another ioctl waiting for control of the
@@ -7054,6 +7057,19 @@
 	stp->sd_flag |= STRGETINPROG;
 	mutex_exit(&stp->sd_lock);
 
+	if ((stp->sd_rputdatafunc != NULL) && (DB_TYPE(bp) == M_DATA) &&
+	    (!(DB_FLAGS(bp) & DBLK_COOKED))) {
+
+		bp = (stp->sd_rputdatafunc)(
+		    stp->sd_vnode, bp, NULL,
+		    NULL, NULL, NULL);
+
+		if (bp == NULL)
+			goto retry;
+
+		DB_FLAGS(bp) |= DBLK_COOKED;
+	}
+
 	if (STREAM_NEEDSERVICE(stp))
 		stream_runservice(stp);
 
--- a/usr/src/uts/common/os/strsubr.c	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/os/strsubr.c	Sat Nov 12 18:58:05 2005 -0800
@@ -2836,6 +2836,8 @@
 	mblk_t *mp = NULL;
 	mblk_t *bp;
 	int wroff = (int)stp->sd_wroff;
+	int tail_len = (int)stp->sd_tail;
+	int extra = wroff + tail_len;
 	int error = 0;
 	ssize_t maxblk;
 	ssize_t count = *iosize;
@@ -2860,10 +2862,10 @@
 
 		size = MIN(count, maxblk);
 
-		while ((bp = allocb_cred(size + wroff, cr)) == NULL) {
+		while ((bp = allocb_cred(size + extra, cr)) == NULL) {
 			error = EAGAIN;
 			if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) ||
-			    (error = strwaitbuf(size + wroff, BPRI_MED)) != 0) {
+			    (error = strwaitbuf(size + extra, BPRI_MED)) != 0) {
 				if (count == *iosize) {
 					freemsg(mp);
 					return (error);
@@ -2889,6 +2891,7 @@
 			dp->db_cksumstuff = 0;
 			dp->db_cksumend = size;
 			*(long long *)dp->db_struioun.data = 0ll;
+			bp->b_wptr += size;
 		} else {
 			if (stp->sd_copyflag & STRCOPYCACHED)
 				uiop->uio_extflg |= UIO_COPY_CACHED;
@@ -2902,9 +2905,22 @@
 					return (error);
 				}
 			}
-		}
-
-		bp->b_wptr += size;
+			bp->b_wptr += size;
+
+			if (stp->sd_wputdatafunc != NULL) {
+				mblk_t *newbp;
+
+				newbp = (stp->sd_wputdatafunc)(stp->sd_vnode,
+				    bp, NULL, NULL, NULL, NULL);
+				if (newbp == NULL) {
+					freeb(bp);
+					freemsg(mp);
+					return (ECOMM);
+				}
+				bp = newbp;
+			}
+		}
+
 		count -= size;
 
 		if (mp == NULL)
@@ -3238,6 +3254,7 @@
 	stp->sd_rprotofunc = strrput_proto;
 	stp->sd_rmiscfunc = strrput_misc;
 	stp->sd_rderrfunc = stp->sd_wrerrfunc = NULL;
+	stp->sd_rputdatafunc = stp->sd_wputdatafunc = NULL;
 	stp->sd_ciputctrl = NULL;
 	stp->sd_nciputctrl = 0;
 	stp->sd_qhead = NULL;
@@ -3246,6 +3263,7 @@
 	stp->sd_nqueues = 0;
 	stp->sd_svcflags = 0;
 	stp->sd_copyflag = 0;
+
 	return (stp);
 }
 
@@ -7975,6 +7993,19 @@
 	mutex_exit(&stp->sd_lock);
 }
 
+void
+strsetrwputdatahooks(vnode_t *vp, msgfunc_t rdatafunc, msgfunc_t wdatafunc)
+{
+	struct stdata *stp = vp->v_stream;
+
+	mutex_enter(&stp->sd_lock);
+
+	stp->sd_rputdatafunc = rdatafunc;
+	stp->sd_wputdatafunc = wdatafunc;
+
+	mutex_exit(&stp->sd_lock);
+}
+
 /* Used within framework when the queue is already locked */
 void
 qenable_locked(queue_t *q)
--- a/usr/src/uts/common/sys/socketvar.h	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/sys/socketvar.h	Sat Nov 12 18:58:05 2005 -0800
@@ -50,6 +50,7 @@
 #include <sys/file.h>
 #include <sys/param.h>
 #include <sys/zone.h>
+#include <inet/kssl/ksslapi.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -324,6 +325,11 @@
 	int64_t		so_nl7c_rcv_rval;
 	void		*so_nl7c_uri;
 	time_t		so_nl7c_rtime;
+
+	/* For sockets acting as an in-kernel SSL proxy */
+	kssl_endpt_type_t	so_kssl_type;	/* is proxy/is proxied/none */
+	kssl_ent_t		so_kssl_ent;	/* SSL config entry */
+	kssl_ctx_t		so_kssl_ctx;	/* SSL session context */
 };
 
 /* flags */
--- a/usr/src/uts/common/sys/stream.h	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/sys/stream.h	Sat Nov 12 18:58:05 2005 -0800
@@ -376,6 +376,7 @@
  * db_flags values (all implementation private!)
  */
 #define	DBLK_REFMIN	0x01		/* min refcnt stored in low bit */
+#define	DBLK_COOKED	0x02		/* message has been processed once */
 
 /*
  * db_struioflag values:
@@ -577,6 +578,7 @@
 	ushort_t so_erropt;		/* error option */
 	ssize_t	so_maxblk;		/* maximum message block size */
 	ushort_t so_copyopt;		/* copy options (see stropts.h) */
+	ushort_t so_tail;		/* space available at the end */
 };
 
 /* flags for stream options set message */
@@ -603,6 +605,7 @@
 #define	SO_ERROPT	0x040000	/* set error option */
 #define	SO_COPYOPT	0x080000	/* copy option(s) present */
 #define	SO_MAXBLK	0x100000	/* set maximum message block size */
+#define	SO_TAIL		0x200000	/* set the extra allocated space */
 
 #ifdef _KERNEL
 /*
--- a/usr/src/uts/common/sys/strsubr.h	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/sys/strsubr.h	Sat Nov 12 18:58:05 2005 -0800
@@ -83,6 +83,7 @@
  *	sd_sidp
  *	sd_pgidp
  *	sd_wroff
+ *	sd_tail
  *	sd_rerror
  *	sd_werror
  *	sd_pushcnt
@@ -181,6 +182,7 @@
 	ushort_t	sd_unused;	/* UNUSED, retained for binary */
 					/* compatibility */
 	ushort_t	sd_wroff;	/* write offset */
+	ushort_t	sd_tail;	/* reserved space in written mblks */
 	int		sd_rerror;	/* error to return on read ops */
 	int		sd_werror;	/* error to return on write ops */
 	int		sd_pushcnt;	/* number of pushes done on stream */
@@ -213,7 +215,9 @@
 	uint_t		sd_wput_opt;	/* options/flags for write/putmsg */
 	uint_t		sd_read_opt;	/* options/flags for strread */
 	msgfunc_t	sd_rprotofunc;	/* rput M_*PROTO routine */
+	msgfunc_t	sd_rputdatafunc; /* read M_DATA routine */
 	msgfunc_t	sd_rmiscfunc;	/* rput routine (non-data/proto) */
+	msgfunc_t	sd_wputdatafunc; /* wput M_DATA routine */
 	errfunc_t	sd_rderrfunc;	/* read side error callback */
 	errfunc_t	sd_wrerrfunc;	/* write side error callback */
 	/*
@@ -1198,6 +1202,7 @@
 extern void strflushrq(vnode_t *, int);
 extern void strsetrputhooks(vnode_t *, uint_t, msgfunc_t, msgfunc_t);
 extern void strsetwputhooks(vnode_t *, uint_t, clock_t);
+extern void strsetrwputdatahooks(vnode_t *, msgfunc_t, msgfunc_t);
 extern int strwaitmark(vnode_t *);
 extern void strsignal_nolock(stdata_t *, int, int32_t);
 
--- a/usr/src/uts/common/sys/strsun.h	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/sys/strsun.h	Sat Nov 12 18:58:05 2005 -0800
@@ -46,6 +46,7 @@
 #define	DB_LIM(mp)	((mp)->b_datap->db_lim)
 #define	DB_REF(mp)	((mp)->b_datap->db_ref)
 #define	DB_TYPE(mp)	((mp)->b_datap->db_type)
+#define	DB_FLAGS(mp)	((mp)->b_datap->db_flags)
 
 #define	MBLKL(mp)	((mp)->b_wptr - (mp)->b_rptr)
 #define	MBLKSIZE(mp)	((mp)->b_datap->db_lim - (mp)->b_datap->db_base)
--- a/usr/src/uts/common/sys/tihdr.h	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/sys/tihdr.h	Sat Nov 12 18:58:05 2005 -0800
@@ -24,8 +24,8 @@
 
 
 /*
- * Copyright (c) 1995,1996 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 #ifndef _SYS_TIHDR_H
@@ -171,7 +171,8 @@
 #ifdef _KERNEL
 /*
  * Sun private TPI extensions. They are currently used for transparently
- * passing options through the connection-oriented loopback transport.
+ * passing options through the connection-oriented loopback transport,
+ * and for setting the kernel SSL proxy.
  * Values assigned to them may change.
  *
  * T_EXTCONN_IND (extended T_CONN_IND) is used to return dst as well as
@@ -180,6 +181,12 @@
 #define	T_OPTDATA_REQ	0x1001	/* data (with options) request	*/
 #define	T_OPTDATA_IND	0x1002	/* data (with options) indication */
 #define	T_EXTCONN_IND	0x1003	/* extended T_CONN_IND to return dst as well */
+
+#define	T_SSL_PROXY_BIND_REQ	0x1004	/* extended T_BIND_REQ to carry a */
+					/* kssl_entry_t to the transport. */
+#define	T_SSL_PROXY_CONN_IND	0x1005	/* conn_ind from an SSL proxy */
+					/* endpoint, carrying a kssl_ctx_t */
+
 #endif /* _KERNEL */
 
 /*
--- a/usr/src/uts/common/syscall/sendfile.c	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/common/syscall/sendfile.c	Sat Nov 12 18:58:05 2005 -0800
@@ -89,6 +89,7 @@
 {
 	struct stdata *stp;
 	struct queue *wqp;
+	mblk_t *newmp;
 	char waitflag;
 	int tempmode;
 	int error = 0;
@@ -137,6 +138,15 @@
 	do {
 		if (canputnext(wqp)) {
 			mutex_exit(&stp->sd_lock);
+			if (stp->sd_wputdatafunc != NULL) {
+				newmp = (stp->sd_wputdatafunc)(vp, mp, NULL,
+				    NULL, NULL, NULL);
+				if (newmp == NULL) {
+					/* The caller will free mp */
+					return (ECOMM);
+				}
+				mp = newmp;
+			}
 			putnext(wqp, mp);
 			return (0);
 		}
@@ -494,6 +504,8 @@
 	size_t	iov_len;
 	mblk_t  *head, *tmp;
 	size_t  size = total_size;
+	size_t  extra;
+	int tail_len;
 
 	fflag = fp->f_flag;
 	vp = fp->f_vnode;
@@ -502,8 +514,11 @@
 	ASSERT(maxblk > 0);
 
 	wroff = (int)vp->v_stream->sd_wroff;
+	tail_len = (int)vp->v_stream->sd_tail;
+	extra = wroff + tail_len;
+
 	buf_left = MIN(total_size, maxblk);
-	head = dmp = allocb(buf_left + wroff, BPRI_HI);
+	head = dmp = allocb(buf_left + extra, BPRI_HI);
 	if (head == NULL)
 		return (ENOMEM);
 	head->b_wptr = head->b_rptr = head->b_rptr + wroff;
@@ -552,7 +567,7 @@
 					tmp = dmp;
 					buf_left = MIN(total_size, maxblk);
 					iov_len = MIN(buf_left, sfv_len);
-					dmp = allocb(buf_left + wroff, BPRI_HI);
+					dmp = allocb(buf_left + extra, BPRI_HI);
 					if (dmp == NULL) {
 						freemsg(head);
 						return (ENOMEM);
@@ -647,7 +662,7 @@
 					tmp = dmp;
 					buf_left = MIN(total_size, maxblk);
 					iov_len = MIN(buf_left, sfv_len);
-					dmp = allocb(buf_left + wroff, BPRI_HI);
+					dmp = allocb(buf_left + extra, BPRI_HI);
 					if (dmp == NULL) {
 						VOP_RWUNLOCK(readvp, readflg,
 									NULL);
@@ -753,10 +768,23 @@
 #endif
 	mblk_t	*dmp = NULL;
 	char	*buf = NULL;
+	size_t  extra;
+	int maxblk, wroff, tail_len;
+	struct sonode *so;
+	stdata_t *stp;
 
 	fflag = fp->f_flag;
 	vp = fp->f_vnode;
 
+	if (vp->v_type == VSOCK) {
+		so = VTOSO(vp);
+		stp = vp->v_stream;
+		wroff = (int)stp->sd_wroff;
+		tail_len = (int)stp->sd_tail;
+		maxblk = (int)stp->sd_maxblk;
+		extra = wroff + tail_len;
+	}
+
 	auio.uio_extflg = UIO_COPY_DEFAULT;
 	for (i = 0; i < copy_cnt; i++) {
 		if (ISSIG(curthread, JUSTLOOKING))
@@ -829,9 +857,8 @@
 				/*
 				 * Optimize for the socket case
 				 */
-				int wroff = (int)vp->v_stream->sd_wroff;
 
-				dmp = allocb(sfv_len + wroff, BPRI_HI);
+				dmp = allocb(sfv_len + extra, BPRI_HI);
 				if (dmp == NULL)
 					return (ENOMEM);
 				dmp->b_wptr = dmp->b_rptr = dmp->b_rptr + wroff;
@@ -926,6 +953,14 @@
 					releasef(sfv->sfv_fd);
 					return (ENOMEM);
 				}
+			} else {
+				/*
+				 * For sockets acting as an SSL proxy, we
+				 * need to adjust the size to the maximum
+				 * SSL record size set in the stream head.
+				 */
+				if (so->so_kssl_ctx != NULL)
+					size = MIN(size, maxblk);
 			}
 
 			while (sfv_len > 0) {
@@ -934,13 +969,15 @@
 				iov_len = MIN(size, sfv_len);
 
 				if (vp->v_type == VSOCK) {
-					dmp = allocb(iov_len, BPRI_HI);
+					dmp = allocb(iov_len + extra, BPRI_HI);
 					if (dmp == NULL) {
 						VOP_RWUNLOCK(readvp, readflg,
 						    NULL);
 						releasef(sfv->sfv_fd);
 						return (ENOMEM);
 					}
+					dmp->b_wptr = dmp->b_rptr =
+					    dmp->b_rptr + wroff;
 					ptr = (caddr_t)dmp->b_rptr;
 				} else {
 					ptr = buf;
@@ -1129,7 +1166,8 @@
 			}
 
 			if ((so->so_state & SS_DIRECT) &&
-			    (so->so_priv != NULL)) {
+			    (so->so_priv != NULL) &&
+			    (so->so_kssl_ctx == NULL)) {
 				maxblk = ((tcp_t *)so->so_priv)->tcp_mss;
 			} else {
 				maxblk = (int)vp->v_stream->sd_maxblk;
--- a/usr/src/uts/intel/Makefile.intel	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/intel/Makefile.intel	Sat Nov 12 18:58:05 2005 -0800
@@ -249,6 +249,7 @@
 DRV_KMODS	+= lofi
 DRV_KMODS	+= log
 DRV_KMODS	+= logindmux
+DRV_KMODS	+= kssl
 DRV_KMODS	+= mm
 DRV_KMODS	+= mouse8042
 DRV_KMODS	+= mpt
--- a/usr/src/uts/intel/ia32/ml/modstubs.s	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/intel/ia32/ml/modstubs.s	Sat Nov 12 18:58:05 2005 -0800
@@ -922,6 +922,7 @@
 	NO_UNLOAD_STUB(c2audit, audit_setfsat_path,	nomod_zero);
 	NO_UNLOAD_STUB(c2audit, audit_cryptoadm,	nomod_zero);
 	NO_UNLOAD_STUB(c2audit, audit_update_context,	nomod_zero);
+	NO_UNLOAD_STUB(c2audit, audit_kssl,		nomod_zero);
 	END_MODULE(c2audit);
 #endif
 
@@ -1154,6 +1155,24 @@
 	END_MODULE(dld);
 #endif
 
+/*
+ * Stubs for kssl, the kernel SSL proxy
+ */
+#ifndef KSSL_MODULE
+	MODULE(kssl,drv);
+	NO_UNLOAD_STUB(kssl, kssl_check_proxy, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_handle_record, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_input, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_build_record, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_hold_ent, nomod_void);
+	NO_UNLOAD_STUB(kssl, kssl_release_ent, nomod_void);
+	NO_UNLOAD_STUB(kssl, kssl_find_fallback, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_init_context, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_hold_ctx, nomod_void);
+	NO_UNLOAD_STUB(kssl, kssl_release_ctx, nomod_void);
+	END_MODULE(kssl);
+#endif
+
 / this is just a marker for the area of text that contains stubs 
 
 	ENTRY_NP(stubs_end)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/kssl/Makefile	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,86 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the kernel SSL driver
+#	kernel module.
+#
+#	intel architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= kssl
+OBJECTS		= $(KSSL_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(KSSL_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/inet/kssl
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE)
+
+LDFLAGS		+= -dy -Nmisc/md5 -Nmisc/kcf
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/intel/os/minor_perm	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/intel/os/minor_perm	Sat Nov 12 18:58:05 2005 -0800
@@ -116,3 +116,4 @@
 zfs:* 0600 root sys
 zfs:zfs 0666 root sys
 scsi_vhci:* 0666 root sys
+kssl:* 0666 root sys
--- a/usr/src/uts/intel/os/name_to_major	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/intel/os/name_to_major	Sat Nov 12 18:58:05 2005 -0800
@@ -118,4 +118,5 @@
 zfs 182
 npe 183
 pcie_pci 184
+kssl 185
 did 239
--- a/usr/src/uts/sparc/Makefile.sparc	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/sparc/Makefile.sparc	Sat Nov 12 18:58:05 2005 -0800
@@ -223,7 +223,7 @@
 DRV_KMODS	+= fssnap glm icmp icmp6 ip ip6 ipsecah
 DRV_KMODS	+= ipsecesp isp iwscn keysock kmdb kstat ksyms llc1 llc2
 DRV_KMODS	+= lofi
-DRV_KMODS	+= log logindmux mm mpt nca pm poll pool
+DRV_KMODS	+= log logindmux kssl mm mpt nca pm poll pool
 DRV_KMODS	+= pseudo ptc ptm pts ptsl ramdisk random rsm rts sad se 
 DRV_KMODS	+= spdsock sppp sppptun sy sysevent sysmsg 
 DRV_KMODS	+= tcp tcp6 tl tnf ttymux udp udp6 vol wc winlock zcons
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/kssl/Makefile	Sat Nov 12 18:58:05 2005 -0800
@@ -0,0 +1,91 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the kernel SSL driver
+#	kernel module.
+#
+#	sparc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= kssl
+OBJECTS		= $(KSSL_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(KSSL_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/inet/kssl
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE)
+
+#
+# lint pass one enforcement
+#
+CFLAGS		+= $(CCVERBOSE)
+
+LDFLAGS		+= -dy -Nmisc/md5 -Nmisc/kcf
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ
--- a/usr/src/uts/sparc/ml/modstubs.s	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/sparc/ml/modstubs.s	Sat Nov 12 18:58:05 2005 -0800
@@ -853,6 +853,7 @@
 	NO_UNLOAD_STUB(c2audit, audit_setfsat_path,	nomod_zero);
 	NO_UNLOAD_STUB(c2audit, audit_cryptoadm,	nomod_zero);
 	NO_UNLOAD_STUB(c2audit, audit_update_context,	nomod_zero);
+	NO_UNLOAD_STUB(c2audit, audit_kssl,		nomod_zero);
 	END_MODULE(c2audit);
 #endif
 
@@ -1096,6 +1097,24 @@
 	END_MODULE(dld);
 #endif
 
+/*
+ * Stubs for kssl, the kernel SSL proxy
+ */
+#ifndef KSSL_MODULE
+	MODULE(kssl,drv);
+	NO_UNLOAD_STUB(kssl, kssl_check_proxy, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_handle_record, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_input, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_build_record, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_hold_ent, nomod_void);
+	NO_UNLOAD_STUB(kssl, kssl_release_ent, nomod_void);
+	NO_UNLOAD_STUB(kssl, kssl_find_fallback, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_init_context, nomod_zero);
+	NO_UNLOAD_STUB(kssl, kssl_hold_ctx, nomod_void);
+	NO_UNLOAD_STUB(kssl, kssl_release_ctx, nomod_void);
+	END_MODULE(kssl);
+#endif
+
 ! this is just a marker for the area of text that contains stubs
 	.seg ".text"
 	.global stubs_end
--- a/usr/src/uts/sparc/os/minor_perm	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/sparc/os/minor_perm	Sat Nov 12 18:58:05 2005 -0800
@@ -165,3 +165,4 @@
 zfs:* 0600 root sys
 zfs:zfs 0666 root sys
 scsi_vhci:* 0666 root sys
+kssl:* 0666 root sys
--- a/usr/src/uts/sparc/os/name_to_major	Sat Nov 12 07:57:48 2005 -0800
+++ b/usr/src/uts/sparc/os/name_to_major	Sat Nov 12 18:58:05 2005 -0800
@@ -204,3 +204,4 @@
 i8042 254
 kb8042 255
 mouse8042 256
+kssl 257