summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/Makefile9
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/Makefile73
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.c169
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.h68
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_create.c972
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_delete.c98
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c265
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/Makefile87
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/kssl-proxy.xml78
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c246
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.h69
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_create.c665
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_delete.c296
-rw-r--r--usr/src/cmd/devfsadm/misc_link.c2
-rw-r--r--usr/src/lib/libbsm/audit_event.txt1
-rw-r--r--usr/src/lib/libsecdb/exec_attr.txt1
-rw-r--r--usr/src/pkgdefs/SUNWckr/prototype_com1
-rw-r--r--usr/src/pkgdefs/SUNWckr/prototype_i3862
-rw-r--r--usr/src/pkgdefs/SUNWckr/prototype_sparc1
-rw-r--r--usr/src/pkgdefs/SUNWcsr/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWcsu/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWhea/prototype_com2
-rw-r--r--usr/src/pkgdefs/etc/exception_list_i3865
-rw-r--r--usr/src/pkgdefs/etc/exception_list_sparc4
-rw-r--r--usr/src/uts/Makefile4
-rw-r--r--usr/src/uts/common/Makefile.files13
-rw-r--r--usr/src/uts/common/Makefile.rules7
-rw-r--r--usr/src/uts/common/c2/audit.c77
-rw-r--r--usr/src/uts/common/c2/audit.h3
-rw-r--r--usr/src/uts/common/c2/audit_kevents.h3
-rw-r--r--usr/src/uts/common/fs/sockfs/sockssl.c116
-rw-r--r--usr/src/uts/common/fs/sockfs/sockstr.c43
-rw-r--r--usr/src/uts/common/fs/sockfs/socktpi.c97
-rw-r--r--usr/src/uts/common/fs/sockfs/sockvnops.c15
-rw-r--r--usr/src/uts/common/inet/ip.h1
-rw-r--r--usr/src/uts/common/inet/kssl/Makefile53
-rw-r--r--usr/src/uts/common/inet/kssl/kssl.c580
-rw-r--r--usr/src/uts/common/inet/kssl/kssl.conf29
-rw-r--r--usr/src/uts/common/inet/kssl/kssl.h111
-rw-r--r--usr/src/uts/common/inet/kssl/ksslapi.c1185
-rw-r--r--usr/src/uts/common/inet/kssl/ksslapi.h109
-rw-r--r--usr/src/uts/common/inet/kssl/kssldebug.h111
-rw-r--r--usr/src/uts/common/inet/kssl/ksslimpl.h208
-rw-r--r--usr/src/uts/common/inet/kssl/ksslioctl.c599
-rw-r--r--usr/src/uts/common/inet/kssl/ksslproto.h355
-rw-r--r--usr/src/uts/common/inet/kssl/ksslrec.c2077
-rw-r--r--usr/src/uts/common/inet/tcp.h8
-rw-r--r--usr/src/uts/common/inet/tcp/tcp.c178
-rw-r--r--usr/src/uts/common/inet/tcp/tcp_kssl.c404
-rw-r--r--usr/src/uts/common/io/stream.c3
-rw-r--r--usr/src/uts/common/io/strsun.c4
-rw-r--r--usr/src/uts/common/os/streamio.c18
-rw-r--r--usr/src/uts/common/os/strsubr.c37
-rw-r--r--usr/src/uts/common/sys/socketvar.h6
-rw-r--r--usr/src/uts/common/sys/stream.h3
-rw-r--r--usr/src/uts/common/sys/strsubr.h5
-rw-r--r--usr/src/uts/common/sys/strsun.h1
-rw-r--r--usr/src/uts/common/sys/tihdr.h13
-rw-r--r--usr/src/uts/common/syscall/sendfile.c52
-rw-r--r--usr/src/uts/intel/Makefile.intel1
-rw-r--r--usr/src/uts/intel/ia32/ml/modstubs.s19
-rw-r--r--usr/src/uts/intel/kssl/Makefile86
-rw-r--r--usr/src/uts/intel/os/minor_perm1
-rw-r--r--usr/src/uts/intel/os/name_to_major1
-rw-r--r--usr/src/uts/sparc/Makefile.sparc2
-rw-r--r--usr/src/uts/sparc/kssl/Makefile91
-rw-r--r--usr/src/uts/sparc/ml/modstubs.s19
-rw-r--r--usr/src/uts/sparc/os/minor_perm1
-rw-r--r--usr/src/uts/sparc/os/name_to_major1
69 files changed, 9823 insertions, 45 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/Makefile
index 457e94cea6..ba670f6d57 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.sbin/Makefile
@@ -68,12 +68,13 @@ K5RSHDOBJS= in.rshd.o
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
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/Makefile
new file mode 100644
index 0000000000..725e3c3ab6
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/Makefile
@@ -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
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.c b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.c
new file mode 100644
index 0000000000..dbc2111ab2
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.c
@@ -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);
+}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.h b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.h
new file mode 100644
index 0000000000..4f1f118959
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.h
@@ -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 */
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_create.c b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_create.c
new file mode 100644
index 0000000000..5ed9c52302
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_create.c
@@ -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);
+}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_delete.c b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_delete.c
new file mode 100644
index 0000000000..e39eb5946c
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_delete.c
@@ -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);
+}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c
new file mode 100644
index 0000000000..27b1f4c159
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c
@@ -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);
+}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/Makefile
new file mode 100644
index 0000000000..c629d9f543
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/Makefile
@@ -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
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/kssl-proxy.xml b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/kssl-proxy.xml
new file mode 100644
index 0000000000..c27ed70e1a
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/kssl-proxy.xml
@@ -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>
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c
new file mode 100644
index 0000000000..de98986984
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c
@@ -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);
+}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.h b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.h
new file mode 100644
index 0000000000..9752cf565c
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.h
@@ -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 */
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_create.c b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_create.c
new file mode 100644
index 0000000000..68a6262b44
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_create.c
@@ -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);
+}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_delete.c b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_delete.c
new file mode 100644
index 0000000000..03144cedc4
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_delete.c
@@ -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);
+}
diff --git a/usr/src/cmd/devfsadm/misc_link.c b/usr/src/cmd/devfsadm/misc_link.c
index f5389ba064..7af08034f5 100644
--- a/usr/src/cmd/devfsadm/misc_link.c
+++ b/usr/src/cmd/devfsadm/misc_link.c
@@ -95,7 +95,7 @@ static devfsadm_create_t misc_cbt[] = {
"(^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",
diff --git a/usr/src/lib/libbsm/audit_event.txt b/usr/src/lib/libbsm/audit_event.txt
index 6cf29074b2..5bcc228838 100644
--- a/usr/src/lib/libbsm/audit_event.txt
+++ b/usr/src/lib/libbsm/audit_event.txt
@@ -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
#
diff --git a/usr/src/lib/libsecdb/exec_attr.txt b/usr/src/lib/libsecdb/exec_attr.txt
index 3e65cf9a7a..6db431d0da 100644
--- a/usr/src/lib/libsecdb/exec_attr.txt
+++ b/usr/src/lib/libsecdb/exec_attr.txt
@@ -198,6 +198,7 @@ Network Security:solaris:cmd:::/usr/sbin/ikecert:privs=sys_net_config
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
diff --git a/usr/src/pkgdefs/SUNWckr/prototype_com b/usr/src/pkgdefs/SUNWckr/prototype_com
index c8aa3dd357..aaedbe8a20 100644
--- a/usr/src/pkgdefs/SUNWckr/prototype_com
+++ b/usr/src/pkgdefs/SUNWckr/prototype_com
@@ -85,6 +85,7 @@ f none kernel/drv/ipsecesp.conf 644 root sys
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
diff --git a/usr/src/pkgdefs/SUNWckr/prototype_i386 b/usr/src/pkgdefs/SUNWckr/prototype_i386
index 9f0b437597..ba72638eeb 100644
--- a/usr/src/pkgdefs/SUNWckr/prototype_i386
+++ b/usr/src/pkgdefs/SUNWckr/prototype_i386
@@ -84,6 +84,7 @@ f none kernel/drv/ipsecesp 755 root sys
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/ipsecesp 755 root sys
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
diff --git a/usr/src/pkgdefs/SUNWckr/prototype_sparc b/usr/src/pkgdefs/SUNWckr/prototype_sparc
index 310574f7af..3cac3b5eb8 100644
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc
@@ -91,6 +91,7 @@ f none kernel/drv/sparcv9/iwscn 755 root sys
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
diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com
index 83724af857..e464b29c63 100644
--- a/usr/src/pkgdefs/SUNWcsr/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsr/prototype_com
@@ -474,6 +474,8 @@ d none var/svc/manifest/network/dns 755 root sys
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
diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com
index 5a2fcf7e23..b782d72e25 100644
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com
@@ -548,6 +548,7 @@ f none usr/lib/inet/in.mpathd 555 root bin
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 @@ s none usr/sbin/init=../../sbin/init
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
diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com
index 5891ee9b17..dbe4e9a427 100644
--- a/usr/src/pkgdefs/SUNWhea/prototype_com
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com
@@ -149,6 +149,8 @@ f none usr/include/inet/sctp_itf.h 644 root bin
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
diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386
index 37252fc182..b1e20e48ad 100644
--- a/usr/src/pkgdefs/etc/exception_list_i386
+++ b/usr/src/pkgdefs/etc/exception_list_i386
@@ -524,6 +524,11 @@ usr/include/inet/nca/ncalogd.h i386
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
diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc
index eb70a2b112..02e1ae373d 100644
--- a/usr/src/pkgdefs/etc/exception_list_sparc
+++ b/usr/src/pkgdefs/etc/exception_list_sparc
@@ -531,6 +531,10 @@ usr/include/inet/nca/ncakmem.h sparc
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
diff --git a/usr/src/uts/Makefile b/usr/src/uts/Makefile
index 4e6b56accd..aed8c29bcf 100644
--- a/usr/src/uts/Makefile
+++ b/usr/src/uts/Makefile
@@ -92,8 +92,8 @@ $(PMTMO_FILE) pmtmo_file: $(PATCH_MAKEUP_TABLE)
#
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
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index fdb7a58762..6d33d420d3 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -417,7 +417,8 @@ ICMP6_OBJS += icmp6ddi.o
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 @@ SPEC_OBJS += specsubr.o specvfsops.o specvnops.o
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 @@ RSAPROV_OBJS += $(COMMON_RSAPROV_OBJS) $(RSAPROV_PSR_OBJS)
SWRANDPROV_OBJS += swrand.o
#
+# kernel SSL
+#
+KSSL_OBJS += kssl.o ksslioctl.o ksslapi.o ksslrec.o
+
+#
# misc. modules
#
AMSRC1_OBJS += am_src1.o
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index b7f5ea902d..0e69f3f507 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -349,6 +349,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/inet/ip/%.c
$(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: $(SRC)/common/ipf/%.c
$(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))
diff --git a/usr/src/uts/common/c2/audit.c b/usr/src/uts/common/c2/audit.c
index 62230f02d6..0ab2dba4d7 100644
--- a/usr/src/uts/common/c2/audit.c
+++ b/usr/src/uts/common/c2/audit.c
@@ -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 @@ audit_cryptoadm(int cmd, char *module_name, crypto_mech_name_t *mech_names,
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);
+}
diff --git a/usr/src/uts/common/c2/audit.h b/usr/src/uts/common/c2/audit.h
index ff4bb14e21..f8c0ffd743 100644
--- a/usr/src/uts/common/c2/audit.h
+++ b/usr/src/uts/common/c2/audit.h
@@ -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_priv(int, const struct priv_set *, int);
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
diff --git a/usr/src/uts/common/c2/audit_kevents.h b/usr/src/uts/common/c2/audit_kevents.h
index e1327d16cb..ab184e973a 100644
--- a/usr/src/uts/common/c2/audit_kevents.h
+++ b/usr/src/uts/common/c2/audit_kevents.h
@@ -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 @@ extern "C" {
#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
diff --git a/usr/src/uts/common/fs/sockfs/sockssl.c b/usr/src/uts/common/fs/sockfs/sockssl.c
new file mode 100644
index 0000000000..4d007adb66
--- /dev/null
+++ b/usr/src/uts/common/fs/sockfs/sockssl.c
@@ -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);
+}
diff --git a/usr/src/uts/common/fs/sockfs/sockstr.c b/usr/src/uts/common/fs/sockfs/sockstr.c
index 6c148d71b6..3fd5a68c7f 100644
--- a/usr/src/uts/common/fs/sockfs/sockstr.c
+++ b/usr/src/uts/common/fs/sockfs/sockstr.c
@@ -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 @@ soflushconnind(struct sonode *so, t_scalar_t seqno)
}
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 @@ strsock_proto(vnode_t *vp, mblk_t *mp,
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 @@ strsock_proto(vnode_t *vp, mblk_t *mp,
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;
diff --git a/usr/src/uts/common/fs/sockfs/socktpi.c b/usr/src/uts/common/fs/sockfs/socktpi.c
index 6a5e48464e..126818ea53 100644
--- a/usr/src/uts/common/fs/sockfs/socktpi.c
+++ b/usr/src/uts/common/fs/sockfs/socktpi.c
@@ -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_lookup_addr(void *, t_uscalar_t);
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 @@ sotpi_create(vnode_t *accessvp, int domain, int type, int protocol, int version,
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 @@ sotpi_bindlisten(struct sonode *so, struct sockaddr *name,
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 @@ sotpi_bindlisten(struct sonode *so, struct sockaddr *name,
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 @@ sotpi_unbind(struct sonode *so, int flags)
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 @@ sotpi_unbind(struct sonode *so, int flags)
}
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 @@ sotpi_accept(struct sonode *so, int fflag, struct sonode **nsop)
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 @@ again:
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 @@ again:
}
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 @@ sostream_direct(struct sonode *so, struct uio *uiop, mblk_t *mp, cred_t *cr)
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 @@ sostream_direct(struct sonode *so, struct uio *uiop, mblk_t *mp, cred_t *cr)
* 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 @@ sostream_direct(struct sonode *so, struct uio *uiop, mblk_t *mp, cred_t *cr)
* 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;
diff --git a/usr/src/uts/common/fs/sockfs/sockvnops.c b/usr/src/uts/common/fs/sockfs/sockvnops.c
index 817e9b5968..bffc2ebc72 100644
--- a/usr/src/uts/common/fs/sockfs/sockvnops.c
+++ b/usr/src/uts/common/fs/sockfs/sockvnops.c
@@ -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 @@ socktpi_close(
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);
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index 23e3069934..e349fc265d 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -3068,6 +3068,7 @@ typedef void (*ipsq_func_t)(ipsq_t *, queue_t *, mblk_t *, void *);
#define SQTAG_UDP_INPUT 33
#define SQTAG_UDP_WPUT 34
#define SQTAG_UDP_OUTPUT 35
+#define SQTAG_TCP_KSSL_INPUT 36
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/inet/kssl/Makefile b/usr/src/uts/common/inet/kssl/Makefile
new file mode 100644
index 0000000000..47df45ba4a
--- /dev/null
+++ b/usr/src/uts/common/inet/kssl/Makefile
@@ -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)
diff --git a/usr/src/uts/common/inet/kssl/kssl.c b/usr/src/uts/common/inet/kssl/kssl.c
new file mode 100644
index 0000000000..9bd2d5dce4
--- /dev/null
+++ b/usr/src/uts/common/inet/kssl/kssl.c
@@ -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);
+}
diff --git a/usr/src/uts/common/inet/kssl/kssl.conf b/usr/src/uts/common/inet/kssl/kssl.conf
new file mode 100644
index 0000000000..4de42d8cb3
--- /dev/null
+++ b/usr/src/uts/common/inet/kssl/kssl.conf
@@ -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;
diff --git a/usr/src/uts/common/inet/kssl/kssl.h b/usr/src/uts/common/inet/kssl/kssl.h
new file mode 100644
index 0000000000..7aad23f521
--- /dev/null
+++ b/usr/src/uts/common/inet/kssl/kssl.h
@@ -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 */
diff --git a/usr/src/uts/common/inet/kssl/ksslapi.c b/usr/src/uts/common/inet/kssl/ksslapi.c
new file mode 100644
index 0000000000..89d461e4f4
--- /dev/null
+++ b/usr/src/uts/common/inet/kssl/ksslapi.c
@@ -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);
+}
diff --git a/usr/src/uts/common/inet/kssl/ksslapi.h b/usr/src/uts/common/inet/kssl/ksslapi.h
new file mode 100644
index 0000000000..f96febe587
--- /dev/null
+++ b/usr/src/uts/common/inet/kssl/ksslapi.h
@@ -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 */
diff --git a/usr/src/uts/common/inet/kssl/kssldebug.h b/usr/src/uts/common/inet/kssl/kssldebug.h
new file mode 100644
index 0000000000..28153fe164
--- /dev/null
+++ b/usr/src/uts/common/inet/kssl/kssldebug.h
@@ -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 */
diff --git a/usr/src/uts/common/inet/kssl/ksslimpl.h b/usr/src/uts/common/inet/kssl/ksslimpl.h
new file mode 100644
index 0000000000..6d22bd94de
--- /dev/null
+++ b/usr/src/uts/common/inet/kssl/ksslimpl.h
@@ -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 */
diff --git a/usr/src/uts/common/inet/kssl/ksslioctl.c b/usr/src/uts/common/inet/kssl/ksslioctl.c
new file mode 100644
index 0000000000..1c2f80aa93
--- /dev/null
+++ b/usr/src/uts/common/inet/kssl/ksslioctl.c
@@ -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);
+}
diff --git a/usr/src/uts/common/inet/kssl/ksslproto.h b/usr/src/uts/common/inet/kssl/ksslproto.h
new file mode 100644
index 0000000000..6286945534
--- /dev/null
+++ b/usr/src/uts/common/inet/kssl/ksslproto.h
@@ -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 */
diff --git a/usr/src/uts/common/inet/kssl/ksslrec.c b/usr/src/uts/common/inet/kssl/ksslrec.c
new file mode 100644
index 0000000000..5ee39fc2e5
--- /dev/null
+++ b/usr/src/uts/common/inet/kssl/ksslrec.c
@@ -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--;
+}
diff --git a/usr/src/uts/common/inet/tcp.h b/usr/src/uts/common/inet/tcp.h
index fbd594e6e6..1e38314815 100644
--- a/usr/src/uts/common/inet/tcp.h
+++ b/usr/src/uts/common/inet/tcp.h
@@ -40,6 +40,7 @@ extern "C" {
#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 @@ typedef struct tcp_s {
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);
diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c
index e89068125f..0df2dd56e2 100644
--- a/usr/src/uts/common/inet/tcp/tcp.c
+++ b/usr/src/uts/common/inet/tcp/tcp.c
@@ -94,6 +94,7 @@ const char tcp_version[] = "%Z%%M% %I% %E% SMI";
#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 @@ static void tcp_wput_proto(void *arg, mblk_t *mp, void *arg2);
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_disable(tcp_t *, mblk_t *);
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 @@ static uint_t tcp_next_port_to_try;
/* 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_cleanup(tcp_t *tcp)
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(queue_t *q, int flags)
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 @@ finish:
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_closei_local(tcp_t *tcp)
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 @@ tcp_closei_local(tcp_t *tcp)
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_conn_create_v6(conn_t *lconnp, conn_t *connp, mblk_t *mp,
}
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_conn_create_v4(conn_t *lconnp, conn_t *connp, ipha_t *ipha,
}
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 @@ tcp_reinit(tcp_t *tcp)
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 @@ tcp_reinit_values(tcp)
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 @@ tcp_maxpsz_set(tcp_t *tcp, boolean_t set_maxblk)
* 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 @@ tcp_rcv_drain(queue_t *q, tcp_t *tcp)
#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 @@ tcp_rput_data(void *arg, mblk_t *mp, void *arg2)
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 @@ process_ack:
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 @@ swnd_update:
}
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 @@ est:
* 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 @@ est:
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 @@ est:
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 @@ tcp_wput_nondata(void *arg, mblk_t *mp, void *arg2)
* 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_accept_finish(void *arg, mblk_t *mp, void *arg2)
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 @@ tcp_wput_accept(queue_t *q, mblk_t *mp)
* 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_wput_accept(queue_t *q, mblk_t *mp)
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 @@ tcp_wput_proto(void *arg, mblk_t *mp, void *arg2)
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);
diff --git a/usr/src/uts/common/inet/tcp/tcp_kssl.c b/usr/src/uts/common/inet/tcp/tcp_kssl.c
new file mode 100644
index 0000000000..74022fcef6
--- /dev/null
+++ b/usr/src/uts/common/inet/tcp/tcp_kssl.c
@@ -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);
+ }
+}
diff --git a/usr/src/uts/common/io/stream.c b/usr/src/uts/common/io/stream.c
index 9baaebd365..e83cd37804 100644
--- a/usr/src/uts/common/io/stream.c
+++ b/usr/src/uts/common/io/stream.c
@@ -542,6 +542,9 @@ dblk_lastfree(mblk_t *mp, dblk_t *dbp)
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);
}
diff --git a/usr/src/uts/common/io/strsun.c b/usr/src/uts/common/io/strsun.c
index 87f0eeaa60..23389c0380 100644
--- a/usr/src/uts/common/io/strsun.c
+++ b/usr/src/uts/common/io/strsun.c
@@ -253,6 +253,7 @@ mcopyinuio(struct stdata *stp, uio_t *uiop, ssize_t iosize,
{
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 @@ mcopyinuio(struct stdata *stp, uio_t *uiop, ssize_t iosize,
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);
}
diff --git a/usr/src/uts/common/os/streamio.c b/usr/src/uts/common/os/streamio.c
index 0b0ac98ca4..ab61c5896b 100644
--- a/usr/src/uts/common/os/streamio.c
+++ b/usr/src/uts/common/os/streamio.c
@@ -370,6 +370,7 @@ ckreturn:
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 @@ strrput_nondata(queue_t *q, mblk_t *bp)
}
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 @@ strdoioctl(
/*
* 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 @@ retry:
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);
diff --git a/usr/src/uts/common/os/strsubr.c b/usr/src/uts/common/os/strsubr.c
index 16dad7e4bb..54fe307e47 100644
--- a/usr/src/uts/common/os/strsubr.c
+++ b/usr/src/uts/common/os/strsubr.c
@@ -2836,6 +2836,8 @@ strmakedata(
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 @@ strmakedata(
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 @@ strmakedata(
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 @@ strmakedata(
return (error);
}
}
+ 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;
+ }
}
- bp->b_wptr += size;
count -= size;
if (mp == NULL)
@@ -3238,6 +3254,7 @@ shalloc(queue_t *qp)
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 @@ shalloc(queue_t *qp)
stp->sd_nqueues = 0;
stp->sd_svcflags = 0;
stp->sd_copyflag = 0;
+
return (stp);
}
@@ -7975,6 +7993,19 @@ strsetwputhooks(vnode_t *vp, uint_t flags, clock_t closetime)
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)
diff --git a/usr/src/uts/common/sys/socketvar.h b/usr/src/uts/common/sys/socketvar.h
index 7bcb924d7d..5e75bd36aa 100644
--- a/usr/src/uts/common/sys/socketvar.h
+++ b/usr/src/uts/common/sys/socketvar.h
@@ -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 @@ struct sonode {
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 */
diff --git a/usr/src/uts/common/sys/stream.h b/usr/src/uts/common/sys/stream.h
index 3c7b9e685c..739d5b264a 100644
--- a/usr/src/uts/common/sys/stream.h
+++ b/usr/src/uts/common/sys/stream.h
@@ -376,6 +376,7 @@ typedef struct bcache {
* 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 @@ struct stroptions {
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 @@ struct stroptions {
#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
/*
diff --git a/usr/src/uts/common/sys/strsubr.h b/usr/src/uts/common/sys/strsubr.h
index f907db2c06..27403d72cc 100644
--- a/usr/src/uts/common/sys/strsubr.h
+++ b/usr/src/uts/common/sys/strsubr.h
@@ -83,6 +83,7 @@ extern "C" {
* sd_sidp
* sd_pgidp
* sd_wroff
+ * sd_tail
* sd_rerror
* sd_werror
* sd_pushcnt
@@ -181,6 +182,7 @@ typedef struct stdata {
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 @@ typedef struct stdata {
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 strseteof(vnode_t *, int);
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);
diff --git a/usr/src/uts/common/sys/strsun.h b/usr/src/uts/common/sys/strsun.h
index bad5ec5bd6..6b56681d2d 100644
--- a/usr/src/uts/common/sys/strsun.h
+++ b/usr/src/uts/common/sys/strsun.h
@@ -46,6 +46,7 @@ extern "C" {
#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)
diff --git a/usr/src/uts/common/sys/tihdr.h b/usr/src/uts/common/sys/tihdr.h
index 56e33384fa..005a96e346 100644
--- a/usr/src/uts/common/sys/tihdr.h
+++ b/usr/src/uts/common/sys/tihdr.h
@@ -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 @@ extern "C" {
#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 @@ extern "C" {
#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 */
/*
diff --git a/usr/src/uts/common/syscall/sendfile.c b/usr/src/uts/common/syscall/sendfile.c
index 04bbd99f65..681cb4b686 100644
--- a/usr/src/uts/common/syscall/sendfile.c
+++ b/usr/src/uts/common/syscall/sendfile.c
@@ -89,6 +89,7 @@ kstrwritemp(struct vnode *vp, mblk_t *mp, ushort_t fmode)
{
struct stdata *stp;
struct queue *wqp;
+ mblk_t *newmp;
char waitflag;
int tempmode;
int error = 0;
@@ -137,6 +138,15 @@ kstrwritemp(struct vnode *vp, mblk_t *mp, ushort_t fmode)
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 @@ sendvec_small_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv,
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 @@ sendvec_small_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv,
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 @@ sendvec_small_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv,
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 @@ sendvec_small_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv,
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 @@ sendvec_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv,
#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 @@ sendvec_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv,
/*
* 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 @@ sendvec_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv,
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 @@ sendvec_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv,
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 @@ sendfilev(int opcode, int fildes, const struct sendfilevec *vec, int sfvcnt,
}
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;
diff --git a/usr/src/uts/intel/Makefile.intel b/usr/src/uts/intel/Makefile.intel
index e535fc2a40..d6a2fc4c30 100644
--- a/usr/src/uts/intel/Makefile.intel
+++ b/usr/src/uts/intel/Makefile.intel
@@ -249,6 +249,7 @@ DRV_KMODS += llc2
DRV_KMODS += lofi
DRV_KMODS += log
DRV_KMODS += logindmux
+DRV_KMODS += kssl
DRV_KMODS += mm
DRV_KMODS += mouse8042
DRV_KMODS += mpt
diff --git a/usr/src/uts/intel/ia32/ml/modstubs.s b/usr/src/uts/intel/ia32/ml/modstubs.s
index d77ddd912b..3f78ef11db 100644
--- a/usr/src/uts/intel/ia32/ml/modstubs.s
+++ b/usr/src/uts/intel/ia32/ml/modstubs.s
@@ -922,6 +922,7 @@ fcnname/**/_info: \
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 @@ fcnname/**/_info: \
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)
diff --git a/usr/src/uts/intel/kssl/Makefile b/usr/src/uts/intel/kssl/Makefile
new file mode 100644
index 0000000000..3baa5f673a
--- /dev/null
+++ b/usr/src/uts/intel/kssl/Makefile
@@ -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
diff --git a/usr/src/uts/intel/os/minor_perm b/usr/src/uts/intel/os/minor_perm
index 4d7aa42b6c..6a591a9f6c 100644
--- a/usr/src/uts/intel/os/minor_perm
+++ b/usr/src/uts/intel/os/minor_perm
@@ -116,3 +116,4 @@ smbios:smbios 0444 root sys
zfs:* 0600 root sys
zfs:zfs 0666 root sys
scsi_vhci:* 0666 root sys
+kssl:* 0666 root sys
diff --git a/usr/src/uts/intel/os/name_to_major b/usr/src/uts/intel/os/name_to_major
index 77b634d1af..72b3a3ab6f 100644
--- a/usr/src/uts/intel/os/name_to_major
+++ b/usr/src/uts/intel/os/name_to_major
@@ -118,4 +118,5 @@ power 181
zfs 182
npe 183
pcie_pci 184
+kssl 185
did 239
diff --git a/usr/src/uts/sparc/Makefile.sparc b/usr/src/uts/sparc/Makefile.sparc
index e429686ae0..cd199deb72 100644
--- a/usr/src/uts/sparc/Makefile.sparc
+++ b/usr/src/uts/sparc/Makefile.sparc
@@ -223,7 +223,7 @@ DRV_KMODS += dtrace fasttrap fbt lockstat profile sdt systrace
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
diff --git a/usr/src/uts/sparc/kssl/Makefile b/usr/src/uts/sparc/kssl/Makefile
new file mode 100644
index 0000000000..c07e86e89d
--- /dev/null
+++ b/usr/src/uts/sparc/kssl/Makefile
@@ -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
diff --git a/usr/src/uts/sparc/ml/modstubs.s b/usr/src/uts/sparc/ml/modstubs.s
index 599658a635..d902d7787d 100644
--- a/usr/src/uts/sparc/ml/modstubs.s
+++ b/usr/src/uts/sparc/ml/modstubs.s
@@ -853,6 +853,7 @@ stubs_base:
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 @@ stubs_base:
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
diff --git a/usr/src/uts/sparc/os/minor_perm b/usr/src/uts/sparc/os/minor_perm
index 07c11962eb..a60739e783 100644
--- a/usr/src/uts/sparc/os/minor_perm
+++ b/usr/src/uts/sparc/os/minor_perm
@@ -165,3 +165,4 @@ ntwdt:* 0644 root sys
zfs:* 0600 root sys
zfs:zfs 0666 root sys
scsi_vhci:* 0666 root sys
+kssl:* 0666 root sys
diff --git a/usr/src/uts/sparc/os/name_to_major b/usr/src/uts/sparc/os/name_to_major
index 055dced312..310ed2ac7f 100644
--- a/usr/src/uts/sparc/os/name_to_major
+++ b/usr/src/uts/sparc/os/name_to_major
@@ -204,3 +204,4 @@ zfs 253
i8042 254
kb8042 255
mouse8042 256
+kssl 257