summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjohnz <none@none>2007-10-05 14:39:44 -0700
committerjohnz <none@none>2007-10-05 14:39:44 -0700
commitdf8bdeb362277e8d95a74d6c097341fe97409948 (patch)
treee17a7e8f36d19701153abab9087e6770576cecb2
parente5819b60c39cd7dfc3604fd88187c257625b42d0 (diff)
downloadillumos-joyent-df8bdeb362277e8d95a74d6c097341fe97409948.tar.gz
6592898 open elfsign, libelfsign
-rw-r--r--usr/src/Makefile2
-rw-r--r--usr/src/Makefile.lint2
-rw-r--r--usr/src/cmd/cmd-crypto/Makefile4
-rw-r--r--usr/src/cmd/cmd-crypto/elfsign/Makefile55
-rw-r--r--usr/src/cmd/cmd-crypto/elfsign/elfsign.c1441
-rw-r--r--usr/src/lib/Makefile10
-rw-r--r--usr/src/lib/libelfsign/Makefile70
-rw-r--r--usr/src/lib/libelfsign/Makefile.com63
-rw-r--r--usr/src/lib/libelfsign/README38
-rw-r--r--usr/src/lib/libelfsign/common/elfcertlib.c644
-rw-r--r--usr/src/lib/libelfsign/common/elfsignlib.c1598
-rw-r--r--usr/src/lib/libelfsign/common/libelfsign.h194
-rw-r--r--usr/src/lib/libelfsign/common/llib-lelfsign32
-rw-r--r--usr/src/lib/libelfsign/common/mapfile.map62
-rw-r--r--usr/src/lib/libelfsign/i386/Makefile35
-rw-r--r--usr/src/lib/libelfsign/sparc/Makefile33
-rw-r--r--usr/src/pkgdefs/etc/exception_list_i3861
-rw-r--r--usr/src/pkgdefs/etc/exception_list_sparc1
-rw-r--r--usr/src/tools/Makefile19
-rw-r--r--usr/src/tools/elfsign/Makefile88
-rw-r--r--usr/src/tools/elfsign/elfsigncmp.sh114
-rw-r--r--usr/src/tools/elfsign/inc.flg34
-rw-r--r--usr/src/uts/common/sys/crypto/elfsign.h81
23 files changed, 4519 insertions, 102 deletions
diff --git a/usr/src/Makefile b/usr/src/Makefile
index 939309b811..4183c65613 100644
--- a/usr/src/Makefile
+++ b/usr/src/Makefile
@@ -243,7 +243,6 @@ EXPORT_SRC:
@cd lib/gss_mechs/mech_krb5; pwd; $(MAKE) EXPORT_SRC
@cd lib/gss_mechs/mech_spnego; pwd; $(MAKE) EXPORT_SRC
@cd lib/libcrypt; pwd; $(MAKE) EXPORT_SRC
- @cd $(CLOSED)/lib/libelfsign; pwd; $(MAKE) EXPORT_SRC
@cd lib/libgss; pwd; $(MAKE) EXPORT_SRC
@cd $(CLOSED)/lib/libike; pwd; $(MAKE) EXPORT_SRC
@cd lib/libnsl; pwd; $(MAKE) EXPORT_SRC
@@ -316,7 +315,6 @@ CRYPT_SRC:
@cd lib/gss_mechs/mech_dh/backend; pwd; $(MAKE) CRYPT_SRC
@cd lib/gss_mechs/mech_krb5; pwd; $(MAKE) CRYPT_SRC
@cd lib/gss_mechs/mech_spnego; pwd; $(MAKE) CRYPT_SRC
- @cd $(CLOSED)/lib/libelfsign; pwd; $(MAKE) CRYPT_SRC
@cd $(CLOSED)/lib/libike; pwd; $(MAKE) CRYPT_SRC
@cd lib/libnsl; pwd; $(MAKE) CRYPT_SRC
@cd lib/libsasl; pwd; $(MAKE) CRYPT_SRC
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint
index 4da8cc8309..fb62aad36b 100644
--- a/usr/src/Makefile.lint
+++ b/usr/src/Makefile.lint
@@ -329,6 +329,7 @@ COMMON_SUBDIRS = \
lib/libdoor \
lib/libdtrace \
lib/libefi \
+ lib/libelfsign \
lib/libexacct \
lib/libgen \
lib/libgss \
@@ -423,7 +424,6 @@ $(CLOSED_BUILD)COMMON_SUBDIRS += \
$(CLOSED)/cmd/tail \
$(CLOSED)/cmd/tr \
$(CLOSED)/lib/libc_i18n \
- $(CLOSED)/lib/libelfsign \
$(CLOSED)/lib/smartcard
i386_SUBDIRS= \
diff --git a/usr/src/cmd/cmd-crypto/Makefile b/usr/src/cmd/cmd-crypto/Makefile
index a046256e8a..05646720de 100644
--- a/usr/src/cmd/cmd-crypto/Makefile
+++ b/usr/src/cmd/cmd-crypto/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -31,11 +31,11 @@ SUBDIRS1 = \
cryptoadm \
decrypt \
digest \
+ elfsign \
pktool \
kmfcfg
$(CLOSED_BUILD)SUBDIRS1 += \
- $(CLOSED)/cmd/cmd-crypto/elfsign \
$(CLOSED)/cmd/cmd-crypto/kcfd
SUBDIRS2 = \
diff --git a/usr/src/cmd/cmd-crypto/elfsign/Makefile b/usr/src/cmd/cmd-crypto/elfsign/Makefile
new file mode 100644
index 0000000000..edaaf597b7
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/elfsign/Makefile
@@ -0,0 +1,55 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG = elfsign
+
+OBJS = elfsign.o
+
+SRCS = $(OBJS:.o=.c)
+
+include $(SRC)/cmd/Makefile.cmd
+
+CFLAGS += $(CCVERBOSE)
+
+LDLIBS += -lkmf -lelfsign -lcryptoutil
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(DYNFLAGS)
+ $(POST_PROCESS)
+
+install: all $(ROOTPROG)
+
+clean:
+ $(RM) -f $(OBJS) $(PROG)
+
+lint: lint_SRCS
+
+include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/cmd/cmd-crypto/elfsign/elfsign.c b/usr/src/cmd/cmd-crypto/elfsign/elfsign.c
new file mode 100644
index 0000000000..1ee38b28eb
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/elfsign/elfsign.c
@@ -0,0 +1,1441 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Developer command for adding the signature section to an ELF object
+ * PSARC 2001/488
+ *
+ * DEBUG Information:
+ * This command uses the cryptodebug() function from libcryptoutil.
+ * Set SUNW_CRYPTO_DEBUG to stderr or syslog for all debug to go to auth.debug
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <locale.h>
+#include <errno.h>
+#include <strings.h>
+#include <langinfo.h>
+
+#include <cryptoutil.h>
+#include <sys/crypto/elfsign.h>
+#include <libelfsign.h>
+
+#include <kmfapi.h>
+
+#define SIGN "sign"
+#define SIGN_OPTS "ac:e:F:k:P:T:v"
+#define VERIFY "verify"
+#define VERIFY_OPTS "c:e:v"
+#define REQUEST "request"
+#define REQUEST_OPTS "i:k:r:T:"
+#define LIST "list"
+#define LIST_OPTS "c:e:f:"
+
+enum cmd_e {
+ ES_SIGN,
+ ES_VERIFY,
+ ES_REQUEST,
+ ES_LIST
+};
+
+enum field_e {
+ FLD_UNKNOWN,
+ FLD_SUBJECT,
+ FLD_ISSUER,
+ FLD_FORMAT,
+ FLD_SIGNER,
+ FLD_TIME
+};
+
+#define MIN_ARGS 3 /* The minimum # args to do anything */
+#define ES_DEFAULT_KEYSIZE 1024
+
+static struct {
+ enum cmd_e cmd; /* sub command: sign | verify | request */
+ char *cert; /* -c <certificate_file> | */
+ /* -r <certificate_request_file> */
+ char **elfobj; /* -e <elf_object> */
+ int elfcnt;
+ enum ES_ACTION es_action;
+ ELFsign_t ess; /* libelfsign opaque "state" */
+ int extracnt;
+ enum field_e field; /* -f <field> */
+ char internal_req; /* Sun internal certificate request */
+ char *pinpath; /* -P <pin> */
+ char *privpath; /* -k <private_key> */
+ char *token_label; /* -T <token_label> */
+ boolean_t verbose; /* chatty output */
+} cmd_info;
+
+enum ret_e {
+ EXIT_OKAY,
+ EXIT_INVALID_ARG,
+ EXIT_VERIFY_FAILED,
+ EXIT_CANT_OPEN_ELF_OBJECT,
+ EXIT_BAD_CERT,
+ EXIT_BAD_PRIVATEKEY,
+ EXIT_SIGN_FAILED,
+ EXIT_VERIFY_FAILED_UNSIGNED,
+ EXIT_CSR_FAILED,
+ EXIT_MEMORY_ERROR
+};
+
+struct field_s {
+ char *name;
+ enum field_e field;
+} fields[] = {
+ { "subject", FLD_SUBJECT },
+ { "issuer", FLD_ISSUER },
+ { "format", FLD_FORMAT },
+ { "signer", FLD_SIGNER },
+ { "time", FLD_TIME },
+ NULL, 0
+};
+
+typedef enum ret_e ret_t;
+
+static void usage(void);
+static ret_t getelfobj(char *);
+static char *getpin(void);
+static ret_t do_sign(char *);
+static ret_t do_verify(char *);
+static ret_t do_cert_request(char *);
+static ret_t do_gen_esa(char *);
+static ret_t do_list(char *);
+static void es_error(const char *fmt, ...);
+static char *time_str(time_t t);
+static void sig_info_print(struct ELFsign_sig_info *esip);
+
+int
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ char *scmd = NULL;
+ char *opts; /* The set of flags for cmd */
+ int errflag = 0; /* We had an options parse error */
+ char c; /* current getopts flag */
+ ret_t (*action)(char *); /* Function pointer for the action */
+ ret_t ret;
+
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN) /* Should be defiend by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ cryptodebug_init("elfsign");
+
+ if (argc < MIN_ARGS) {
+ es_error(gettext("invalid number of arguments"));
+ usage();
+ return (EXIT_INVALID_ARG);
+ }
+
+ scmd = argv[1];
+ cmd_info.cert = NULL;
+ cmd_info.elfobj = NULL;
+ cmd_info.elfcnt = 0;
+ cmd_info.es_action = ES_GET;
+ cmd_info.ess = NULL;
+ cmd_info.extracnt = 0;
+ cmd_info.field = FLD_UNKNOWN;
+ cmd_info.internal_req = '\0';
+ cmd_info.pinpath = NULL;
+ cmd_info.privpath = NULL;
+ cmd_info.token_label = NULL;
+ cmd_info.verbose = B_FALSE;
+
+ if (strcmp(scmd, SIGN) == 0) {
+ cmd_info.cmd = ES_SIGN;
+ opts = SIGN_OPTS;
+ cryptodebug("cmd=sign opts=%s", opts);
+ action = do_sign;
+ cmd_info.es_action = ES_UPDATE_RSA_SHA1;
+ } else if (strcmp(scmd, VERIFY) == 0) {
+ cmd_info.cmd = ES_VERIFY;
+ opts = VERIFY_OPTS;
+ cryptodebug("cmd=verify opts=%s", opts);
+ action = do_verify;
+ } else if (strcmp(scmd, REQUEST) == 0) {
+ cmd_info.cmd = ES_REQUEST;
+ opts = REQUEST_OPTS;
+ cryptodebug("cmd=request opts=%s", opts);
+ action = do_cert_request;
+ } else if (strcmp(scmd, LIST) == 0) {
+ cmd_info.cmd = ES_LIST;
+ opts = LIST_OPTS;
+ cryptodebug("cmd=list opts=%s", opts);
+ action = do_list;
+ } else {
+ es_error(gettext("Unknown sub-command: %s"),
+ scmd);
+ usage();
+ return (EXIT_INVALID_ARG);
+ }
+
+ /*
+ * Note: There is no need to check that optarg isn't NULL
+ * because getopt does that for us.
+ */
+ while (!errflag && (c = getopt(argc - 1, argv + 1, opts)) != EOF) {
+ if (strchr("ceFihkPr", c) != NULL)
+ cryptodebug("c=%c, '%s'", c, optarg);
+ else
+ cryptodebug("c=%c", c);
+
+ switch (c) {
+ case 'a':
+ /* not a normal sign operation, change the action */
+ cmd_info.es_action = ES_GET;
+ action = do_gen_esa;
+ break;
+ case 'c':
+ cmd_info.cert = optarg;
+ break;
+ case 'e':
+ cmd_info.elfcnt++;
+ cmd_info.elfobj = (char **)realloc(cmd_info.elfobj,
+ sizeof (char *) * cmd_info.elfcnt);
+ if (cmd_info.elfobj == NULL) {
+ es_error(gettext(
+ "Too many elf objects specified."));
+ return (EXIT_INVALID_ARG);
+ }
+ cmd_info.elfobj[cmd_info.elfcnt - 1] = optarg;
+ break;
+ case 'f':
+ {
+ struct field_s *fp;
+ cmd_info.field = FLD_UNKNOWN;
+ for (fp = fields; fp->name != NULL; fp++) {
+ if (strcasecmp(optarg, fp->name) == 0) {
+ cmd_info.field = fp->field;
+ break;
+ }
+ }
+ if (cmd_info.field == FLD_UNKNOWN) {
+ cryptodebug("Invalid field option");
+ errflag++;
+ }
+ }
+ break;
+ case 'F':
+ if (strcasecmp(optarg, ES_FMT_RSA_MD5_SHA1) == 0)
+ cmd_info.es_action = ES_UPDATE_RSA_MD5_SHA1;
+ else if (strcasecmp(optarg, ES_FMT_RSA_SHA1) == 0)
+ cmd_info.es_action = ES_UPDATE_RSA_SHA1;
+ else {
+ cryptodebug("Invalid format option");
+ errflag++;
+ }
+ break;
+ case 'i': /* Undocumented internal Sun use only */
+ cmd_info.internal_req = *optarg;
+ break;
+ case 'k':
+ cmd_info.privpath = optarg;
+ if (cmd_info.token_label != NULL ||
+ cmd_info.pinpath != NULL)
+ errflag++;
+ break;
+ case 'P':
+ cmd_info.pinpath = optarg;
+ if (cmd_info.privpath != NULL)
+ errflag++;
+ break;
+ case 'r':
+ cmd_info.cert = optarg;
+ break;
+ case 'T':
+ cmd_info.token_label = optarg;
+ if (cmd_info.privpath != NULL)
+ errflag++;
+ break;
+ case 'v':
+ cmd_info.verbose = B_TRUE;
+ break;
+ default:
+ errflag++;
+ }
+ }
+
+ optind++; /* we skipped over subcommand */
+ cmd_info.extracnt = argc - optind;
+
+ if (cmd_info.extracnt != 0 &&
+ cmd_info.cmd != ES_SIGN && cmd_info.cmd != ES_VERIFY) {
+ cryptodebug("Extra arguments, optind=%d, argc=%d",
+ optind, argc);
+ errflag++;
+ }
+
+ switch (cmd_info.cmd) {
+ case ES_VERIFY:
+ if (cmd_info.elfcnt + argc - optind == 0) {
+ cryptodebug("Missing elfobj");
+ errflag++;
+ }
+ break;
+
+ case ES_SIGN:
+ if (((cmd_info.privpath == NULL) &&
+ (cmd_info.token_label == NULL)) ||
+ (cmd_info.cert == NULL) ||
+ (cmd_info.elfcnt + argc - optind == 0)) {
+ cryptodebug("Missing privpath|token_label/cert/elfobj");
+ errflag++;
+ }
+ break;
+
+ case ES_REQUEST:
+ if (((cmd_info.privpath == NULL) &&
+ (cmd_info.token_label == NULL)) ||
+ (cmd_info.cert == NULL)) {
+ cryptodebug("Missing privpath|token_label/certreq");
+ errflag++;
+ }
+ break;
+ case ES_LIST:
+ if ((cmd_info.cert != NULL) == (cmd_info.elfcnt > 0)) {
+ cryptodebug("Neither or both of cert/elfobj");
+ errflag++;
+ }
+ break;
+ }
+
+ if (errflag) {
+ usage();
+ return (EXIT_INVALID_ARG);
+ }
+
+ switch (cmd_info.cmd) {
+ case ES_REQUEST:
+ case ES_LIST:
+ ret = action(NULL);
+ break;
+ default:
+ {
+ int i;
+ ret_t iret;
+
+ ret = EXIT_OKAY;
+ iret = EXIT_OKAY;
+ for (i = 0; i < cmd_info.elfcnt &&
+ (ret == EXIT_OKAY || cmd_info.cmd != ES_SIGN); i++) {
+ iret = action(cmd_info.elfobj[i]);
+ if (iret > ret)
+ ret = iret;
+ }
+ for (i = optind; i < argc &&
+ (ret == EXIT_OKAY || cmd_info.cmd != ES_SIGN); i++) {
+ iret = action(argv[i]);
+ if (iret > ret)
+ ret = iret;
+ }
+ break;
+ }
+ }
+
+ if (cmd_info.elfobj != NULL)
+ free(cmd_info.elfobj);
+
+ return (ret);
+}
+
+
+static void
+usage(void)
+{
+/* BEGIN CSTYLED */
+ (void) fprintf(stderr, gettext(
+ "usage:\n"
+ "\telfsign sign [-a] [-v] [-e <elf_object>] -c <certificate_file>\n"
+ "\t\t[-F <format>] -k <private_key_file> [elf_object]..."
+ "\n"
+ "\telfsign sign [-a] [-v] [-e <elf_object>] -c <certificate_file>\n"
+ "\t\t[-F <format>] -T <token_label> [-P <pin_file>] [elf_object]..."
+ "\n\n"
+ "\telfsign verify [-v] [-c <certificate_file>] [-e <elf_object>]\n"
+ "\t\t[elf_object]..."
+ "\n\n"
+ "\telfsign request -r <certificate_request_file> -k <private_key_file>"
+ "\n"
+ "\telfsign request -r <certificate_request_file> -T <token_label>"
+ "\n\n"
+ "\telfsign list -f field -c <certificate_file>"
+ "\n"
+ "\telfsign list -f field -e <elf_object>"
+ "\n"));
+/* END CSTYLED */
+}
+
+static ret_t
+getelfobj(char *elfpath)
+{
+ ELFsign_status_t estatus;
+ ret_t ret;
+
+ estatus = elfsign_begin(elfpath, cmd_info.es_action, &(cmd_info.ess));
+ switch (estatus) {
+ case ELFSIGN_SUCCESS:
+ case ELFSIGN_RESTRICTED:
+ ret = EXIT_OKAY;
+ break;
+ case ELFSIGN_INVALID_ELFOBJ:
+ es_error(gettext(
+ "Unable to open %s as an ELF object."),
+ elfpath);
+ ret = EXIT_CANT_OPEN_ELF_OBJECT;
+ break;
+ default:
+ es_error(gettext("unexpected failure: %d"), estatus);
+ if (cmd_info.cmd == ES_SIGN) {
+ ret = EXIT_SIGN_FAILED;
+ } else if (cmd_info.cmd == ES_VERIFY) {
+ ret = EXIT_VERIFY_FAILED;
+ }
+ }
+
+ return (ret);
+}
+
+static ret_t
+setcertpath(void)
+{
+ ELFsign_status_t estatus;
+ ret_t ret;
+
+ if (cmd_info.cert == NULL)
+ return (EXIT_OKAY);
+ estatus = elfsign_setcertpath(cmd_info.ess, cmd_info.cert);
+ switch (estatus) {
+ case ELFSIGN_SUCCESS:
+ ret = EXIT_OKAY;
+ break;
+ case ELFSIGN_INVALID_CERTPATH:
+ if (cmd_info.cert != NULL) {
+ es_error(gettext("Unable to open %s as a certificate."),
+ cmd_info.cert);
+ }
+ ret = EXIT_BAD_CERT;
+ break;
+ default:
+ es_error(gettext("unusable certificate: %d"), cmd_info.cert);
+ if (cmd_info.cmd == ES_SIGN) {
+ ret = EXIT_SIGN_FAILED;
+ } else if (cmd_info.cmd == ES_VERIFY) {
+ ret = EXIT_VERIFY_FAILED;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * getpin - return pointer to token PIN in static storage
+ */
+static char *
+getpin(void)
+{
+ static char pinbuf[PASS_MAX + 1];
+ char *pp;
+ FILE *pinfile;
+
+ if (cmd_info.pinpath == NULL)
+ return (getpassphrase(
+ gettext("Enter PIN for PKCS#11 token: ")));
+ if ((pinfile = fopen(cmd_info.pinpath, "r")) == NULL) {
+ es_error(gettext("failed to open %s."),
+ cmd_info.pinpath);
+ return (NULL);
+ }
+
+ pp = fgets(pinbuf, sizeof (pinbuf), pinfile);
+ (void) fclose(pinfile);
+ if (pp == NULL) {
+ es_error(gettext("failed to read PIN from %s."),
+ cmd_info.pinpath);
+ return (NULL);
+ }
+ pp = &pinbuf[strlen(pinbuf) - 1];
+ if (*pp == '\n')
+ *pp = '\0';
+ return (pinbuf);
+}
+
+/*
+ * Add the .SUNW_signature sections for the ELF signature
+ */
+static ret_t
+do_sign(char *object)
+{
+ ret_t ret;
+ ELFsign_status_t elfstat;
+ struct filesignatures *fssp = NULL;
+ size_t fs_len;
+ uchar_t sig[SIG_MAX_LENGTH];
+ size_t sig_len = SIG_MAX_LENGTH;
+ uchar_t hash[SIG_MAX_LENGTH];
+ size_t hash_len = SIG_MAX_LENGTH;
+ ELFCert_t cert = NULL;
+ char *dn;
+ size_t dn_len;
+
+ cryptodebug("do_sign");
+ if ((ret = getelfobj(object)) != EXIT_OKAY)
+ return (ret);
+
+ if (cmd_info.token_label &&
+ !elfcertlib_settoken(cmd_info.ess, cmd_info.token_label)) {
+ elfsign_end(cmd_info.ess);
+ es_error(gettext("Unable to access token: %s"),
+ cmd_info.token_label);
+ ret = EXIT_SIGN_FAILED;
+ goto cleanup;
+ }
+
+ if ((ret = setcertpath()) != EXIT_OKAY)
+ goto cleanup;
+
+ if (!elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, &cert,
+ cmd_info.es_action)) {
+ es_error(gettext("Unable to load certificate: %s"),
+ cmd_info.cert);
+ ret = EXIT_BAD_CERT;
+ goto cleanup;
+ }
+
+ if (cmd_info.privpath != NULL) {
+ if (!elfcertlib_loadprivatekey(cmd_info.ess, cert,
+ cmd_info.privpath)) {
+ es_error(gettext("Unable to load private key: %s"),
+ cmd_info.privpath);
+ ret = EXIT_BAD_PRIVATEKEY;
+ goto cleanup;
+ }
+ } else {
+ char *pin = getpin();
+ if (pin == NULL) {
+ es_error(gettext("Unable to get PIN"));
+ ret = EXIT_BAD_PRIVATEKEY;
+ goto cleanup;
+ }
+ if (!elfcertlib_loadtokenkey(cmd_info.ess, cert,
+ cmd_info.token_label, pin)) {
+ es_error(gettext("Unable to access private key "
+ "in token %s"), cmd_info.token_label);
+ ret = EXIT_BAD_PRIVATEKEY;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Get the DN from the certificate.
+ */
+ if ((dn = elfcertlib_getdn(cert)) == NULL) {
+ es_error(gettext("Unable to find DN in certificate %s"),
+ cmd_info.cert);
+ ret = EXIT_SIGN_FAILED;
+ goto cleanup;
+ }
+ dn_len = strlen(dn);
+ cryptodebug("DN = %s", dn);
+
+ elfstat = elfsign_signatures(cmd_info.ess, &fssp, &fs_len, ES_GET);
+ if (elfstat != ELFSIGN_SUCCESS) {
+ if (elfstat != ELFSIGN_NOTSIGNED) {
+ es_error(gettext("Unable to retrieve existing "
+ "signature block in %s"), object);
+ ret = EXIT_SIGN_FAILED;
+ goto cleanup;
+ }
+ fssp = NULL;
+ /*
+ * force creation and naming of signature section
+ * so the hash doesn't change
+ */
+ if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len,
+ cmd_info.es_action) != ELFSIGN_SUCCESS) {
+ es_error(gettext("Unable to insert "
+ "signature block into %s"), object);
+ ret = EXIT_SIGN_FAILED;
+ goto cleanup;
+ }
+ }
+
+ bzero(hash, sizeof (hash));
+ if (elfsign_hash(cmd_info.ess, hash, &hash_len) != ELFSIGN_SUCCESS) {
+ es_error(gettext("Unable to calculate hash of ELF object %s"),
+ object);
+ ret = EXIT_SIGN_FAILED;
+ goto cleanup;
+ }
+
+ bzero(sig, sizeof (sig));
+ if (!elfcertlib_sign(cmd_info.ess, cert,
+ hash, hash_len, sig, &sig_len)) {
+ es_error(gettext("Unable to sign %s using key from %s"),
+ object, cmd_info.privpath ?
+ cmd_info.privpath : cmd_info.token_label);
+ ret = EXIT_SIGN_FAILED;
+ goto cleanup;
+ }
+
+ { /* DEBUG START */
+ const int sigstr_len = sizeof (char) * sig_len * 2 + 1;
+ char *sigstr = malloc(sigstr_len);
+
+ tohexstr(sig, sig_len, sigstr, sigstr_len);
+ cryptodebug("sig value is: %s", sigstr);
+ free(sigstr);
+ } /* DEBUG END */
+
+ fssp = elfsign_insert_dso(cmd_info.ess, fssp,
+ dn, dn_len, sig, sig_len, NULL, 0);
+ if (fssp == NULL) {
+ es_error(gettext("Unable to prepare signature for %s"),
+ object);
+ ret = EXIT_SIGN_FAILED;
+ goto cleanup;
+ }
+ if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len,
+ cmd_info.es_action) != ELFSIGN_SUCCESS) {
+ es_error(gettext("Unable to update %s: with signature"),
+ object);
+ ret = EXIT_SIGN_FAILED;
+ goto cleanup;
+ }
+ if (cmd_info.verbose || (cmd_info.elfcnt + cmd_info.extracnt) > 1) {
+ (void) fprintf(stdout,
+ gettext("elfsign: %s signed successfully.\n"),
+ object);
+ }
+ if (cmd_info.verbose) {
+ struct ELFsign_sig_info *esip;
+
+ if (elfsign_sig_info(fssp, &esip)) {
+ sig_info_print(esip);
+ elfsign_sig_info_free(esip);
+ }
+ }
+
+ ret = EXIT_OKAY;
+
+cleanup:
+ free(fssp);
+ bzero(sig, sig_len);
+ bzero(hash, hash_len);
+
+ if (cert != NULL)
+ elfcertlib_releasecert(cmd_info.ess, cert);
+ if (cmd_info.ess != NULL)
+ elfsign_end(cmd_info.ess);
+
+ return (ret);
+}
+
+#define ESA_ERROR(str, esa_file) { \
+ int realerrno = errno; \
+ es_error(gettext(str), esa_file, strerror(realerrno)); \
+ goto clean_esa; \
+}
+
+/*
+ * Generate the elfsign activation file (.esa) for this request.
+ * The .esa file should contain the signature of main binary
+ * signed with an unlimited certificate, the DN and its own signature.
+ *
+ * The format is as follows:
+ * -----------------------------
+ * A | main signature length |
+ * -----------------------------
+ * B | main signature (copy of |
+ * | signature from original |
+ * | limited-use binary |
+ * -----------------------------
+ * C | signing DN length |
+ * -----------------------------
+ * D | signing DN |
+ * -----------------------------
+ * E | esa signature length |
+ * -----------------------------
+ * F | esa signature = |
+ * | RSA(HASH(A||B) |
+ * -----------------------------
+ * (lengths are in the same endianness as the original object)
+ *
+ * cmd_info.ess set for the main binary is correct here, since this
+ * is the only elf object we are actually dealing with during the .esa
+ * generation.
+ */
+static ret_t
+do_gen_esa(char *object)
+{
+ ret_t ret;
+
+ /* variables used for signing and writing to .esa file */
+ char *elfobj_esa;
+ size_t elfobj_esa_len;
+ int esa_fd;
+ mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
+ uchar_t *esa_buf = NULL;
+ size_t esa_buf_len = 0;
+ uchar_t hash[SIG_MAX_LENGTH], *hash_ptr = hash;
+ size_t hash_len = SIG_MAX_LENGTH;
+ uchar_t esa_sig[SIG_MAX_LENGTH];
+ size_t esa_sig_len = SIG_MAX_LENGTH;
+ struct filesignatures *fssp = NULL;
+ size_t fslen;
+ ELFCert_t cert = NULL;
+ char *dn;
+ size_t dn_len;
+ uchar_t tmp_buf[sizeof (uint32_t)];
+ int realerrno = 0;
+
+ /*
+ * variables used for finding information on signer of main
+ * elfobject.
+ */
+ uchar_t orig_signature[SIG_MAX_LENGTH];
+ size_t orig_sig_len = sizeof (orig_signature);
+
+ cryptodebug("do_gen_esa");
+ if ((ret = getelfobj(object)) != EXIT_OKAY)
+ return (ret);
+ ret = EXIT_SIGN_FAILED;
+
+ /*
+ * Find the certificate we need to sign the activation file with.
+ */
+ if (!elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, &cert,
+ cmd_info.es_action)) {
+ es_error(gettext("Unable to load certificate: %s"),
+ cmd_info.cert);
+ ret = EXIT_BAD_CERT;
+ goto clean_esa;
+ }
+
+ if (cmd_info.privpath != NULL) {
+ if (!elfcertlib_loadprivatekey(cmd_info.ess, cert,
+ cmd_info.privpath)) {
+ es_error(gettext("Unable to load private key: %s"),
+ cmd_info.privpath);
+ ret = EXIT_BAD_PRIVATEKEY;
+ goto clean_esa;
+ }
+ } else {
+ char *pin = getpin();
+
+ if (pin == NULL) {
+ cryptoerror(LOG_STDERR, gettext("Unable to get PIN"));
+ ret = EXIT_BAD_PRIVATEKEY;
+ goto clean_esa;
+ }
+ if (!elfcertlib_loadtokenkey(cmd_info.ess, cert,
+ cmd_info.token_label, pin)) {
+ es_error(gettext("Unable to access private key "
+ "in token %s"), cmd_info.token_label);
+ ret = EXIT_BAD_PRIVATEKEY;
+ goto clean_esa;
+ }
+ }
+
+ /*
+ * Get the DN from the certificate.
+ */
+ if ((dn = elfcertlib_getdn(cert)) == NULL) {
+ es_error(gettext("Unable to find DN in certifiate %s"),
+ cmd_info.cert);
+ goto clean_esa;
+ }
+ dn_len = strlen(dn);
+ cryptodebug("DN = %s", dn);
+
+ /*
+ * Make sure they are not trying to sign .esa file with a
+ * limited certificate.
+ */
+ if (strstr(dn, USAGELIMITED) != NULL) {
+ es_error(gettext("Activation file must be signed with a "
+ "certficate without %s."), USAGELIMITED);
+ goto clean_esa;
+ }
+
+ /*
+ * Find information in the associated elfobject that will
+ * be needed to generate the activation file.
+ */
+ if (elfsign_signatures(cmd_info.ess, &fssp, &fslen, ES_GET) !=
+ ELFSIGN_SUCCESS) {
+ es_error(gettext("%s must be signed first, before an "
+ "associated activation file can be created."),
+ object);
+ goto clean_esa;
+ }
+ if (elfsign_extract_sig(cmd_info.ess, fssp,
+ orig_signature, &orig_sig_len) == FILESIG_UNKNOWN) {
+ es_error(gettext("elfsign can not create "
+ "an associated activation file for the "
+ "signature format of %s."),
+ object);
+ goto clean_esa;
+ }
+ { /* DEBUG START */
+ const int sigstr_len = orig_sig_len * 2 + 1;
+ char *sigstr = malloc(sigstr_len);
+
+ tohexstr(orig_signature, orig_sig_len, sigstr, sigstr_len);
+ cryptodebug("signature value is: %s", sigstr);
+ cryptodebug("sig size value is: %d", orig_sig_len);
+ free(sigstr);
+ } /* DEBUG END */
+
+ esa_buf_len = sizeof (uint32_t) + orig_sig_len;
+ esa_buf = malloc(esa_buf_len);
+ if (esa_buf == NULL) {
+ es_error(gettext("Unable to allocate memory for .esa buffer"));
+ goto clean_esa;
+ }
+
+ /*
+ * Write eventual contents of .esa file to a temporary
+ * buffer, so we can sign it before writing out to
+ * the file.
+ */
+ elfsign_buffer_len(cmd_info.ess, &orig_sig_len, esa_buf, ES_UPDATE);
+ (void) memcpy(esa_buf + sizeof (uint32_t), orig_signature,
+ orig_sig_len);
+
+ if (elfsign_hash_esa(cmd_info.ess, esa_buf, esa_buf_len,
+ &hash_ptr, &hash_len) != ELFSIGN_SUCCESS) {
+ es_error(gettext("Unable to calculate activation hash"));
+ goto clean_esa;
+ }
+
+ /*
+ * sign the buffer for the .esa file
+ */
+ if (!elfcertlib_sign(cmd_info.ess, cert,
+ hash_ptr, hash_len, esa_sig, &esa_sig_len)) {
+ es_error(gettext("Unable to sign .esa data using key from %s"),
+ cmd_info.privpath ?
+ cmd_info.privpath : cmd_info.token_label);
+ goto clean_esa;
+ }
+
+ { /* DEBUG START */
+ const int sigstr_len = esa_sig_len * 2 + 1;
+ char *sigstr = malloc(sigstr_len);
+
+ tohexstr(esa_sig, esa_sig_len, sigstr, sigstr_len);
+ cryptodebug("esa signature value is: %s", sigstr);
+ cryptodebug("esa size value is: %d", esa_sig_len);
+ free(sigstr);
+ } /* DEBUG END */
+
+ /*
+ * Create the empty activation file once we know
+ * we are working with the good data.
+ */
+ elfobj_esa_len = strlen(object) + ESA_LEN + 1;
+ elfobj_esa = malloc(elfobj_esa_len);
+
+ if (elfobj_esa == NULL) {
+ es_error(gettext("Unable to allocate buffer for esa filename"));
+ goto clean_esa;
+ }
+
+ (void) strlcpy(elfobj_esa, object, elfobj_esa_len);
+ (void) strlcat(elfobj_esa, ESA, elfobj_esa_len);
+
+ cryptodebug("Creating .esa file: %s", elfobj_esa);
+
+ if ((esa_fd = open(elfobj_esa, O_WRONLY|O_CREAT|O_EXCL, mode)) == -1) {
+ ESA_ERROR("Unable to create activation file: %s. %s.",
+ elfobj_esa);
+ }
+
+ if (write(esa_fd, esa_buf, esa_buf_len) != esa_buf_len) {
+ ESA_ERROR("Unable to write contents to %s. %s.",
+ elfobj_esa);
+ }
+
+ { /* DEBUG START */
+ const int sigstr_len = dn_len * 2 + 1;
+ char *sigstr = malloc(sigstr_len);
+
+ tohexstr((uchar_t *)dn, dn_len, sigstr, sigstr_len);
+ cryptodebug("dn value is: %s", sigstr);
+ cryptodebug("dn size value is: %d", dn_len);
+ free(sigstr);
+ } /* DEBUG END */
+
+ elfsign_buffer_len(cmd_info.ess, &dn_len, tmp_buf, ES_UPDATE);
+ if (write(esa_fd, tmp_buf, sizeof (tmp_buf)) != sizeof (tmp_buf)) {
+ ESA_ERROR("Unable to write dn_len to %s. %s.", elfobj_esa);
+ }
+
+ if (write(esa_fd, dn, dn_len) != dn_len) {
+ ESA_ERROR("Unable to write dn to %s. %s.", elfobj_esa);
+ }
+
+ elfsign_buffer_len(cmd_info.ess, &esa_sig_len, tmp_buf, ES_UPDATE);
+ if (write(esa_fd, tmp_buf, sizeof (tmp_buf)) != sizeof (tmp_buf)) {
+ ESA_ERROR("Unable to write .esa signature len to %s. %s.",
+ elfobj_esa);
+ }
+
+ if (write(esa_fd, esa_sig, esa_sig_len) != esa_sig_len) {
+ realerrno = errno;
+ es_error(gettext("Unable to write .esa signature. %s."),
+ strerror(realerrno));
+ goto clean_esa;
+ }
+
+ ret = EXIT_OKAY;
+
+clean_esa:
+ free(fssp);
+ if (esa_fd != -1)
+ (void) close(esa_fd);
+
+ if (esa_buf != NULL)
+ free(esa_buf);
+
+ bzero(esa_sig, esa_sig_len);
+
+ if (cert != NULL)
+ elfcertlib_releasecert(cmd_info.ess, cert);
+ if (cmd_info.ess != NULL)
+ elfsign_end(cmd_info.ess);
+
+ return (ret);
+}
+
+/*
+ * Verify the signature of the object
+ * This subcommand is intended to be used by developers during their build
+ * processes. Therefore we can not assume that the certificate is in
+ * /etc/crypto/certs so we must use the path we got from the commandline.
+ */
+static ret_t
+do_verify(char *object)
+{
+ ELFsign_status_t res;
+ struct ELFsign_sig_info *esip;
+ ret_t retval;
+
+ cryptodebug("do_verify");
+ if ((retval = getelfobj(object)) != EXIT_OKAY)
+ return (retval);
+
+ if ((retval = setcertpath()) != EXIT_OKAY) {
+ elfsign_end(cmd_info.ess);
+ return (retval);
+ }
+
+ res = elfsign_verify_signature(cmd_info.ess, &esip);
+ switch (res) {
+ case ELFSIGN_SUCCESS:
+ (void) fprintf(stdout,
+ gettext("elfsign: verification of %s passed.\n"),
+ object);
+ if (cmd_info.verbose)
+ sig_info_print(esip);
+ retval = EXIT_OKAY;
+ break;
+ case ELFSIGN_RESTRICTED:
+ (void) fprintf(stdout,
+ gettext("elfsign: verification of %s passed, "
+ "but restricted.\n"), object);
+ if (cmd_info.verbose)
+ sig_info_print(esip);
+ retval = EXIT_OKAY;
+ break;
+ case ELFSIGN_FAILED:
+ case ELFSIGN_INVALID_CERTPATH:
+ es_error(gettext("verification of %s failed."),
+ object);
+ if (cmd_info.verbose)
+ sig_info_print(esip);
+ retval = EXIT_VERIFY_FAILED;
+ break;
+ case ELFSIGN_NOTSIGNED:
+ es_error(gettext("no signature found in %s."),
+ object);
+ retval = EXIT_VERIFY_FAILED_UNSIGNED;
+ break;
+ default:
+ es_error(gettext("unexpected failure attempting verification "
+ "of %s."), object);
+ retval = EXIT_VERIFY_FAILED_UNSIGNED;
+ break;
+ }
+
+ if (esip != NULL)
+ elfsign_sig_info_free(esip);
+ if (cmd_info.ess != NULL)
+ elfsign_end(cmd_info.ess);
+ return (retval);
+}
+
+#define SET_VALUE(f, s) \
+ kmfrv = f; \
+ if (kmfrv != KMF_OK) { \
+ char *e = NULL; \
+ (void) KMF_GetKMFErrorString(kmfrv, &e); \
+ cryptoerror(LOG_STDERR, \
+ gettext("Failed to %s: %s\n"), \
+ s, (e ? e : "unknown error")); \
+ if (e) free(e); \
+ goto cleanup; \
+ }
+
+static KMF_RETURN
+create_csr(char *dn)
+{
+ KMF_RETURN kmfrv = KMF_OK;
+ KMF_HANDLE_T kmfhandle = NULL;
+ KMF_CREATEKEYPAIR_PARAMS kp_params;
+ KMF_KEY_HANDLE pubk, prik;
+ KMF_X509_NAME csrSubject;
+ KMF_CSR_DATA csr;
+ KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_MD5WithRSA;
+ KMF_DATA signedCsr = { NULL, 0 };
+ KMF_CONFIG_PARAMS config;
+ char *err;
+
+ if ((kmfrv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
+ (void) KMF_GetKMFErrorString(kmfrv, &err);
+ cryptoerror(LOG_STDERR,
+ gettext("Error initializing KMF: %s\n"),
+ (err ? err : "unknown error"));
+ if (err)
+ free(err);
+ return (kmfrv);
+ }
+ (void) memset(&csr, 0, sizeof (csr));
+ (void) memset(&csrSubject, 0, sizeof (csrSubject));
+ (void) memset(&kp_params, 0, sizeof (kp_params));
+
+ if (cmd_info.privpath != NULL) {
+ kp_params.kstype = KMF_KEYSTORE_OPENSSL;
+ kp_params.sslparms.keyfile = cmd_info.privpath;
+ kp_params.sslparms.format = KMF_FORMAT_ASN1;
+ } else if (cmd_info.token_label != NULL) {
+
+ /* Get a PIN to store the private key in the token */
+ char *pin = getpin();
+
+ if (pin == NULL) {
+ (void) KMF_Finalize(kmfhandle);
+ return (KMF_ERR_AUTH_FAILED);
+ }
+
+ kp_params.kstype = KMF_KEYSTORE_PK11TOKEN;
+ kp_params.cred.cred = pin;
+ kp_params.cred.credlen = strlen(pin);
+
+ (void) memset(&config, 0, sizeof (config));
+ config.kstype = KMF_KEYSTORE_PK11TOKEN;
+ config.pkcs11config.label = cmd_info.token_label;
+ config.pkcs11config.readonly = FALSE;
+ kmfrv = KMF_ConfigureKeystore(kmfhandle, &config);
+ if (kmfrv != KMF_OK) {
+ goto cleanup;
+ }
+ }
+
+ /* Create the RSA keypair */
+ kp_params.keytype = KMF_RSA;
+ kp_params.keylength = ES_DEFAULT_KEYSIZE;
+
+ kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk);
+ if (kmfrv != KMF_OK) {
+ (void) KMF_GetKMFErrorString(kmfrv, &err);
+ if (err != NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("Create RSA keypair failed: %s"), err);
+ free(err);
+ }
+ goto cleanup;
+ }
+
+ kmfrv = KMF_DNParser(dn, &csrSubject);
+ if (kmfrv != KMF_OK) {
+ (void) KMF_GetKMFErrorString(kmfrv, &err);
+ if (err != NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("Error parsing subject name: %s\n"), err);
+ free(err);
+ }
+ goto cleanup;
+ }
+
+ SET_VALUE(KMF_SetCSRPubKey(kmfhandle, &pubk, &csr), "keypair");
+
+ SET_VALUE(KMF_SetCSRVersion(&csr, 2), "version number");
+
+ SET_VALUE(KMF_SetCSRSubjectName(&csr, &csrSubject), "subject name");
+
+ SET_VALUE(KMF_SetCSRSignatureAlgorithm(&csr, sigAlg),
+ "SignatureAlgorithm");
+
+ if ((kmfrv = KMF_SignCSR(kmfhandle, &csr, &prik, &signedCsr)) ==
+ KMF_OK) {
+ kmfrv = KMF_CreateCSRFile(&signedCsr, KMF_FORMAT_PEM,
+ cmd_info.cert);
+ }
+
+cleanup:
+ (void) KMF_FreeKMFKey(kmfhandle, &prik);
+ (void) KMF_FreeData(&signedCsr);
+ (void) KMF_FreeSignedCSR(&csr);
+ (void) KMF_Finalize(kmfhandle);
+
+ return (kmfrv);
+}
+
+static boolean_t
+is_restricted(void)
+{
+ char nr[80]; /* Non-retail provider? big buffer for l10n */
+ char *yeschar = nl_langinfo(YESSTR);
+ char *nochar = nl_langinfo(NOSTR);
+
+ /*
+ * Find out if user will need an activation file.
+ * These questions cover cases #1 and #2 from the Jumbo Export
+ * Control case. The logic of these questions should not be modified
+ * without consulting the jumbo case, unless there is a new
+ * export case or a change in export/import regulations for Sun
+ * and Sun customers.
+ * Case #3 should be covered in the developer documentation.
+ */
+/* BEGIN CSTYLED */
+ (void) fprintf(stdout, gettext("\n"
+"The government of the United States of America restricts the export of \n"
+"\"open cryptographic interfaces\", also known as \"crypto-with-a-hole\".\n"
+"Due to this restriction, all providers for the Solaris cryptographic\n"
+"framework must be signed, regardless of the country of origin.\n\n"));
+
+ (void) fprintf(stdout, gettext(
+"The terms \"retail\" and \"non-retail\" refer to export classifications \n"
+"for products manufactured in the USA. These terms define the portion of the\n"
+"world where the product may be shipped. Roughly speaking, \"retail\" is \n"
+"worldwide (minus certain excluded nations) and \"non-retail\" is domestic \n"
+"only (plus some highly favored nations). If your provider is subject to\n"
+"USA export control, then you must obtain an export approval (classification)\n"
+"from the government of the USA before exporting your provider. It is\n"
+"critical that you specify the obtained (or expected, when used during \n"
+"development) classification to the following questions so that your provider\n"
+"will be appropriately signed.\n\n"));
+
+ for (;;) {
+ (void) fprintf(stdout, gettext(
+"Do you have retail export approval for use without restrictions based \n"
+"on the caller (for example, IPsec)? [Yes/No] "));
+/* END CSTYLED */
+
+ (void) fflush(stdout);
+
+ (void) fgets(nr, sizeof (nr), stdin);
+ if (nr == NULL)
+ goto demand_answer;
+
+ nr[strlen(nr) - 1] = '\0';
+
+ if (strncasecmp(nochar, nr, 1) == 0) {
+/* BEGIN CSTYLED */
+ (void) fprintf(stdout, gettext("\n"
+"If you have non-retail export approval for unrestricted use of your provider\n"
+"by callers, are you also planning to receive retail approval by restricting \n"
+"which export sensitive callers (for example, IPsec) may use your \n"
+"provider? [Yes/No] "));
+/* END CSTYLED */
+
+ (void) fflush(stdout);
+
+ (void) fgets(nr, sizeof (nr), stdin);
+
+ /*
+ * flush standard input so any remaining text
+ * does not affect next read.
+ */
+ (void) fflush(stdin);
+
+ if (nr == NULL)
+ goto demand_answer;
+
+ nr[strlen(nr) - 1] = '\0';
+
+ if (strncasecmp(nochar, nr, 1) == 0) {
+ return (B_FALSE);
+ } else if (strncasecmp(yeschar, nr, 1) == 0) {
+ return (B_TRUE);
+ } else
+ goto demand_answer;
+
+ } else if (strncasecmp(yeschar, nr, 1) == 0) {
+ return (B_FALSE);
+ }
+
+ demand_answer:
+ (void) fprintf(stdout,
+ gettext("You must specify an answer.\n\n"));
+ }
+}
+
+#define CN_MAX_LENGTH 64 /* Verisign implementation limit */
+/*
+ * Generate a certificate request into the file named cmd_info.cert
+ */
+/*ARGSUSED*/
+static ret_t
+do_cert_request(char *object)
+{
+ const char PartnerDNFMT[] =
+ "CN=%s, "
+ "OU=Class B, "
+ "%sOU=Solaris Cryptographic Framework, "
+ "OU=Partner Object Signing, "
+ "O=Sun Microsystems Inc";
+ const char SunCDNFMT[] =
+ "CN=%s, "
+ "OU=Class B, "
+ "%sOU=Solaris Cryptographic Framework, "
+ "OU=Corporate Object Signing, "
+ "O=Sun Microsystems Inc";
+ const char SunSDNFMT[] =
+ "CN=%s, "
+ "OU=Class B, "
+ "%sOU=Solaris Signed Execution, "
+ "OU=Corporate Object Signing, "
+ "O=Sun Microsystems Inc";
+ const char *dnfmt = NULL;
+ char cn[CN_MAX_LENGTH + 1];
+ char *dn = NULL;
+ size_t dn_len;
+ char *restriction = "";
+ KMF_RETURN kmfret;
+ cryptodebug("do_cert_request");
+
+ /*
+ * Get the DN prefix from the user
+ */
+ switch (cmd_info.internal_req) {
+ case 'c':
+ dnfmt = SunCDNFMT;
+ (void) fprintf(stdout, gettext(
+ "Enter Sun Microsystems, Inc. Release name.\n"
+ "This will be the prefix of the Certificate DN: "));
+ break;
+ case 's':
+ dnfmt = SunSDNFMT;
+ (void) fprintf(stdout, gettext(
+ "Enter Sun Microsystems, Inc. Release name.\n"
+ "This will be the prefix of the Certificate DN: "));
+ break;
+ default:
+ dnfmt = PartnerDNFMT;
+ (void) fprintf(stdout, gettext(
+ "Enter Company Name / Stock Symbol"
+ " or some other globally unique identifier.\n"
+ "This will be the prefix of the Certificate DN: "));
+ break;
+ }
+
+ (void) fgets(cn, sizeof (cn), stdin);
+ if ((cn == NULL) || (cn[0] == '\n')) {
+ es_error(gettext("you must specify a Certificate DN prefix"));
+ return (EXIT_INVALID_ARG);
+ }
+
+ if (cn[strlen(cn) - 1] == '\n') {
+ cn[strlen(cn) - 1] = '\0'; /* chop trailing \n */
+ } else {
+ es_error(gettext("You must specify a Certificate DN prefix "
+ "of no more than %d characters"), CN_MAX_LENGTH);
+ return (EXIT_INVALID_ARG);
+ }
+
+ /*
+ * determine if there is an export restriction
+ */
+ switch (cmd_info.internal_req) {
+ case 's':
+ restriction = "";
+ break;
+ default:
+ restriction = is_restricted() ? USAGELIMITED ", " : "";
+ break;
+ }
+
+ /* Update DN string */
+ dn_len = strlen(cn) + strlen(dnfmt) + strlen(restriction);
+ dn = malloc(dn_len + 1);
+ (void) snprintf(dn, dn_len, dnfmt, cn, restriction);
+
+ cryptodebug("Generating Certificate request for DN: %s", dn);
+ kmfret = create_csr(dn);
+ free(dn);
+ if (kmfret == KMF_OK)
+ return (EXIT_OKAY);
+ else
+ return (EXIT_CSR_FAILED);
+}
+
+static void
+str_print(char *s)
+{
+ if (s == NULL)
+ return;
+ (void) fprintf(stdout, "%s\n", s);
+}
+
+/*ARGSUSED*/
+static ret_t
+do_list(char *object)
+{
+ ret_t retval;
+
+ if (cmd_info.elfcnt > 0) {
+ ELFsign_status_t elfstat;
+ struct filesignatures *fssp = NULL;
+ size_t fs_len;
+ struct ELFsign_sig_info *esip;
+
+ if ((retval = getelfobj(cmd_info.elfobj[0])) != EXIT_OKAY)
+ return (retval);
+ elfstat = elfsign_signatures(cmd_info.ess,
+ &fssp, &fs_len, ES_GET);
+ if (elfstat == ELFSIGN_SUCCESS) {
+ retval = EXIT_OKAY;
+ if (elfsign_sig_info(fssp, &esip)) {
+ switch (cmd_info.field) {
+ case FLD_FORMAT:
+ str_print(esip->esi_format);
+ break;
+ case FLD_SIGNER:
+ str_print(esip->esi_signer);
+ break;
+ case FLD_TIME:
+ if (esip->esi_time == 0)
+ retval = EXIT_INVALID_ARG;
+ else
+ str_print(time_str(
+ esip->esi_time));
+ break;
+ default:
+ retval = EXIT_INVALID_ARG;
+ }
+ elfsign_sig_info_free(esip);
+ }
+ free(fssp);
+ } else
+ retval = EXIT_VERIFY_FAILED_UNSIGNED;
+ elfsign_end(cmd_info.ess);
+ } else {
+ ELFCert_t cert;
+ /*
+ * Initialize the ESS record here even though we are not
+ * actually opening any ELF files.
+ */
+ if (elfsign_begin(NULL, ES_GET, &(cmd_info.ess)) !=
+ ELFSIGN_SUCCESS)
+ return (EXIT_MEMORY_ERROR);
+
+ if (elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL,
+ &cert, cmd_info.es_action)) {
+ retval = EXIT_OKAY;
+ switch (cmd_info.field) {
+ case FLD_SUBJECT:
+ str_print(elfcertlib_getdn(cert));
+ break;
+ case FLD_ISSUER:
+ str_print(elfcertlib_getissuer(cert));
+ break;
+ default:
+ retval = EXIT_INVALID_ARG;
+ }
+ elfcertlib_releasecert(cmd_info.ess, cert);
+ } else
+ retval = EXIT_BAD_CERT;
+ elfsign_end(cmd_info.ess);
+ }
+
+ return (retval);
+}
+
+static void
+es_error(const char *fmt, ...)
+{
+ char msgbuf[BUFSIZ];
+ va_list args;
+
+ va_start(args, fmt);
+ (void) vsnprintf(msgbuf, sizeof (msgbuf), fmt, args);
+ va_end(args);
+ (void) fflush(stdout);
+ cryptoerror(LOG_STDERR, "%s", msgbuf);
+ (void) fflush(stderr);
+}
+
+static char *
+time_str(time_t t)
+{
+ static char buf[80];
+ char *bufp;
+
+ bufp = buf;
+ if (strftime(buf, sizeof (buf), NULL, localtime(&t)) == 0)
+ bufp = ctime(&t);
+ return (bufp);
+}
+
+static void
+sig_info_print(struct ELFsign_sig_info *esip)
+{
+ if (esip == NULL)
+ return;
+ (void) fprintf(stdout, gettext("format: %s.\n"), esip->esi_format);
+ (void) fprintf(stdout, gettext("signer: %s.\n"), esip->esi_signer);
+ if (esip->esi_time == 0)
+ return;
+ (void) fprintf(stdout, gettext("signed on: %s.\n"),
+ time_str(esip->esi_time));
+}
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index d72f17bb58..bc98394c86 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -176,10 +176,8 @@ SUBDIRS += \
libscf \
libinetsvc \
librestart \
- libsched
-$(CLOSED_BUILD)SUBDIRS += \
- $(CLOSED)/lib/libelfsign
-SUBDIRS += \
+ libsched \
+ libelfsign \
pkcs11 .WAIT \
libpctx .WAIT \
libcpc \
@@ -350,6 +348,7 @@ HDRSUBDIRS= \
libdns_sd \
libdtrace \
libdtrace_jni \
+ libelfsign \
libeti \
libfstyp \
libgen \
@@ -499,8 +498,7 @@ libdtrace: libproc libgen libctf
libdtrace_jni: libuutil libdtrace
libefi: libuuid
libfstyp: libnvpair
-$(CLOSED_BUILD)$(CLOSED)/lib/libelfsign: \
- $(CLOSED)/lib/libike libcryptoutil pkcs11
+libelfsign: libcryptoutil libkmf
libidmap: libnsl
libinetcfg: libnsl libsocket libdevinfo
libkmf: libcryptoutil pkcs11 openssl
diff --git a/usr/src/lib/libelfsign/Makefile b/usr/src/lib/libelfsign/Makefile
new file mode 100644
index 0000000000..1d663e73d1
--- /dev/null
+++ b/usr/src/lib/libelfsign/Makefile
@@ -0,0 +1,70 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# lib/libelfsign/Makefile
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS= $(MACH)
+
+POFILE= libelfsign.po
+MSGFILES= common/elfsignlib.c common/elfcertlib.c
+XGETFLAGS= -a
+
+HDRS= libelfsign.h
+ROOTHDRDIR= $(ROOT)/usr/include
+HDRDIR= common
+
+all:= TARGET= all
+clean:= TARGET= clean
+clobber:= TARGET= clobber
+install:= TARGET= install
+lint:= TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install: .WAIT $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+$(POFILE): $(MSGFILES)
+ $(BUILDPO.msgfiles)
+
+_msg: $(MSGDOMAINPOFILE)
+
+include $(SRC)/Makefile.msg.targ
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libelfsign/Makefile.com b/usr/src/lib/libelfsign/Makefile.com
new file mode 100644
index 0000000000..c5faa4ea7e
--- /dev/null
+++ b/usr/src/lib/libelfsign/Makefile.com
@@ -0,0 +1,63 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = libelfsign.a
+VERS = .1
+
+OBJECTS = \
+ elfcertlib.o \
+ elfsignlib.o
+
+include $(SRC)/lib/Makefile.lib
+
+SRCDIR = ../common
+
+LIBS = $(DYNLIB) $(LINTLIB)
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+
+LDLIBS += -lmd -lelf -lkmf -lcryptoutil -lc
+
+MAPFILE = mapfile
+MAPFILES = $(MAPFILE)
+
+CFLAGS += $(CCMT) $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+$(MAPFILE): $(SRCDIR)/$(MAPFILE).map
+ $(RM) $@
+ $(CPP) $(SRCDIR)/$(MAPFILE).map > $@
+
+CLEANFILES += $(MAPFILE)
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libelfsign/README b/usr/src/lib/libelfsign/README
new file mode 100644
index 0000000000..059b4c7869
--- /dev/null
+++ b/usr/src/lib/libelfsign/README
@@ -0,0 +1,38 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+
+Note that this library does not have a spec file.
+
+There are no interfaces in this library that are public so an abi_
+library for appcert and friends doesn't make any sense. If the APIs
+here are ever elevated to a public taxonomy then a spec file needs to
+be introduced.
+
+A 64 bit version of this library does not exist.
+That isn't an issue since kcfd(1m) and elfsign(1) are 32 bit
+applications and are the only consumers.
diff --git a/usr/src/lib/libelfsign/common/elfcertlib.c b/usr/src/lib/libelfsign/common/elfcertlib.c
new file mode 100644
index 0000000000..ddf24e6659
--- /dev/null
+++ b/usr/src/lib/libelfsign/common/elfcertlib.c
@@ -0,0 +1,644 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <strings.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <md5.h>
+#include <pthread.h>
+
+#include <cryptoutil.h>
+
+#include <kmfapi.h>
+#include <sys/crypto/elfsign.h>
+#include <libelfsign.h>
+
+#include <synch.h>
+
+const char _PATH_ELFSIGN_CRYPTO_CERTS[] = CRYPTO_CERTS_DIR;
+const char _PATH_ELFSIGN_ETC_CERTS[] = ETC_CERTS_DIR;
+
+/*
+ * The CACERT and OBJCACERT are the Cryptographic Trust Anchors
+ * for the Solaris Cryptographic Framework.
+ */
+static const char _PATH_CRYPTO_CACERT[] = CRYPTO_CERTS_DIR "/CA";
+static const char _PATH_CRYPTO_OBJCACERT[] = CRYPTO_CERTS_DIR "/SUNWObjectCA";
+static ELFCert_t CACERT = NULL;
+static ELFCert_t OBJCACERT = NULL;
+static pthread_mutex_t ca_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void elfcertlib_freecert(ELFsign_t, ELFCert_t);
+static ELFCert_t elfcertlib_allocatecert(void);
+
+/*
+ * elfcertlib_verifycert - Verify the Cert with a Trust Anchor
+ *
+ * IN ess - elfsign context structure
+ * cert
+ * OUT NONE
+ * RETURN TRUE/FALSE
+ *
+ * We first setup the Trust Anchor (CA and SUNWObjectCA) certs
+ * if it hasn't been done already. We verify that the files on disk
+ * are those we expected.
+ *
+ * We then verify the given cert using the publickey of a TA.
+ * If the passed in cert is a TA or it has been verified already we
+ * short cut and return TRUE without futher validation.
+ */
+/*ARGSUSED*/
+boolean_t
+elfcertlib_verifycert(ELFsign_t ess, ELFCert_t cert)
+{
+ KMF_RETURN rv;
+ if ((cert->c_verified == E_OK) || (cert->c_verified == E_IS_TA)) {
+ return (B_TRUE);
+ }
+
+ (void) pthread_mutex_lock(&ca_mutex);
+ if (CACERT == NULL) {
+ (void) elfcertlib_getcert(ess, (char *)_PATH_CRYPTO_CACERT,
+ NULL, &CACERT, ES_GET);
+ }
+ if (OBJCACERT == NULL) {
+ (void) elfcertlib_getcert(ess, (char *)_PATH_CRYPTO_OBJCACERT,
+ NULL, &OBJCACERT, ES_GET);
+ }
+ (void) pthread_mutex_unlock(&ca_mutex);
+
+ if (CACERT != NULL) {
+ rv = KMF_VerifyCertWithCert(ess->es_kmfhandle,
+ (const KMF_DATA *)&cert->c_cert,
+ (const KMF_DATA *)&CACERT->c_cert.certificate);
+ if (rv == KMF_OK) {
+ if (ess->es_certCAcallback != NULL)
+ (ess->es_certvercallback)(ess->es_callbackctx,
+ cert, CACERT);
+ cert->c_verified = E_OK;
+ return (B_TRUE);
+ }
+ }
+
+ if (OBJCACERT != NULL) {
+ rv = KMF_VerifyCertWithCert(ess->es_kmfhandle,
+ (const KMF_DATA *)&cert->c_cert,
+ (const KMF_DATA *)&OBJCACERT->c_cert.certificate);
+ if (rv == KMF_OK) {
+ if (ess->es_certCAcallback != NULL)
+ (ess->es_certvercallback)(ess->es_callbackctx,
+ cert, OBJCACERT);
+ cert->c_verified = E_OK;
+ return (B_TRUE);
+ }
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * elfcertlib_getcert - Get the certificate for signer_DN
+ *
+ * IN ess - elfsign context structure
+ * cert_pathname - path to cert (May be NULL)
+ * signer_DN - The DN we are looking for (May be NULL)
+ * action - indicates crypto verification call
+ * OUT certp - allocated/loaded ELFCert_t
+ *
+ * If the cert_pathname is passed use it and don't search.
+ * Otherwise, go looking in certificate directories
+ */
+boolean_t
+elfcertlib_getcert(ELFsign_t ess, char *cert_pathname,
+ char *signer_DN, ELFCert_t *certp, enum ES_ACTION action)
+{
+ KMF_RETURN rv;
+ ELFCert_t cert = NULL;
+ KMF_FINDCERT_PARAMS fcparams;
+ KMF_X509_DER_CERT certbuf[2];
+ uint32_t ncerts;
+ boolean_t ret = B_FALSE;
+ char *pathlist[3], **plp;
+
+ cryptodebug("elfcertlib_getcert: path=%s, DN=%s",
+ cert_pathname ? cert_pathname : "-none-",
+ signer_DN ? signer_DN : "-none-");
+ *certp = NULL;
+ if (cert_pathname == NULL && signer_DN == NULL) {
+ cryptodebug("elfcertlib_getcert: lack of specificity");
+ return (ret);
+ }
+
+ plp = pathlist;
+ if (cert_pathname != NULL) {
+ /* look in the specified object */
+ *plp++ = cert_pathname;
+ } else {
+ /* look in the certificate directories */
+ *plp++ = (char *)_PATH_ELFSIGN_CRYPTO_CERTS;
+ /*
+ * crypto verifications don't search beyond
+ * _PATH_ELFSIGN_CRYPTO_CERTS
+ */
+ if (action != ES_GET_CRYPTO)
+ *plp++ = (char *)_PATH_ELFSIGN_ETC_CERTS;
+ }
+ *plp = NULL;
+
+ if ((cert = elfcertlib_allocatecert()) == NULL) {
+ return (ret);
+ }
+
+ for (plp = pathlist; *plp; plp++) {
+ (void) memset(&fcparams, 0, sizeof (fcparams));
+ fcparams.kstype = KMF_KEYSTORE_OPENSSL;
+ fcparams.sslparms.certfile = *plp;
+ fcparams.subject = signer_DN;
+ ncerts = 2;
+
+ rv = KMF_FindCert(ess->es_kmfhandle, &fcparams, certbuf,
+ &ncerts);
+ if (rv != KMF_OK)
+ continue;
+ if (ncerts > 1 && signer_DN == NULL) {
+ /* There can be only one */
+ cryptodebug("elfcertlib_getcert: "
+ "too many certificates found in %s",
+ cert_pathname);
+ goto cleanup;
+ }
+ /* found it, cache subject and issuer */
+ cert->c_cert = certbuf[0];
+ rv = KMF_GetCertSubjectNameString(ess->es_kmfhandle,
+ &cert->c_cert.certificate, &cert->c_subject);
+ if (rv != KMF_OK)
+ goto cleanup;
+
+ rv = KMF_GetCertIssuerNameString(ess->es_kmfhandle,
+ &cert->c_cert.certificate, &cert->c_issuer);
+ if (rv != KMF_OK)
+ goto cleanup;
+ break;
+ }
+ if (*plp == NULL) {
+ cryptodebug("elfcertlib_getcert: no certificate found");
+ goto cleanup;
+ }
+
+ cert->c_verified = E_UNCHECKED;
+
+ /*
+ * If the cert we are loading it the trust anchor (ie the CA) then
+ * we mark it as such in cert. This is so that we don't attempt
+ * to verify it later. The CA is always implicitly verified.
+ */
+ if (cert_pathname != NULL && (
+ strcmp(cert_pathname, _PATH_CRYPTO_CACERT) == 0 ||
+ strcmp(cert_pathname, _PATH_CRYPTO_OBJCACERT) == 0)) {
+ if (ess->es_certCAcallback != NULL)
+ (ess->es_certCAcallback)(ess->es_callbackctx, cert,
+ cert_pathname);
+ cert->c_verified = E_IS_TA;
+ }
+
+ ret = B_TRUE;
+
+cleanup:
+ if (ret) {
+ *certp = cert;
+ } else {
+ if (cert != NULL)
+ elfcertlib_freecert(ess, cert);
+ if (signer_DN != NULL)
+ cryptoerror(LOG_ERR, "unable to find a certificate "
+ "for DN: %s", signer_DN);
+ else
+ cryptoerror(LOG_ERR, "unable to load certificate "
+ "from %s", cert_pathname);
+ }
+ return (ret);
+}
+
+/*
+ * elfcertlib_loadprivatekey - Load the private key from path
+ *
+ * IN ess - elfsign context structure
+ * cert
+ * pathname
+ * OUT cert
+ * RETURNS TRUE/FALSE
+ */
+boolean_t
+elfcertlib_loadprivatekey(ELFsign_t ess, ELFCert_t cert, const char *pathname)
+{
+ KMF_RETURN rv = KMF_OK;
+ uint32_t nkeys = 2;
+ KMF_FINDKEY_PARAMS fkparams;
+ KMF_KEY_HANDLE keybuf[2];
+
+ (void) memset(&fkparams, 0, sizeof (fkparams));
+ fkparams.keyclass = KMF_ASYM_PRI;
+ fkparams.kstype = KMF_KEYSTORE_OPENSSL;
+ fkparams.sslparms.keyfile = (char *)pathname;
+
+ rv = KMF_FindKey(ess->es_kmfhandle, &fkparams, keybuf, &nkeys);
+ if (rv != KMF_OK)
+ return (B_FALSE);
+ if (nkeys != 1) {
+ /* lack of specificity */
+ cryptodebug("found %d keys at %s", nkeys, pathname);
+ return (B_FALSE);
+ }
+ cert->c_privatekey = keybuf[0];
+ cryptodebug("key %s loaded", pathname);
+ return (B_TRUE);
+}
+
+/*
+ * elfcertlib_loadtokenkey - Load the private key from token
+ *
+ * IN ess - elfsign context structure
+ * cert
+ * token_label
+ * pin
+ * OUT cert
+ * RETURNS TRUE/FALSE
+ */
+boolean_t
+elfcertlib_loadtokenkey(ELFsign_t ess, ELFCert_t cert,
+ const char *token_label, const char *pin)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_FINDKEY_PARAMS fkparams;
+ KMF_CONFIG_PARAMS cfgparams;
+ uint32_t nkeys = 1;
+ char *idstr = NULL;
+ char *err = NULL;
+
+ (void) memset(&fkparams, 0, sizeof (fkparams));
+ (void) memset(&cfgparams, 0, sizeof (cfgparams));
+
+ cfgparams.kstype = KMF_KEYSTORE_PK11TOKEN;
+ cfgparams.pkcs11config.label = (char *)token_label;
+ cfgparams.pkcs11config.readonly = B_TRUE;
+ rv = KMF_ConfigureKeystore(ess->es_kmfhandle, &cfgparams);
+ if (rv != KMF_OK) {
+ if (KMF_GetKMFErrorString(rv, &err) == KMF_OK) {
+ cryptodebug("Error configuring token access:"
+ " %s\n", err);
+ free(err);
+ }
+ return (B_FALSE);
+ }
+
+ fkparams.idstr = idstr;
+ fkparams.kstype = KMF_KEYSTORE_PK11TOKEN;
+ fkparams.keyclass = KMF_ASYM_PRI;
+ fkparams.cred.cred = (char *)pin;
+ fkparams.cred.credlen = (pin != NULL ? strlen(pin) : 0);
+ fkparams.pkcs11parms.private = B_TRUE;
+
+ /*
+ * We will search for the key based on the ID attribute
+ * which was added when the key was created. ID is
+ * a SHA-1 hash of the public modulus shared by the
+ * key and the certificate.
+ */
+ rv = KMF_GetCertIDString(&cert->c_cert.certificate, &idstr);
+ if (rv != KMF_OK) {
+ if (KMF_GetKMFErrorString(rv, &err) == KMF_OK) {
+ cryptodebug("Error getting ID from cert: %s\n", err);
+ free(err);
+ }
+ return (B_FALSE);
+ }
+ fkparams.idstr = idstr;
+
+ rv = KMF_FindKey(ess->es_kmfhandle, &fkparams,
+ &cert->c_privatekey, &nkeys);
+ if (rv != KMF_OK || nkeys != 1) {
+ if (KMF_GetKMFErrorString(rv, &err) == KMF_OK) {
+ cryptodebug("Error finding private key: %s\n", err);
+ free(err);
+ }
+ free(idstr);
+ return (B_FALSE);
+ }
+ cryptodebug("key found in %s", token_label);
+ cryptodebug("elfcertlib_loadprivatekey = 0x%.8X",
+ &cert->c_privatekey);
+
+ free(idstr);
+ return (B_TRUE);
+}
+
+static const CK_BYTE MD5_DER_PREFIX[] = {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10};
+
+/*
+ * elfcertlib_sign - sign the given DATA using the privatekey in cert
+ *
+ * IN ess - elfsign context structure
+ * cert
+ * data
+ * data_len
+ * OUT sig - must be big enough to hold the signature of data
+ * Caller must allocate
+ * sig_len - actual length used; 0 on failure.
+ * RETURNS TRUE/FALSE
+ */
+/*ARGSUSED*/
+boolean_t
+elfcertlib_sign(ELFsign_t ess, ELFCert_t cert,
+ const uchar_t *data, size_t data_len,
+ uchar_t *sig, size_t *sig_len)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_DATA tobesigned;
+ KMF_DATA signature;
+ uchar_t der_data[sizeof (MD5_DER_PREFIX) + MD5_DIGEST_LENGTH];
+
+ if (ess->es_version <= FILESIG_VERSION2) {
+ /* compatibility: take MD5 hash of SHA1 hash */
+ size_t derlen = MD5_DIGEST_LENGTH;
+ MD5_CTX ctx;
+
+ /*
+ * first: digest using software-based methods, don't
+ * rely on the token for hashing.
+ */
+ MD5Init(&ctx);
+ MD5Update(&ctx, data, data_len);
+ MD5Final(&der_data[sizeof (MD5_DER_PREFIX)], &ctx);
+
+ /*
+ * second: insert prefix
+ */
+ (void) memcpy(der_data, MD5_DER_PREFIX,
+ sizeof (MD5_DER_PREFIX));
+ /*
+ * prepare to sign the local buffer
+ */
+ tobesigned.Data = (uchar_t *)der_data;
+ tobesigned.Length = sizeof (MD5_DER_PREFIX) + derlen;
+ } else {
+ tobesigned.Data = (uchar_t *)data;
+ tobesigned.Length = data_len;
+ }
+
+ signature.Data = (uchar_t *)sig;
+ signature.Length = *sig_len;
+
+ ret = KMF_SignDataWithKey(ess->es_kmfhandle,
+ &cert->c_privatekey, (KMF_OID *)&KMFOID_RSA,
+ &tobesigned, &signature);
+
+ if (ret != KMF_OK) {
+ char *err;
+ if (KMF_GetKMFErrorString(ret, &err) == KMF_OK &&
+ err != NULL) {
+ cryptodebug("Error signing data: %s\n", err);
+ free(err);
+ }
+ *sig_len = 0;
+ return (B_FALSE);
+ }
+ *sig_len = signature.Length;
+ return (B_TRUE);
+}
+
+/*
+ * elfcertlib_verifysig - verify the given DATA using the public key in cert
+ *
+ * IN ess - elfsign context structure
+ * cert
+ * signature
+ * sig_len
+ * data
+ * data_len
+ * OUT N/A
+ * RETURNS TRUE/FALSE
+ */
+boolean_t
+elfcertlib_verifysig(ELFsign_t ess, ELFCert_t cert,
+ const uchar_t *signature, size_t sig_len,
+ const uchar_t *data, size_t data_len)
+{
+ KMF_RETURN rv;
+ KMF_DATA indata;
+ KMF_DATA insig;
+ KMF_ALGORITHM_INDEX algid;
+
+ indata.Data = (uchar_t *)data;
+ indata.Length = data_len;
+ insig.Data = (uchar_t *)signature;
+ insig.Length = sig_len;
+
+ if (ess->es_version <= FILESIG_VERSION2)
+ algid = KMF_ALGID_MD5WithRSA;
+ else
+ algid = KMF_ALGID_RSA;
+
+ /*
+ * We tell KMF to use the OpenSSL verification
+ * APIs here to avoid a circular dependency with
+ * kcfd and libpkcs11.
+ */
+ rv = KMF_VerifyDataWithCert(ess->es_kmfhandle,
+ KMF_KEYSTORE_OPENSSL, algid,
+ &indata, &insig, &cert->c_cert.certificate);
+
+ return ((rv == KMF_OK));
+}
+
+/*
+ * elfcertlib_getdn
+ *
+ * IN cert
+ * OUT NONE
+ * RETURN dn or NULL
+ */
+char *
+elfcertlib_getdn(ELFCert_t cert)
+{
+ cryptodebug("elfcertlib_getdn");
+
+ return (cert->c_subject);
+}
+
+/*
+ * elfcertlib_getissuer
+ *
+ * IN cert
+ * OUT NONE
+ * RETURN dn or NULL
+ */
+char *
+elfcertlib_getissuer(ELFCert_t cert)
+{
+ cryptodebug("elfcertlib_issuer");
+
+ return (cert->c_issuer);
+}
+
+boolean_t
+elfcertlib_init(ELFsign_t ess)
+{
+ boolean_t rc = B_TRUE;
+ KMF_RETURN rv;
+ if (ess->es_kmfhandle == NULL) {
+ rv = KMF_Initialize(&ess->es_kmfhandle, NULL, NULL);
+ if (rv != KMF_OK) {
+ cryptoerror(LOG_ERR,
+ "unable to initialize KMF library");
+ rc = B_FALSE;
+ }
+ }
+ return (rc);
+}
+
+void
+elfcertlib_fini(ELFsign_t ess)
+{
+ (void) KMF_Finalize(ess->es_kmfhandle);
+}
+
+/*
+ * set the token device
+ */
+boolean_t
+elfcertlib_settoken(ELFsign_t ess, char *token)
+{
+ boolean_t rc = B_TRUE;
+ KMF_RETURN rv;
+ KMF_CONFIG_PARAMS cfgparams;
+
+ (void) memset(&cfgparams, 0, sizeof (cfgparams));
+ cfgparams.kstype = KMF_KEYSTORE_PK11TOKEN;
+ cfgparams.pkcs11config.label = token;
+ cfgparams.pkcs11config.readonly = B_TRUE;
+ rv = KMF_ConfigureKeystore(ess->es_kmfhandle, &cfgparams);
+ if (rv != KMF_OK) {
+ cryptoerror(LOG_ERR, "unable to select token\n");
+ rc = B_FALSE;
+ }
+
+ return (rc);
+}
+
+/*
+ * set the certificate CA identification callback
+ */
+void
+elfcertlib_setcertCAcallback(ELFsign_t ess,
+ void (*cb)(void *, ELFCert_t, char *))
+{
+ ess->es_certCAcallback = cb;
+}
+
+/*
+ * set the certificate verification callback
+ */
+void
+elfcertlib_setcertvercallback(ELFsign_t ess,
+ void (*cb)(void *, ELFCert_t, ELFCert_t))
+{
+ ess->es_certvercallback = cb;
+}
+
+
+/*
+ * elfcertlib_releasecert - release a cert
+ *
+ * IN cert
+ * OUT cert
+ * RETURN N/A
+ *
+ */
+void
+elfcertlib_releasecert(ELFsign_t ess, ELFCert_t cert)
+{
+ elfcertlib_freecert(ess, cert);
+}
+
+/*
+ * elfcertlib_allocatecert - create a new ELFCert_t
+ *
+ * IN N/A
+ * OUT N/A
+ * RETURN ELFCert_t, NULL on failure.
+ */
+static ELFCert_t
+elfcertlib_allocatecert(void)
+{
+ ELFCert_t cert = NULL;
+
+ cert = malloc(sizeof (struct ELFCert_s));
+ if (cert == NULL) {
+ cryptoerror(LOG_ERR,
+ "elfcertlib_allocatecert: malloc failed %s",
+ strerror(errno));
+ return (NULL);
+ }
+ (void) memset(cert, 0, sizeof (struct ELFCert_s));
+ cert->c_verified = E_UNCHECKED;
+ cert->c_subject = NULL;
+ cert->c_issuer = NULL;
+ return (cert);
+}
+
+/*
+ * elfcertlib_freecert - freeup the memory of a cert
+ *
+ * IN cert
+ * OUT cert
+ * RETURN N/A
+ *
+ */
+static void
+elfcertlib_freecert(ELFsign_t ess, ELFCert_t cert)
+{
+ if (cert == NULL)
+ return;
+
+ free(cert->c_subject);
+ free(cert->c_issuer);
+
+ KMF_FreeKMFCert(ess->es_kmfhandle, &cert->c_cert);
+ KMF_FreeKMFKey(ess->es_kmfhandle, &cert->c_privatekey);
+
+ free(cert);
+}
diff --git a/usr/src/lib/libelfsign/common/elfsignlib.c b/usr/src/lib/libelfsign/common/elfsignlib.c
new file mode 100644
index 0000000000..00f71a125d
--- /dev/null
+++ b/usr/src/lib/libelfsign/common/elfsignlib.c
@@ -0,0 +1,1598 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#define ELF_TARGET_ALL /* get definitions of all section flags */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <sys/mman.h>
+#include <cryptoutil.h>
+#include <sha1.h>
+#include <sys/crypto/elfsign.h>
+#include <libelfsign.h>
+
+#ifndef SHA1_DIGEST_LENGTH
+#define SHA1_DIGEST_LENGTH 20
+#endif /* SHA1_DIGEST_LENGTH */
+
+const char SUNW_ELF_SIGNATURE_ID[] = ELF_SIGNATURE_SECTION;
+const char OID_sha1WithRSAEncryption[] = "1.2.840.113549.1.1.5";
+
+static ELFsign_status_t elfsign_adjustoffsets(ELFsign_t ess,
+ Elf_Scn *scn, uint64_t new_size);
+static ELFsign_status_t elfsign_verify_esa(ELFsign_t ess,
+ uchar_t *sig, size_t sig_len);
+static uint32_t elfsign_switch_uint32(uint32_t i);
+static ELFsign_status_t elfsign_switch(ELFsign_t ess,
+ struct filesignatures *fssp, enum ES_ACTION action);
+
+struct filesig_extraction {
+ filesig_vers_t fsx_version;
+ char *fsx_format;
+ char fsx_signer_DN[ELFCERT_MAX_DN_LEN];
+ size_t fsx_signer_DN_len;
+ uchar_t fsx_signature[SIG_MAX_LENGTH];
+ size_t fsx_sig_len;
+ char fsx_sig_oid[100];
+ size_t fsx_sig_oid_len;
+ time_t fsx_time;
+};
+
+static char *
+version_to_str(filesig_vers_t v)
+{
+ char *ret;
+
+ switch (v) {
+ case FILESIG_VERSION1:
+ ret = "VERSION1";
+ break;
+ case FILESIG_VERSION2:
+ ret = "VERSION2";
+ break;
+ case FILESIG_VERSION3:
+ ret = "VERSION3";
+ break;
+ case FILESIG_VERSION4:
+ ret = "VERSION4";
+ break;
+ default:
+ ret = "UNKNOWN";
+ break;
+ }
+ return (ret);
+}
+
+/*
+ * Update filesignatures to include the v1/v2 filesig,
+ * composed of signer DN, signature, and OID.
+ */
+static struct filesignatures *
+filesig_insert_dso(struct filesignatures *fssp,
+ filesig_vers_t version,
+ const char *dn,
+ int dn_len,
+ const uchar_t *sig,
+ int sig_len,
+ const char *oid,
+ int oid_len)
+{
+ struct filesig *fsgp;
+ char *fsdatap;
+
+ if (oid == NULL) {
+ /*
+ * This OID is used for the rsa_md5_sha1 format signature also.
+ * This use is historical, and is hence continued,
+ * despite its lack of technical accuracy.
+ */
+ oid = OID_sha1WithRSAEncryption;
+ oid_len = strlen(oid);
+ }
+
+ /*
+ * for now, always insert a single-signature signature block
+ */
+ if (fssp != NULL)
+ free(fssp);
+ fssp = (struct filesignatures *)
+ malloc(filesig_ALIGN(sizeof (struct filesignatures) +
+ dn_len + sig_len + oid_len));
+ if (fssp == NULL)
+ return (fssp);
+
+ fssp->filesig_cnt = 1;
+ fssp->filesig_pad = 0; /* reserve for future use */
+
+ fsgp = &fssp->filesig_sig;
+ fsgp->filesig_size = sizeof (struct filesig) +
+ dn_len + sig_len + oid_len;
+ fsgp->filesig_version = version;
+ switch (version) {
+ case FILESIG_VERSION1:
+ case FILESIG_VERSION2:
+ fsgp->filesig_size -= sizeof (struct filesig) -
+ offsetof(struct filesig, filesig_v1_data[0]);
+ fsgp->filesig_v1_dnsize = dn_len;
+ fsgp->filesig_v1_sigsize = sig_len;
+ fsgp->filesig_v1_oidsize = oid_len;
+ fsdatap = &fsgp->filesig_v1_data[0];
+ break;
+ case FILESIG_VERSION3:
+ case FILESIG_VERSION4:
+ fsgp->filesig_size -= sizeof (struct filesig) -
+ offsetof(struct filesig, filesig_v3_data[0]);
+ fsgp->filesig_v3_time = time(NULL);
+ fsgp->filesig_v3_dnsize = dn_len;
+ fsgp->filesig_v3_sigsize = sig_len;
+ fsgp->filesig_v3_oidsize = oid_len;
+ fsdatap = &fsgp->filesig_v3_data[0];
+ break;
+ default:
+ cryptodebug("filesig_insert_dso: unknown version: %d",
+ version);
+ free(fssp);
+ return (NULL);
+ }
+ (void) memcpy(fsdatap, dn, dn_len);
+ fsdatap += dn_len;
+ (void) memcpy(fsdatap, (char *)sig, sig_len);
+ fsdatap += sig_len;
+ (void) memcpy(fsdatap, oid, oid_len);
+ fsdatap += oid_len;
+ fsgp = filesig_next(fsgp);
+ (void) memset(fsdatap, 0, (char *)(fsgp) - fsdatap);
+
+ return (fssp);
+}
+
+/*
+ * filesig_extract - extract filesig structure to internal form
+ */
+static filesig_vers_t
+filesig_extract(struct filesig *fsgp, struct filesig_extraction *fsxp)
+{
+ char *fsdp;
+
+#define filesig_extract_common(cp, field, data_var, len_var, len_limit) { \
+ len_var = len_limit; \
+ if (len_var > fsgp->field) \
+ len_var = fsgp->field; \
+ (void) memcpy(data_var, cp, len_var); \
+ cp += fsgp->field; }
+#define filesig_extract_str(cp, field, data_var, len_var) \
+ filesig_extract_common(cp, field, data_var, len_var, \
+ sizeof (data_var) - 1); \
+ data_var[len_var] = '\0';
+#define filesig_extract_opaque(cp, field, data_var, len_var) \
+ filesig_extract_common(cp, field, data_var, len_var, sizeof (data_var))
+
+ fsxp->fsx_version = fsgp->filesig_version;
+ cryptodebug("filesig_extract: version=%s",
+ version_to_str(fsxp->fsx_version));
+ switch (fsxp->fsx_version) {
+ case FILESIG_VERSION1:
+ case FILESIG_VERSION2:
+ /*
+ * extract VERSION1 DN, signature, and OID
+ */
+ fsdp = fsgp->filesig_v1_data;
+ fsxp->fsx_format = ES_FMT_RSA_MD5_SHA1;
+ fsxp->fsx_time = 0;
+ filesig_extract_str(fsdp, filesig_v1_dnsize,
+ fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
+ filesig_extract_opaque(fsdp, filesig_v1_sigsize,
+ fsxp->fsx_signature, fsxp->fsx_sig_len);
+ filesig_extract_str(fsdp, filesig_v1_oidsize,
+ fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
+ break;
+ case FILESIG_VERSION3:
+ case FILESIG_VERSION4:
+ fsdp = fsgp->filesig_v3_data;
+ fsxp->fsx_format = ES_FMT_RSA_SHA1;
+ fsxp->fsx_time = fsgp->filesig_v3_time;
+ filesig_extract_str(fsdp, filesig_v3_dnsize,
+ fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
+ filesig_extract_opaque(fsdp, filesig_v3_sigsize,
+ fsxp->fsx_signature, fsxp->fsx_sig_len);
+ filesig_extract_str(fsdp, filesig_v3_oidsize,
+ fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
+ break;
+ default:
+ break;
+ }
+
+ return (fsxp->fsx_version);
+}
+
+ELFsign_status_t
+elfsign_begin(const char *filename, enum ES_ACTION action, ELFsign_t *essp)
+{
+ Elf_Cmd elfcmd;
+ int oflags = 0;
+ short l_type;
+ ELFsign_t ess;
+ struct stat stb;
+ union {
+ char c[2];
+ short s;
+ } uorder;
+ GElf_Ehdr elfehdr;
+ char *ident;
+
+ switch (action) {
+ case ES_GET:
+ case ES_GET_CRYPTO:
+ cryptodebug("elfsign_begin for get");
+ elfcmd = ELF_C_READ;
+ oflags = O_RDONLY | O_NOCTTY | O_NDELAY;
+ l_type = F_RDLCK;
+ break;
+ case ES_UPDATE_RSA_MD5_SHA1:
+ case ES_UPDATE_RSA_SHA1:
+ cryptodebug("elfsign_begin for update");
+ elfcmd = ELF_C_RDWR;
+ oflags = O_RDWR | O_NOCTTY | O_NDELAY;
+ l_type = F_WRLCK;
+ break;
+ default:
+ return (ELFSIGN_UNKNOWN);
+ }
+
+ if ((ess = malloc(sizeof (struct ELFsign_s))) == NULL) {
+ return (ELFSIGN_UNKNOWN);
+ }
+ (void) memset((void *)ess, 0, sizeof (struct ELFsign_s));
+
+ if (!elfcertlib_init(ess)) {
+ cryptodebug("elfsign_begin: failed initialization");
+ return (ELFSIGN_UNKNOWN);
+ }
+
+ ess->es_elf = NULL;
+ ess->es_action = action;
+ ess->es_version = FILESIG_UNKNOWN;
+ ess->es_pathname = NULL;
+ ess->es_certpath = NULL;
+
+ if (filename == NULL) {
+ *essp = ess;
+ return (ELFSIGN_SUCCESS);
+ }
+
+ if ((ess->es_fd = open(filename, oflags)) == -1) {
+ elfsign_end(ess);
+ return (ELFSIGN_INVALID_ELFOBJ);
+ }
+ if ((fstat(ess->es_fd, &stb) == -1) || !S_ISREG(stb.st_mode)) {
+ elfsign_end(ess);
+ return (ELFSIGN_INVALID_ELFOBJ);
+ }
+ if ((ess->es_pathname = strdup(filename)) == NULL) {
+ elfsign_end(ess);
+ return (ELFSIGN_UNKNOWN);
+ }
+ /*
+ * The following lock is released in elfsign_end() when we close(2)
+ * the es_fd. This ensures that we aren't trying verify a file
+ * we are currently updating.
+ */
+ ess->es_flock.l_type = l_type;
+ ess->es_flock.l_whence = SEEK_CUR;
+ ess->es_flock.l_start = 0;
+ ess->es_flock.l_len = 0;
+ if (fcntl(ess->es_fd, F_SETLK, &ess->es_flock) == -1) {
+ cryptodebug("fcntl(F_SETLK) of %s failed with: %s",
+ ess->es_pathname, strerror(errno));
+ elfsign_end(ess);
+ return (ELFSIGN_UNKNOWN);
+ }
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ elfsign_end(ess);
+ return (ELFSIGN_UNKNOWN);
+ }
+
+ if ((ess->es_elf = elf_begin(ess->es_fd, elfcmd,
+ (Elf *)NULL)) == NULL) {
+ cryptodebug("elf_begin() failed: %s", elf_errmsg(-1));
+ elfsign_end(ess);
+ return (ELFSIGN_INVALID_ELFOBJ);
+ }
+
+ if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
+ cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
+ elfsign_end(ess);
+ return (ELFSIGN_INVALID_ELFOBJ);
+ }
+ ess->es_has_phdr = (elfehdr.e_phnum != 0);
+
+ uorder.s = ELFDATA2MSB << 8 | ELFDATA2LSB;
+ ident = elf_getident(ess->es_elf, NULL);
+ if (ident == NULL) {
+ cryptodebug("elf_getident() failed: %s", elf_errmsg(-1));
+ elfsign_end(ess);
+ return (ELFSIGN_INVALID_ELFOBJ);
+ }
+ ess->es_same_endian = (ident[EI_DATA] == uorder.c[0]);
+ ess->es_ei_class = ident[EI_CLASS];
+
+ /*
+ * Call elf_getshstrndx to be sure we have a real ELF object
+ * this is required because elf_begin doesn't check that.
+ */
+ if (elf_getshstrndx(ess->es_elf, &ess->es_shstrndx) == 0) {
+ elfsign_end(ess);
+ cryptodebug("elfsign_begin: elf_getshstrndx failed");
+ return (ELFSIGN_INVALID_ELFOBJ);
+ }
+
+ /*
+ * Make sure libelf doesn't rearrange section ordering / offsets.
+ */
+ (void) elf_flagelf(ess->es_elf, ELF_C_SET, ELF_F_LAYOUT);
+
+ *essp = ess;
+
+ return (ELFSIGN_SUCCESS);
+}
+
+/*
+ * elfsign_end - cleanup the ELFsign_t
+ *
+ * IN/OUT: ess
+ */
+void
+elfsign_end(ELFsign_t ess)
+{
+ if (ess == NULL)
+ return;
+
+ if (ess->es_elf != NULL && ES_ACTISUPDATE(ess->es_action)) {
+ if (elf_update(ess->es_elf, ELF_C_WRITE) == -1) {
+ cryptodebug("elf_update() failed: %s",
+ elf_errmsg(-1));
+ return;
+ }
+ }
+
+ if (ess->es_fd != -1) {
+ (void) close(ess->es_fd);
+ ess->es_fd = -1;
+ }
+
+ if (ess->es_pathname != NULL) {
+ free(ess->es_pathname);
+ ess->es_pathname = NULL;
+ }
+ if (ess->es_certpath != NULL) {
+ free(ess->es_certpath);
+ ess->es_certpath = NULL;
+ }
+
+ if (ess->es_elf != NULL) {
+ (void) elf_end(ess->es_elf);
+ ess->es_elf = NULL;
+ }
+
+ elfcertlib_fini(ess);
+
+ free(ess);
+}
+
+/*
+ * set the certificate path
+ */
+ELFsign_status_t
+elfsign_setcertpath(ELFsign_t ess, const char *certpath)
+{
+ /*
+ * Normally use of access(2) is insecure, here we are only
+ * doing it to help provide early failure and better error
+ * checking, so there is no race condition.
+ */
+ if (access(certpath, R_OK) != 0) {
+ elfsign_end(ess);
+ return (ELFSIGN_INVALID_CERTPATH);
+ }
+ ess->es_certpath = strdup(certpath);
+
+ if (ES_ACTISUPDATE(ess->es_action)) {
+ ELFCert_t cert = NULL;
+ char *subject;
+
+ /* set the version based on the certificate */
+ if (elfcertlib_getcert(ess, ess->es_certpath, NULL,
+ &cert, ess->es_action)) {
+ if ((subject = elfcertlib_getdn(cert)) != NULL) {
+ if (strstr(subject, ELFSIGN_CRYPTO))
+ ess->es_version = (ess->es_action ==
+ ES_UPDATE_RSA_MD5_SHA1) ?
+ FILESIG_VERSION1 : FILESIG_VERSION3;
+ else
+ ess->es_version = (ess->es_action ==
+ ES_UPDATE_RSA_MD5_SHA1) ?
+ FILESIG_VERSION2 : FILESIG_VERSION4;
+ }
+ elfcertlib_releasecert(ess, cert);
+ }
+ if (ess->es_version == FILESIG_UNKNOWN)
+ return (ELFSIGN_FAILED);
+ }
+ return (ELFSIGN_SUCCESS);
+}
+
+/*
+ * set the callback context
+ */
+void
+elfsign_setcallbackctx(ELFsign_t ess, void *ctx)
+{
+ ess->es_callbackctx = ctx;
+}
+
+/*
+ * set the signature extraction callback
+ */
+void
+elfsign_setsigvercallback(ELFsign_t ess,
+ void (*cb)(void *, void *, size_t, ELFCert_t))
+{
+ ess->es_sigvercallback = cb;
+}
+
+/*
+ * elfsign_signatures
+ *
+ * IN: ess, fsspp, action
+ * OUT: fsspp
+ */
+ELFsign_status_t
+elfsign_signatures(ELFsign_t ess,
+ struct filesignatures **fsspp,
+ size_t *fslen,
+ enum ES_ACTION action)
+{
+ Elf_Scn *scn = NULL, *sig_scn = NULL;
+ GElf_Shdr shdr;
+ Elf_Data *data = NULL;
+ const char *elf_section = SUNW_ELF_SIGNATURE_ID;
+ int fscnt, fssize;
+ struct filesig *fsgp, *fsgpnext;
+ uint64_t sig_offset = 0;
+
+ cryptodebug("elfsign_signature");
+ if ((ess == NULL) || (fsspp == NULL)) {
+ cryptodebug("invalid arguments");
+ return (ELFSIGN_UNKNOWN);
+ }
+
+ cryptodebug("elfsign_signature %s for %s",
+ ES_ACTISUPDATE(action) ? "ES_UPDATE" : "ES_GET", elf_section);
+
+ (void) elf_errno();
+ while ((scn = elf_nextscn(ess->es_elf, scn)) != NULL) {
+ const char *sh_name;
+ /*
+ * Do a string compare to examine each section header
+ * to see if this is the section that needs to be updated.
+ */
+ if (gelf_getshdr(scn, &shdr) == NULL) {
+ cryptodebug("gelf_getshdr() failed: %s",
+ elf_errmsg(-1));
+ return (ELFSIGN_FAILED);
+ }
+ sh_name = elf_strptr(ess->es_elf, ess->es_shstrndx,
+ (size_t)shdr.sh_name);
+ if (strcmp(sh_name, elf_section) == 0) {
+ cryptodebug("elfsign_signature: found %s", elf_section);
+ sig_scn = scn;
+ break;
+ }
+ if (shdr.sh_type != SHT_NOBITS &&
+ sig_offset < shdr.sh_offset + shdr.sh_size) {
+ sig_offset = shdr.sh_offset + shdr.sh_size;
+ }
+ }
+ if (elf_errmsg(0) != NULL) {
+ cryptodebug("unexpected error: %s", elf_section,
+ elf_errmsg(-1));
+ return (ELFSIGN_FAILED);
+ }
+
+ if (ES_ACTISUPDATE(action) && (sig_scn == NULL)) {
+ size_t old_size, new_size;
+ char *new_d_buf;
+
+ cryptodebug("elfsign_signature: %s not found - creating",
+ elf_section);
+
+ /*
+ * insert section name in .shstrtab
+ */
+ if ((scn = elf_getscn(ess->es_elf, ess->es_shstrndx)) == 0) {
+ cryptodebug("elf_getscn() failed: %s",
+ elf_errmsg(-1));
+ return (ELFSIGN_FAILED);
+ }
+ if (gelf_getshdr(scn, &shdr) == NULL) {
+ cryptodebug("gelf_getshdr() failed: %s",
+ elf_errmsg(-1));
+ return (ELFSIGN_FAILED);
+ }
+ if ((data = elf_getdata(scn, data)) == NULL) {
+ cryptodebug("elf_getdata() failed: %s",
+ elf_errmsg(-1));
+ return (ELFSIGN_FAILED);
+ }
+ old_size = data->d_size;
+ if (old_size != shdr.sh_size) {
+ cryptodebug("mismatch between data size %d "
+ "and section size %lld", old_size, shdr.sh_size);
+ return (ELFSIGN_FAILED);
+ }
+ new_size = old_size + strlen(elf_section) + 1;
+ if ((new_d_buf = malloc(new_size)) == NULL)
+ return (ELFSIGN_FAILED);
+
+ (void) memcpy(new_d_buf, data->d_buf, old_size);
+ (void) strlcpy(new_d_buf + old_size, elf_section,
+ new_size - old_size);
+ data->d_buf = new_d_buf;
+ data->d_size = new_size;
+ data->d_align = 1;
+ /*
+ * Add the section name passed in to the end of the file.
+ * Initialize the fields in the Section Header that
+ * libelf will not fill in.
+ */
+ if ((sig_scn = elf_newscn(ess->es_elf)) == 0) {
+ cryptodebug("elf_newscn() failed: %s",
+ elf_errmsg(-1));
+ return (ELFSIGN_FAILED);
+ }
+ if (gelf_getshdr(sig_scn, &shdr) == 0) {
+ cryptodebug("gelf_getshdr() failed: %s",
+ elf_errmsg(-1));
+ return (ELFSIGN_FAILED);
+ }
+ shdr.sh_name = old_size;
+ shdr.sh_type = SHT_SUNW_SIGNATURE;
+ shdr.sh_flags = SHF_EXCLUDE;
+ shdr.sh_addr = 0;
+ shdr.sh_link = 0;
+ shdr.sh_info = 0;
+ shdr.sh_size = 0;
+ shdr.sh_offset = sig_offset;
+ shdr.sh_addralign = 1;
+
+ /*
+ * Flush the changes to the underlying elf32 or elf64
+ * section header.
+ */
+ if (gelf_update_shdr(sig_scn, &shdr) == 0) {
+ cryptodebug("gelf_update_shdr failed");
+ return (ELFSIGN_FAILED);
+ }
+
+ if ((data = elf_newdata(sig_scn)) == NULL) {
+ cryptodebug("can't add elf data area for %s: %s",
+ elf_section, elf_errmsg(-1));
+ return (ELFSIGN_FAILED);
+ }
+ if (elfsign_adjustoffsets(ess, scn,
+ old_size + strlen(elf_section) + 1) != ELFSIGN_SUCCESS) {
+ cryptodebug("can't adjust for new section name %s",
+ elf_section);
+ return (ELFSIGN_FAILED);
+ }
+ } else {
+ if (sig_scn == NULL) {
+ cryptodebug("can't find signature section");
+ *fsspp = NULL;
+ return (ELFSIGN_NOTSIGNED);
+ }
+ if ((data = elf_getdata(sig_scn, NULL)) == 0) {
+ cryptodebug("can't get section data for %s",
+ elf_section);
+ return (ELFSIGN_FAILED);
+ }
+ }
+
+ if (ES_ACTISUPDATE(action)) {
+ fssize = offsetof(struct filesignatures, _u1);
+ if (*fsspp != NULL) {
+ fsgp = &(*fsspp)->filesig_sig;
+ for (fscnt = 0; fscnt < (*fsspp)->filesig_cnt;
+ fscnt++) {
+ fsgpnext = filesig_next(fsgp);
+ fssize += (char *)(fsgpnext) - (char *)(fsgp);
+ fsgp = fsgpnext;
+ }
+ }
+ if (shdr.sh_addr != 0) {
+ cryptodebug("section %s is part of a loadable segment, "
+ "it cannot be changed.\n", elf_section);
+ return (ELFSIGN_FAILED);
+ }
+ if ((data->d_buf = malloc(fssize)) == NULL)
+ return (ELFSIGN_FAILED);
+ if (*fsspp != NULL) {
+ (void) memcpy(data->d_buf, *fsspp, fssize);
+ (void) elfsign_switch(ess,
+ (struct filesignatures *)data->d_buf, action);
+ }
+ data->d_size = fssize;
+ data->d_align = 1;
+ data->d_type = ELF_T_BYTE;
+ cryptodebug("elfsign_signature: data->d_size = %d",
+ data->d_size);
+ if (elfsign_adjustoffsets(ess, sig_scn, fssize) !=
+ ELFSIGN_SUCCESS) {
+ cryptodebug("can't adjust for revised signature "
+ "section contents");
+ return (ELFSIGN_FAILED);
+ }
+ } else {
+ *fsspp = malloc(data->d_size);
+ if (*fsspp == NULL)
+ return (ELFSIGN_FAILED);
+ (void) memcpy(*fsspp, data->d_buf, data->d_size);
+ if (elfsign_switch(ess, *fsspp, ES_GET) != ELFSIGN_SUCCESS) {
+ free(*fsspp);
+ *fsspp = NULL;
+ return (ELFSIGN_FAILED);
+ }
+ *fslen = data->d_size;
+ }
+
+ return (ELFSIGN_SUCCESS);
+}
+
+static ELFsign_status_t
+elfsign_adjustoffsets(ELFsign_t ess, Elf_Scn *scn, uint64_t new_size)
+{
+ GElf_Ehdr elfehdr;
+ GElf_Shdr shdr;
+ uint64_t prev_end, scn_offset;
+ char *name;
+ Elf_Scn *scnp;
+ Elf_Data *data;
+ ELFsign_status_t retval = ELFSIGN_FAILED;
+ struct scninfo {
+ struct scninfo *scni_next;
+ Elf_Scn *scni_scn;
+ uint64_t scni_offset;
+ } *scnip = NULL, *tmpscnip, **scnipp;
+
+ /* get the size of the current section */
+ if (gelf_getshdr(scn, &shdr) == NULL)
+ return (ELFSIGN_FAILED);
+ if (shdr.sh_size == new_size)
+ return (ELFSIGN_SUCCESS);
+ scn_offset = shdr.sh_offset;
+ name = elf_strptr(ess->es_elf, ess->es_shstrndx,
+ (size_t)shdr.sh_name);
+ if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
+ cryptodebug("elfsign_adjustoffsets: "
+ "can't move allocated section %s", name ? name : "NULL");
+ return (ELFSIGN_FAILED);
+ }
+
+ /* resize the desired section */
+ cryptodebug("elfsign_adjustoffsets: "
+ "resizing %s at 0x%llx from 0x%llx to 0x%llx",
+ name ? name : "NULL", shdr.sh_offset, shdr.sh_size, new_size);
+ shdr.sh_size = new_size;
+ if (gelf_update_shdr(scn, &shdr) == 0) {
+ cryptodebug("gelf_update_shdr failed");
+ goto bad;
+ }
+ prev_end = shdr.sh_offset + shdr.sh_size;
+
+ /*
+ * find sections whose data follows the changed section
+ * must scan all sections since section data may not
+ * be in same order as section headers
+ */
+ scnp = elf_getscn(ess->es_elf, 0); /* "seek" to start */
+ while ((scnp = elf_nextscn(ess->es_elf, scnp)) != NULL) {
+ if (gelf_getshdr(scnp, &shdr) == NULL)
+ goto bad;
+ if (shdr.sh_offset <= scn_offset)
+ continue;
+ name = elf_strptr(ess->es_elf, ess->es_shstrndx,
+ (size_t)shdr.sh_name);
+ if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
+ if (shdr.sh_type == SHT_NOBITS) {
+ /* .bss can occasionally overlap .shrtab */
+ continue;
+ }
+ cryptodebug("elfsign_adjustoffsets: "
+ "can't move allocated section %s",
+ name ? name : "NULL");
+ goto bad;
+ }
+ /*
+ * force reading of data to memory image
+ */
+ data = NULL;
+ while ((data = elf_rawdata(scnp, data)) != NULL)
+ ;
+ /*
+ * capture section information
+ * insert into list in order of sh_offset
+ */
+ cryptodebug("elfsign_adjustoffsets: "
+ "may have to adjust section %s, offset 0x%llx",
+ name ? name : "NULL", shdr.sh_offset);
+ tmpscnip = (struct scninfo *)malloc(sizeof (struct scninfo));
+ if (tmpscnip == NULL) {
+ cryptodebug("elfsign_adjustoffsets: "
+ "memory allocation failure");
+ goto bad;
+ }
+ tmpscnip->scni_scn = scnp;
+ tmpscnip->scni_offset = shdr.sh_offset;
+ for (scnipp = &scnip; *scnipp != NULL;
+ scnipp = &(*scnipp)->scni_next) {
+ if ((*scnipp)->scni_offset > tmpscnip->scni_offset)
+ break;
+ }
+ tmpscnip->scni_next = *scnipp;
+ *scnipp = tmpscnip;
+ }
+
+ /* move following sections as necessary */
+ for (tmpscnip = scnip; tmpscnip != NULL;
+ tmpscnip = tmpscnip->scni_next) {
+ scnp = tmpscnip->scni_scn;
+ if (gelf_getshdr(scnp, &shdr) == NULL) {
+ cryptodebug("elfsign_adjustoffsets: "
+ "elf_getshdr for section %d failed",
+ elf_ndxscn(scnp));
+ goto bad;
+ }
+ if (shdr.sh_offset >= prev_end)
+ break;
+ prev_end = (prev_end + shdr.sh_addralign - 1) &
+ (-shdr.sh_addralign);
+ name = elf_strptr(ess->es_elf, ess->es_shstrndx,
+ (size_t)shdr.sh_name);
+ cryptodebug("elfsign_adjustoffsets: "
+ "moving %s size 0x%llx from 0x%llx to 0x%llx",
+ name ? name : "NULL", shdr.sh_size,
+ shdr.sh_offset, prev_end);
+ shdr.sh_offset = prev_end;
+ if (gelf_update_shdr(scnp, &shdr) == 0) {
+ cryptodebug("gelf_update_shdr failed");
+ goto bad;
+ }
+ prev_end = shdr.sh_offset + shdr.sh_size;
+ }
+
+ /*
+ * adjust section header offset in elf header
+ */
+ if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
+ cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
+ goto bad;
+ }
+ if (elfehdr.e_shoff < prev_end) {
+ if (ess->es_ei_class == ELFCLASS32)
+ prev_end = (prev_end + ELF32_FSZ_OFF - 1) &
+ (-ELF32_FSZ_OFF);
+ else if (ess->es_ei_class == ELFCLASS64)
+ prev_end = (prev_end + ELF64_FSZ_OFF - 1) &
+ (-ELF64_FSZ_OFF);
+ cryptodebug("elfsign_adjustoffsets: "
+ "move sh_off from 0x%llx to 0x%llx",
+ elfehdr.e_shoff, prev_end);
+ elfehdr.e_shoff = prev_end;
+ if (gelf_update_ehdr(ess->es_elf, &elfehdr) == 0) {
+ cryptodebug("elf_update_ehdr() failed: %s",
+ elf_errmsg(-1));
+ goto bad;
+ }
+ }
+
+ retval = ELFSIGN_SUCCESS;
+
+bad:
+ while (scnip != NULL) {
+ tmpscnip = scnip->scni_next;
+ free(scnip);
+ scnip = tmpscnip;
+ }
+ return (retval);
+}
+
+struct filesignatures *
+elfsign_insert_dso(ELFsign_t ess,
+ struct filesignatures *fssp,
+ const char *dn,
+ int dn_len,
+ const uchar_t *sig,
+ int sig_len,
+ const char *oid,
+ int oid_len)
+{
+ return (filesig_insert_dso(fssp, ess->es_version, dn, dn_len,
+ sig, sig_len, oid, oid_len));
+}
+
+/*ARGSUSED*/
+filesig_vers_t
+elfsign_extract_sig(ELFsign_t ess,
+ struct filesignatures *fssp,
+ uchar_t *sig,
+ size_t *sig_len)
+{
+ struct filesig_extraction fsx;
+ filesig_vers_t version;
+
+ if (fssp == NULL)
+ return (FILESIG_UNKNOWN);
+ if (fssp->filesig_cnt != 1)
+ return (FILESIG_UNKNOWN);
+ version = filesig_extract(&fssp->filesig_sig, &fsx);
+ switch (version) {
+ case FILESIG_VERSION1:
+ case FILESIG_VERSION2:
+ case FILESIG_VERSION3:
+ case FILESIG_VERSION4:
+ if (*sig_len >= fsx.fsx_sig_len) {
+ (void) memcpy((char *)sig, (char *)fsx.fsx_signature,
+ *sig_len);
+ *sig_len = fsx.fsx_sig_len;
+ } else
+ version = FILESIG_UNKNOWN;
+ break;
+ default:
+ version = FILESIG_UNKNOWN;
+ break;
+ }
+
+ if (ess->es_version == FILESIG_UNKNOWN) {
+ ess->es_version = version;
+ }
+
+ return (version);
+}
+
+static ELFsign_status_t
+elfsign_hash_common(ELFsign_t ess, uchar_t *hash, size_t *hash_len,
+ boolean_t hash_mem_resident)
+{
+ Elf_Scn *scn = NULL;
+ ELFsign_status_t elfstat;
+ GElf_Shdr shdr;
+ SHA1_CTX ctx;
+
+ /* The buffer must be large enough to hold the hash */
+ if (*hash_len < SHA1_DIGEST_LENGTH)
+ return (ELFSIGN_FAILED);
+
+ bzero(hash, *hash_len);
+
+ /* Initialize the digest session */
+ SHA1Init(&ctx);
+
+ scn = elf_getscn(ess->es_elf, 0); /* "seek" to start */
+ (void) elf_errno();
+ while ((scn = elf_nextscn(ess->es_elf, scn)) != 0) {
+ char *name = NULL;
+ Elf_Data *data = NULL;
+
+ if (gelf_getshdr(scn, &shdr) == NULL) {
+ elfstat = ELFSIGN_FAILED;
+ goto done;
+ }
+
+ name = elf_strptr(ess->es_elf, ess->es_shstrndx,
+ (size_t)shdr.sh_name);
+ if (name == NULL)
+ name = "NULL";
+
+ if (!hash_mem_resident &&
+ (ess->es_version == FILESIG_VERSION1 ||
+ ess->es_version == FILESIG_VERSION3)) {
+ /*
+ * skip the signature section only
+ */
+ if (shdr.sh_type == SHT_SUNW_SIGNATURE) {
+ cryptodebug("elfsign_hash: skipping %s", name);
+ continue;
+ }
+ } else if (!(shdr.sh_flags & SHF_ALLOC)) {
+ /*
+ * select only memory resident sections
+ */
+ cryptodebug("elfsign_hash: skipping %s", name);
+ continue;
+ }
+
+ /*
+ * throw this section into the hash
+ * use elf_rawdata for endian-independence
+ * use elf_getdata to get update of .shstrtab
+ */
+ while ((data = (shdr.sh_type == SHT_STRTAB ?
+ elf_getdata(scn, data) : elf_rawdata(scn, data))) != NULL) {
+ if (data->d_buf == NULL) {
+ cryptodebug("elfsign_hash: %s has NULL data",
+ name);
+ continue;
+ }
+ cryptodebug("elfsign_hash: updating hash "
+ "with %s data size=%d", name, data->d_size);
+ SHA1Update(&ctx, data->d_buf, data->d_size);
+ }
+ }
+ if (elf_errmsg(0) != NULL) {
+ cryptodebug("elfsign_hash: %s", elf_errmsg(-1));
+ elfstat = ELFSIGN_FAILED;
+ goto done;
+ }
+
+ SHA1Final(hash, &ctx);
+ *hash_len = SHA1_DIGEST_LENGTH;
+ { /* DEBUG START */
+ const int hashstr_len = (*hash_len) * 2 + 1;
+ char *hashstr = malloc(hashstr_len);
+
+ if (hashstr != NULL) {
+ tohexstr(hash, *hash_len, hashstr, hashstr_len);
+ cryptodebug("hash value is: %s", hashstr);
+ free(hashstr);
+ }
+ } /* DEBUG END */
+ elfstat = ELFSIGN_SUCCESS;
+done:
+ return (elfstat);
+}
+
+/*
+ * elfsign_hash - return the hash of the ELF sections affecting execution.
+ *
+ * IN: ess, hash_len
+ * OUT: hash, hash_len
+ */
+ELFsign_status_t
+elfsign_hash(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
+{
+ return (elfsign_hash_common(ess, hash, hash_len, B_FALSE));
+}
+
+/*
+ * elfsign_hash_mem_resident - return the hash of the ELF sections
+ * with only memory resident sections.
+ *
+ * IN: ess, hash_len
+ * OUT: hash, hash_len
+ */
+ELFsign_status_t
+elfsign_hash_mem_resident(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
+{
+ return (elfsign_hash_common(ess, hash, hash_len, B_TRUE));
+}
+
+/*
+ * elfsign_hash_esa = return the hash of the esa_buffer
+ *
+ * IN: ess, esa_buf, esa_buf_len, hash_len
+ * OUT: hash, hash_len
+ */
+ELFsign_status_t
+elfsign_hash_esa(ELFsign_t ess, uchar_t *esa_buf, size_t esa_buf_len,
+ uchar_t **hash, size_t *hash_len)
+{
+ SHA1_CTX ctx;
+
+ cryptodebug("esa_hash version is: %s",
+ version_to_str(ess->es_version));
+ if (ess->es_version <= FILESIG_VERSION2) {
+ /*
+ * old rsa_md5_sha1 format
+ * signed with MD5 digest, just pass full esa_buf
+ */
+ *hash = esa_buf;
+ *hash_len = esa_buf_len;
+ return (ELFSIGN_SUCCESS);
+ }
+
+ if (*hash_len < SHA1_DIGEST_LENGTH)
+ return (ELFSIGN_FAILED);
+
+ bzero(*hash, *hash_len);
+ SHA1Init(&ctx);
+ SHA1Update(&ctx, esa_buf, esa_buf_len);
+ SHA1Final(*hash, &ctx);
+ *hash_len = SHA1_DIGEST_LENGTH;
+
+ { /* DEBUG START */
+ const int hashstr_len = (*hash_len) * 2 + 1;
+ char *hashstr = malloc(hashstr_len);
+
+ if (hashstr != NULL) {
+ tohexstr(*hash, *hash_len, hashstr, hashstr_len);
+ cryptodebug("esa_hash value is: %s", hashstr);
+ free(hashstr);
+ }
+ } /* DEBUG END */
+
+ return (ELFSIGN_SUCCESS);
+}
+
+/*
+ * elfsign_verify_signature - Verify the signature of the ELF object.
+ *
+ * IN: ess
+ * OUT: esipp
+ * RETURNS:
+ * ELFsign_status_t
+ */
+ELFsign_status_t
+elfsign_verify_signature(ELFsign_t ess, struct ELFsign_sig_info **esipp)
+{
+ ELFsign_status_t ret = ELFSIGN_FAILED;
+ struct filesignatures *fssp;
+ struct filesig *fsgp;
+ size_t fslen;
+ struct filesig_extraction fsx;
+ uchar_t hash[SIG_MAX_LENGTH];
+ size_t hash_len;
+ ELFCert_t cert = NULL;
+ int sigcnt;
+ int nocert = 0;
+ struct ELFsign_sig_info *esip = NULL;
+
+ if (esipp != NULL) {
+ esip = (struct ELFsign_sig_info *)
+ calloc(1, sizeof (struct ELFsign_sig_info));
+ *esipp = esip;
+ }
+
+ /*
+ * Find out which cert we need, based on who signed the ELF object
+ */
+ if (elfsign_signatures(ess, &fssp, &fslen, ES_GET) != ELFSIGN_SUCCESS) {
+ return (ELFSIGN_NOTSIGNED);
+ }
+
+ if (fssp->filesig_cnt < 1) {
+ ret = ELFSIGN_FAILED;
+ goto cleanup;
+ }
+
+ fsgp = &fssp->filesig_sig;
+
+ /*
+ * Scan the signature block, looking for a verifiable signature
+ */
+ for (sigcnt = 0; sigcnt < fssp->filesig_cnt;
+ sigcnt++, fsgp = filesig_next(fsgp)) {
+ ess->es_version = filesig_extract(fsgp, &fsx);
+ cryptodebug("elfsign_verify_signature: version=%s",
+ version_to_str(ess->es_version));
+ switch (ess->es_version) {
+ case FILESIG_VERSION1:
+ case FILESIG_VERSION2:
+ case FILESIG_VERSION3:
+ case FILESIG_VERSION4:
+ break;
+ default:
+ ret = ELFSIGN_FAILED;
+ goto cleanup;
+ }
+
+ cryptodebug("elfsign_verify_signature: signer_DN=\"%s\"",
+ fsx.fsx_signer_DN);
+ cryptodebug("elfsign_verify_signature: algorithmOID=\"%s\"",
+ fsx.fsx_sig_oid);
+ /* return signer DN if requested */
+ if (esipp != NULL) {
+ esip->esi_format = fsx.fsx_format;
+ if (esip->esi_signer != NULL)
+ free(esip->esi_signer);
+ esip->esi_signer = strdup(fsx.fsx_signer_DN);
+ esip->esi_time = fsx.fsx_time;
+ }
+
+ /*
+ * look for certificate
+ */
+ if (cert != NULL)
+ elfcertlib_releasecert(ess, cert);
+
+ /*
+ * skip unfound certificates
+ */
+ if (!elfcertlib_getcert(ess, ess->es_certpath,
+ fsx.fsx_signer_DN, &cert, ess->es_action)) {
+ cryptodebug("unable to find certificate "
+ "with DN=\"%s\" for %s",
+ fsx.fsx_signer_DN, ess->es_pathname);
+ nocert++;
+ continue;
+ }
+
+ /*
+ * skip unverified certificates
+ * force verification of crypto certs
+ */
+ if ((ess->es_action == ES_GET_CRYPTO ||
+ strstr(fsx.fsx_signer_DN, ELFSIGN_CRYPTO)) &&
+ !elfcertlib_verifycert(ess, cert)) {
+ cryptodebug("elfsign_verify_signature: invalid cert");
+ nocert++;
+ continue;
+ }
+
+ /*
+ * At this time the only sha1WithRSAEncryption is supported,
+ * so check that is what we have and skip with anything else.
+ */
+ if (strcmp(fsx.fsx_sig_oid, OID_sha1WithRSAEncryption) != 0) {
+ continue;
+ }
+
+ nocert = 0;
+ /*
+ * compute file hash
+ */
+ hash_len = sizeof (hash);
+ if (elfsign_hash(ess, hash, &hash_len) != ELFSIGN_SUCCESS) {
+ cryptodebug("elfsign_verify_signature:"
+ " elfsign_hash failed");
+ ret = ELFSIGN_FAILED;
+ break;
+ }
+
+ { /* DEBUG START */
+ const int sigstr_len = fsx.fsx_sig_len * 2 + 1;
+ char *sigstr = malloc(sigstr_len);
+
+ if (sigstr != NULL) {
+ tohexstr(fsx.fsx_signature, fsx.fsx_sig_len,
+ sigstr, sigstr_len);
+ cryptodebug("signature value is: %s", sigstr);
+ free(sigstr);
+ }
+ } /* DEBUG END */
+
+ if (elfcertlib_verifysig(ess, cert,
+ fsx.fsx_signature, fsx.fsx_sig_len, hash, hash_len)) {
+ if (ess->es_sigvercallback)
+ (ess->es_sigvercallback)
+ (ess->es_callbackctx, fssp, fslen, cert);
+ /*
+ * The signature is verified!
+ * Check if this is a restricted provider
+ */
+ if (strstr(fsx.fsx_signer_DN, USAGELIMITED) == NULL)
+ ret = ELFSIGN_SUCCESS;
+ else {
+ cryptodebug("DN is tagged for usagelimited");
+ ret = elfsign_verify_esa(ess,
+ fsx.fsx_signature, fsx.fsx_sig_len);
+ }
+ break;
+ }
+
+ cryptodebug("elfsign_verify_signature: invalid signature");
+ }
+
+cleanup:
+ if (cert != NULL)
+ elfcertlib_releasecert(ess, cert);
+
+ free(fssp);
+ if (ret == ELFSIGN_FAILED && nocert)
+ ret = ELFSIGN_INVALID_CERTPATH;
+ return (ret);
+}
+
+/*
+ * Verify the contents of the .esa file, as per Jumbo export control
+ * document. Logic in this function should remain unchanged, unless
+ * a misinterpretation of the jumbo case was found or if there are
+ * changes in export regulations necessitating a change.
+ *
+ * If the .esa file exists, but is somehow corrupted, we just return
+ * that this is restricted. This is consistent with the Jumbo export
+ * case covering this library and other compenents of ON. Do not change
+ * this logic without consulting export control.
+ *
+ * Please see do_gen_esa() for a description of the esa file format.
+ *
+ */
+static ELFsign_status_t
+elfsign_verify_esa(ELFsign_t ess, uchar_t *orig_sig, size_t orig_sig_len)
+{
+ ELFsign_status_t ret = ELFSIGN_RESTRICTED;
+ char *elfobj_esa = NULL;
+ size_t elfobj_esa_len;
+ int esa_fd = -1;
+ size_t esa_buf_len = 0;
+ uchar_t *main_sig;
+ size_t main_sig_len = 0;
+ uchar_t hash[SIG_MAX_LENGTH], *hash_ptr = hash;
+ size_t hash_len = SIG_MAX_LENGTH;
+ char *esa_dn = NULL;
+ size_t esa_dn_len = 0;
+ uchar_t *esa_sig;
+ size_t esa_sig_len = 0;
+ uchar_t *esa_file_buffer = NULL, *esa_file_ptr;
+ struct stat statbuf;
+ ELFCert_t cert = NULL;
+
+ cryptodebug("elfsign_verify_esa");
+
+ /* does the activation file exist? */
+ elfobj_esa_len = strlen(ess->es_pathname) + ESA_LEN + 1;
+ elfobj_esa = malloc(elfobj_esa_len);
+ if (elfobj_esa == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to allocate buffer for esa filename."));
+ goto cleanup;
+ }
+
+ (void) strlcpy(elfobj_esa, ess->es_pathname, elfobj_esa_len);
+ (void) strlcat(elfobj_esa, ESA, elfobj_esa_len);
+
+ if ((esa_fd = open(elfobj_esa, O_RDONLY|O_NONBLOCK)) == -1) {
+ cryptodebug("No .esa file was found, or it was unreadable");
+ goto cleanup;
+ }
+
+ cryptodebug("Reading contents of esa file %s", elfobj_esa);
+
+ if (fstat(esa_fd, &statbuf) == -1) {
+ cryptoerror(LOG_STDERR,
+ gettext("Can't stat %s"), elfobj_esa);
+ goto cleanup;
+ }
+
+ /*
+ * mmap the buffer to save on syscalls
+ */
+ esa_file_buffer = (uchar_t *)mmap(NULL, statbuf.st_size, PROT_READ,
+ MAP_PRIVATE, esa_fd, 0);
+
+ if (esa_file_buffer == MAP_FAILED) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to mmap file to a buffer for %s."),
+ elfobj_esa);
+ goto cleanup;
+ }
+
+ esa_file_ptr = esa_file_buffer;
+ elfsign_buffer_len(ess, &main_sig_len, esa_file_ptr, ES_GET);
+ esa_file_ptr += sizeof (uint32_t);
+ cryptodebug("Contents of esa file: main_sig_len=%d", main_sig_len);
+ main_sig = esa_file_ptr;
+
+ esa_file_ptr += main_sig_len;
+
+ /* verify .esa main signature versus original signature */
+ if (main_sig_len != orig_sig_len ||
+ memcmp(main_sig, orig_sig, orig_sig_len) != 0) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to match original signature from %s."),
+ elfobj_esa);
+ goto cleanup;
+ }
+
+ elfsign_buffer_len(ess, &esa_dn_len, esa_file_ptr, ES_GET);
+ esa_file_ptr += sizeof (uint32_t);
+ cryptodebug("Contents of esa file: esa_dn_len=%d", esa_dn_len);
+
+ esa_dn = malloc(esa_dn_len + 1);
+ if (esa_dn == NULL) {
+ cryptoerror(LOG_ERR,
+ gettext("Unable to allocate memory for dn buffer."));
+ goto cleanup;
+ }
+ (void) memcpy(esa_dn, esa_file_ptr, esa_dn_len);
+ esa_dn[esa_dn_len] = '\0';
+ esa_file_ptr += esa_dn_len;
+ cryptodebug("Contents of esa file: esa_dn=%s", esa_dn);
+
+ elfsign_buffer_len(ess, &esa_sig_len, esa_file_ptr, ES_GET);
+ esa_file_ptr += sizeof (uint32_t);
+ cryptodebug("Contents of esa file: esa_sig_len=%d", esa_sig_len);
+
+ esa_sig = esa_file_ptr;
+
+ cryptodebug("Read esa contents, now verifying");
+
+ /*
+ * dn used in .esa file should not be limited.
+ */
+ if (strstr(esa_dn, USAGELIMITED) != NULL) {
+ cryptoerror(LOG_ERR,
+ gettext("DN for .esa file is tagged as limited for %s.\n"
+ "Activation files should only be tagged as unlimited.\n"
+ "Please contact vendor for this provider"),
+ ess->es_pathname);
+ goto cleanup;
+ }
+
+ if (!elfcertlib_getcert(ess, ess->es_certpath, esa_dn, &cert,
+ ess->es_action)) {
+ cryptodebug(gettext("unable to find certificate "
+ "with DN=\"%s\" for %s"),
+ esa_dn, ess->es_pathname);
+ goto cleanup;
+ }
+
+ /*
+ * Since we've already matched the original signature
+ * and the main file signature, we can just verify the esa signature
+ * against the main file signature.
+ */
+ esa_buf_len = sizeof (uint32_t) + main_sig_len;
+
+ if (elfsign_hash_esa(ess, esa_file_buffer, esa_buf_len,
+ &hash_ptr, &hash_len) != ELFSIGN_SUCCESS) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to hash activation contents."));
+ goto cleanup;
+ }
+
+
+ if (!elfcertlib_verifysig(ess, cert, esa_sig, esa_sig_len,
+ hash_ptr, hash_len)) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to verify .esa contents for %s"),
+ ess->es_pathname);
+ goto cleanup;
+ }
+
+ cryptodebug("Verified esa contents");
+ if (ess->es_sigvercallback)
+ (ess->es_sigvercallback) (ess->es_callbackctx,
+ esa_file_buffer, statbuf.st_size, cert);
+
+ /*
+ * validate the certificate used to sign the activation file
+ */
+ if (!elfcertlib_verifycert(ess, cert)) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to verify .esa certificate %s for %s"),
+ esa_dn, ess->es_pathname);
+ goto cleanup;
+ }
+
+ cryptodebug("Verified esa certificate");
+ ret = ELFSIGN_SUCCESS;
+
+cleanup:
+ if (elfobj_esa != NULL)
+ free(elfobj_esa);
+
+ if (esa_fd != -1)
+ (void) close(esa_fd);
+
+ if (esa_file_buffer != NULL)
+ (void) munmap((caddr_t)esa_file_buffer, statbuf.st_size);
+
+ if (esa_dn != NULL)
+ free(esa_dn);
+
+ if (cert != NULL)
+ elfcertlib_releasecert(ess, cert);
+
+ return (ret);
+}
+
+static uint32_t
+elfsign_switch_uint32(uint32_t i)
+{
+ return (((i & 0xff) << 24) | ((i & 0xff00) << 8) |
+ ((i >> 8) & 0xff00) | ((i >> 24) & 0xff));
+}
+
+static uint64_t
+elfsign_switch_uint64(uint64_t i)
+{
+ return (((uint64_t)elfsign_switch_uint32(i) << 32) |
+ (elfsign_switch_uint32(i >> 32)));
+}
+
+/*
+ * If appropriate, switch the endianness of the filesignatures structure
+ * Examine the structure only when it is in native endianness
+ */
+static ELFsign_status_t
+elfsign_switch(ELFsign_t ess, struct filesignatures *fssp,
+ enum ES_ACTION action)
+{
+ int fscnt;
+ filesig_vers_t version;
+ struct filesig *fsgp, *fsgpnext;
+
+ if (ess->es_same_endian)
+ return (ELFSIGN_SUCCESS);
+
+ if (ES_ACTISUPDATE(action))
+ fscnt = fssp->filesig_cnt;
+ fssp->filesig_cnt = elfsign_switch_uint32(fssp->filesig_cnt);
+ if (!ES_ACTISUPDATE(action))
+ fscnt = fssp->filesig_cnt;
+
+ fsgp = &(fssp)->filesig_sig;
+ for (; fscnt > 0; fscnt--, fsgp = fsgpnext) {
+ if (ES_ACTISUPDATE(action)) {
+ version = fsgp->filesig_version;
+ fsgpnext = filesig_next(fsgp);
+ }
+ fsgp->filesig_size =
+ elfsign_switch_uint32(fsgp->filesig_size);
+ fsgp->filesig_version =
+ elfsign_switch_uint32(fsgp->filesig_version);
+ if (!ES_ACTISUPDATE(action)) {
+ version = fsgp->filesig_version;
+ fsgpnext = filesig_next(fsgp);
+ }
+ switch (version) {
+ case FILESIG_VERSION1:
+ case FILESIG_VERSION2:
+ fsgp->filesig_v1_dnsize =
+ elfsign_switch_uint32(fsgp->filesig_v1_dnsize);
+ fsgp->filesig_v1_sigsize =
+ elfsign_switch_uint32(fsgp->filesig_v1_sigsize);
+ fsgp->filesig_v1_oidsize =
+ elfsign_switch_uint32(fsgp->filesig_v1_oidsize);
+ break;
+ case FILESIG_VERSION3:
+ case FILESIG_VERSION4:
+ fsgp->filesig_v3_time =
+ elfsign_switch_uint64(fsgp->filesig_v3_time);
+ fsgp->filesig_v3_dnsize =
+ elfsign_switch_uint32(fsgp->filesig_v3_dnsize);
+ fsgp->filesig_v3_sigsize =
+ elfsign_switch_uint32(fsgp->filesig_v3_sigsize);
+ fsgp->filesig_v3_oidsize =
+ elfsign_switch_uint32(fsgp->filesig_v3_oidsize);
+ break;
+ default:
+ cryptodebug("elfsign_switch: failed");
+ return (ELFSIGN_FAILED);
+ }
+ }
+ return (ELFSIGN_SUCCESS);
+}
+
+/*
+ * get/put an integer value from/to a buffer, possibly of opposite endianness
+ */
+void
+elfsign_buffer_len(ELFsign_t ess, size_t *ip, uchar_t *cp,
+ enum ES_ACTION action)
+{
+ uint32_t tmp;
+
+ if (!ES_ACTISUPDATE(action)) {
+ /* fetch integer from buffer */
+ (void) memcpy(&tmp, cp, sizeof (tmp));
+ if (!ess->es_same_endian) {
+ tmp = elfsign_switch_uint32(tmp);
+ }
+ *ip = tmp;
+ } else {
+ /* put integer into buffer */
+ tmp = *ip;
+ if (!ess->es_same_endian) {
+ tmp = elfsign_switch_uint32(tmp);
+ }
+ (void) memcpy(cp, &tmp, sizeof (tmp));
+ }
+}
+
+char const *
+elfsign_strerror(ELFsign_status_t elferror)
+{
+ char const *msg = NULL;
+
+ switch (elferror) {
+ case ELFSIGN_SUCCESS:
+ msg = gettext("sign or verify of ELF object succeeded");
+ break;
+ case ELFSIGN_FAILED:
+ msg = gettext("sign or verify of ELF object failed");
+ break;
+ case ELFSIGN_NOTSIGNED:
+ msg = gettext("ELF object not signed");
+ break;
+ case ELFSIGN_INVALID_CERTPATH:
+ msg = gettext("cannot access certificate");
+ break;
+ case ELFSIGN_INVALID_ELFOBJ:
+ msg = gettext("unable to open as an ELF object");
+ break;
+ case ELFSIGN_RESTRICTED:
+ msg = gettext("ELF object is restricted");
+ break;
+ case ELFSIGN_UNKNOWN:
+ default:
+ msg = gettext("Unknown error");
+ break;
+ }
+
+ return (msg);
+}
+
+boolean_t
+elfsign_sig_info(struct filesignatures *fssp, struct ELFsign_sig_info **esipp)
+{
+ struct filesig_extraction fsx;
+ struct ELFsign_sig_info *esip;
+
+ esip = (struct ELFsign_sig_info *)
+ calloc(1, sizeof (struct ELFsign_sig_info));
+ *esipp = esip;
+ if (esip == NULL)
+ return (B_FALSE);
+
+ switch (filesig_extract(&fssp->filesig_sig, &fsx)) {
+ case FILESIG_VERSION1:
+ case FILESIG_VERSION2:
+ case FILESIG_VERSION3:
+ case FILESIG_VERSION4:
+ esip->esi_format = fsx.fsx_format;
+ esip->esi_signer = strdup(fsx.fsx_signer_DN);
+ esip->esi_time = fsx.fsx_time;
+ break;
+ default:
+ free(esip);
+ *esipp = NULL;
+ }
+
+ return (*esipp != NULL);
+}
+
+void
+elfsign_sig_info_free(struct ELFsign_sig_info *esip)
+{
+ if (esip != NULL) {
+ free(esip->esi_signer);
+ free(esip);
+ }
+}
diff --git a/usr/src/lib/libelfsign/common/libelfsign.h b/usr/src/lib/libelfsign/common/libelfsign.h
new file mode 100644
index 0000000000..8637fc4c6d
--- /dev/null
+++ b/usr/src/lib/libelfsign/common/libelfsign.h
@@ -0,0 +1,194 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBELFSIGN_H
+#define _LIBELFSIGN_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * libelfsign Private Interfaces
+ * This Header file should not be shipped as part of Solaris binary or
+ * source products.
+ */
+
+#include <sys/crypto/elfsign.h>
+#include <libelf.h>
+#include <fcntl.h>
+#include <md5.h>
+#include <sha1.h>
+#include <kmfapi.h>
+
+/*
+ * Certificate-related definitions
+ */
+#define ELFSIGN_CRYPTO "Solaris Cryptographic Framework"
+#define USAGELIMITED "OU=UsageLimited"
+#define ESA ".esa"
+#define ESA_LEN sizeof (".esa")
+
+typedef enum ELFCert_VStatus_e {
+ E_UNCHECKED,
+ E_OK,
+ E_IS_TA,
+ E_FAILED
+} ELFCert_VStatus_t;
+
+typedef struct ELFCert_s {
+ ELFCert_VStatus_t c_verified;
+ char *c_subject;
+ char *c_issuer;
+ KMF_X509_DER_CERT c_cert;
+ KMF_KEY_HANDLE c_privatekey;
+} *ELFCert_t;
+
+#define CRYPTO_CERTS_DIR "/etc/crypto/certs"
+#define ETC_CERTS_DIR "/etc/certs"
+
+/*
+ * libelfsign actions
+ */
+enum ES_ACTION {
+ ES_GET,
+ ES_GET_CRYPTO,
+ ES_UPDATE,
+ ES_UPDATE_RSA_MD5_SHA1,
+ ES_UPDATE_RSA_SHA1
+};
+#define ES_ACTISUPDATE(a) ((a) >= ES_UPDATE)
+
+/*
+ * Context for elfsign operation
+ */
+struct ELFsign_s {
+ Elf *es_elf;
+ char *es_pathname;
+ char *es_certpath;
+ int es_fd;
+ size_t es_shstrndx;
+ enum ES_ACTION es_action;
+ KMF_KEY_HANDLE es_privatekey;
+ filesig_vers_t es_version;
+ boolean_t es_same_endian;
+ boolean_t es_has_phdr;
+ char es_ei_class;
+ struct flock es_flock;
+ KMF_HANDLE_T es_kmfhandle;
+ void *es_callbackctx;
+ void (*es_sigvercallback)(void *, void *, size_t, ELFCert_t);
+ void (*es_certCAcallback)(void *, ELFCert_t, char *);
+ void (*es_certvercallback)(void *, ELFCert_t, ELFCert_t);
+};
+
+#define ES_FMT_RSA_MD5_SHA1 "rsa_md5_sha1"
+#define ES_FMT_RSA_SHA1 "rsa_sha1"
+
+/*
+ * ELF signature handling
+ */
+typedef struct ELFsign_s *ELFsign_t;
+struct ELFsign_sig_info {
+ char *esi_format;
+ char *esi_signer;
+ time_t esi_time;
+};
+
+extern struct filesignatures *elfsign_insert_dso(ELFsign_t ess,
+ struct filesignatures *fsp, const char *dn, int dn_len,
+ const uchar_t *sig, int sig_len, const char *oid, int oid_len);
+extern filesig_vers_t elfsign_extract_sig(ELFsign_t ess,
+ struct filesignatures *fsp, uchar_t *sig, size_t *sig_len);
+extern ELFsign_status_t elfsign_begin(const char *,
+ enum ES_ACTION, ELFsign_t *);
+extern void elfsign_end(ELFsign_t ess);
+extern ELFsign_status_t elfsign_setcertpath(ELFsign_t ess, const char *path);
+extern ELFsign_status_t elfsign_verify_signature(ELFsign_t ess,
+ struct ELFsign_sig_info **esipp);
+extern ELFsign_status_t elfsign_hash(ELFsign_t ess, uchar_t *hash,
+ size_t *hash_len);
+extern ELFsign_status_t elfsign_hash_mem_resident(ELFsign_t ess,
+ uchar_t *hash, size_t *hash_len);
+extern ELFsign_status_t elfsign_hash_esa(ELFsign_t ess,
+ uchar_t *esa_buf, size_t esa_buf_len, uchar_t **hash, size_t *hash_len);
+extern void elfsign_buffer_len(ELFsign_t ess, size_t *ip, uchar_t *cp,
+ enum ES_ACTION action);
+
+extern void elfsign_setcallbackctx(ELFsign_t ess, void *ctx);
+extern void elfsign_setsigvercallback(ELFsign_t ess,
+ void (*cb)(void *, void *, size_t, ELFCert_t));
+extern ELFsign_status_t elfsign_signatures(ELFsign_t ess,
+ struct filesignatures **fspp, size_t *fs_len, enum ES_ACTION action);
+
+extern char const *elfsign_strerror(ELFsign_status_t);
+extern boolean_t elfsign_sig_info(struct filesignatures *fssp,
+ struct ELFsign_sig_info **esipp);
+extern void elfsign_sig_info_free(struct ELFsign_sig_info *);
+
+/*
+ * ELF "Certificate Library"
+ */
+
+extern const char _PATH_ELFSIGN_CERTS[];
+
+#define ELFCERT_MAX_DN_LEN 255
+
+extern boolean_t elfcertlib_init(ELFsign_t);
+extern void elfcertlib_fini(ELFsign_t);
+extern boolean_t elfcertlib_settoken(ELFsign_t, char *);
+extern void elfcertlib_setcertCAcallback(ELFsign_t ess,
+ void (*cb)(void *, ELFCert_t, char *));
+extern void elfcertlib_setcertvercallback(ELFsign_t ess,
+ void (*cb)(void *, ELFCert_t, ELFCert_t));
+
+extern boolean_t elfcertlib_getcert(ELFsign_t ess, char *cert_pathname,
+ char *signer_DN, ELFCert_t *certp, enum ES_ACTION action);
+extern void elfcertlib_releasecert(ELFsign_t, ELFCert_t);
+extern char *elfcertlib_getdn(ELFCert_t cert);
+extern char *elfcertlib_getissuer(ELFCert_t cert);
+
+extern boolean_t elfcertlib_loadprivatekey(ELFsign_t ess, ELFCert_t cert,
+ const char *path);
+extern boolean_t elfcertlib_loadtokenkey(ELFsign_t ess, ELFCert_t cert,
+ const char *token_id, const char *pin);
+
+extern boolean_t elfcertlib_sign(ELFsign_t ess, ELFCert_t cert,
+ const uchar_t *data, size_t data_len, uchar_t *sig,
+ size_t *sig_len);
+
+extern boolean_t elfcertlib_verifycert(ELFsign_t ess, ELFCert_t cert);
+extern boolean_t elfcertlib_verifysig(ELFsign_t ess, ELFCert_t cert,
+ const uchar_t *sig, size_t sig_len,
+ const uchar_t *data, size_t data_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBELFSIGN_H */
diff --git a/usr/src/lib/libelfsign/common/llib-lelfsign b/usr/src/lib/libelfsign/common/llib-lelfsign
new file mode 100644
index 0000000000..5ed60d4a75
--- /dev/null
+++ b/usr/src/lib/libelfsign/common/llib-lelfsign
@@ -0,0 +1,32 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <sys/crypto/elfsign.h>
+#include <libelfsign.h>
diff --git a/usr/src/lib/libelfsign/common/mapfile.map b/usr/src/lib/libelfsign/common/mapfile.map
new file mode 100644
index 0000000000..b79ca2d3a9
--- /dev/null
+++ b/usr/src/lib/libelfsign/common/mapfile.map
@@ -0,0 +1,62 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+SUNW_1.1 {
+ global:
+ elfsign_begin;
+ elfsign_buffer_len;
+ elfsign_end;
+ elfsign_extract_sig;
+ elfsign_hash;
+ elfsign_hash_esa;
+ elfsign_hash_mem_resident;
+ elfsign_insert_dso;
+ elfsign_setcallbackctx;
+ elfsign_setsigvercallback;
+ elfsign_setcertpath;
+ elfsign_sig_info;
+ elfsign_sig_info_free;
+ elfsign_signatures;
+ elfsign_strerror;
+ elfsign_verify_signature;
+ elfcertlib_getcert;
+ elfcertlib_getdn;
+ elfcertlib_getissuer;
+ elfcertlib_init;
+ elfcertlib_loadprivatekey;
+ elfcertlib_loadtokenkey;
+ elfcertlib_releasecert;
+ elfcertlib_setcertCAcallback;
+ elfcertlib_setcertvercallback;
+ elfcertlib_settoken;
+ elfcertlib_sign;
+ elfcertlib_verifycert;
+ elfcertlib_verifysig;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libelfsign/i386/Makefile b/usr/src/lib/libelfsign/i386/Makefile
new file mode 100644
index 0000000000..a31def5dc7
--- /dev/null
+++ b/usr/src/lib/libelfsign/i386/Makefile
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libelfsign/i386/Makefile
+#
+
+include ../Makefile.com
+
+.KEEP_STATE:
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libelfsign/sparc/Makefile b/usr/src/lib/libelfsign/sparc/Makefile
new file mode 100644
index 0000000000..7c783f69c9
--- /dev/null
+++ b/usr/src/lib/libelfsign/sparc/Makefile
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+.KEEP_STATE:
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386
index 6137bd6000..99ade1781a 100644
--- a/usr/src/pkgdefs/etc/exception_list_i386
+++ b/usr/src/pkgdefs/etc/exception_list_i386
@@ -65,6 +65,7 @@ usr/lib/llib-lcryptoutil.ln i386
usr/lib/llib-lcryptoutil i386
usr/lib/amd64/llib-lcryptoutil.ln i386
usr/include/cryptoutil.h i386
+usr/include/libelfsign.h i386
#
# The following files are used by the DHCP service, the
# standalone's DHCP implementation, and the kernel (nfs_dlboot).
diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc
index 7eaadb2d7d..321746afcb 100644
--- a/usr/src/pkgdefs/etc/exception_list_sparc
+++ b/usr/src/pkgdefs/etc/exception_list_sparc
@@ -54,6 +54,7 @@ usr/lib/llib-lcryptoutil.ln sparc
usr/lib/llib-lcryptoutil sparc
usr/lib/sparcv9/llib-lcryptoutil.ln sparc
usr/include/cryptoutil.h sparc
+usr/include/libelfsign.h sparc
#
# The following files are used by libdhcpsvc, the
# standalone's DHCP implementation, and the kernel (nfs_dlboot).
diff --git a/usr/src/tools/Makefile b/usr/src/tools/Makefile
index 55d1ee70c0..b42ce1b22f 100644
--- a/usr/src/tools/Makefile
+++ b/usr/src/tools/Makefile
@@ -54,7 +54,7 @@ COMMON_SUBDIRS= \
#
# special versions of commands for use only in build
#
-CLOSED_UNSHIPPED_SUBDIRS = \
+UNSHIPPED_SUBDIRS = \
elfsign
sparc_SUBDIRS= \
@@ -75,9 +75,11 @@ LINTSUBDIRS= \
protocmp \
protolist
-SUBDIRS= $(BOOT_SUBDIRS) $($(MACH)_SUBDIRS) $(COMMON_SUBDIRS)
-
-$(CLOSED_BUILD)CLOSED_SUBDIRS= $(CLOSED_UNSHIPPED_SUBDIRS)
+SUBDIRS= \
+ $(BOOT_SUBDIRS) \
+ $($(MACH)_SUBDIRS) \
+ $(COMMON_SUBDIRS) \
+ $(UNSHIPPED_SUBDIRS)
#
# Packages built here
@@ -116,11 +118,11 @@ _msg := TARGET= _msg
.KEEP_STATE:
-all install: $(ROOTDIRS) .WAIT $(SUBDIRS) $(CLOSED_SUBDIRS)
+all install: $(ROOTDIRS) .WAIT $(SUBDIRS)
-clean: $(SUBDIRS) $(CLOSED_SUBDIRS)
+clean: $(SUBDIRS)
-clobber: $(SUBDIRS) $(CLOSED_SUBDIRS)
+clobber: $(SUBDIRS)
$(RM) -rf $(TOOLS_PROTO)
pkg: install .WAIT $(PKG_SUBDIRS)
@@ -135,9 +137,6 @@ $(SUBDIRS): FRC
$(PKG_SUBDIRS): FRC
@cd $@; pwd; $(MAKE) install
-$(CLOSED_SUBDIRS): FRC
- cd $(CLOSED)/tools/$@; pwd; $(MAKE) $(TARGET)
-
FRC:
$(ROOTDIRS):
diff --git a/usr/src/tools/elfsign/Makefile b/usr/src/tools/elfsign/Makefile
new file mode 100644
index 0000000000..21a095650f
--- /dev/null
+++ b/usr/src/tools/elfsign/Makefile
@@ -0,0 +1,88 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+PROG= elfsign
+SHFILES= elfsigncmp
+
+LIBOBJS= elfcertlib.o elfsignlib.o
+OBJS= $(PROG).o $(LIBOBJS)
+
+.PARALLEL: $(OBJS)
+
+CMDDIR= $(SRC)/cmd/cmd-crypto/elfsign
+LIBDIR= $(SRC)/lib/libelfsign/common
+SRCS= $(CMDDIR)/$(PROG).c $(LIBOBJS:%.o=$(LIBDIR)/%.c)
+CLEANFILES= $(PROG) $(OBJS) $(SHFILES)
+
+include ../../../src/tools/Makefile.tools
+
+OWNER= root
+GROUP= bin
+CFLAGS += $(CCVERBOSE)
+CFLAGS += -_gcc=-fasm
+
+CPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS
+CPPFLAGS += -I$(SRC)/lib/libelfsign/common
+CPPFLAGS += -I$(SRC)/uts/common
+CPPFLAGS += -I$(SRC)/lib/libkmf/include
+CPPFLAGS += -I$(SRC)/lib/libcryptoutil/common
+LDFLAGS += -lmd -lelf -lkmf -lcryptoutil -lc
+
+#
+# While the gate builds a libelfsign.so linked staticly against
+# pksc11_softtoken, the tools version of libelfsign is dynamically linked
+# against the build machines pkcs11_softtoken.so.
+#
+SOFTTOKENDIR = /usr/lib/security
+SOFTTOKENLIB = pkcs11_softtoken.so
+LDFLAGS += -R $(SOFTTOKENDIR) $(SOFTTOKENDIR)/$(SOFTTOKENLIB)
+
+MKDIR= mkdir
+
+.KEEP_STATE:
+
+all: $(PROG) $(SHFILES)
+
+install: all .WAIT $(ROOTONBLDMACHPROG) $(ROOTONBLDSHFILES)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+%.o: $(CMDDIR)/%.c
+ $(COMPILE.c) -o $@ $<
+
+%.o: $(LIBDIR)/%.c
+ $(COMPILE.c) -o $@ $<
+
+lint: lint_SRCS
+
+clean:
+ $(RM) $(CLEANFILES)
+
+include ../../../src/tools/Makefile.targ
diff --git a/usr/src/tools/elfsign/elfsigncmp.sh b/usr/src/tools/elfsign/elfsigncmp.sh
new file mode 100644
index 0000000000..97f046a166
--- /dev/null
+++ b/usr/src/tools/elfsign/elfsigncmp.sh
@@ -0,0 +1,114 @@
+#! /usr/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+prog=$0
+pd=`dirname $prog`
+MACH=`uname -p`
+elfcmp=$pd/elfcmp
+elfsign=$pd/$MACH/elfsign
+
+aopt=
+copt=
+eopt=
+Fopt=
+kopt=
+vopt=
+
+Usage() {
+ echo "Usage: $prog {sign|verify} [-v] [-a]" \
+ "[-c <cert>] [-k <key>] [-F <format>] -e <elf>" 1>&2
+ exit 1
+}
+
+if [ $# -lt 1 ]; then
+ Usage
+ fi
+cmd=$1
+shift
+
+while getopts "ac:e:F:k:v" opt ; do
+ case $opt in
+ a) aopt=-a;;
+ c) copt="$OPTARG";;
+ e) eopt="$OPTARG";;
+ F) Fopt="$OPTARG";;
+ k) kopt="$OPTARG";;
+ v) vopt=-v;;
+ \?) Usage;;
+ esac
+done
+
+case X$eopt in X) Usage;; esac
+
+tmpe=$eopt.e$$
+tmpo=$eopt.o$$
+
+cpq() {
+ cp -p $1 $2 > /dev/null 2>&1
+}
+
+restore() {
+ cpq $tmpe $eopt
+}
+
+cleanup() {
+ restore
+ rm -f $tmpe $tmpo
+}
+
+trap cleanup 1 2 3 13 15
+
+cpq $eopt $tmpe
+
+eval $elfsign $cmd $aopt $vopt ${copt:+-c} ${copt} ${kopt:+-k} ${kopt} \
+ ${Fopt:+-F} ${Fopt} -e ${eopt}
+rv=$?
+
+case $cmd:$rv in
+sign:0)
+ if $elfcmp -v -S $tmpe $eopt > $tmpo 2>&1
+ then
+ : # all's fine
+ else
+ rv=$?
+ echo "Warning: elfcmp failed: $eopt" 1>&2
+ cat ${tmpo} 1>&2
+ echo "current directory: `pwd`" 1>&2
+ restore
+ cpq ${eopt} ${eopt}.elfcmp.failed.$$
+ fi
+ ;;
+sign:*)
+ restore
+ cpq ${eopt} ${eopt}.elfsign.failed.$$
+ ;;
+esac
+
+rm -f $tmpe $tmpo
+exit $rv
diff --git a/usr/src/tools/elfsign/inc.flg b/usr/src/tools/elfsign/inc.flg
new file mode 100644
index 0000000000..315fa0558d
--- /dev/null
+++ b/usr/src/tools/elfsign/inc.flg
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+echo_file usr/src/uts/common/sys/crypto/elfsign.h
+find_files "s.*.h" \
+ usr/src/lib/libcryptoutil/
+find_files "s.*" \
+ usr/src/cmd/cmd-crypto/elfsign \
+ usr/src/lib/libelfsign/
diff --git a/usr/src/uts/common/sys/crypto/elfsign.h b/usr/src/uts/common/sys/crypto/elfsign.h
index 107a0c8220..bbf58b87f4 100644
--- a/usr/src/uts/common/sys/crypto/elfsign.h
+++ b/usr/src/uts/common/sys/crypto/elfsign.h
@@ -58,10 +58,6 @@ typedef enum ELFsign_status_e {
#define SIG_MAX_LENGTH 1024
#define ELF_SIGNATURE_SECTION ".SUNW_signature"
-#define ELFSIGN_CRYPTO "Solaris Cryptographic Framework"
-#define USAGELIMITED "OU=UsageLimited"
-#define ESA ".esa"
-#define ESA_LEN sizeof (".esa")
typedef struct kcf_door_arg_s {
short da_version;
@@ -139,83 +135,6 @@ struct filesignatures {
#define _PATH_KCFD_DOOR "/var/run/kcfd_door"
-#define ES_FMT_RSA_MD5_SHA1 "rsa_md5_sha1"
-#define ES_FMT_RSA_SHA1 "rsa_sha1"
-enum ES_ACTION {
- ES_GET,
- ES_GET_CRYPTO,
- ES_UPDATE,
- ES_UPDATE_RSA_MD5_SHA1,
- ES_UPDATE_RSA_SHA1
-};
-#define ES_ACTISUPDATE(a) ((a) >= ES_UPDATE)
-
-/*
- * ELF signature handling
- */
-typedef struct ELFsign_s *ELFsign_t;
-struct ELFsign_sig_info {
- char *esi_format;
- char *esi_signer;
- time_t esi_time;
-};
-
-extern struct filesignatures *elfsign_insert_dso(ELFsign_t ess,
- struct filesignatures *fsp, const char *dn, int dn_len,
- const uchar_t *sig, int sig_len, const char *oid, int oid_len);
-extern filesig_vers_t elfsign_extract_sig(ELFsign_t ess,
- struct filesignatures *fsp, uchar_t *sig, size_t *sig_len);
-extern ELFsign_status_t elfsign_begin(const char *,
- const char *, char *, enum ES_ACTION, ELFsign_t *);
-extern void elfsign_end(ELFsign_t ess);
-extern ELFsign_status_t elfsign_verify_signature(ELFsign_t ess,
- struct ELFsign_sig_info **esipp);
-extern ELFsign_status_t elfsign_hash(ELFsign_t ess, uchar_t *hash,
- size_t *hash_len);
-extern ELFsign_status_t elfsign_hash_mem_resident(ELFsign_t ess,
- uchar_t *hash, size_t *hash_len);
-extern ELFsign_status_t elfsign_hash_esa(ELFsign_t ess,
- uchar_t *esa_buf, size_t esa_buf_len, uchar_t **hash, size_t *hash_len);
-extern void elfsign_buffer_len(ELFsign_t ess, size_t *ip, uchar_t *cp,
- enum ES_ACTION action);
-
-extern ELFsign_status_t elfsign_signatures(ELFsign_t ess,
- struct filesignatures **fspp, size_t *fs_len, enum ES_ACTION action);
-
-extern char const *elfsign_strerror(ELFsign_status_t);
-extern boolean_t elfsign_sig_info(struct filesignatures *fssp,
- struct ELFsign_sig_info **esipp);
-extern void elfsign_sig_info_free(struct ELFsign_sig_info *);
-
-extern ELFsign_t elfsign_new_ess(void);
-
-/*
- * ELF "Certificate Library"
- */
-
-extern const char _PATH_ELFSIGN_CERTS[];
-
-#define ELFCERT_MAX_DN_LEN 255
-
-typedef struct ELFCert_s *ELFCert_t;
-
-extern boolean_t elfcertlib_init(ELFsign_t, char *);
-
-extern boolean_t elfcertlib_getcert(ELFsign_t ess, char *cert_pathname,
- char *signer_DN, ELFCert_t *certp, enum ES_ACTION action);
-extern void elfcertlib_releasecert(ELFsign_t, ELFCert_t);
-extern char *elfcertlib_getdn(ELFCert_t cert);
-extern char *elfcertlib_getissuer(ELFCert_t cert);
-
-extern boolean_t elfcertlib_loadprivatekey(ELFsign_t ess, ELFCert_t cert,
- const char *path);
-extern boolean_t elfcertlib_loadtokenkey(ELFsign_t ess, ELFCert_t cert,
- const char *token_id, const char *pin);
-
-extern boolean_t elfcertlib_sign(ELFsign_t ess, ELFCert_t cert,
- const uchar_t *data, size_t data_len, uchar_t *sig,
- size_t *sig_len);
-
#endif /* _KERNEL */
#ifdef __cplusplus