summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorwyllys <none@none>2006-11-10 15:34:56 -0800
committerwyllys <none@none>2006-11-10 15:34:56 -0800
commit99ebb4ca412cb0a19d77a3899a87c055b9c30fa8 (patch)
treea972f78468519a4e00234388688f45a506e934ba /usr/src
parent177fd15c9f814babb60e824f89984cdd8acf7c85 (diff)
downloadillumos-joyent-99ebb4ca412cb0a19d77a3899a87c055b9c30fa8.tar.gz
PSARC 2005/074 Solaris Key Management Framework
6224192 Solaris needs unified key management interfaces --HG-- rename : usr/src/cmd/cmd-crypto/pktool/biginteger.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/biginteger.h rename : usr/src/cmd/cmd-crypto/pktool/derparse.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/derparse.c rename : usr/src/cmd/cmd-crypto/pktool/derparse.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/derparse.h rename : usr/src/cmd/cmd-crypto/pktool/osslcommon.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/osslcommon.c rename : usr/src/cmd/cmd-crypto/pktool/osslcommon.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/osslcommon.h rename : usr/src/cmd/cmd-crypto/pktool/p12common.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/p12common.c rename : usr/src/cmd/cmd-crypto/pktool/p12common.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/p12common.h
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/Makefile.lint1
-rw-r--r--usr/src/cmd/cmd-crypto/Makefile10
-rw-r--r--usr/src/cmd/cmd-crypto/cryptoadm/adm_uef.c120
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/Makefile91
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/create.c498
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/delete.c132
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/export.c167
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/import.c169
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c245
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.dtd84
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml40
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/list.c277
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/modify.c845
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/util.c497
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/util.h66
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/Makefile33
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/biginteger.h58
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/common.c1471
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/common.h86
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/delete.c739
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/derparse.c371
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/download.c274
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/export.c1682
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/gencert.c729
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/gencsr.c631
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/genkey.c450
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/import.c1341
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/list.c1479
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/osslcommon.c224
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/osslcommon.h50
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/p12common.c103
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/pktool.c455
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/setpin.c264
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/tokens.c13
-rw-r--r--usr/src/lib/Makefile2
-rw-r--r--usr/src/lib/libcryptoutil/Makefile.com3
-rw-r--r--usr/src/lib/libcryptoutil/common/config_parsing.c175
-rw-r--r--usr/src/lib/libcryptoutil/common/cryptoutil.h15
-rw-r--r--usr/src/lib/libcryptoutil/common/mapfile-vers4
-rw-r--r--usr/src/lib/libcryptoutil/common/util.c116
-rw-r--r--usr/src/lib/libkmf/Makefile56
-rw-r--r--usr/src/lib/libkmf/ber_der/Makefile49
-rw-r--r--usr/src/lib/libkmf/ber_der/Makefile.com57
-rw-r--r--usr/src/lib/libkmf/ber_der/amd64/Makefile31
-rw-r--r--usr/src/lib/libkmf/ber_der/common/clasn1.c2452
-rw-r--r--usr/src/lib/libkmf/ber_der/common/decode.c817
-rw-r--r--usr/src/lib/libkmf/ber_der/common/encode.c744
-rw-r--r--usr/src/lib/libkmf/ber_der/common/io.c419
-rw-r--r--usr/src/lib/libkmf/ber_der/common/llib-lkmfberder (renamed from usr/src/cmd/cmd-crypto/pktool/p12common.h)27
-rw-r--r--usr/src/lib/libkmf/ber_der/common/mapfile-vers67
-rw-r--r--usr/src/lib/libkmf/ber_der/i386/Makefile29
-rw-r--r--usr/src/lib/libkmf/ber_der/inc/ber_der.h180
-rw-r--r--usr/src/lib/libkmf/ber_der/inc/kmfber_int.h128
-rw-r--r--usr/src/lib/libkmf/ber_der/sparc/Makefile29
-rw-r--r--usr/src/lib/libkmf/ber_der/sparcv9/Makefile30
-rw-r--r--usr/src/lib/libkmf/include/algorithm.h69
-rw-r--r--usr/src/lib/libkmf/include/kmfapi.h346
-rw-r--r--usr/src/lib/libkmf/include/kmfapiP.h348
-rw-r--r--usr/src/lib/libkmf/include/kmfpolicy.h197
-rw-r--r--usr/src/lib/libkmf/include/kmftypes.h1363
-rw-r--r--usr/src/lib/libkmf/include/oidsalg.h73
-rw-r--r--usr/src/lib/libkmf/include/pem_encode.h137
-rw-r--r--usr/src/lib/libkmf/include/rdn_parser.h126
-rw-r--r--usr/src/lib/libkmf/libkmf/Makefile51
-rw-r--r--usr/src/lib/libkmf/libkmf/Makefile.com76
-rw-r--r--usr/src/lib/libkmf/libkmf/amd64/Makefile30
-rw-r--r--usr/src/lib/libkmf/libkmf/common/algoid.c126
-rw-r--r--usr/src/lib/libkmf/libkmf/common/algorithm.c172
-rw-r--r--usr/src/lib/libkmf/libkmf/common/certgetsetop.c2300
-rw-r--r--usr/src/lib/libkmf/libkmf/common/certop.c2773
-rw-r--r--usr/src/lib/libkmf/libkmf/common/client.c954
-rw-r--r--usr/src/lib/libkmf/libkmf/common/csrcrlop.c563
-rw-r--r--usr/src/lib/libkmf/libkmf/common/generalop.c1742
-rw-r--r--usr/src/lib/libkmf/libkmf/common/keyop.c375
-rw-r--r--usr/src/lib/libkmf/libkmf/common/kmfoids.c375
-rw-r--r--usr/src/lib/libkmf/libkmf/common/llib-lkmf (renamed from usr/src/cmd/cmd-crypto/pktool/derparse.h)38
-rw-r--r--usr/src/lib/libkmf/libkmf/common/mapfile-vers288
-rw-r--r--usr/src/lib/libkmf/libkmf/common/pem_encode.c628
-rw-r--r--usr/src/lib/libkmf/libkmf/common/pk11keys.c735
-rw-r--r--usr/src/lib/libkmf/libkmf/common/pk11tokens.c531
-rw-r--r--usr/src/lib/libkmf/libkmf/common/policy.c1460
-rw-r--r--usr/src/lib/libkmf/libkmf/common/rdn_parser.c546
-rw-r--r--usr/src/lib/libkmf/libkmf/i386/Makefile29
-rw-r--r--usr/src/lib/libkmf/libkmf/sparc/Makefile29
-rw-r--r--usr/src/lib/libkmf/libkmf/sparcv9/Makefile30
-rw-r--r--usr/src/lib/libkmf/plugins/Makefile48
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/Makefile47
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com74
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile32
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers56
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c2508
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile32
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/Makefile46
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com78
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile32
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers61
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c4198
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile31
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile46
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com65
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile30
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers50
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c2945
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile30
-rw-r--r--usr/src/lib/libsecdb/exec_attr.txt1
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_i3862
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_sparc2
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_com7
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_i3867
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_sparc7
-rw-r--r--usr/src/pkgdefs/SUNWcsr/prototype_com1
-rw-r--r--usr/src/pkgdefs/SUNWcsu/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWhea/prototype_com2
120 files changed, 40999 insertions, 5252 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint
index 95d7251dd1..cd4f2cdcb6 100644
--- a/usr/src/Makefile.lint
+++ b/usr/src/Makefile.lint
@@ -332,6 +332,7 @@ COMMON_SUBDIRS = \
lib/libipmp \
lib/libipp \
lib/libipsecutil \
+ lib/libkmf \
lib/libkstat \
lib/liblaadm \
lib/liblgrp \
diff --git a/usr/src/cmd/cmd-crypto/Makefile b/usr/src/cmd/cmd-crypto/Makefile
index f02549ce64..a046256e8a 100644
--- a/usr/src/cmd/cmd-crypto/Makefile
+++ b/usr/src/cmd/cmd-crypto/Makefile
@@ -2,9 +2,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# 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.
@@ -20,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -32,7 +31,8 @@ SUBDIRS1 = \
cryptoadm \
decrypt \
digest \
- pktool
+ pktool \
+ kmfcfg
$(CLOSED_BUILD)SUBDIRS1 += \
$(CLOSED)/cmd/cmd-crypto/elfsign \
diff --git a/usr/src/cmd/cmd-crypto/cryptoadm/adm_uef.c b/usr/src/cmd/cmd-crypto/cryptoadm/adm_uef.c
index 999ab4cb17..aad2a69f84 100644
--- a/usr/src/cmd/cmd-crypto/cryptoadm/adm_uef.c
+++ b/usr/src/cmd/cmd-crypto/cryptoadm/adm_uef.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -52,8 +51,6 @@
static int err; /* To store errno which may be overwritten by gettext() */
static boolean_t is_in_policylist(midstr_t, umechlist_t *);
-static umechlist_t *dup_umechlist(umechlist_t *);
-static uentry_t *dup_uentry(uentry_t *);
static char *uent2str(uentry_t *);
static boolean_t check_random(CK_SLOT_ID, CK_FUNCTION_LIST_PTR);
@@ -1114,117 +1111,6 @@ uninstall_uef_lib(char *libname)
}
-
-/*
- * Duplicate an UEF mechanism list. A NULL pointer is returned if out of
- * memory or the input argument is NULL.
- */
-static umechlist_t *
-dup_umechlist(umechlist_t *plist)
-{
- umechlist_t *pres = NULL;
- umechlist_t *pcur;
- umechlist_t *ptmp;
- int rc = SUCCESS;
-
- while (plist != NULL) {
- if (!(ptmp = create_umech(plist->name))) {
- rc = FAILURE;
- break;
- }
-
- if (pres == NULL) {
- pres = pcur = ptmp;
- } else {
- pcur->next = ptmp;
- pcur = pcur->next;
- }
- plist = plist->next;
- }
-
- if (rc != SUCCESS) {
- free_umechlist(pres);
- return (NULL);
- }
-
- return (pres);
-}
-
-
-
-/*
- * Duplicate an uentry. A NULL pointer is returned if out of memory
- * or the input argument is NULL.
- */
-static uentry_t *
-dup_uentry(uentry_t *puent1)
-{
- uentry_t *puent2 = NULL;
-
- if (puent1 == NULL) {
- return (NULL);
- }
-
- if ((puent2 = malloc(sizeof (uentry_t))) == NULL) {
- cryptoerror(LOG_STDERR, gettext("out of memory."));
- return (NULL);
- } else {
- (void) strlcpy(puent2->name, puent1->name,
- sizeof (puent2->name));
- puent2->flag_norandom = puent1->flag_norandom;
- puent2->flag_enabledlist = puent1->flag_enabledlist;
- puent2->count = puent1->count;
- puent2->policylist = dup_umechlist(puent1->policylist);
- puent2->flag_metaslot_enabled = puent1->flag_metaslot_enabled;
- puent2->flag_metaslot_auto_key_migrate
- = puent1->flag_metaslot_auto_key_migrate;
- (void) memcpy(puent2->metaslot_ks_slot,
- puent1->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE);
- (void) memcpy(puent2->metaslot_ks_token,
- puent1->metaslot_ks_token, TOKEN_LABEL_SIZE);
- return (puent2);
- }
-}
-
-
-/*
- * Find the entry in the "pkcs11.conf" file with "libname" as the provider
- * name. Return the entry if found, otherwise return NULL.
- */
-uentry_t *
-getent_uef(char *libname)
-{
- uentrylist_t *pliblist = NULL;
- uentrylist_t *plib = NULL;
- uentry_t *puent = NULL;
- boolean_t found = B_FALSE;
-
- if (libname == NULL) {
- return (NULL);
- }
-
- if ((get_pkcs11conf_info(&pliblist)) == FAILURE) {
- return (NULL);
- }
-
- plib = pliblist;
- while (plib) {
- if (strcmp(plib->puent->name, libname) == 0) {
- found = B_TRUE;
- break;
- } else {
- plib = plib->next;
- }
- }
-
- if (found) {
- puent = dup_uentry(plib->puent);
- }
-
- free_uentrylist(pliblist);
- return (puent);
-}
-
int
display_policy(uentry_t *puent)
{
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/Makefile b/usr/src/cmd/cmd-crypto/kmfcfg/Makefile
new file mode 100644
index 0000000000..86fd4eb30e
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/Makefile
@@ -0,0 +1,91 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Makefile for policy testing code
+#
+
+PROG = kmfcfg
+
+OBJS = kmfcfg.o \
+ list.o \
+ delete.o \
+ util.o \
+ create.o \
+ modify.o \
+ export.o \
+ import.o
+
+include ../../Makefile.cmd
+
+KMFDIR = $(SRC)/lib/libkmf
+SRCS = $(OBJS:%.o=%.c)
+
+POFILES = $(OBJS:%.o=%.po)
+POFILE = $(PROG)_msg.po
+MSGFILES = $(SRCS:%.c=%.i)
+
+CPPFLAGS += -I/usr/include/libxml2 -I$(KMFDIR)/include -I.
+LDLIBS += -L$(ROOT)/usr/lib -lkmf -lcryptoutil
+XMLLIB = -lxml2
+
+.KEEP_STATE:
+
+XMLDIR= $(ROOT)/etc/security
+DTDDIR= $(ROOT)/usr/share/lib/xml/dtd
+ROOTDTDS= $(DTDDIR)/kmfpolicy.dtd
+ROOTXML= $(XMLDIR)/kmfpolicy.xml
+
+$(ROOTDTDS) := FILEMODE = 444
+$(ROOTDTDS) := OWNER = root
+$(ROOTDTDS) := GROUP = bin
+
+$(ROOTXML) := FILEMODE = 644
+$(ROOTXML) := OWNER = root
+$(ROOTXML) := GROUP = bin
+
+all: $(PROG) $(ROOTDTDS)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(XMLLIB)
+ $(POST_PROCESS)
+
+$(POFILE): $(POFILES)
+ $(BUILDPO.pofiles)
+
+install: all $(ROOTDTDS) $(ROOTXML) $(ROOTPROG)
+
+$(XMLDIR)/%: %
+ $(INS.file)
+
+$(DTDDIR)/%: %
+ $(INS.file)
+
+clean:
+ $(RM) $(OBJS)
+
+lint : lint_SRCS
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/create.c b/usr/src/cmd/cmd-crypto/kmfcfg/create.c
new file mode 100644
index 0000000000..ceacf5f5d5
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/create.c
@@ -0,0 +1,498 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <errno.h>
+#include <kmfapiP.h>
+#include <cryptoutil.h>
+#include "util.h"
+
+int
+kc_create(int argc, char *argv[])
+{
+ KMF_RETURN ret;
+ int rv = KC_OK;
+ int opt;
+ extern int optind_av;
+ extern char *optarg_av;
+ char *filename = NULL;
+ int ocsp_set_attr = 0;
+ boolean_t crl_set_attr = 0;
+ KMF_POLICY_RECORD plc;
+
+ (void) memset(&plc, 0, sizeof (KMF_POLICY_RECORD));
+
+ while ((opt = getopt_av(argc, argv,
+ "i:(dbfile)"
+ "p:(policy)"
+ "d:(ignore-date)"
+ "e:(ignore-unknown-eku)"
+ "a:(ignore-trust-anchor)"
+ "v:(validity-adjusttime)"
+ "t:(ta-name)"
+ "s:(ta-serial)"
+ "o:(ocsp-responder)"
+ "P:(ocsp-proxy)"
+ "r:(ocsp-use-cert-responder)"
+ "T:(ocsp-response-lifetime)"
+ "R:(ocsp-ignore-response-sign)"
+ "n:(ocsp-responder-cert-name)"
+ "A:(ocsp-responder-cert-serial)"
+ "c:(crl-basefilename)"
+ "I:(crl-directory)"
+ "g:(crl-get-crl-uri)"
+ "X:(crl-proxy)"
+ "S:(crl-ignore-crl-sign)"
+ "D:(crl-ignore-crl-date)"
+ "u:(keyusage)"
+ "E:(ekunames)"
+ "O:(ekuoids)")) != EOF) {
+ switch (opt) {
+ case 'i':
+ filename = get_string(optarg_av, &rv);
+ if (filename == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error dbfile input.\n"));
+ }
+ break;
+ case 'p':
+ plc.name = get_string(optarg_av, &rv);
+ if (plc.name == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error policy name.\n"));
+ }
+ break;
+ case 'd':
+ plc.ignore_date = get_boolean(optarg_av);
+ if (plc.ignore_date == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ }
+ break;
+ case 'e':
+ plc.ignore_unknown_ekus =
+ get_boolean(optarg_av);
+ if (plc.ignore_unknown_ekus == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ }
+ break;
+ case 'a':
+ plc.ignore_trust_anchor =
+ get_boolean(optarg_av);
+ if (plc.ignore_trust_anchor == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ }
+ break;
+ case 'v':
+ plc.validity_adjusttime =
+ get_string(optarg_av, &rv);
+ if (plc.validity_adjusttime == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error time input.\n"));
+ } else {
+ uint32_t adj;
+ /* for syntax checking */
+ if (str2lifetime(
+ plc.validity_adjusttime,
+ &adj) < 0) {
+ (void) fprintf(stderr,
+ gettext("Error time "
+ "input.\n"));
+ rv = KC_ERR_USAGE;
+ }
+ }
+ break;
+ case 't':
+ plc.ta_name = get_string(optarg_av, &rv);
+ if (plc.ta_name == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error name input.\n"));
+ } else {
+ KMF_X509_NAME taDN;
+ /* for syntax checking */
+ if (KMF_DNParser(plc.ta_name,
+ &taDN) != KMF_OK) {
+ (void) fprintf(stderr,
+ gettext("Error name "
+ "input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ KMF_FreeDN(&taDN);
+ }
+ }
+ break;
+ case 's':
+ plc.ta_serial = get_string(optarg_av, &rv);
+ if (plc.ta_serial == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error serial input.\n"));
+ } else {
+ uchar_t *bytes = NULL;
+ size_t bytelen;
+
+ ret = KMF_HexString2Bytes(
+ (uchar_t *)plc.ta_serial,
+ &bytes, &bytelen);
+ if (ret != KMF_OK || bytes == NULL) {
+ (void) fprintf(stderr,
+ gettext("serial number "
+ "must be specified as a "
+ "hex number "
+ "(ex: 0x0102030405"
+ "ffeeddee)\n"));
+ rv = KC_ERR_USAGE;
+ }
+ if (bytes != NULL)
+ free(bytes);
+ }
+ break;
+ case 'o':
+ plc.VAL_OCSP_RESPONDER_URI =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_OCSP_RESPONDER_URI == NULL) {
+ (void) fprintf(stderr, gettext(
+ "Error responder input.\n"));
+ } else {
+ ocsp_set_attr++;
+ }
+ break;
+ case 'P':
+ plc.VAL_OCSP_PROXY =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_OCSP_PROXY == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error proxy input.\n"));
+ } else {
+ ocsp_set_attr++;
+ }
+ break;
+ case 'r':
+ plc.VAL_OCSP_URI_FROM_CERT =
+ get_boolean(optarg_av);
+ if (plc.VAL_OCSP_URI_FROM_CERT == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ ocsp_set_attr++;
+ }
+ break;
+ case 'T':
+ plc.VAL_OCSP_RESP_LIFETIME =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_OCSP_RESP_LIFETIME == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error time input.\n"));
+ } else {
+ uint32_t adj;
+ /* for syntax checking */
+ if (str2lifetime(
+ plc.VAL_OCSP_RESP_LIFETIME,
+ &adj) < 0) {
+ (void) fprintf(stderr,
+ gettext("Error time "
+ "input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ ocsp_set_attr++;
+ }
+ }
+ break;
+ case 'R':
+ plc.VAL_OCSP_IGNORE_RESP_SIGN =
+ get_boolean(optarg_av);
+ if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ ocsp_set_attr++;
+ }
+ break;
+ case 'n':
+ plc.VAL_OCSP_RESP_CERT_NAME =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error name input.\n"));
+ } else {
+ KMF_X509_NAME respDN;
+ /* for syntax checking */
+ if (KMF_DNParser(
+ plc.VAL_OCSP_RESP_CERT_NAME,
+ &respDN) != KMF_OK) {
+ (void) fprintf(stderr,
+ gettext("Error name "
+ "input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ KMF_FreeDN(&respDN);
+ ocsp_set_attr++;
+ }
+ }
+ break;
+ case 'A':
+ plc.VAL_OCSP_RESP_CERT_SERIAL =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error serial input.\n"));
+ } else {
+ uchar_t *bytes = NULL;
+ size_t bytelen;
+
+ ret = KMF_HexString2Bytes((uchar_t *)
+ plc.VAL_OCSP_RESP_CERT_SERIAL,
+ &bytes, &bytelen);
+ if (ret != KMF_OK || bytes == NULL) {
+ (void) fprintf(stderr,
+ gettext("serial number "
+ "must be specified as a "
+ "hex number "
+ "(ex: 0x0102030405"
+ "ffeeddee)\n"));
+ rv = KC_ERR_USAGE;
+ break;
+ }
+ if (bytes != NULL)
+ free(bytes);
+ ocsp_set_attr++;
+ }
+ break;
+ case 'c':
+ plc.VAL_CRL_BASEFILENAME =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_CRL_BASEFILENAME == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ } else {
+ crl_set_attr++;
+ }
+ break;
+ case 'I':
+ plc.VAL_CRL_DIRECTORY =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_CRL_DIRECTORY == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ } else {
+ crl_set_attr++;
+ }
+ break;
+ case 'g':
+ plc.VAL_CRL_GET_URI = get_boolean(optarg_av);
+ if (plc.VAL_CRL_GET_URI == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ crl_set_attr++;
+ }
+ break;
+ case 'X':
+ plc.VAL_CRL_PROXY = get_string(optarg_av, &rv);
+ if (plc.VAL_CRL_PROXY == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error proxy input.\n"));
+ } else {
+ crl_set_attr++;
+ }
+ break;
+ case 'S':
+ plc.VAL_CRL_IGNORE_SIGN =
+ get_boolean(optarg_av);
+ if (plc.VAL_CRL_IGNORE_SIGN == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ crl_set_attr++;
+ }
+ break;
+ case 'D':
+ plc.VAL_CRL_IGNORE_DATE =
+ get_boolean(optarg_av);
+ if (plc.VAL_CRL_IGNORE_DATE == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ crl_set_attr++;
+ }
+ break;
+ case 'u':
+ plc.ku_bits = parseKUlist(optarg_av);
+ if (plc.ku_bits == 0) {
+ (void) fprintf(stderr, gettext(
+ "Error keyusage input.\n"));
+ rv = KC_ERR_USAGE;
+ }
+ break;
+ case 'E':
+ if (parseEKUNames(optarg_av, &plc) != 0) {
+ (void) fprintf(stderr,
+ gettext("Error EKU input.\n"));
+ rv = KC_ERR_USAGE;
+ }
+ break;
+ case 'O':
+ if (parseEKUOIDs(optarg_av, &plc) != 0) {
+ (void) fprintf(stderr,
+ gettext("Error EKU OID input.\n"));
+ rv = KC_ERR_USAGE;
+ }
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("Error input option.\n"));
+ rv = KC_ERR_USAGE;
+ break;
+ }
+
+ if (rv != KC_OK)
+ goto out;
+ }
+
+ /* No additional args allowed. */
+ argc -= optind_av;
+ if (argc) {
+ (void) fprintf(stderr,
+ gettext("Error input option\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ if (filename == NULL) {
+ filename = strdup(KMF_DEFAULT_POLICY_FILE);
+ if (filename == NULL) {
+ rv = KC_ERR_MEMORY;
+ goto out;
+ }
+ }
+
+ /*
+ * Must have a policy name. The policy name can not be default
+ * if using the default policy file.
+ */
+ if (plc.name == NULL) {
+ (void) fprintf(stderr,
+ gettext("You must specify a policy name\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 &&
+ strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) {
+ (void) fprintf(stderr,
+ gettext("Can not create a default policy in the default "
+ "policy file\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ /*
+ * If the policy file exists and the policy is in the policy file
+ * already, we will not create it again.
+ */
+ if (access(filename, R_OK) == 0) {
+ POLICY_LIST *plclist = NULL, *pnode;
+ int found = 0;
+
+ rv = load_policies(filename, &plclist);
+ if (rv != KMF_OK)
+ goto out;
+
+ pnode = plclist;
+ while (pnode != NULL && !found) {
+ if (strcmp(plc.name, pnode->plc.name) == 0)
+ found++;
+ pnode = pnode->next;
+ }
+ free_policy_list(plclist);
+
+ if (found) {
+ (void) fprintf(stderr,
+ gettext("Could not create policy \"%s\" - exists "
+ "already\n"), plc.name);
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+ }
+
+ /*
+ * If any OCSP attribute is set, turn on the OCSP checking flag.
+ * Also set "has_resp_cert" to be true, if the responder cert
+ * is provided.
+ */
+ if (ocsp_set_attr > 0)
+ plc.revocation |= KMF_REVOCATION_METHOD_OCSP;
+
+ if (plc.VAL_OCSP_RESP_CERT.name != NULL &&
+ plc.VAL_OCSP_RESP_CERT.serial != NULL) {
+ plc.VAL_OCSP.has_resp_cert = B_TRUE;
+ }
+
+ /*
+ * If any CRL attribute is set, turn on the CRL checking flag.
+ */
+ if (crl_set_attr > 0)
+ plc.revocation |= KMF_REVOCATION_METHOD_CRL;
+
+ /*
+ * Does a sanity check on the new policy.
+ */
+ ret = KMF_VerifyPolicy(&plc);
+ if (ret != KMF_OK) {
+ print_sanity_error(ret);
+ rv = KC_ERR_ADD_POLICY;
+ goto out;
+ }
+
+ /*
+ * Add to the DB.
+ */
+ ret = KMF_AddPolicyToDB(&plc, filename, B_FALSE);
+ if (ret != KMF_OK) {
+ (void) fprintf(stderr,
+ gettext("Error adding policy to database: 0x%04x\n"), ret);
+ rv = KC_ERR_ADD_POLICY;
+ }
+
+out:
+ if (filename != NULL)
+ free(filename);
+
+ KMF_FreePolicyRecord(&plc);
+
+ return (rv);
+}
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/delete.c b/usr/src/cmd/cmd-crypto/kmfcfg/delete.c
new file mode 100644
index 0000000000..7e0a1c7d45
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/delete.c
@@ -0,0 +1,132 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <errno.h>
+#include <kmfapiP.h>
+#include "util.h"
+
+int
+kc_delete(int argc, char *argv[])
+{
+ int rv = KC_OK;
+ KMF_RETURN kmfrv = KMF_OK;
+ int opt;
+ extern int optind_av;
+ extern char *optarg_av;
+ char *filename = NULL;
+ char *policyname = NULL;
+
+ while ((opt = getopt_av(argc, argv, "i:(dbfile)p:(policy)")) != EOF) {
+ switch (opt) {
+ case 'i':
+ filename = get_string(optarg_av, &rv);
+ if (filename == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error dbfile input.\n"));
+ }
+ break;
+ case 'p':
+ policyname = get_string(optarg_av, &rv);
+ if (policyname == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error policy name.\n"));
+ }
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("Error input option.\n"));
+ rv = KC_ERR_USAGE;
+ break;
+
+ }
+
+ if (rv != KC_OK)
+ goto out;
+ }
+
+ /* No additional args allowed. */
+ argc -= optind_av;
+ if (argc) {
+ (void) fprintf(stderr,
+ gettext("Error input option\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ if (filename == NULL) {
+ filename = strdup(KMF_DEFAULT_POLICY_FILE);
+ if (filename == NULL) {
+ rv = KC_ERR_MEMORY;
+ goto out;
+ }
+ }
+
+ /*
+ * Must have a policy name. The policy name can not be default
+ * if using the default policy file.
+ */
+ if (policyname == NULL) {
+ (void) fprintf(stderr,
+ gettext("You must specify a policy name\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 &&
+ strcmp(policyname, KMF_DEFAULT_POLICY_NAME) == 0) {
+ (void) fprintf(stderr,
+ gettext("Can not delete the default policy in the default "
+ "policy file\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ /* Check the access permission of the policy DB */
+ if (access(filename, W_OK) < 0) {
+ int err = errno;
+ (void) fprintf(stderr,
+ gettext("Cannot access \"%s\" for delete - %s\n"),
+ filename, strerror(err));
+ rv = KC_ERR_ACCESS;
+ goto out;
+ }
+
+ kmfrv = KMF_DeletePolicyFromDB(policyname, filename);
+ if (kmfrv != KMF_OK)
+ rv = KC_ERR_DELETE_POLICY;
+
+out:
+ if (filename != NULL)
+ free(filename);
+
+ if (policyname != NULL)
+ free(policyname);
+
+ return (rv);
+}
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/export.c b/usr/src/cmd/cmd-crypto/kmfcfg/export.c
new file mode 100644
index 0000000000..c1ddab153c
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/export.c
@@ -0,0 +1,167 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <locale.h>
+#include <errno.h>
+#include <kmfapiP.h>
+
+#include "util.h"
+
+int
+kc_export(int argc, char *argv[])
+{
+ int rv = KC_OK;
+ char *filename = NULL;
+ char *outfile = NULL;
+ char *policyname = NULL;
+ POLICY_LIST *plclist = NULL, *pnode;
+ int opt, found = 0;
+ extern int optind_av;
+ extern char *optarg_av;
+
+ while ((opt = getopt_av(argc, argv,
+ "d:(dbfile)p:(policy)o:(outfile)")) != EOF) {
+ switch (opt) {
+ case 'd':
+ filename = get_string(optarg_av, &rv);
+ if (filename == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error dbfile input.\n"));
+ }
+ break;
+ case 'p':
+ policyname = get_string(optarg_av, &rv);
+ if (policyname == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error policy name.\n"));
+ }
+ break;
+ case 'o':
+ outfile = get_string(optarg_av, &rv);
+ if (outfile == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error outfile input.\n"));
+ }
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("Error input option.\n"));
+ rv = KC_ERR_USAGE;
+ break;
+ }
+
+ if (rv != KC_OK)
+ goto out;
+ }
+
+ /* No additional args allowed. */
+ argc -= optind_av;
+ if (argc) {
+ (void) fprintf(stderr,
+ gettext("Error input option\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ if (filename == NULL) {
+ filename = strdup(KMF_DEFAULT_POLICY_FILE);
+ if (filename == NULL) {
+ rv = KC_ERR_MEMORY;
+ goto out;
+ }
+ }
+
+ if (policyname == NULL) {
+ (void) fprintf(stderr,
+ gettext("You must specify a policy name\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ if (outfile == NULL) {
+ (void) fprintf(stderr,
+ gettext("You must specify a output DB file\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ if (strcmp(outfile, KMF_DEFAULT_POLICY_FILE) == 0 &&
+ strcmp(policyname, KMF_DEFAULT_POLICY_NAME) == 0) {
+ (void) fprintf(stderr,
+ gettext("Can not export the default policy record to "
+ "the system default policy database\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ rv = load_policies(filename, &plclist);
+ if (rv != KMF_OK)
+ goto out;
+
+ pnode = plclist;
+ while (pnode != NULL && !found) {
+ if (strcmp(policyname, pnode->plc.name) == 0) {
+ KMF_RETURN ret;
+
+ found++;
+ ret = KMF_VerifyPolicy(&pnode->plc);
+ if (ret != KMF_OK) {
+ print_sanity_error(ret);
+ rv = KC_ERR_VERIFY_POLICY;
+ break;
+ }
+ rv = KMF_AddPolicyToDB(&pnode->plc, outfile, B_FALSE);
+ }
+ pnode = pnode->next;
+ }
+
+ if (!found) {
+ (void) fprintf(stderr,
+ gettext("Could not find policy \"%s\" in %s\n"),
+ policyname, filename);
+ rv = KC_ERR_FIND_POLICY;
+ }
+
+out:
+ if (filename != NULL)
+ free(filename);
+
+ if (policyname != NULL)
+ free(policyname);
+
+ if (outfile != NULL)
+ free(outfile);
+
+ free_policy_list(plclist);
+
+ return (rv);
+}
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/import.c b/usr/src/cmd/cmd-crypto/kmfcfg/import.c
new file mode 100644
index 0000000000..b55caac068
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/import.c
@@ -0,0 +1,169 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <locale.h>
+#include <errno.h>
+
+#include <kmfapiP.h>
+
+#include "util.h"
+
+int
+kc_import(int argc, char *argv[])
+{
+ int rv = KC_OK;
+ char *filename = NULL;
+ char *infile = NULL;
+ char *policyname = NULL;
+ POLICY_LIST *plclist = NULL, *pnode;
+ int opt, found = 0;
+ extern int optind_av;
+ extern char *optarg_av;
+
+ while ((opt = getopt_av(argc, argv,
+ "d:(dbfile)p:(policy)i:(infile)")) != EOF) {
+ switch (opt) {
+ case 'd':
+ filename = get_string(optarg_av, &rv);
+ if (filename == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error dbfile input.\n"));
+ }
+ break;
+ case 'p':
+ policyname = get_string(optarg_av, &rv);
+ if (policyname == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error policy name.\n"));
+ }
+ break;
+ case 'i':
+ infile = get_string(optarg_av, &rv);
+ if (infile == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error infile input.\n"));
+ }
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("Error input option.\n"));
+ rv = KC_ERR_USAGE;
+ break;
+ }
+
+ if (rv != KC_OK)
+ goto out;
+
+ }
+
+ /* No additional args allowed. */
+ argc -= optind_av;
+ if (argc) {
+ (void) fprintf(stderr,
+ gettext("Error input option\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ if (filename == NULL) {
+ filename = strdup(KMF_DEFAULT_POLICY_FILE);
+ if (filename == NULL) {
+ rv = KC_ERR_MEMORY;
+ goto out;
+ }
+ }
+
+ if (policyname == NULL) {
+ (void) fprintf(stderr,
+ gettext("You must specify a policy name\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ if (infile == NULL) {
+ (void) fprintf(stderr,
+ gettext("You must specify a input DB file\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 &&
+ strcmp(policyname, KMF_DEFAULT_POLICY_NAME) == 0) {
+ (void) fprintf(stderr,
+ gettext("Can not import the default policy record to "
+ "the system default policy database\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ rv = load_policies(infile, &plclist);
+ if (rv != KMF_OK)
+ goto out;
+
+ pnode = plclist;
+ while (pnode != NULL && !found) {
+ if (strcmp(policyname, pnode->plc.name) == 0) {
+ KMF_RETURN ret;
+
+ found++;
+ ret = KMF_VerifyPolicy(&pnode->plc);
+ if (ret != KMF_OK) {
+ print_sanity_error(ret);
+ rv = KC_ERR_VERIFY_POLICY;
+ break;
+ }
+ rv = KMF_AddPolicyToDB(&pnode->plc, filename, B_FALSE);
+ }
+ pnode = pnode->next;
+ }
+
+ if (!found) {
+ (void) fprintf(stderr,
+ gettext("Could not find policy \"%s\" in %s\n"),
+ policyname, infile);
+ rv = KC_ERR_FIND_POLICY;
+ }
+
+out:
+ if (filename != NULL)
+ free(filename);
+
+ if (policyname != NULL)
+ free(policyname);
+
+ if (infile != NULL)
+ free(infile);
+
+ free_policy_list(plclist);
+
+ return (rv);
+}
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c b/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c
new file mode 100644
index 0000000000..e58368284f
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c
@@ -0,0 +1,245 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <locale.h>
+
+#include <kmfapiP.h>
+
+#include "util.h"
+
+/*
+ * The verbcmd construct allows genericizing information about a verb so
+ * that it is easier to manipulate. Makes parsing code easier to read,
+ * fix, and extend with new verbs.
+ */
+typedef struct verbcmd_s {
+ char *verb;
+ int (*action)(int, char *[]);
+ char *synopsis;
+} verbcmd;
+
+int kc_list(int argc, char *argv[]);
+int kc_delete(int argc, char *argv[]);
+int kc_create(int argc, char *argv[]);
+int kc_modify(int argc, char *argv[]);
+int kc_export(int argc, char *argv[]);
+int kc_import(int argc, char *argv[]);
+static int kc_help();
+
+static verbcmd cmds[] = {
+ { "list", kc_list, "list [dbfile=dbfile] "
+ "[policy=policyname]" },
+ { "delete", kc_delete, "delete [dbfile=dbfile] "
+ "policy=policyname" },
+ { "create", kc_create,
+ "create [dbfile=dbfile] policy=policyname\n"
+ "\t\t[ignore-date=true|false]\n"
+ "\t\t[ignore-unknown-eku=true|false]\n"
+ "\t\t[ignore-trust-anchor=true|false]\n"
+ "\t\t[validity-adjusttime=adjusttime]\n"
+ "\t\t[ta-name=trust anchor subject DN]\n"
+ "\t\t[ta-serial=trust anchor serial number]\n"
+ "\t\t[ocsp-responder=URL]\n"
+ "\t\t[ocsp-proxy=URL]\n"
+ "\t\t[ocsp-use-cert-responder=true|false]\n"
+ "\t\t[ocsp-response-lifetime=timelimit]\n"
+ "\t\t[ocsp-ignore-response-sign=true|false]\n"
+ "\t\t[ocsp-responder-cert-name=Issuer DN]\n"
+ "\t\t[ocsp-responder-cert-serial=serial number]\n"
+ "\t\t[crl-basefilename=basefilename]\n"
+ "\t\t[crl-directory=directory]\n"
+ "\t\t[crl-get-crl-uri=true|false]\n"
+ "\t\t[crl-proxy=URL]\n"
+ "\t\t[crl-ignore-crl-sign=true|false]\n"
+ "\t\t[crl-ignore-crl-date=true|false]\n"
+ "\t\t[keyusage=digitalSignature|nonRepudiation\n\t"
+ "\t\t|keyEncipherment | dataEncipherment |\n\t"
+ "\t\tkeyAgreement |keyCertSign |\n\t"
+ "\t\tcRLSign | encipherOnly | decipherOnly],[...]\n"
+ "\t\t[ekunames=serverAuth | clientAuth |\n\t"
+ "\t\tcodeSigning | emailProtection |\n\t"
+ "\t\tipsecEndSystem | ipsecTunnel |\n\t"
+ "\t\tipsecUser | timeStamping |\n\t"
+ "\t\tOCSPSigning],[...]\n"
+ "\t\t[ekuoids=OID,OID,OID...]\n" },
+ { "modify", kc_modify,
+ "modify [dbfile=dbfile] policy=policyname\n"
+ "\t\t[ignore-date=true|false]\n"
+ "\t\t[ignore-unknown-eku=true|false]\n"
+ "\t\t[ignore-trust-anchor=true|false]\n"
+ "\t\t[validity-adjusttime=adjusttime]\n"
+ "\t\t[ta-name=trust anchor subject DN]\n"
+ "\t\t[ta-serial=trust anchor serial number]\n"
+ "\t\t[ocsp-responder=URL]\n"
+ "\t\t[ocsp-proxy=URL]\n"
+ "\t\t[ocsp-use-cert-responder=true|false]\n"
+ "\t\t[ocsp-response-lifetime=timelimit]\n"
+ "\t\t[ocsp-ignore-response-sign=true|false]\n"
+ "\t\t[ocsp-responder-cert-name=Issuer DN]\n"
+ "\t\t[ocsp-responder-cert-serial=serial number]\n"
+ "\t\t[ocsp-none=true|false]\n"
+ "\t\t[crl-basefilename=basefilename]\n"
+ "\t\t[crl-directory=directory]\n"
+ "\t\t[crl-get-crl-uri=true|false]\n"
+ "\t\t[crl-proxy=URL]\n"
+ "\t\t[crl-ignore-crl-sign=true|false]\n"
+ "\t\t[crl-ignore-crl-date=true|false]\n"
+ "\t\t[crl-none=true|false]\n"
+ "\t\t[keyusage=digitalSignature|nonRepudiation\n\t"
+ "\t\t|keyEncipherment | dataEncipherment |\n\t"
+ "\t\tkeyAgreement |keyCertSign |\n\t"
+ "\t\tcRLSign | encipherOnly | decipherOnly],[...]\n"
+ "\t\t[keyusage-none=true|false]\n"
+ "\t\t[ekunames=serverAuth | clientAuth |\n\t"
+ "\t\tcodeSigning | emailProtection |\n\t"
+ "\t\tipsecEndSystem | ipsecTunnel |\n\t"
+ "\t\tipsecUser | timeStamping |\n\t"
+ "\t\tOCSPSigning],[...]\n"
+ "\t\t[ekuoids=OID,OID,OID...]\n"
+ "\t\t[eku-none=true|false]\n" },
+ { "import", kc_import, "import [dbfile=dbfile] policy=policyname "
+ "infile=inputdbfile\n" },
+ { "export", kc_export, "export [dbfile=dbfile] policy=policyname "
+ "outfile=newdbfile\n" },
+ { "-?", kc_help, "help"},
+ { "help", kc_help, ""}
+};
+
+static int num_cmds = sizeof (cmds) / sizeof (verbcmd);
+static char *prog;
+
+static void
+usage(void)
+{
+ int i;
+
+ /* Display this block only in command-line mode. */
+ (void) fprintf(stdout, gettext("Usage:\n"));
+ (void) fprintf(stdout, gettext("\t%s -?\t(help and usage)\n"), prog);
+ (void) fprintf(stdout, gettext("\t%s subcommand [options...]\n"), prog);
+ (void) fprintf(stdout, gettext("where subcommands may be:\n"));
+
+ /* Display only those verbs that match the current tool mode. */
+ for (i = 0; i < num_cmds; i++) {
+ /* Do NOT i18n/l10n. */
+ (void) fprintf(stdout, "\t%s\n", cmds[i].synopsis);
+ }
+}
+
+static int
+kc_help()
+{
+ usage();
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ KMF_RETURN ret;
+ int found;
+ int i;
+
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D. */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ prog = basename(argv[0]);
+ argv++; argc--;
+
+ if (argc == 0) {
+ usage();
+ exit(1);
+ }
+
+ if (argc == 1 && argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case '?':
+ return (kc_help());
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ found = -1;
+ for (i = 0; i < num_cmds; i++) {
+ if (strcmp(cmds[i].verb, argv[0]) == 0) {
+ found = i;
+ break;
+ }
+ }
+
+ if (found < 0) {
+ (void) fprintf(stderr, gettext("Invalid command: %s\n"),
+ argv[0]);
+ exit(1);
+ }
+
+ ret = (*cmds[found].action)(argc, argv);
+
+ switch (ret) {
+ case KC_OK:
+ break;
+ case KC_ERR_USAGE:
+ break;
+ case KC_ERR_LOADDB:
+ (void) fprintf(stderr,
+ gettext("Error loading database\n"));
+ break;
+ case KC_ERR_FIND_POLICY:
+ break;
+ case KC_ERR_DELETE_POLICY:
+ (void) fprintf(stderr, gettext("Error deleting policy "
+ "from database.\n"));
+ break;
+ case KC_ERR_ADD_POLICY:
+ break;
+ case KC_ERR_VERIFY_POLICY:
+ break;
+ case KC_ERR_INCOMPLETE_POLICY:
+ break;
+ case KC_ERR_MEMORY:
+ (void) fprintf(stderr, gettext("Out of memory.\n"));
+ break;
+ case KC_ERR_ACCESS:
+ break;
+ default:
+ (void) fprintf(stderr, gettext("%s operation failed. "
+ "error 0x%02x\n"), cmds[found].verb, ret);
+ break;
+ }
+
+ return (ret);
+}
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.dtd b/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.dtd
new file mode 100644
index 0000000000..32fa28e99a
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.dtd
@@ -0,0 +1,84 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+
+<!--
+ Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (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"
+-->
+
+<!--Element Definitions-->
+
+<!ELEMENT kmf-policy-db (kmf-policy*)>
+<!ATTLIST kmf-policy-db allow-local-files (TRUE|FALSE) #IMPLIED>
+
+<!ELEMENT kmf-policy (validation-methods, key-usage-set?, ext-key-usage?)>
+<!ATTLIST kmf-policy name CDATA #REQUIRED>
+<!ATTLIST kmf-policy ignore-date (TRUE|FALSE) #IMPLIED>
+<!ATTLIST kmf-policy ignore-unknown-eku (TRUE|FALSE) #IMPLIED>
+<!ATTLIST kmf-policy ignore-trust-anchor (TRUE|FALSE) #IMPLIED>
+<!ATTLIST kmf-policy validity-adjusttime CDATA #IMPLIED>
+<!ATTLIST kmf-policy ta-name CDATA #IMPLIED>
+<!ATTLIST kmf-policy ta-serial CDATA #IMPLIED>
+
+<!ELEMENT validation-methods (ocsp?, crl?)>
+<!ELEMENT ocsp (ocsp-basic, responder-cert?)>
+
+<!ELEMENT ocsp-basic EMPTY>
+<!ATTLIST ocsp-basic
+ responder CDATA #IMPLIED
+ proxy CDATA #IMPLIED
+ uri-from-cert (TRUE|FALSE) #IMPLIED
+ response-lifetime CDATA #IMPLIED
+ ignore-response-sign (TRUE|FALSE) #IMPLIED
+>
+
+<!ELEMENT responder-cert EMPTY>
+<!ATTLIST responder-cert
+ name CDATA #REQUIRED
+ serial CDATA #REQUIRED
+>
+
+<!ELEMENT crl EMPTY>
+<!ATTLIST crl basefilename CDATA #IMPLIED>
+<!ATTLIST crl directory CDATA #IMPLIED>
+<!ATTLIST crl get-crl-uri (TRUE|FALSE) #IMPLIED>
+<!ATTLIST crl proxy CDATA #IMPLIED>
+<!ATTLIST crl ignore-crl-sign (TRUE|FALSE) #IMPLIED>
+<!ATTLIST crl ignore-crl-date (TRUE|FALSE) #IMPLIED>
+
+<!ELEMENT key-usage-set (key-usage+)>
+
+<!ELEMENT key-usage EMPTY>
+<!ATTLIST key-usage use (digitalSignature | nonRepudiation |
+ keyEncipherment | dataEncipherment | keyAgreement |
+ keyCertSign | cRLSign | encipherOnly | decipherOnly) #IMPLIED>
+
+<!ELEMENT ext-key-usage (eku-name*, eku-oid*)>
+
+<!ELEMENT eku-name EMPTY>
+<!ATTLIST eku-name name (serverAuth | clientAuth |
+ codeSigning | emailProtection |
+ ipsecEndSystem | ipsecTunnel | ipsecUser |
+ timeStamping | OCSPSigning) #IMPLIED >
+<!ELEMENT eku-oid EMPTY>
+<!ATTLIST eku-oid oid CDATA #IMPLIED>
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml b/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml
new file mode 100644
index 0000000000..2c2ed35e2c
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (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
+
+ Sample KMF Policy Database file.
+
+ ident "%Z%%M% %I% %E% SMI"
+-->
+<!DOCTYPE kmf-policy-db SYSTEM "/usr/share/lib/xml/dtd/kmfpolicy.dtd">
+<kmf-policy-db>
+
+<kmf-policy name="default" ignore-date="TRUE" ignore-trust-anchor="TRUE">
+ <validation-methods>
+ <ocsp>
+ <ocsp-basic uri-from-cert="TRUE"
+ ignore-response-sign="TRUE"/>
+ </ocsp>
+ </validation-methods>
+</kmf-policy>
+</kmf-policy-db>
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/list.c b/usr/src/cmd/cmd-crypto/kmfcfg/list.c
new file mode 100644
index 0000000000..e68e2b8643
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/list.c
@@ -0,0 +1,277 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <errno.h>
+#include <kmfapiP.h>
+
+#include "util.h"
+
+static void
+show_policy(KMF_POLICY_RECORD *plc)
+{
+ int i;
+ if (plc == NULL)
+ return;
+
+ (void) printf("Name: %s\n", plc->name);
+
+ (void) printf(gettext("Ignore Date: %s\n"),
+ plc->ignore_date ? gettext("true") : gettext("false"));
+
+ (void) printf(gettext("Ignore Unknown EKUs: %s\n"),
+ plc->ignore_unknown_ekus ? gettext("true") : gettext("false"));
+
+ (void) printf(gettext("Ignore TA: %s\n"),
+ plc->ignore_trust_anchor ? gettext("true") : gettext("false"));
+
+ (void) printf(gettext("Validity Adjusted Time: %s\n"),
+ plc->validity_adjusttime ?
+ plc->validity_adjusttime : "<null>");
+
+ if (plc->ta_name == NULL && plc->ta_serial == NULL) {
+ (void) printf(gettext("Trust Anchor Certificate: <null>\n"));
+ } else {
+ (void) printf(gettext("Trust Anchor Certificate:\n"));
+ (void) printf(gettext("\tName: %s\n"),
+ plc->ta_name ? plc->ta_name : "<null>");
+ (void) printf(gettext("\tSerial Number: %s\n"),
+ plc->ta_serial ? plc->ta_serial : "<null>");
+ }
+
+ if (plc->ku_bits != 0) {
+ (void) printf(gettext("Key Usage Bits: "));
+ for (i = KULOWBIT; i <= KUHIGHBIT; i++) {
+ char *s = ku2str((plc->ku_bits & (1<<i)));
+ if (s != NULL) {
+ (void) printf("%s ", s);
+ }
+ }
+ (void) printf("\n");
+ } else {
+ (void) printf(gettext("Key Usage Bits: 0\n"));
+ }
+
+ if (plc->eku_set.eku_count > 0) {
+ (void) printf(gettext("Extended Key Usage Values:\n"));
+ for (i = 0; i < plc->eku_set.eku_count; i++) {
+ char *s = KMF_OID2EKUString(&plc->eku_set.ekulist[i]);
+ (void) printf("\t%s\t(%s)\n",
+ KMF_OID2String(&plc->eku_set.ekulist[i]),
+ s ? s : "unknown");
+ }
+ } else {
+ (void) printf(gettext("Extended Key Usage Values: <null>\n"));
+ }
+
+ (void) printf(gettext("Validation Policy Information:\n"));
+
+ if (plc->revocation & KMF_REVOCATION_METHOD_OCSP) {
+ (void) printf(gettext(" OCSP:\n"));
+
+ (void) printf(gettext("\tResponder URI: %s\n"),
+ plc->VAL_OCSP_BASIC.responderURI ?
+ plc->VAL_OCSP_BASIC.responderURI : "<null>");
+
+ (void) printf(gettext("\tProxy: %s\n"),
+ plc->VAL_OCSP_BASIC.proxy ?
+ plc->VAL_OCSP_BASIC.proxy : "<null>");
+
+ (void) printf(gettext("\tUse ResponderURI from Certificate: "
+ "%s\n"), plc->VAL_OCSP_BASIC.uri_from_cert ?
+ gettext("true") : gettext("false"));
+
+ (void) printf(gettext("\tResponse lifetime: %s\n"),
+ plc->VAL_OCSP_BASIC.response_lifetime ?
+ plc->VAL_OCSP_BASIC.response_lifetime : "<null>");
+
+ (void) printf(gettext("\tIgnore Response signature: %s\n"),
+ plc->VAL_OCSP_BASIC.ignore_response_sign ?
+ gettext("true") : gettext("false"));
+
+ if (!plc->VAL_OCSP.has_resp_cert) {
+ (void) printf(gettext("\tResponder Certificate:"
+ " <null>\n"));
+ } else {
+ (void) printf(gettext("\tResponder Certificate:\n"));
+ (void) printf(gettext("\t\tName: %s\n"),
+ plc->VAL_OCSP_RESP_CERT.name ?
+ plc->VAL_OCSP_RESP_CERT.name : "<null>");
+ (void) printf(gettext("\t\tSerial: %s\n"),
+ plc->VAL_OCSP_RESP_CERT.serial ?
+ plc->VAL_OCSP_RESP_CERT.serial : "<null>");
+ }
+ }
+
+ if (plc->revocation & KMF_REVOCATION_METHOD_CRL) {
+ (void) printf(gettext(" CRL:\n"));
+
+ (void) printf(gettext("\tBase filename: %s\n"),
+ plc->validation_info.crl_info.basefilename ?
+ plc->validation_info.crl_info.basefilename : "<null>");
+
+ (void) printf(gettext("\tDirectory: %s\n"),
+ plc->validation_info.crl_info.directory ?
+ plc->validation_info.crl_info.directory : "<null>");
+
+ (void) printf(gettext("\tDownload and cache CRL: %s\n"),
+ plc->validation_info.crl_info.get_crl_uri ?
+ gettext("true") : gettext("false"));
+
+ (void) printf(gettext("\tProxy: %s\n"),
+ plc->validation_info.crl_info.proxy ?
+ plc->validation_info.crl_info.proxy : "<null>");
+
+ (void) printf(gettext("\tIgnore CRL signature: %s\n"),
+ plc->validation_info.crl_info.ignore_crl_sign ?
+ gettext("true") : gettext("false"));
+
+ (void) printf(gettext("\tIgnore CRL validity date: %s\n"),
+ plc->validation_info.crl_info.ignore_crl_date ?
+ gettext("true") : gettext("false"));
+ }
+
+ (void) printf("\n");
+}
+
+int
+kc_list(int argc, char *argv[])
+{
+ int rv = KC_OK;
+ int opt, found = 0;
+ extern int optind_av;
+ extern char *optarg_av;
+ char *filename = NULL;
+ char *policyname = NULL;
+ POLICY_LIST *plclist = NULL, *pnode;
+ int sanity_err = 0;
+
+ while ((opt = getopt_av(argc, argv, "i:(dbfile)p:(policy)")) != EOF) {
+ switch (opt) {
+ case 'i':
+ filename = get_string(optarg_av, &rv);
+ if (filename == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error dbfile input.\n"));
+ }
+ break;
+ case 'p':
+ policyname = get_string(optarg_av, &rv);
+ if (policyname == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error policy name.\n"));
+ }
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("Error input option.\n"));
+ rv = KC_ERR_USAGE;
+ break;
+ }
+ if (rv != KC_OK)
+ goto out;
+ }
+
+ /* No additional args allowed. */
+ argc -= optind_av;
+ if (argc) {
+ (void) fprintf(stderr,
+ gettext("Error input option\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ if (filename == NULL) {
+ filename = strdup(KMF_DEFAULT_POLICY_FILE);
+ if (filename == NULL) {
+ rv = KC_ERR_MEMORY;
+ goto out;
+ }
+ }
+
+ /* Check the access permission of the policy DB */
+ if (access(filename, R_OK) < 0) {
+ int err = errno;
+ (void) fprintf(stderr,
+ gettext("Cannot access \"%s\" for list - %s\n"), filename,
+ strerror(err));
+ rv = KC_ERR_ACCESS;
+ goto out;
+ }
+
+ rv = load_policies(filename, &plclist);
+ if (rv != KMF_OK) {
+ goto out;
+ }
+
+ pnode = plclist;
+ while (pnode != NULL) {
+ if (policyname == NULL ||
+ strcmp(policyname, pnode->plc.name) == 0) {
+ KMF_POLICY_RECORD *plc = &pnode->plc;
+
+ found++;
+ rv = KMF_VerifyPolicy(plc);
+ if (rv != KMF_OK) {
+ (void) fprintf(stderr, gettext(
+ "Policy Name: '%s' is invalid\n"),
+ plc->name);
+ sanity_err++;
+ } else {
+ show_policy(&pnode->plc);
+ }
+ }
+ pnode = pnode->next;
+ }
+
+ free_policy_list(plclist);
+
+ if (!found) {
+ if (policyname)
+ (void) fprintf(stderr, gettext(
+ "Cannot find policy '%s'\n"), policyname);
+ else
+ (void) fprintf(stderr, gettext("Cannot find "
+ "any policies to display\n"));
+ rv = KC_ERR_FIND_POLICY;
+ } else if (sanity_err) {
+ rv = KC_ERR_VERIFY_POLICY;
+ }
+
+out:
+
+ if (filename != NULL)
+ free(filename);
+
+ if (policyname != NULL)
+ free(policyname);
+
+ return (rv);
+}
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/modify.c b/usr/src/cmd/cmd-crypto/kmfcfg/modify.c
new file mode 100644
index 0000000000..413bda3be7
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/modify.c
@@ -0,0 +1,845 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <errno.h>
+#include <kmfapiP.h>
+#include <cryptoutil.h>
+#include "util.h"
+
+#define KC_IGNORE_DATE 0x0000001
+#define KC_IGNORE_UNKNOWN_EKUS 0x0000002
+#define KC_IGNORE_TRUST_ANCHOR 0x0000004
+#define KC_VALIDITY_ADJUSTTIME 0x0000008
+#define KC_TA_NAME 0x0000010
+#define KC_TA_SERIAL 0x0000020
+#define KC_OCSP_RESPONDER_URI 0x0000040
+#define KC_OCSP_PROXY 0x0000080
+#define KC_OCSP_URI_FROM_CERT 0x0000100
+#define KC_OCSP_RESP_LIFETIME 0x0000200
+#define KC_OCSP_IGNORE_RESP_SIGN 0x0000400
+#define KC_OCSP_RESP_CERT_NAME 0x0000800
+#define KC_OCSP_RESP_CERT_SERIAL 0x0001000
+#define KC_OCSP_NONE 0x0002000
+#define KC_CRL_BASEFILENAME 0x0004000
+#define KC_CRL_DIRECTORY 0x0008000
+#define KC_CRL_GET_URI 0x0010000
+#define KC_CRL_PROXY 0x0020000
+#define KC_CRL_IGNORE_SIGN 0x0040000
+#define KC_CRL_IGNORE_DATE 0x0080000
+#define KC_CRL_NONE 0x0100000
+#define KC_KEYUSAGE 0x0200000
+#define KC_KEYUSAGE_NONE 0x0400000
+#define KC_EKUS 0x0800000
+#define KC_EKUS_NONE 0x1000000
+
+int
+kc_modify(int argc, char *argv[])
+{
+ KMF_RETURN ret;
+ int rv = KC_OK;
+ int opt;
+ extern int optind_av;
+ extern char *optarg_av;
+ char *filename = NULL;
+ uint32_t flags = 0;
+ boolean_t ocsp_none_opt = B_FALSE;
+ boolean_t crl_none_opt = B_FALSE;
+ boolean_t ku_none_opt = B_FALSE;
+ boolean_t eku_none_opt = B_FALSE;
+ int ocsp_set_attr = 0;
+ int crl_set_attr = 0;
+ KMF_POLICY_RECORD oplc, plc;
+
+ (void) memset(&plc, 0, sizeof (KMF_POLICY_RECORD));
+ (void) memset(&oplc, 0, sizeof (KMF_POLICY_RECORD));
+
+ while ((opt = getopt_av(argc, argv,
+ "i:(dbfile)"
+ "p:(policy)"
+ "d:(ignore-date)"
+ "e:(ignore-unknown-eku)"
+ "a:(ignore-trust-anchor)"
+ "v:(validity-adjusttime)"
+ "t:(ta-name)"
+ "s:(ta-serial)"
+ "o:(ocsp-responder)"
+ "P:(ocsp-proxy)"
+ "r:(ocsp-use-cert-responder)"
+ "T:(ocsp-response-lifetime)"
+ "R:(ocsp-ignore-response-sign)"
+ "n:(ocsp-responder-cert-name)"
+ "A:(ocsp-responder-cert-serial)"
+ "y:(ocsp-none)"
+ "c:(crl-basefilename)"
+ "I:(crl-directory)"
+ "g:(crl-get-crl-uri)"
+ "X:(crl-proxy)"
+ "S:(crl-ignore-crl-sign)"
+ "D:(crl-ignore-crl-date)"
+ "z:(crl-none)"
+ "u:(keyusage)"
+ "Y:(keyusage-none)"
+ "E:(ekunames)"
+ "O:(ekuoids)"
+ "Z:(eku-none)")) != EOF) {
+ switch (opt) {
+ case 'i':
+ filename = get_string(optarg_av, &rv);
+ if (filename == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error dbfile input.\n"));
+ }
+ break;
+ case 'p':
+ plc.name = get_string(optarg_av, &rv);
+ if (plc.name == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error policy name.\n"));
+ }
+ break;
+ case 'd':
+ plc.ignore_date = get_boolean(optarg_av);
+ if (plc.ignore_date == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_IGNORE_DATE;
+ }
+ break;
+ case 'e':
+ plc.ignore_unknown_ekus =
+ get_boolean(optarg_av);
+ if (plc.ignore_unknown_ekus == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_IGNORE_UNKNOWN_EKUS;
+ }
+ break;
+ case 'a':
+ plc.ignore_trust_anchor =
+ get_boolean(optarg_av);
+ if (plc.ignore_trust_anchor == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_IGNORE_TRUST_ANCHOR;
+ }
+ break;
+ case 'v':
+ plc.validity_adjusttime =
+ get_string(optarg_av, &rv);
+ if (plc.validity_adjusttime == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error time input.\n"));
+ } else {
+ uint32_t adj;
+ /* for syntax checking */
+ if (str2lifetime(
+ plc.validity_adjusttime,
+ &adj) < 0) {
+ (void) fprintf(stderr,
+ gettext("Error time "
+ "input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_VALIDITY_ADJUSTTIME;
+ }
+ }
+ break;
+ case 't':
+ plc.ta_name = get_string(optarg_av, &rv);
+ if (plc.ta_name == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error name input.\n"));
+ } else {
+ KMF_X509_NAME taDN;
+ /* for syntax checking */
+ if (KMF_DNParser(plc.ta_name,
+ &taDN) != KMF_OK) {
+ (void) fprintf(stderr,
+ gettext("Error name "
+ "input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ KMF_FreeDN(&taDN);
+ flags |= KC_TA_NAME;
+ }
+ }
+ break;
+ case 's':
+ plc.ta_serial = get_string(optarg_av, &rv);
+ if (plc.ta_serial == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error serial input.\n"));
+ } else {
+ uchar_t *bytes = NULL;
+ size_t bytelen;
+
+ ret = KMF_HexString2Bytes(
+ (uchar_t *)plc.ta_serial,
+ &bytes, &bytelen);
+ if (ret != KMF_OK || bytes == NULL) {
+ (void) fprintf(stderr,
+ gettext("serial number "
+ "must be specified as a "
+ "hex number "
+ "(ex: 0x0102030405"
+ "ffeeddee)\n"));
+ rv = KC_ERR_USAGE;
+ break;
+ }
+ if (bytes != NULL)
+ free(bytes);
+ flags |= KC_TA_SERIAL;
+ }
+ break;
+ case 'o':
+ plc.VAL_OCSP_RESPONDER_URI =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_OCSP_RESPONDER_URI == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error responder "
+ "input.\n"));
+ } else {
+ flags |= KC_OCSP_RESPONDER_URI;
+ ocsp_set_attr++;
+ }
+ break;
+ case 'P':
+ plc.VAL_OCSP_PROXY = get_string(optarg_av, &rv);
+ if (plc.VAL_OCSP_PROXY == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error proxy input.\n"));
+ } else {
+ flags |= KC_OCSP_PROXY;
+ ocsp_set_attr++;
+ }
+ break;
+ case 'r':
+ plc.VAL_OCSP_URI_FROM_CERT =
+ get_boolean(optarg_av);
+ if (plc.VAL_OCSP_URI_FROM_CERT == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_OCSP_URI_FROM_CERT;
+ ocsp_set_attr++;
+ }
+ break;
+ case 'T':
+ plc.VAL_OCSP_RESP_LIFETIME =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_OCSP_RESP_LIFETIME == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error time input.\n"));
+ } else {
+ uint32_t adj;
+ /* for syntax checking */
+ if (str2lifetime(
+ plc.VAL_OCSP_RESP_LIFETIME,
+ &adj) < 0) {
+ (void) fprintf(stderr,
+ gettext("Error time "
+ "input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_OCSP_RESP_LIFETIME;
+ ocsp_set_attr++;
+ }
+ }
+ break;
+ case 'R':
+ plc.VAL_OCSP_IGNORE_RESP_SIGN =
+ get_boolean(optarg_av);
+ if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_OCSP_IGNORE_RESP_SIGN;
+ ocsp_set_attr++;
+ }
+ break;
+ case 'n':
+ plc.VAL_OCSP_RESP_CERT_NAME =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error name input.\n"));
+ } else {
+ KMF_X509_NAME respDN;
+ /* for syntax checking */
+ if (KMF_DNParser(
+ plc.VAL_OCSP_RESP_CERT_NAME,
+ &respDN) != KMF_OK) {
+ (void) fprintf(stderr,
+ gettext("Error name "
+ "input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ KMF_FreeDN(&respDN);
+ flags |= KC_OCSP_RESP_CERT_NAME;
+ ocsp_set_attr++;
+ }
+ }
+ break;
+ case 'A':
+ plc.VAL_OCSP_RESP_CERT_SERIAL =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error serial input.\n"));
+ } else {
+ uchar_t *bytes = NULL;
+ size_t bytelen;
+
+ ret = KMF_HexString2Bytes((uchar_t *)
+ plc.VAL_OCSP_RESP_CERT_SERIAL,
+ &bytes, &bytelen);
+ if (ret != KMF_OK || bytes == NULL) {
+ (void) fprintf(stderr,
+ gettext("serial number "
+ "must be specified as a "
+ "hex number "
+ "(ex: 0x0102030405"
+ "ffeeddee)\n"));
+ rv = KC_ERR_USAGE;
+ break;
+ }
+ if (bytes != NULL)
+ free(bytes);
+ flags |= KC_OCSP_RESP_CERT_SERIAL;
+ ocsp_set_attr++;
+ }
+ break;
+ case 'y':
+ ocsp_none_opt = get_boolean(optarg_av);
+ if (ocsp_none_opt == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_OCSP_NONE;
+ }
+ break;
+ case 'c':
+ plc.VAL_CRL_BASEFILENAME =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_CRL_BASEFILENAME == NULL) {
+ (void) fprintf(stderr, gettext(
+ "Error basefilename input.\n"));
+ } else {
+ flags |= KC_CRL_BASEFILENAME;
+ crl_set_attr++;
+ }
+ break;
+ case 'I':
+ plc.VAL_CRL_DIRECTORY =
+ get_string(optarg_av, &rv);
+ if (plc.VAL_CRL_DIRECTORY == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ } else {
+ flags |= KC_CRL_DIRECTORY;
+ crl_set_attr++;
+ }
+ break;
+ case 'g':
+ plc.VAL_CRL_GET_URI = get_boolean(optarg_av);
+ if (plc.VAL_CRL_GET_URI == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_CRL_GET_URI;
+ crl_set_attr++;
+ }
+ break;
+ case 'X':
+ plc.VAL_CRL_PROXY = get_string(optarg_av, &rv);
+ if (plc.VAL_CRL_PROXY == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error proxy input.\n"));
+ } else {
+ flags |= KC_CRL_PROXY;
+ crl_set_attr++;
+ }
+ break;
+ case 'S':
+ plc.VAL_CRL_IGNORE_SIGN =
+ get_boolean(optarg_av);
+ if (plc.VAL_CRL_IGNORE_SIGN == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_CRL_IGNORE_SIGN;
+ crl_set_attr++;
+ }
+ break;
+ case 'D':
+ plc.VAL_CRL_IGNORE_DATE =
+ get_boolean(optarg_av);
+ if (plc.VAL_CRL_IGNORE_DATE == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_CRL_IGNORE_DATE;
+ crl_set_attr++;
+ }
+ break;
+ case 'z':
+ crl_none_opt = get_boolean(optarg_av);
+ if (crl_none_opt == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_CRL_NONE;
+ }
+ break;
+ case 'u':
+ plc.ku_bits = parseKUlist(optarg_av);
+ if (plc.ku_bits == 0) {
+ (void) fprintf(stderr, gettext(
+ "Error keyusage input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_KEYUSAGE;
+ }
+ break;
+ case 'Y':
+ ku_none_opt = get_boolean(optarg_av);
+ if (ku_none_opt == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_KEYUSAGE_NONE;
+ }
+ break;
+ case 'E':
+ if (parseEKUNames(optarg_av, &plc) != 0) {
+ (void) fprintf(stderr,
+ gettext("Error EKU input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_EKUS;
+ }
+ break;
+ case 'O':
+ if (parseEKUOIDs(optarg_av, &plc) != 0) {
+ (void) fprintf(stderr,
+ gettext("Error EKU OID input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_EKUS;
+ }
+ break;
+ case 'Z':
+ eku_none_opt = get_boolean(optarg_av);
+ if (eku_none_opt == -1) {
+ (void) fprintf(stderr,
+ gettext("Error boolean input.\n"));
+ rv = KC_ERR_USAGE;
+ } else {
+ flags |= KC_EKUS_NONE;
+ }
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("Error input option.\n"));
+ rv = KC_ERR_USAGE;
+ break;
+ }
+ if (rv != KC_OK)
+ goto out;
+ }
+
+ /* No additional args allowed. */
+ argc -= optind_av;
+ if (argc) {
+ (void) fprintf(stderr,
+ gettext("Error input option\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ if (filename == NULL) {
+ filename = strdup(KMF_DEFAULT_POLICY_FILE);
+ if (filename == NULL) {
+ rv = KC_ERR_MEMORY;
+ goto out;
+ }
+ }
+
+ /*
+ * Must have a policy name. The policy name can not be default
+ * if using the default policy file.
+ */
+ if (plc.name == NULL) {
+ (void) fprintf(stderr,
+ gettext("You must specify a policy name.\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 &&
+ strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) {
+ (void) fprintf(stderr,
+ gettext("Can not modify the default policy in the default "
+ "policy file.\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ /* Check the access permission of the policy DB */
+ if (access(filename, W_OK) < 0) {
+ int err = errno;
+ (void) fprintf(stderr,
+ gettext("Cannot access \"%s\" for modify - %s\n"),
+ filename, strerror(err));
+ rv = KC_ERR_ACCESS;
+ goto out;
+ }
+
+ /* Try to load the named policy from the DB */
+ ret = KMF_GetPolicy(filename, plc.name, &oplc);
+ if (ret != KMF_OK) {
+ (void) fprintf(stderr,
+ gettext("Error loading policy \"%s\" from %s\n"), filename,
+ plc.name);
+ return (KC_ERR_FIND_POLICY);
+ }
+
+ /* Update the general policy attributes. */
+ if (flags & KC_IGNORE_DATE)
+ oplc.ignore_date = plc.ignore_date;
+
+ if (flags & KC_IGNORE_UNKNOWN_EKUS)
+ oplc.ignore_unknown_ekus = plc.ignore_unknown_ekus;
+
+ if (flags & KC_IGNORE_TRUST_ANCHOR)
+ oplc.ignore_trust_anchor = plc.ignore_trust_anchor;
+
+ if (flags & KC_VALIDITY_ADJUSTTIME) {
+ if (oplc.validity_adjusttime)
+ free(oplc.validity_adjusttime);
+ oplc.validity_adjusttime =
+ plc.validity_adjusttime;
+ }
+
+ if (flags & KC_TA_NAME) {
+ if (oplc.ta_name)
+ free(oplc.ta_name);
+ oplc.ta_name = plc.ta_name;
+ }
+ if (flags & KC_TA_SERIAL) {
+ if (oplc.ta_serial)
+ free(oplc.ta_serial);
+ oplc.ta_serial = plc.ta_serial;
+ }
+
+ /* Update the OCSP policy */
+ if (ocsp_none_opt == B_TRUE) {
+ if (ocsp_set_attr > 0) {
+ (void) fprintf(stderr,
+ gettext("Can not set ocsp-none=true and other "
+ "OCSP attributes at the same time.\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ /*
+ * If the original policy does not have OCSP checking,
+ * then we do not need to do anything. If the original
+ * policy has the OCSP checking, then we need to release the
+ * space of OCSP attributes and turn the OCSP checking off.
+ */
+ if (oplc.revocation & KMF_REVOCATION_METHOD_OCSP) {
+ if (oplc.VAL_OCSP_BASIC.responderURI) {
+ free(oplc.VAL_OCSP_BASIC.responderURI);
+ oplc.VAL_OCSP_BASIC.responderURI = NULL;
+ }
+
+ if (oplc.VAL_OCSP_BASIC.proxy) {
+ free(oplc.VAL_OCSP_BASIC.proxy);
+ oplc.VAL_OCSP_BASIC.proxy = NULL;
+ }
+
+ if (oplc.VAL_OCSP_BASIC.response_lifetime) {
+ free(oplc.VAL_OCSP_BASIC.response_lifetime);
+ oplc.VAL_OCSP_BASIC.response_lifetime = NULL;
+ }
+
+ if (flags & KC_OCSP_RESP_CERT_NAME) {
+ free(oplc.VAL_OCSP_RESP_CERT.name);
+ oplc.VAL_OCSP_RESP_CERT.name = NULL;
+ }
+
+ if (flags & KC_OCSP_RESP_CERT_SERIAL) {
+ free(oplc.VAL_OCSP_RESP_CERT.serial);
+ oplc.VAL_OCSP_RESP_CERT.serial = NULL;
+ }
+
+ /* Turn off the OCSP checking */
+ oplc.revocation &= ~KMF_REVOCATION_METHOD_OCSP;
+ }
+
+ } else {
+ /*
+ * If the "ocsp-none" option is not set or is set to false,
+ * then we only need to do the modification if there is at
+ * least one OCSP attribute is specified.
+ */
+ if (ocsp_set_attr > 0) {
+ if (flags & KC_OCSP_RESPONDER_URI) {
+ if (oplc.VAL_OCSP_RESPONDER_URI)
+ free(oplc.VAL_OCSP_RESPONDER_URI);
+ oplc.VAL_OCSP_RESPONDER_URI =
+ plc.VAL_OCSP_RESPONDER_URI;
+ }
+
+ if (flags & KC_OCSP_PROXY) {
+ if (oplc.VAL_OCSP_PROXY)
+ free(oplc.VAL_OCSP_PROXY);
+ oplc.VAL_OCSP_PROXY = plc.VAL_OCSP_PROXY;
+ }
+
+ if (flags & KC_OCSP_URI_FROM_CERT)
+ oplc.VAL_OCSP_URI_FROM_CERT =
+ plc.VAL_OCSP_URI_FROM_CERT;
+
+ if (flags & KC_OCSP_RESP_LIFETIME) {
+ if (oplc.VAL_OCSP_RESP_LIFETIME)
+ free(oplc.VAL_OCSP_RESP_LIFETIME);
+ oplc.VAL_OCSP_RESP_LIFETIME =
+ plc.VAL_OCSP_RESP_LIFETIME;
+ }
+
+ if (flags & KC_OCSP_IGNORE_RESP_SIGN)
+ oplc.VAL_OCSP_IGNORE_RESP_SIGN =
+ plc.VAL_OCSP_IGNORE_RESP_SIGN;
+
+ if (flags & KC_OCSP_RESP_CERT_NAME) {
+ if (oplc.VAL_OCSP_RESP_CERT_NAME)
+ free(oplc.VAL_OCSP_RESP_CERT_NAME);
+ oplc.VAL_OCSP_RESP_CERT_NAME =
+ plc.VAL_OCSP_RESP_CERT_NAME;
+ }
+
+ if (flags & KC_OCSP_RESP_CERT_SERIAL) {
+ if (oplc.VAL_OCSP_RESP_CERT_SERIAL)
+ free(oplc.VAL_OCSP_RESP_CERT_SERIAL);
+ oplc.VAL_OCSP_RESP_CERT_SERIAL =
+ plc.VAL_OCSP_RESP_CERT_SERIAL;
+ }
+
+ if (oplc.VAL_OCSP_RESP_CERT_NAME != NULL &&
+ oplc.VAL_OCSP_RESP_CERT_SERIAL != NULL)
+ oplc.VAL_OCSP.has_resp_cert = B_TRUE;
+ else
+ oplc.VAL_OCSP.has_resp_cert = B_FALSE;
+
+ /* Turn on the OCSP checking */
+ oplc.revocation |= KMF_REVOCATION_METHOD_OCSP;
+ }
+ }
+
+ /* Update the CRL policy */
+ if (crl_none_opt == B_TRUE) {
+ if (crl_set_attr > 0) {
+ (void) fprintf(stderr,
+ gettext("Can not set crl-none=true and other CRL "
+ "attributes at the same time.\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ /*
+ * If the original policy does not have CRL checking,
+ * then we do not need to do anything. If the original
+ * policy has the CRL checking, then we need to release the
+ * space of CRL attributes and turn the CRL checking off.
+ */
+ if (oplc.revocation & KMF_REVOCATION_METHOD_CRL) {
+ if (oplc.VAL_CRL_BASEFILENAME) {
+ free(oplc.VAL_CRL_BASEFILENAME);
+ oplc.VAL_CRL_BASEFILENAME = NULL;
+ }
+
+ if (oplc.VAL_CRL_DIRECTORY) {
+ free(oplc.VAL_CRL_DIRECTORY);
+ oplc.VAL_CRL_DIRECTORY = NULL;
+ }
+
+ if (oplc.VAL_CRL_PROXY) {
+ free(oplc.VAL_CRL_PROXY);
+ oplc.VAL_CRL_PROXY = NULL;
+ }
+
+ /* Turn off the CRL checking */
+ oplc.revocation &= ~KMF_REVOCATION_METHOD_CRL;
+ }
+ } else {
+ /*
+ * If the "ocsp-none" option is not set or is set to false,
+ * then we only need to do the modification if there is at
+ * least one CRL attribute is specified.
+ */
+ if (crl_set_attr > 0) {
+ if (flags & KC_CRL_BASEFILENAME) {
+ if (oplc.VAL_CRL_BASEFILENAME)
+ free(oplc.VAL_CRL_BASEFILENAME);
+ oplc.VAL_CRL_BASEFILENAME =
+ plc.VAL_CRL_BASEFILENAME;
+ }
+
+ if (flags & KC_CRL_DIRECTORY) {
+ if (oplc.VAL_CRL_DIRECTORY)
+ free(oplc.VAL_CRL_DIRECTORY);
+ oplc.VAL_CRL_DIRECTORY = plc.VAL_CRL_DIRECTORY;
+ }
+
+ if (flags & KC_CRL_GET_URI) {
+ oplc.VAL_CRL_GET_URI = plc.VAL_CRL_GET_URI;
+ }
+
+ if (flags & KC_CRL_PROXY) {
+ if (oplc.VAL_CRL_PROXY)
+ free(oplc.VAL_CRL_PROXY);
+ oplc.VAL_CRL_PROXY = plc.VAL_CRL_PROXY;
+ }
+
+ if (flags & KC_CRL_IGNORE_SIGN) {
+ oplc.VAL_CRL_IGNORE_SIGN =
+ plc.VAL_CRL_IGNORE_SIGN;
+ }
+
+ if (flags & KC_CRL_IGNORE_DATE) {
+ oplc.VAL_CRL_IGNORE_DATE =
+ plc.VAL_CRL_IGNORE_DATE;
+ }
+
+ /* Turn on the CRL checking */
+ oplc.revocation |= KMF_REVOCATION_METHOD_CRL;
+ }
+ }
+
+ /* Update the Key Usage */
+ if (ku_none_opt == B_TRUE) {
+ if (flags & KC_KEYUSAGE) {
+ (void) fprintf(stderr,
+ gettext("Can not set keyusage-none=true and "
+ "modify the keyusage value at the same time.\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ oplc.ku_bits = 0;
+ } else {
+ /*
+ * If the "keyusage-none" option is not set or is set to
+ * false, then we only need to do the modification if
+ * the keyusage value is specified.
+ */
+ if (flags & KC_KEYUSAGE)
+ oplc.ku_bits = plc.ku_bits;
+ }
+
+
+ /* Update the Extended Key Usage */
+ if (eku_none_opt == B_TRUE) {
+ if (flags & KC_EKUS) {
+ (void) fprintf(stderr,
+ gettext("Can not set eku-none=true and modify "
+ "EKU values at the same time.\n"));
+ rv = KC_ERR_USAGE;
+ goto out;
+ }
+
+ /* Release current EKU list (if any) */
+ if (oplc.eku_set.eku_count > 0) {
+ KMF_FreeEKUPolicy(&oplc.eku_set);
+ oplc.eku_set.eku_count = 0;
+ oplc.eku_set.ekulist = NULL;
+ }
+ } else {
+ /*
+ * If the "eku-none" option is not set or is set to false,
+ * then we only need to do the modification if either
+ * "ekuname" or "ekuoids" is specified.
+ */
+ if (flags & KC_EKUS) {
+ /* Release current EKU list (if any) */
+ KMF_FreeEKUPolicy(&oplc.eku_set);
+ oplc.eku_set = plc.eku_set;
+ }
+ }
+
+ /* Do a sanity check on the modified policy */
+ ret = KMF_VerifyPolicy(&oplc);
+ if (ret != KMF_OK) {
+ print_sanity_error(ret);
+ rv = KC_ERR_VERIFY_POLICY;
+ goto out;
+ }
+
+ /* The modify operation is a delete followed by an add */
+ ret = KMF_DeletePolicyFromDB(oplc.name, filename);
+ if (ret != KMF_OK) {
+ rv = KC_ERR_DELETE_POLICY;
+ goto out;
+ }
+
+ /*
+ * Now add the modified policy back to the DB.
+ */
+ ret = KMF_AddPolicyToDB(&oplc, filename, B_FALSE);
+ if (ret != KMF_OK) {
+ (void) fprintf(stderr,
+ gettext("Error adding policy to database: 0x%04x\n"), ret);
+ rv = KC_ERR_ADD_POLICY;
+ goto out;
+ }
+
+out:
+ if (filename != NULL)
+ free(filename);
+
+ KMF_FreePolicyRecord(&oplc);
+
+ return (rv);
+}
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/util.c b/usr/src/cmd/cmd-crypto/kmfcfg/util.c
new file mode 100644
index 0000000000..f3bdc633f2
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/util.c
@@ -0,0 +1,497 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <libintl.h>
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+
+#include <kmfapiP.h>
+
+#include "util.h"
+
+/* Supporting structures and global variables for getopt_av(). */
+typedef struct av_opts_s {
+ int shortnm; /* short name character */
+ char *longnm; /* long name string, NOT terminated */
+ int longnm_len; /* length of long name string */
+ boolean_t has_arg; /* takes optional argument */
+} av_opts;
+
+static av_opts *opts_av = NULL;
+static const char *_save_optstr = NULL;
+static int _save_numopts = 0;
+int optind_av = 1;
+char *optarg_av = NULL;
+
+void
+free_policy_list(POLICY_LIST *plist)
+{
+ POLICY_LIST *n = plist, *old;
+
+ if (plist == NULL)
+ return;
+
+ while (n != NULL) {
+ old = n;
+ KMF_FreePolicyRecord(&n->plc);
+ n = n->next;
+ free(old);
+ }
+ plist = NULL;
+}
+
+int
+load_policies(char *file, POLICY_LIST **policy_list)
+{
+ int rv = KC_OK;
+ KMF_RETURN kmfrv = KMF_OK;
+ POLICY_LIST *newitem, *plist = NULL;
+ xmlParserCtxtPtr ctxt;
+ xmlDocPtr doc = NULL;
+ xmlNodePtr cur, node;
+
+ /* Create a parser context */
+ ctxt = xmlNewParserCtxt();
+ if (ctxt == NULL)
+ return (KMF_ERR_POLICY_DB_FORMAT);
+
+ /* Read the policy DB and verify it against the schema. */
+ doc = xmlCtxtReadFile(ctxt, file, NULL,
+ XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
+ if (doc == NULL || ctxt->valid == 0) {
+ kmfrv = KMF_ERR_POLICY_DB_FORMAT;
+ goto end;
+ }
+
+ cur = xmlDocGetRootElement(doc);
+ if (cur == NULL) {
+ kmfrv = KMF_ERR_POLICY_DB_FORMAT;
+ goto end;
+ }
+
+ node = cur->xmlChildrenNode;
+ while (node != NULL) {
+ char *c;
+ /*
+ * Search for the policy that matches the given name.
+ */
+ if (!xmlStrcmp((const xmlChar *)node->name,
+ (const xmlChar *)KMF_POLICY_ELEMENT)) {
+ /* Check the name attribute */
+ c = (char *)xmlGetProp(node,
+ (const xmlChar *)KMF_POLICY_NAME_ATTR);
+
+ /* If a match, parse the rest of the data */
+ if (c != NULL) {
+ xmlFree(c);
+ newitem = malloc(sizeof (POLICY_LIST));
+ if (newitem != NULL) {
+ (void) memset(newitem, 0,
+ sizeof (POLICY_LIST));
+ kmfrv = parsePolicyElement(node,
+ &newitem->plc);
+ } else {
+ kmfrv = KMF_ERR_MEMORY;
+ goto end;
+ }
+ /* add to linked list */
+ if (plist == NULL) {
+ plist = newitem;
+ } else {
+ POLICY_LIST *n = plist;
+ while (n->next != NULL)
+ n = n->next;
+
+ n->next = newitem;
+ newitem->next = NULL;
+ }
+ }
+ }
+ node = node->next;
+ }
+
+end:
+ if (ctxt != NULL)
+ xmlFreeParserCtxt(ctxt);
+
+ if (doc != NULL)
+ xmlFreeDoc(doc);
+
+ if (kmfrv != KMF_OK) {
+ free_policy_list(plist);
+ rv = KC_ERR_LOADDB;
+ } else {
+ *policy_list = plist;
+ }
+
+ return (rv);
+}
+
+/*
+ * Return 0 if there is any error in the input string.
+ */
+uint16_t
+parseKUlist(char *kustring)
+{
+ uint16_t cur_bit;
+ uint16_t kubits = 0;
+ char *p;
+
+ p = strtok(kustring, ",");
+ while (p != NULL) {
+ cur_bit = KMF_StringToKeyUsage(p);
+ if (cur_bit == 0) {
+ kubits = 0;
+ break;
+ }
+ kubits |= cur_bit;
+ p = strtok(NULL, ",");
+ }
+
+ return (kubits);
+}
+
+static void
+addToEKUList(KMF_EKU_POLICY *ekus, KMF_OID *newoid)
+{
+ if (newoid != NULL && ekus != NULL) {
+ ekus->eku_count++;
+ ekus->ekulist = realloc(
+ ekus->ekulist,
+ ekus->eku_count * sizeof (KMF_OID));
+ if (ekus->ekulist != NULL) {
+ ekus->ekulist[ekus->eku_count-1] = *newoid;
+ }
+ }
+}
+
+int
+parseEKUNames(char *ekulist, KMF_POLICY_RECORD *plc)
+{
+ int rv = KC_OK;
+ char *p;
+ KMF_OID *newoid;
+ KMF_EKU_POLICY *ekus = &plc->eku_set;
+
+ if (ekulist == NULL || !strlen(ekulist))
+ return (0);
+
+ /*
+ * The list should be comma separated list of EKU Names.
+ */
+ p = strtok(ekulist, ",");
+
+ /* If no tokens found, then maybe its just a single EKU value */
+ if (p == NULL) {
+ newoid = kmf_ekuname2oid(ekulist);
+ if (newoid != NULL) {
+ addToEKUList(ekus, newoid);
+ free(newoid);
+ } else {
+ rv = KC_ERR_USAGE;
+ }
+ }
+
+ while (p != NULL) {
+ newoid = kmf_ekuname2oid(p);
+ if (newoid != NULL) {
+ addToEKUList(ekus, newoid);
+ free(newoid);
+ } else {
+ rv = KC_ERR_USAGE;
+ break;
+ }
+ p = strtok(NULL, ",");
+ }
+
+ if (rv != KC_OK)
+ KMF_FreeEKUPolicy(ekus);
+
+ return (rv);
+}
+
+int
+parseEKUOIDs(char *ekulist, KMF_POLICY_RECORD *plc)
+{
+ int rv = KC_OK;
+ char *p;
+ KMF_OID *newoid;
+ KMF_EKU_POLICY *ekus = &plc->eku_set;
+
+ if (ekulist == NULL || !strlen(ekulist))
+ return (0);
+
+ /*
+ * The list should be comma separated list of EKU Names.
+ */
+ p = strtok(ekulist, ",");
+ if (p == NULL) {
+ newoid = kmf_string2oid(ekulist);
+ if (newoid != NULL) {
+ addToEKUList(ekus, newoid);
+ free(newoid);
+ } else {
+ rv = KC_ERR_USAGE;
+ }
+ }
+
+ while (p != NULL && rv == 0) {
+ newoid = kmf_string2oid(p);
+ if (newoid != NULL) {
+ addToEKUList(ekus, newoid);
+ free(newoid);
+ } else {
+ rv = KC_ERR_USAGE;
+ break;
+ }
+ p = strtok(NULL, ",");
+ }
+
+ if (rv != KC_OK)
+ KMF_FreeEKUPolicy(ekus);
+
+ return (rv);
+}
+
+int
+get_boolean(char *arg)
+{
+ if (arg == NULL)
+ return (-1);
+ if (strcasecmp(arg, "true") == 0)
+ return (1);
+ if (strcasecmp(arg, "false") == 0)
+ return (0);
+ return (-1);
+}
+
+/*
+ * This function processes the input string. It removes the beginning
+ * and ending blank's first, makes a copy of the resulting string and
+ * return it.
+ *
+ * This function returns NULL, if there is an error in the
+ * input string or when the system is out of memory. The output
+ * "err_flag" argument will record the error code, if it is not NULL.
+ */
+char *
+get_string(char *str, int *err_flag)
+{
+ char *p;
+ int len, i;
+ char *retstr = NULL;
+
+ if (str == NULL) {
+ if (err_flag != NULL)
+ *err_flag = KC_ERR_USAGE;
+ return (NULL);
+ }
+
+ /* Remove beginning whitespace */
+ p = str;
+ while (p != NULL && isspace(*p))
+ p++;
+
+ if (p == NULL) {
+ if (err_flag != NULL)
+ *err_flag = KC_ERR_USAGE;
+ return (NULL);
+ }
+
+ /* Remove the trailing blanks */
+ len = strlen(p);
+ while (len > 0 && isspace(p[len-1]))
+ len--;
+
+ if (len == 0) {
+ if (err_flag != NULL)
+ *err_flag = KC_ERR_USAGE;
+ return (NULL);
+ }
+
+ /* Check if there is any non-printable character */
+ i = 0;
+ while (i < len) {
+ if (isprint(p[i]))
+ i++;
+ else {
+ if (err_flag != NULL)
+ *err_flag = KC_ERR_USAGE;
+ return (NULL);
+ }
+ }
+
+ /* Make a copy of the string and return it */
+ retstr = malloc(len + 1);
+ if (retstr == NULL) {
+ if (err_flag != NULL)
+ *err_flag = KC_ERR_MEMORY;
+ return (NULL);
+ }
+
+ if (err_flag != NULL)
+ *err_flag = KC_OK;
+
+ (void) strncpy(retstr, p, len);
+ retstr[len] = '\0';
+ return (retstr);
+}
+
+/*
+ * Breaks out the getopt-style option string into a structure that can be
+ * traversed later for calls to getopt_av(). Option string is NOT altered,
+ * but the struct fields point to locations within option string.
+ */
+static int
+populate_opts(char *optstring)
+{
+ int i;
+ av_opts *temp;
+ char *marker;
+
+ if (optstring == NULL || *optstring == '\0')
+ return (0);
+
+ /*
+ * This tries to imitate getopt(3c) Each option must conform to:
+ * <short name char> [ ':' ] [ '(' <long name string> ')' ]
+ * If long name is missing, the short name is used for long name.
+ */
+ for (i = 0; *optstring != '\0'; i++) {
+ if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
+ realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
+ free(opts_av);
+ opts_av = NULL;
+ return (0);
+ } else
+ opts_av = (av_opts *)temp;
+
+ marker = optstring; /* may need optstring later */
+
+ opts_av[i].shortnm = *marker++; /* set short name */
+
+ if (*marker == ':') { /* check for opt arg */
+ marker++;
+ opts_av[i].has_arg = B_TRUE;
+ }
+
+ if (*marker == '(') { /* check and set long name */
+ marker++;
+ opts_av[i].longnm = marker;
+ opts_av[i].longnm_len = strcspn(marker, ")");
+ optstring = marker + opts_av[i].longnm_len + 1;
+ } else {
+ /* use short name option character */
+ opts_av[i].longnm = optstring;
+ opts_av[i].longnm_len = 1;
+ optstring = marker;
+ }
+ }
+
+ return (i);
+}
+
+/*
+ * getopt_av() is very similar to getopt(3c) in that the takes an option
+ * string, compares command line arguments for matches, and returns a single
+ * letter option when a match is found. However, getopt_av() differs from
+ * getopt(3c) by allowing both longname options and values be found
+ * on the command line.
+ */
+int
+getopt_av(int argc, char * const *argv, const char *optstring)
+{
+ int i;
+ int len;
+
+ if (optind_av >= argc)
+ return (EOF);
+
+ /* First time or when optstring changes from previous one */
+ if (_save_optstr != optstring) {
+ if (opts_av != NULL)
+ free(opts_av);
+ opts_av = NULL;
+ _save_optstr = optstring;
+ _save_numopts = populate_opts((char *)optstring);
+ }
+
+ for (i = 0; i < _save_numopts; i++) {
+ if (strcmp(argv[optind_av], "--") == 0) {
+ optind_av++;
+ break;
+ }
+
+ len = strcspn(argv[optind_av], "=");
+
+ if (len == opts_av[i].longnm_len && strncmp(argv[optind_av],
+ opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
+ /* matched */
+ if (!opts_av[i].has_arg) {
+ optind_av++;
+ return (opts_av[i].shortnm);
+ }
+
+ /* needs optarg */
+ if (argv[optind_av][len] == '=') {
+ optarg_av = &(argv[optind_av][len+1]);
+ optind_av++;
+ return (opts_av[i].shortnm);
+ }
+
+ optarg_av = NULL;
+ optind_av++;
+ return ((int)'?');
+ }
+ }
+
+ return (EOF);
+}
+
+void
+print_sanity_error(KMF_RETURN ret)
+{
+ switch (ret) {
+ case KMF_ERR_POLICY_NAME:
+ (void) fprintf(stderr, gettext("Error in the policy name\n"));
+ break;
+ case KMF_ERR_TA_POLICY:
+ (void) fprintf(stderr,
+ gettext("Error in trust anchor attributes\n"));
+ break;
+ case KMF_ERR_OCSP_POLICY:
+ (void) fprintf(stderr,
+ gettext("Error in OCSP policy attributes\n"));
+ break;
+ default:
+ break;
+ }
+}
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/util.h b/usr/src/cmd/cmd-crypto/kmfcfg/util.h
new file mode 100644
index 0000000000..74f4b0be9b
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/util.h
@@ -0,0 +1,66 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kmfapiP.h>
+
+
+typedef struct _policy_list {
+ KMF_POLICY_RECORD plc;
+ struct _policy_list *next;
+} POLICY_LIST;
+
+void free_policy_list(POLICY_LIST *);
+int getopt_av(int, char * const *, const char *);
+
+int load_policies(char *, POLICY_LIST **);
+int get_boolean(char *);
+char *get_string(char *, int *err_flag);
+int parseEKUOIDs(char *, KMF_POLICY_RECORD *);
+int parseEKUNames(char *, KMF_POLICY_RECORD *);
+uint16_t parseKUlist(char *);
+void print_sanity_error(KMF_RETURN);
+
+#define KC_OK 0
+#define KC_ERR_USAGE 1
+#define KC_ERR_LOADDB 2
+#define KC_ERR_FIND_POLICY 3
+#define KC_ERR_DELETE_POLICY 4
+#define KC_ERR_ADD_POLICY 5
+#define KC_ERR_VERIFY_POLICY 6
+#define KC_ERR_INCOMPLETE_POLICY 7
+#define KC_ERR_MEMORY 8
+#define KC_ERR_ACCESS 9
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _UTIL_H */
diff --git a/usr/src/cmd/cmd-crypto/pktool/Makefile b/usr/src/cmd/cmd-crypto/pktool/Makefile
index 0ad8e96905..dcfefac49a 100644
--- a/usr/src/cmd/cmd-crypto/pktool/Makefile
+++ b/usr/src/cmd/cmd-crypto/pktool/Makefile
@@ -2,9 +2,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# 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.
@@ -20,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -30,31 +29,30 @@ PROG = pktool
OBJS = pktool.o \
common.o \
- derparse.o \
- osslcommon.o \
- p12common.o \
setpin.o \
list.o \
delete.o \
import.o \
export.o \
- tokens.o
+ tokens.o \
+ gencert.o \
+ gencsr.o \
+ download.o \
+ genkey.o
include ../../Makefile.cmd
-include $(SRC)/lib/openssl/Makefile.openssl
+KMFDIR = $(SRC)/lib/libkmf
SRCS = $(OBJS:%.o=%.c)
POFILES = $(OBJS:%.o=%.po)
POFILE = $(PROG)_msg.po
+MSGFILES=$(SRCS:%.c=%.i)
-CPPFLAGS += -I. $(OPENSSL_CPPFLAGS)
-CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I. -I$(KMFDIR)/include
+CFLAGS += $(CCVERBOSE) -DDEBUG
-DYNFLAGS += $(OPENSSL_DYNFLAGS)
-LDFLAGS += $(OPENSSL_LDFLAGS)
-LDLIBS += -lpkcs11 -lcryptoutil -lcrypto -lldap
-
-LINTFLAGS += $(OPENSSL_LDFLAGS)
+LDFLAGS += -L$(SRC)/lib/libkmf/libkmf/$(MACH)
+LDLIBS += -lkmf -lpkcs11 -lcryptoutil
.KEEP_STATE:
@@ -65,7 +63,7 @@ $(PROG) : $(OBJS)
$(POST_PROCESS)
$(POFILE) : $(POFILES)
- $(RM) $@; cat $(POFILES) > $@
+ $(BUILDPO.pofiles)
install : all $(ROOTPROG)
@@ -75,4 +73,3 @@ clean :
lint : lint_SRCS
include ../../Makefile.targ
-
diff --git a/usr/src/cmd/cmd-crypto/pktool/biginteger.h b/usr/src/cmd/cmd-crypto/pktool/biginteger.h
deleted file mode 100644
index 3764e47aaa..0000000000
--- a/usr/src/cmd/cmd-crypto/pktool/biginteger.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _PKTOOL_BIGINTEGER_H
-#define _PKTOOL_BIGINTEGER_H
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <security/pkcs11t.h>
-
-/*
- * NOTE:
- *
- * This is same "biginteger_t" found in both these places:
- * usr/src/lib/pkcs11/pkcs11_softtoken/common/softObject.h
- * usr/src/lib/pkcs11/pkcs11_kernel/common/kernelObject.h
- * The BIGNUM implementation in usr/src/common/bignum does not
- * meet the need. It is recommended that the biginteger_t be
- * factored out of pkcs11_softtoken/pkcs11_kernel/pktool and
- * the pkcs11 libraries and moved into cryptoutil.h
- */
-typedef struct biginteger {
- CK_BYTE *big_value;
- CK_ULONG big_value_len;
-} biginteger_t;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PKTOOL_BIGINTEGER_H */
diff --git a/usr/src/cmd/cmd-crypto/pktool/common.c b/usr/src/cmd/cmd-crypto/pktool/common.c
index 030f8c158a..660afe2d57 100644
--- a/usr/src/cmd/cmd-crypto/pktool/common.c
+++ b/usr/src/cmd/cmd-crypto/pktool/common.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -38,19 +37,19 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <tzfile.h>
#include <cryptoutil.h>
#include <security/cryptoki.h>
-#include "common.h"
-#include "biginteger.h"
+#include <kmfapi.h>
-/* True and false for attribute templates. */
-CK_BBOOL pk_true = B_TRUE;
-CK_BBOOL pk_false = B_FALSE;
+#include "common.h"
/* Local status variables. */
static boolean_t initialized = B_FALSE;
static boolean_t session_opened = B_FALSE;
-static boolean_t session_writable = B_FALSE;
static boolean_t logged_in = B_FALSE;
/* Supporting structures and global variables for getopt_av(). */
@@ -67,6 +66,9 @@ static int _save_numopts = 0;
int optind_av = 1;
char *optarg_av = NULL;
+static void close_sess(CK_SESSION_HANDLE);
+static void logout_token(CK_SESSION_HANDLE);
+
/*
* Perform PKCS#11 setup here. Currently only C_Initialize is required,
* along with setting/resetting state variables.
@@ -76,19 +78,15 @@ init_pk11(void)
{
CK_RV rv = CKR_OK;
- cryptodebug("inside init_pk11");
-
/* If C_Initialize() already called, nothing to do here. */
if (initialized == B_TRUE)
return (CKR_OK);
/* Reset state variables because C_Initialize() not yet done. */
session_opened = B_FALSE;
- session_writable = B_FALSE;
logged_in = B_FALSE;
/* Initialize PKCS#11 library. */
- cryptodebug("calling C_Initialize()");
if ((rv = C_Initialize(NULL_PTR)) != CKR_OK &&
rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
return (rv);
@@ -105,7 +103,6 @@ init_pk11(void)
void
final_pk11(CK_SESSION_HANDLE sess)
{
- cryptodebug("inside final_pk11");
/* If the library wasn't initialized, nothing to do here. */
if (!initialized)
@@ -114,127 +111,41 @@ final_pk11(CK_SESSION_HANDLE sess)
/* Make sure the sesion is closed first. */
close_sess(sess);
- cryptodebug("calling C_Finalize()");
(void) C_Finalize(NULL);
initialized = B_FALSE;
}
/*
- * Create a PKCS#11 session on the given slot, and set state information.
- * If session is already open, check that the read-only/read-write state
- * requested matches that of the session. If it doesn't, make it so.
- */
-CK_RV
-open_sess(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_SESSION_HANDLE_PTR sess)
-{
- CK_RV rv = CKR_OK;
-
- cryptodebug("inside open_sess");
-
- /* If the session is already open, check the session flags. */
- if (session_opened) {
- /*
- * If requesting R/W session and it is currently R/O,
- * need to close the session and reopen it R/W. The
- * other cases are considered acceptable:
- * sess_flags current state
- * ---------- -------------
- * ~CKF_RW_SESSION !session_writable
- * ~CKF_RW_SESSION session_writable
- * CKF_RW_SESSION session_writable
- */
- if ((sess_flags & CKF_RW_SESSION) && !session_writable)
- close_sess(*sess);
- else
- return (CKR_OK);
- }
-
- /* Make sure the PKCS#11 is already initialized. */
- if (!initialized)
- if ((rv = init_pk11()) != CKR_OK)
- return (rv);
-
- /* Create a session for subsequent operations. */
- cryptodebug("calling C_OpenSession()");
- if ((rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION|sess_flags,
- NULL, NULL, sess)) != CKR_OK)
- return (rv);
- session_opened = B_TRUE;
- session_writable = (sess_flags & CKF_RW_SESSION) ? B_TRUE : B_FALSE;
- return (CKR_OK);
-}
-
-/*
* Close PKCS#11 session and reset state variables. Any logins are
* logged out.
*/
-void
+static void
close_sess(CK_SESSION_HANDLE sess)
{
- cryptodebug("inside close_sess");
if (sess == NULL) {
- cryptodebug("session handle is null");
return;
}
/* If session is already closed, nothing to do here. */
- session_writable = B_FALSE;
if (!session_opened)
return;
/* Make sure user is logged out of token. */
logout_token(sess);
- cryptodebug("calling C_CloseSession()");
(void) C_CloseSession(sess);
session_opened = B_FALSE;
}
/*
- * Log user into token in given slot. If this first login ever for this
- * token, the initial PIN is "changeme", C_Login() will succeed, but all
- * PKCS#11 calls following the C_Login() will fail with CKR_PIN_EXPIRED.
- */
-CK_RV
-login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen,
- CK_SESSION_HANDLE_PTR sess)
-{
- CK_RV rv = CKR_OK;
-
- cryptodebug("inside login_token");
-
- /* If already logged in, nothing to do here. */
- if (logged_in)
- return (CKR_OK);
-
- /* Make sure we have a session first, assume R/O is enough. */
- if (!session_opened)
- if ((rv = open_sess(slot_id, CKF_SERIAL_SESSION, sess)) !=
- CKR_OK)
- return (rv);
-
- /* Log the user into the token. */
- cryptodebug("calling C_Login()");
- if ((rv = C_Login(*sess, CKU_USER, pin, pinlen)) != CKR_OK) {
- cryptodebug("C_Login returns %s", pkcs11_strerror(rv));
- return (rv);
- }
-
- logged_in = B_TRUE;
- return (CKR_OK);
-}
-
-/*
* Log user out of token and reset status variable.
*/
-void
+static void
logout_token(CK_SESSION_HANDLE sess)
{
- cryptodebug("inside logout_token");
if (sess == NULL) {
- cryptodebug("session handle is null");
return;
}
@@ -242,49 +153,11 @@ logout_token(CK_SESSION_HANDLE sess)
if (!logged_in)
return;
- cryptodebug("calling C_Logout()");
(void) C_Logout(sess);
logged_in = B_FALSE;
}
/*
- * Shortcut function to get from an uninitialized state to user logged in.
- * If the library is already initialized, the session is already opened,
- * or the user is already logged in, those steps are skipped and the next
- * step is checked.
- */
-CK_RV
-quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_UTF8CHAR_PTR pin,
- CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess)
-{
- CK_RV rv = CKR_OK;
-
- cryptodebug("inside quick_start");
-
- /* Call open_sess() explicitly if R/W session is needed. */
- if (sess_flags & CKF_RW_SESSION)
- if ((rv = open_sess(slot_id, sess_flags, sess)) != CKR_OK)
- return (rv);
-
- if ((rv = login_token(slot_id, pin, pinlen, sess)) != CKR_OK)
- return (rv);
-
- return (CKR_OK);
-}
-
-/*
- * Shortcut function to go from any state to uninitialized PKCS#11 library.
- */
-void
-quick_finish(CK_SESSION_HANDLE sess)
-{
- cryptodebug("inside quick_finish");
-
- /* All the needed calls are done implicitly. */
- final_pk11(sess);
-}
-
-/*
* Gets PIN from user. Caller needs to free the returned PIN when done.
* If two prompts are given, the PIN is confirmed with second prompt.
* Note that getphassphrase() may return data in static memory area.
@@ -294,15 +167,20 @@ get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
{
char *save_phrase, *phrase1, *phrase2;
- cryptodebug("inside get_pin");
+
+#ifdef DEBUG
+ if (getenv("TOKENPIN") != NULL) {
+ *pin = (CK_UTF8CHAR_PTR)strdup(getenv("TOKENPIN"));
+ *pinlen = strlen((char *)(*pin));
+ return (CKR_OK);
+ }
+#endif /* DEBUG */
/* Prompt user for a PIN. */
if (prompt1 == NULL) {
- cryptodebug("no passphrase prompt given");
return (CKR_ARGUMENTS_BAD);
}
if ((phrase1 = getpassphrase(prompt1)) == NULL) {
- cryptodebug("getpassphrase() failed");
return (CKR_FUNCTION_FAILED);
}
@@ -313,12 +191,10 @@ get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
/* If second prompt given, PIN confirmation is requested. */
if (prompt2 != NULL) {
if ((phrase2 = getpassphrase(prompt2)) == NULL) {
- cryptodebug("getpassphrase() confirmation failed");
free(save_phrase);
return (CKR_FUNCTION_FAILED);
}
if (strcmp(save_phrase, phrase2) != 0) {
- cryptodebug("passphrases do not match");
free(save_phrase);
return (CKR_PIN_INCORRECT);
}
@@ -343,7 +219,13 @@ yesno(char *prompt, char *invalid, boolean_t dflt)
char *yes = gettext("yes");
char *no = gettext("no");
- cryptodebug("inside yesno");
+
+#ifdef DEBUG
+ /* If debugging or testing, return TRUE and avoid prompting */
+ if (getenv("TOKENPIN") != NULL) {
+ return (B_TRUE);
+ }
+#endif /* DEBUG */
if (prompt == NULL)
prompt = gettext("Enter (y)es or (n)o? ");
@@ -388,8 +270,6 @@ get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
int rv = CKR_OK;
- cryptodebug("inside get_token_slots");
-
if (!initialized)
if ((rv = init_pk11()) != CKR_OK)
return (rv);
@@ -402,12 +282,10 @@ get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
* Also select only those slots that have tokens in them,
* because this tool has no need to know about empty slots.
*/
- cryptodebug("calling C_GetSlotList() for slot count");
if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK)
return (rv);
if (tmp_count == 0) {
- cryptodebug("no slots with tokens found");
*slot_list = NULL_PTR;
*slot_count = 0;
return (CKR_OK);
@@ -420,7 +298,6 @@ get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
/* Then get the slot list itself. */
for (;;) {
- cryptodebug("calling C_GetSlotList()");
if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) {
*slot_list = tmp_list;
*slot_count = tmp_count;
@@ -433,7 +310,6 @@ get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
}
/* If the number of slots grew, try again. */
- cryptodebug("number of tokens present increased");
if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
free(tmp_list);
@@ -447,878 +323,683 @@ get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
}
/*
- * memcmp_pad_max() is a specialized version of memcmp() which
- * compares two pieces of data up to a maximum length. If the
- * the two data match up the maximum length, they are considered
- * matching. Trailing blanks do not cause the match to fail if
- * one of the data is shorted.
- *
- * Examples of matches:
- * "one" |
- * "one " |
- * ^maximum length
- *
- * "Number One | X" (X is beyond maximum length)
- * "Number One " |
- * ^maximum length
- *
- * Examples of mismatches:
- * " one"
- * "one"
- *
- * "Number One X|"
- * "Number One |"
- * ^maximum length
+ * Breaks out the getopt-style option string into a structure that can be
+ * traversed later for calls to getopt_av(). Option string is NOT altered,
+ * but the struct fields point to locations within option string.
*/
static int
-memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz)
+populate_opts(char *optstring)
{
- uint_t len, extra_len;
+ int i;
+ av_opts *temp;
char *marker;
- /* No point in comparing anything beyond max_sz */
- if (d1_len > max_sz)
- d1_len = max_sz;
- if (d2_len > max_sz)
- d2_len = max_sz;
-
- /* Find shorter of the two data. */
- if (d1_len <= d2_len) {
- len = d1_len;
- extra_len = d2_len;
- marker = d2;
- } else { /* d1_len > d2_len */
- len = d2_len;
- extra_len = d1_len;
- marker = d1;
- }
+ if (optstring == NULL || *optstring == '\0')
+ return (0);
+
+ /*
+ * This tries to imitate getopt(3c) Each option must conform to:
+ * <short name char> [ ':' ] [ '(' <long name string> ')' ]
+ * If long name is missing, the short name is used for long name.
+ */
+ for (i = 0; *optstring != '\0'; i++) {
+ if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
+ realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
+ if (opts_av != NULL)
+ free(opts_av);
+ opts_av = NULL;
+ return (0);
+ } else {
+ opts_av = (av_opts *)temp;
+ }
- /* Have a match in the shortest length of data? */
- if (memcmp(d1, d2, len) != 0)
- /* CONSTCOND */
- return (!0);
+ (void) memset(&opts_av[i], 0, sizeof (av_opts));
+ marker = optstring; /* may need optstring later */
- /* If the rest of longer data is nulls or blanks, call it a match. */
- while (len < extra_len)
- if (!isspace(marker[len++]))
- /* CONSTCOND */
- return (!0);
- return (0);
+ opts_av[i].shortnm = *marker++; /* set short name */
+
+ if (*marker == ':') { /* check for opt arg */
+ marker++;
+ opts_av[i].has_arg = B_TRUE;
+ }
+
+ if (*marker == '(') { /* check and set long name */
+ marker++;
+ opts_av[i].longnm = marker;
+ opts_av[i].longnm_len = strcspn(marker, ")");
+ optstring = marker + opts_av[i].longnm_len + 1;
+ } else {
+ /* use short name option character */
+ opts_av[i].longnm = optstring;
+ opts_av[i].longnm_len = 1;
+ optstring = marker;
+ }
+ }
+
+ return (i);
}
/*
- * Locate a token slot whose token matches the label, manufacturer ID, and
- * serial number given. Token label must be specified, manufacturer ID and
- * serial number are optional. When the token is located, the PIN state
- * is also returned to determine if it still has the default PIN.
+ * getopt_av() is very similar to getopt(3c) in that the takes an option
+ * string, compares command line arguments for matches, and returns a single
+ * letter option when a match is found. However, getopt_av() differs from
+ * getopt(3c) by requiring that only longname options and values be found
+ * on the command line and all leading dashes are omitted. In other words,
+ * it tries to enforce only longname "option=value" arguments on the command
+ * line. Boolean options are not allowed either.
*/
-CK_RV
-find_token_slot(char *token_name, char *manuf_id, char *serial_no,
- CK_SLOT_ID *slot_id, CK_FLAGS *pin_state)
+int
+getopt_av(int argc, char * const *argv, const char *optstring)
{
- CK_SLOT_ID_PTR slot_list;
- CK_TOKEN_INFO token_info;
- CK_ULONG slot_count = 0;
- int rv = CKR_OK;
- int i;
- uint_t len, max_sz;
- boolean_t tok_match = B_FALSE,
- man_match = B_FALSE,
- ser_match = B_FALSE;
+ int i;
+ int len;
+ char *cur_option;
- cryptodebug("inside find_token_slot");
+ if (optind_av >= argc)
+ return (EOF);
- if (token_name == NULL)
- return (CKR_ARGUMENTS_BAD);
+ /* First time or when optstring changes from previous one */
+ if (_save_optstr != optstring) {
+ if (opts_av != NULL)
+ free(opts_av);
+ opts_av = NULL;
+ _save_optstr = optstring;
+ _save_numopts = populate_opts((char *)optstring);
+ }
- /* Get a list of all slots with tokens present. */
- if ((rv = get_token_slots(&slot_list, &slot_count)) != CKR_OK)
- return (rv);
+ for (i = 0; i < _save_numopts; i++) {
+ cur_option = argv[optind_av];
- /* If there are no such slots, the desired token won't be found. */
- if (slot_count == 0)
- return (CKR_TOKEN_NOT_PRESENT);
-
- /* Search the slot list for the token. */
- for (i = 0; i < slot_count; i++) {
- cryptodebug("calling C_GetTokenInfo()");
- if ((rv = C_GetTokenInfo(slot_list[i], &token_info)) !=
- CKR_OK) {
- cryptodebug("token in slot %d returns %s", i,
- pkcs11_strerror(rv));
- continue;
+ if (strcmp(cur_option, "--") == 0) {
+ optind_av++;
+ break;
}
- /* See if the token label matches. */
- len = strlen(token_name);
- max_sz = sizeof (token_info.label);
- if (memcmp_pad_max(&(token_info.label), max_sz, token_name, len,
- max_sz) == 0)
- tok_match = B_TRUE;
-
- /*
- * If manufacturer id was given, see if it actually matches.
- * If no manufacturer id was given, assume match is true.
- */
- if (manuf_id) {
- len = strlen(manuf_id);
- max_sz = sizeof ((char *)(token_info.manufacturerID));
- if (memcmp_pad_max(&(token_info.manufacturerID), max_sz,
- manuf_id, len, max_sz) == 0)
- man_match = B_TRUE;
- } else
- man_match = B_TRUE;
-
- /*
- * If serial number was given, see if it actually matches.
- * If no serial number was given, assume match is true.
- */
- if (serial_no) {
- len = strlen(serial_no);
- max_sz = sizeof ((char *)(token_info.serialNumber));
- if (memcmp_pad_max(&(token_info.serialNumber), max_sz,
- serial_no, len, max_sz) == 0)
- ser_match = B_TRUE;
- } else
- ser_match = B_TRUE;
-
- cryptodebug("slot %d:", i);
- cryptodebug("\tlabel = \"%.32s\"%s", token_info.label,
- tok_match ? " match" : "");
- cryptodebug("\tmanuf = \"%.32s\"%s", token_info.manufacturerID,
- man_match ? " match" : "");
- cryptodebug("\tserno = \"%.16s\"%s", token_info.serialNumber,
- ser_match ? " match" : "");
- cryptodebug("\tmodel = \"%.16s\"", token_info.model);
-
- cryptodebug("\tCKF_USER_PIN_INITIALIZED = %s",
- (token_info.flags & CKF_USER_PIN_INITIALIZED) ?
- "true" : "false");
- cryptodebug("\tCKF_USER_PIN_TO_BE_CHANGED = %s",
- (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ?
- "true" : "false");
-
- if (tok_match && man_match && ser_match)
- break; /* found it! */
- }
+ if (cur_option[0] == '-' && strlen(cur_option) == 2) {
+ len = 1;
+ cur_option++; /* remove "-" */
+ } else {
+ len = strcspn(cur_option, "=");
+ }
- /* Scanned the whole list without finding the token. */
- if (i == slot_count) {
- cryptodebug("token not found");
- free(slot_list);
- return (CKR_TOKEN_NOT_PRESENT);
+ if (len == opts_av[i].longnm_len && strncmp(cur_option,
+ opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
+ /* matched */
+ if (!opts_av[i].has_arg) {
+ optind_av++;
+ return (opts_av[i].shortnm);
+ }
+
+ /* needs optarg */
+ if (cur_option[len] == '=') {
+ optarg_av = &(cur_option[len+1]);
+ optind_av++;
+ return (opts_av[i].shortnm);
+ }
+
+ optarg_av = NULL;
+ optind_av++;
+ return ((int)'?');
+ }
}
- /* Return slot id where token was found and its PIN state. */
- cryptodebug("token found at slot %d", i);
- *slot_id = slot_list[i];
- *pin_state = (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED);
- free(slot_list);
- return (CKR_OK);
+ return (EOF);
}
-/*
- * Returns pointer to either null-terminator or next unescaped colon. The
- * string to be extracted starts at the beginning and goes until one character
- * before this pointer. If NULL is returned, the string itself is NULL.
- */
-static char *
-find_unescaped_colon(char *str)
+KMF_KEYSTORE_TYPE
+KS2Int(char *keystore_str)
{
- char *end;
+ if (keystore_str == NULL)
+ return (0);
+ if (!strcasecmp(keystore_str, "pkcs11"))
+ return (KMF_KEYSTORE_PK11TOKEN);
+ else if (!strcasecmp(keystore_str, "nss"))
+ return (KMF_KEYSTORE_NSS);
+ else if (!strcasecmp(keystore_str, "file"))
+ return (KMF_KEYSTORE_OPENSSL);
+ else
+ return (0);
+}
- if (str == NULL)
- return (NULL);
- while ((end = strchr(str, ':')) != NULL) {
- if (end != str && *(end-1) != '\\')
- return (end);
- str = end + 1; /* could point to null-terminator */
+int
+Str2KeyType(char *algm, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg)
+{
+ if (algm == NULL) {
+ *sigAlg = KMF_ALGID_MD5WithRSA;
+ *ktype = KMF_RSA;
+ } else if (strcasecmp(algm, "DSA") == 0) {
+ *sigAlg = KMF_ALGID_SHA1WithDSA;
+ *ktype = KMF_DSA;
+ } else if (strcasecmp(algm, "RSA") == 0) {
+ *sigAlg = KMF_ALGID_MD5WithRSA;
+ *ktype = KMF_RSA;
+ } else {
+ return (-1);
}
- if (end == NULL)
- end = strchr(str, '\0');
- return (end);
+ return (0);
}
-/*
- * Compresses away any characters escaped with backslash from given string.
- * The string is altered in-place. Example, "ab\:\\e" becomes "ab:\e".
- */
-static void
-unescape_str(char *str)
+int
+Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype)
{
- boolean_t escaped = B_FALSE;
- char *mark;
-
- if (str == NULL)
- return;
+ if (algm == NULL)
+ *ktype = KMF_AES;
+ else if (strcasecmp(algm, "aes") == 0)
+ *ktype = KMF_AES;
+ else if (strcasecmp(algm, "arcfour") == 0)
+ *ktype = KMF_RC4;
+ else if (strcasecmp(algm, "des") == 0)
+ *ktype = KMF_DES;
+ else if (strcasecmp(algm, "3des") == 0)
+ *ktype = KMF_DES3;
+ else
+ return (-1);
- for (mark = str; *str != '\0'; str++) {
- if (*str != '\\' || escaped == B_TRUE) {
- *mark++ = *str;
- escaped = B_FALSE;
- } else {
- escaped = B_TRUE;
- }
- }
- *mark = '\0';
+ return (0);
}
-/*
- * Given a colon-separated token specifier, this functions splits it into
- * its label, manufacturer ID (if any), and serial number (if any). Literal
- * colons within the label/manuf/serial can be escaped with a backslash.
- * Fields can left blank and trailing colons can be omitted, however leading
- * colons are required as placeholders. For example, these are equivalent:
- * (a) "lbl", "lbl:", "lbl::" (b) "lbl:man", "lbl:man:"
- * but these are not:
- * (c) "man", ":man" (d) "ser", "::ser"
- * Furthermore, the token label is required always.
- *
- * The buffer containing the token specifier is altered by replacing the
- * colons to null-terminators, and pointers returned are pointers into this
- * string. No new memory is allocated.
- */
int
-parse_token_spec(char *token_spec, char **token_name, char **manuf_id,
- char **serial_no)
+Str2Lifetime(char *ltimestr, uint32_t *ltime)
{
- char *mark;
+ int num;
+ char timetok[6];
- if (token_spec == NULL || *token_spec == '\0') {
- cryptodebug("token specifier is empty");
- return (-1);
+ if (ltimestr == NULL || !strlen(ltimestr)) {
+ /* default to 1 year lifetime */
+ *ltime = SECSPERDAY * DAYSPERNYEAR;
+ return (0);
}
- *token_name = NULL;
- *manuf_id = NULL;
- *serial_no = NULL;
-
- /* Token label (required) */
- mark = find_unescaped_colon(token_spec);
- *token_name = token_spec;
- if (*mark != '\0')
- *mark++ = '\0'; /* mark points to next field, if any */
- unescape_str(*token_name);
+ (void) memset(timetok, 0, sizeof (timetok));
+ if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2)
+ return (-1);
- if (*(*token_name) == '\0') { /* token label is required */
- cryptodebug("no token label found");
+ if (!strcasecmp(timetok, "day") ||
+ !strcasecmp(timetok, "days")) {
+ *ltime = num * SECSPERDAY;
+ } else if (!strcasecmp(timetok, "hour") ||
+ !strcasecmp(timetok, "hours")) {
+ *ltime = num * SECSPERHOUR;
+ } else if (!strcasecmp(timetok, "year") ||
+ !strcasecmp(timetok, "years")) {
+ *ltime = num * SECSPERDAY * DAYSPERNYEAR;
+ } else {
+ *ltime = 0;
return (-1);
}
- if (*mark == '\0' || *(mark+1) == '\0') /* no more fields */
- return (0);
- token_spec = mark;
-
- /* Manufacturer identifier (optional) */
- mark = find_unescaped_colon(token_spec);
- *manuf_id = token_spec;
- if (*mark != '\0')
- *mark++ = '\0'; /* mark points to next field, if any */
- unescape_str(*manuf_id);
+ return (0);
+}
- if (*mark == '\0' || *(mark+1) == '\0') /* no more fields */
- return (0);
- token_spec = mark;
+int
+OT2Int(char *objclass)
+{
+ char *c = NULL;
+ int retval = 0;
- /* Serial number (optional) */
- mark = find_unescaped_colon(token_spec);
- *serial_no = token_spec;
- if (*mark != '\0')
- *mark++ = '\0'; /* null-terminate, just in case */
- unescape_str(*serial_no);
+ if (objclass == NULL)
+ return (-1);
- return (0);
+ c = strchr(objclass, ':');
+ if (c != NULL) {
+ if (!strcasecmp(c, ":private"))
+ retval = PK_PRIVATE_OBJ;
+ else if (!strcasecmp(c, ":public"))
+ retval = PK_PUBLIC_OBJ;
+ else if (!strcasecmp(c, ":both"))
+ retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ;
+ else /* unrecognized option */
+ return (-1);
+
+ *c = '\0';
+ }
+
+ if (!strcasecmp(objclass, "public")) {
+ if (retval)
+ return (-1);
+ return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ |
+ PK_PUBKEY_OBJ);
+ } else if (!strcasecmp(objclass, "private")) {
+ if (retval)
+ return (-1);
+ return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ);
+ } else if (!strcasecmp(objclass, "both")) {
+ if (retval)
+ return (-1);
+ return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ);
+ } else if (!strcasecmp(objclass, "cert")) {
+ return (retval | PK_CERT_OBJ);
+ } else if (!strcasecmp(objclass, "key")) {
+ if (retval == 0) /* return all keys */
+ return (retval | PK_KEY_OBJ);
+ else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ))
+ /* return all keys */
+ return (retval | PK_KEY_OBJ);
+ else if (retval & PK_PUBLIC_OBJ)
+ /* Only return public keys */
+ return (retval | PK_PUBKEY_OBJ);
+ else if (retval & PK_PRIVATE_OBJ)
+ /* Only return private keys */
+ return (retval | PK_PRIKEY_OBJ);
+ } else if (!strcasecmp(objclass, "crl")) {
+ if (retval)
+ return (-1);
+ return (retval | PK_CRL_OBJ);
+ }
+
+ if (retval == 0) /* No matches found */
+ retval = -1;
+ return (retval);
}
-/*
- * Constructs a fully qualified token name from its label, manufacturer ID
- * (if any), and its serial number (if any). Note that the given buf must
- * be big enough. Do NOT i18n/l10n.
- *
- * FULL_NAME_LEN is defined in common.h to be 91 because a fully qualified
- * token name adds up this way:
- * =32(label) + 32(manuf) + 16(serial) + 4("", ) + 4("", ) + 3("" and nul)
- */
-void
-full_token_name(char *token_name, char *manuf_id, char *serial_no, char *buf)
+KMF_ENCODE_FORMAT
+Str2Format(char *formstr)
{
- char *marker = buf;
- int n_written = 0;
- int space_left = FULL_NAME_LEN;
+ if (formstr == NULL || !strcasecmp(formstr, "der"))
+ return (KMF_FORMAT_ASN1);
+ if (!strcasecmp(formstr, "pem"))
+ return (KMF_FORMAT_PEM);
+ if (!strcasecmp(formstr, "pkcs12"))
+ return (KMF_FORMAT_PKCS12);
+
+ return (KMF_FORMAT_UNDEF);
+}
- if (!token_name)
- return;
- n_written = sprintf(buf, "\"%.32s\"", token_name);
- marker += n_written;
- space_left -= n_written;
+KMF_RETURN
+select_token(void *kmfhandle, char *token,
+ int readonly)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_CONFIG_PARAMS config;
- n_written = sprintf(marker, ", \"%.32s\"", manuf_id ? manuf_id : "");
- marker += n_written;
- space_left -= n_written;
+ if (token == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
- n_written = sprintf(marker, ", \"%.16s\"", serial_no ? serial_no : "");
- marker += n_written;
- space_left -= n_written;
+ (void) memset(&config, 0, sizeof (config));
+ config.kstype = KMF_KEYSTORE_PK11TOKEN;
+ config.pkcs11config.label = token;
+ config.pkcs11config.readonly = readonly;
- /* space_left should always be >= 1 */
+ rv = KMF_ConfigureKeystore(kmfhandle, &config);
+ if (rv == KMF_ERR_TOKEN_SELECTED)
+ rv = KMF_OK;
+ return (rv);
}
-/*
- * Find how many token objects with the given label.
- */
-CK_RV
-find_obj_count(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label,
- CK_ULONG *count)
+
+KMF_RETURN
+configure_nss(void *kmfhandle, char *dir, char *prefix)
{
- CK_RV rv = CKR_OK;
- CK_ATTRIBUTE attrs[4] = {
- { CKA_TOKEN, &pk_true, sizeof (pk_true) },
- { 0, NULL, 0 },
- { 0, NULL, 0 },
- { 0, NULL, 0 }
- };
- CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
- CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */
- CK_OBJECT_CLASS obj_class;
- CK_OBJECT_HANDLE tmp_obj;
- CK_ULONG obj_count = 0;
-
- cryptodebug("inside find_obj_count");
-
- if (!session_opened || sess == NULL) {
- cryptodebug("session handle is null");
- return (CKR_SESSION_HANDLE_INVALID);
- }
+ KMF_RETURN rv = KMF_OK;
+ KMF_CONFIG_PARAMS config;
- if (label) {
- cryptodebug("object label was specified");
- attrs[cur_attr].type = CKA_LABEL;
- attrs[cur_attr].pValue = label;
- attrs[cur_attr].ulValueLen = strlen((char *)label);
- cur_attr++;
- }
+ (void) memset(&config, 0, sizeof (config));
+ config.kstype = KMF_KEYSTORE_NSS;
+ config.nssconfig.configdir = dir;
+ config.nssconfig.certPrefix = prefix;
+ config.nssconfig.keyPrefix = prefix;
+ config.nssconfig.secModName = NULL;
- if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) {
- cryptodebug("only searching for private objects");
- attrs[cur_attr].type = CKA_PRIVATE;
- attrs[cur_attr].pValue = &pk_true;
- attrs[cur_attr].ulValueLen = sizeof (pk_true);
- cur_attr++;
- }
+ rv = KMF_ConfigureKeystore(kmfhandle, &config);
+ if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED)
+ rv = KMF_OK;
- /*
- * If "certs and all keys" is not specified, but at least either
- * "certs" or some "keys" is specified, then go into this block.
- * If all certs and keys were specified, there's no point in
- * putting that fact in the attribute template -- leave that open,
- * and all certs and keys will be matched automatically.
- * In other words, only if at least one of 0x10,0x20,0x40,0x80
- * bits is off, go into this code block.
- *
- * NOTE: For now, only one of cert or key types is allowed.
- * This needs to change in the future.
- */
- if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) &&
- ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) {
- if (obj_type & PK_CERT_OBJ) {
- cryptodebug("only searching for certificates");
- obj_class = CKO_CERTIFICATE;
- } else if (obj_type & PK_PRIKEY_OBJ) {
- cryptodebug("only searching for private keys");
- obj_class = CKO_PRIVATE_KEY;
- } else if (obj_type & PK_PUBKEY_OBJ) {
- cryptodebug("only searching for public keys");
- obj_class = CKO_PUBLIC_KEY;
- } else if (obj_type & PK_SECKEY_OBJ) {
- cryptodebug("only searching for secret keys");
- obj_class = CKO_SECRET_KEY;
- }
+ return (rv);
+}
- attrs[cur_attr].type = CKA_CLASS;
- attrs[cur_attr].pValue = &obj_class;
- attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS);
- cur_attr++;
- }
+
+KMF_RETURN
+get_pk12_password(KMF_CREDENTIAL *cred)
+{
+ KMF_RETURN rv = KMF_OK;
+ char prompt[1024];
/*
- * This can't happen now. When finding objects is enhanced in the
- * future. this could lead to buffer overruns.
+ * Get the password to use for the PK12 encryption.
*/
- if (cur_attr > num_attrs)
- cryptodebug("internal error: attr template overrun");
+ (void) strlcpy(prompt,
+ gettext("Enter password to use for "
+ "accessing the PKCS12 file: "),
+ sizeof (prompt));
- cryptodebug("calling C_FindObjectsInit");
- if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK)
- return (rv);
-
- /* Look for the object, checking if there are more than one. */
- cryptodebug("calling C_FindObjects");
- for (*count = 0; /* empty */; (*count)++) {
- if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) !=
- CKR_OK)
- break;
-
- /* No more found. */
- if (obj_count == 0)
- break;
+ if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
+ (ulong_t *)&cred->credlen) != CKR_OK) {
+ cred->cred = NULL;
+ cred->credlen = 0;
}
- cryptodebug("%d matching objects found", *count);
-
- cryptodebug("calling C_FindObjectsFinal");
- (void) C_FindObjectsFinal(sess);
return (rv);
}
-/*
- * Find the token object with the given label.
- */
-CK_RV
-find_objs(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label,
- CK_OBJECT_HANDLE_PTR *obj, CK_ULONG *count)
-{
- CK_RV rv = CKR_OK;
- CK_ATTRIBUTE attrs[4] = {
- { CKA_TOKEN, &pk_true, sizeof (pk_true) },
- { 0, NULL, 0 },
- { 0, NULL, 0 },
- { 0, NULL, 0 }
- };
- CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
- CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */
- CK_OBJECT_CLASS obj_class;
- CK_OBJECT_HANDLE tmp_obj;
- CK_ULONG obj_count = 0;
- int i;
-
- cryptodebug("inside find_obj");
-
- if ((rv = find_obj_count(sess, obj_type, label, count)) != CKR_OK)
- return (rv);
- if (*count == 0)
- return (CKR_OK);
+#define COUNTRY_PROMPT "Country Name (2 letter code) [US]:"
+#define STATE_PROMPT "State or Province Name (full name) [Some-State]:"
+#define LOCALITY_PROMPT "Locality Name (eg, city) []:"
+#define ORG_PROMPT "Organization Name (eg, company) []:"
+#define UNIT_PROMPT "Organizational Unit Name (eg, section) []:"
+#define NAME_PROMPT "Common Name (eg, YOUR name) []:"
+#define EMAIL_PROMPT "Email Address []:"
- if ((*obj = (CK_OBJECT_HANDLE_PTR) malloc((*count) *
- sizeof (CK_OBJECT_HANDLE))) == NULL) {
- cryptodebug("no memory for found object");
- return (CKR_HOST_MEMORY);
- }
+#define COUNTRY_DEFAULT "US"
+#define STATE_DEFAULT "Some-State"
+#define INVALID_INPUT "Invalid input; please re-enter ..."
- if (label) {
- cryptodebug("object label was specified");
- attrs[cur_attr].type = CKA_LABEL;
- attrs[cur_attr].pValue = label;
- attrs[cur_attr].ulValueLen = strlen((char *)label);
- cur_attr++;
- }
+#define SUBNAMESIZ 1024
+#define RDN_MIN 1
+#define RDN_MAX 64
+#define COUNTRYNAME_MIN 2
+#define COUNTRYNAME_MAX 2
- if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) {
- cryptodebug("only searching for private objects");
- attrs[cur_attr].type = CKA_PRIVATE;
- attrs[cur_attr].pValue = &pk_true;
- attrs[cur_attr].ulValueLen = sizeof (pk_true);
- cur_attr++;
- }
+static char *
+get_input_string(char *prompt, char *default_str, int min_len, int max_len)
+{
+ char buf[1024];
+ char *response = NULL;
+ char *ret = NULL;
+ int len;
- /*
- * If "certs and all keys" is not specified, but at least either
- * "certs" or some "keys" is specified, then go into this block.
- * If all certs and keys were specified, there's no point in
- * putting that fact in the attribute template -- leave that open,
- * and all certs and keys will be matched automatically.
- * In other words, only if at least one of 0x10,0x20,0x40,0x80
- * bits is off, go into this code block.
- *
- * NOTE: For now, only one of cert or key types is allowed.
- * This needs to change in the future.
- */
- if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) &&
- ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) {
- if (obj_type & PK_CERT_OBJ) {
- cryptodebug("only searching for certificates");
- obj_class = CKO_CERTIFICATE;
- } else if (obj_type & PK_PRIKEY_OBJ) {
- cryptodebug("only searching for private keys");
- obj_class = CKO_PRIVATE_KEY;
- } else if (obj_type & PK_PUBKEY_OBJ) {
- cryptodebug("only searching for public keys");
- obj_class = CKO_PUBLIC_KEY;
- } else if (obj_type & PK_SECKEY_OBJ) {
- cryptodebug("only searching for secret keys");
- obj_class = CKO_SECRET_KEY;
+ for (;;) {
+ (void) printf("\t%s", prompt);
+ (void) fflush(stdout);
+
+ response = fgets(buf, sizeof (buf), stdin);
+ if (response == NULL) {
+ if (default_str != NULL) {
+ ret = strdup(default_str);
+ }
+ break;
+ }
+
+ /* Skip any leading white space. */
+ while (isspace(*response))
+ response++;
+ if (*response == '\0') {
+ if (default_str != NULL) {
+ ret = strdup(default_str);
+ }
+ break;
+ }
+
+ len = strlen(response);
+ response[len-1] = '\0'; /* get rid of "LF" */
+ len--;
+ if (len >= min_len && len <= max_len) {
+ ret = strdup(response);
+ break;
}
- attrs[cur_attr].type = CKA_CLASS;
- attrs[cur_attr].pValue = &obj_class;
- attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS);
- cur_attr++;
+ (void) printf("%s\n", INVALID_INPUT);
+
}
- /*
- * This can't happen now. When finding objects is enhanced in the
- * future. this could lead to buffer overruns.
- */
- if (cur_attr > num_attrs)
- cryptodebug("internal error: attr template overrun");
+ return (ret);
+}
- cryptodebug("calling C_FindObjectsInit");
- if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK) {
- free(*obj);
- return (rv);
+int
+get_subname(char **result)
+{
+ char *country = NULL;
+ char *state = NULL;
+ char *locality = NULL;
+ char *org = NULL;
+ char *unit = NULL;
+ char *name = NULL;
+ char *email = NULL;
+ char *subname = NULL;
+
+ (void) printf("Entering following fields for subject (a DN) ...\n");
+ country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT,
+ COUNTRYNAME_MIN, COUNTRYNAME_MAX);
+ if (country == NULL)
+ return (-1);
+
+ state = get_input_string(STATE_PROMPT, STATE_DEFAULT,
+ RDN_MIN, RDN_MAX);
+ if (state == NULL) {
+ goto out;
}
- /*
- * Find all the matching objects. The loop goes 1 more beyond
- * the number of objects found to determine if any new objects
- * were created since the time the object count was done.
- */
- cryptodebug("calling C_FindObjects");
- for (i = 0; i < (*count) + 1; i++) {
- if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) !=
- CKR_OK)
- break;
+ locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX);
+ org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX);
+ unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX);
+ name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX);
+ email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX);
- /* No more found. */
- if (obj_count == 0)
- break;
+ /* Now create a subject name from the input strings */
+ if ((subname = malloc(SUBNAMESIZ)) == NULL)
+ goto out;
+
+ (void) memset(subname, 0, SUBNAMESIZ);
+ (void) strlcpy(subname, "C=", SUBNAMESIZ);
+ (void) strlcat(subname, country, SUBNAMESIZ);
+ (void) strlcat(subname, ", ", SUBNAMESIZ);
+ (void) strlcat(subname, "ST=", SUBNAMESIZ);
+ (void) strlcat(subname, state, SUBNAMESIZ);
- /*
- * Save the object in the list being created, as long as
- * we don't overrun the size of the list.
- */
- if (i < *count)
- (*obj)[i] = tmp_obj;
- else
- cryptodebug("number of objects changed since last count");
+ if (locality) {
+ (void) strlcat(subname, ", ", SUBNAMESIZ);
+ (void) strlcat(subname, "L=", SUBNAMESIZ);
+ (void) strlcat(subname, locality, SUBNAMESIZ);
}
- if (rv != CKR_OK) {
- free(*obj);
- } else {
- /*
- * There are three cases to handle: (1) fewer objects were
- * found than originally counted => change *count to the
- * smaller number; (2) the number of objects found matches
- * the number originally counted => do nothing; (3) more
- * objects found than originally counted => list passed
- * in is too small to contain the extra object(s), flag
- * that in the debug output but don't change number of
- * objects returned. The caller can double-check by
- * calling find_obj_count() after this function to make
- * sure the numbers match, if desired.
- */
- /* Case 1: Fewer objects. */
- if (i < *count) {
- cryptodebug("%d objects found, expected %d", i, *count);
- *count = i;
- /* Case 3: More objects. */
- } else if (i > *count) {
- cryptodebug("at least %d objects found, expected %d",
- i, *count);
- }
- /*
- * Case 2: Same number of objects.
- *
- * else if (i == *count)
- * ;
- */
+ if (org) {
+ (void) strlcat(subname, ", ", SUBNAMESIZ);
+ (void) strlcat(subname, "O=", SUBNAMESIZ);
+ (void) strlcat(subname, org, SUBNAMESIZ);
}
- cryptodebug("calling C_FindObjectsFinal");
- (void) C_FindObjectsFinal(sess);
- return (rv);
-}
+ if (unit) {
+ (void) strlcat(subname, ", ", SUBNAMESIZ);
+ (void) strlcat(subname, "OU=", SUBNAMESIZ);
+ (void) strlcat(subname, unit, SUBNAMESIZ);
+ }
-char *
-class_str(CK_OBJECT_CLASS class)
-{
- switch (class) {
- case CKO_DATA: return (gettext("data"));
- case CKO_CERTIFICATE: return (gettext("certificate"));
- case CKO_PUBLIC_KEY: return (gettext("public key"));
- case CKO_PRIVATE_KEY: return (gettext("private key"));
- case CKO_SECRET_KEY: return (gettext("secret key"));
- case CKO_DOMAIN_PARAMETERS: return (gettext("domain parameter"));
- default: return (gettext("unknown object"));
+ if (name) {
+ (void) strlcat(subname, ", ", SUBNAMESIZ);
+ (void) strlcat(subname, "CN=", SUBNAMESIZ);
+ (void) strlcat(subname, name, SUBNAMESIZ);
}
-}
-char *
-keytype_str(CK_KEY_TYPE keytype)
-{
- switch (keytype) {
- case CKK_RSA: return (gettext("RSA"));
- case CKK_DSA: return (gettext("DSA"));
- case CKK_DH: return (gettext("Diffie-Hellman"));
- case CKK_X9_42_DH: return (gettext("X9.42 Diffie-Hellman"));
- case CKK_GENERIC_SECRET: return (gettext("generic"));
- case CKK_RC2: return (gettext("RC2"));
- case CKK_RC4: return (gettext("RC4"));
- case CKK_DES: return (gettext("DES"));
- case CKK_DES2: return (gettext("Double-DES"));
- case CKK_DES3: return (gettext("Triple-DES"));
- case CKK_RC5: return (gettext("RC5"));
- case CKK_AES: return (gettext("AES"));
- default: return (gettext("typeless"));
+ if (email) {
+ (void) strlcat(subname, ", ", SUBNAMESIZ);
+ (void) strlcat(subname, "E=", SUBNAMESIZ);
+ (void) strlcat(subname, email, SUBNAMESIZ);
}
-}
-char *
-attr_str(CK_ATTRIBUTE_TYPE attrtype)
-{
- switch (attrtype) {
- case CKA_PRIVATE: return (gettext("private"));
- case CKA_LOCAL: return (gettext("local"));
- case CKA_SENSITIVE: return (gettext("sensitive"));
- case CKA_EXTRACTABLE: return (gettext("extractable"));
- case CKA_ENCRYPT: return (gettext("encrypt"));
- case CKA_DECRYPT: return (gettext("decrypt"));
- case CKA_WRAP: return (gettext("wrap"));
- case CKA_UNWRAP: return (gettext("unwrap"));
- case CKA_SIGN: return (gettext("sign"));
- case CKA_SIGN_RECOVER: return (gettext("sign-recover"));
- case CKA_VERIFY: return (gettext("verify"));
- case CKA_VERIFY_RECOVER: return (gettext("verify-recover"));
- case CKA_DERIVE: return (gettext("derive"));
- case CKA_ALWAYS_SENSITIVE: return (gettext("always sensitive"));
- case CKA_NEVER_EXTRACTABLE: return (gettext("never extractable"));
- default: return (gettext("unknown capability"));
+out:
+ if (country)
+ free(country);
+ if (state)
+ free(state);
+ if (locality)
+ free(locality);
+ if (org)
+ free(org);
+ if (unit)
+ free(unit);
+ if (name)
+ free(name);
+ if (email)
+ free(email);
+
+ if (subname == NULL)
+ return (-1);
+ else {
+ *result = subname;
+ return (0);
}
}
/*
- * Convert a byte string into a string of octets formatted like this:
- * oo oo oo oo oo ... oo
- * where each "oo" is an octet is space separated and in the form:
- * [0-f][0-f] if the octet is a non-printable character
- * <space><char> if the octet is a printable character
- *
- * Note: octets_sz must be 3 * str_sz + 1, or at least as long as "blank"
+ * Parse a string of KeyUsage values and convert
+ * them to the correct KU Bits.
+ * The field may be marked "critical" by prepending
+ * "critical:" to the list.
+ * EX: critical:digitialSignature,keyEncipherment
*/
-void
-octetify(CK_BYTE *str, CK_ULONG str_sz, char *octets, int octets_sz,
- boolean_t stop_on_nul, boolean_t do_ascii, int limit, char *indent,
- char *blank)
+KMF_RETURN
+verify_keyusage(char *kustr, uint16_t *kubits, int *critical)
{
- char *marker;
- int nc;
- int newline;
- int indent_len;
- boolean_t first = B_TRUE;
-
- cryptodebug("inside octetify");
-
- cryptodebug(stop_on_nul ? "stopping on first nul found" :
- "continuing to full length of buffer");
- cryptodebug(do_ascii ? "using ascii chars where printable" :
- "using only hex octets");
- cryptodebug("every %d characters indent with \"%s\"\n ", limit, indent);
- cryptodebug("return \"%s\" if buffer is null or empty", blank);
-
- /* If string is empty, write as much of the blank string and leave. */
- if (str_sz == 0) {
- (void) snprintf(octets, octets_sz, "%s", blank);
- return;
+ KMF_RETURN ret = KMF_OK;
+ uint16_t kuval;
+ char *k;
+
+ *kubits = 0;
+ if (kustr == NULL || !strlen(kustr))
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Check to see if this is critical */
+ if (!strncasecmp(kustr, "critical:", strlen("critical:"))) {
+ *critical = TRUE;
+ kustr += strlen("critical:");
+ } else {
+ *critical = FALSE;
}
- /* If only limit or indent is set, pick default for the other. */
- if (limit > 0 && indent == NULL)
- indent = "\n";
- if (indent != NULL && limit == 0)
- limit = 60;
- indent_len = strlen(indent);
-
- for (marker = octets, newline = 0, first = B_TRUE;
- (stop_on_nul && *str != '\0') ||
- (!stop_on_nul && str_sz > 0 && octets_sz > 0);
- str++, str_sz--, marker += nc, octets_sz -= nc) {
- if (!first) {
- if (limit > 0 && ((marker - octets) / limit) >
- newline) {
- nc = snprintf(marker, indent_len, "%s", indent);
- newline++;
- continue;
- }
- nc = sprintf(marker,
- ((do_ascii && isprint(*str) && !isspace(*str)) ?
- "%s%c" : "%s%02x"), (do_ascii ? " " : ":"), *str);
- } else {
- nc = sprintf(marker,
- ((do_ascii && isprint(*str) && !isspace(*str)) ?
- "%c" : "%02x"), *str);
- first = B_FALSE;
+ k = strtok(kustr, ",");
+ while (k != NULL) {
+ kuval = KMF_StringToKeyUsage(k);
+ if (kuval == 0) {
+ *kubits = 0;
+ return (KMF_ERR_BAD_PARAMETER);
}
+ *kubits |= kuval;
+ k = strtok(NULL, ",");
}
- *marker = '\0';
-}
-/*
- * Copies a biginteger_t to a template attribute.
- * Should be a macro instead of a function.
- */
-void
-copy_bigint_to_attr(biginteger_t big, CK_ATTRIBUTE_PTR attr)
-{
- attr->pValue = big.big_value;
- attr->ulValueLen = big.big_value_len;
+ return (ret);
}
/*
- * Copies a string and its length to a template attribute.
- * Should be a macro instead of a function.
+ * Verify the alternate subject label is real or invalid.
+ *
+ * The field may be marked "critical" by prepending
+ * "critical:" to the list.
+ * EX: "critical:IP=1.2.3.4"
*/
-void
-copy_string_to_attr(CK_BYTE *buf, CK_ULONG buflen, CK_ATTRIBUTE_PTR attr)
+KMF_RETURN
+verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical)
{
- attr->pValue = buf;
- attr->ulValueLen = buflen;
-}
+ char *p;
+ KMF_RETURN rv = KMF_OK;
-/*
- * Copies a template attribute to a biginteger_t.
- * Should be a macro instead of a function.
- */
-void
-copy_attr_to_bigint(CK_ATTRIBUTE_PTR attr, biginteger_t *big)
-{
- big->big_value = attr->pValue;
- big->big_value_len = attr->ulValueLen;
-}
+ /* Check to see if this is critical */
+ if (!strncasecmp(arg, "critical:", strlen("critical:"))) {
+ *critical = TRUE;
+ arg += strlen("critical:");
+ } else {
+ *critical = FALSE;
+ }
-/*
- * Copies a template attribute to a string and its length.
- * Should be a macro instead of a function.
- */
-void
-copy_attr_to_string(CK_ATTRIBUTE_PTR attr, CK_BYTE **buf, CK_ULONG *buflen)
-{
- *buf = attr->pValue;
- *buflen = attr->ulValueLen;
-}
+ /* Make sure there is an "=" sign */
+ p = strchr(arg, '=');
+ if (p == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
-/*
- * Copies a template attribute to a date and its length.
- * Should be a macro instead of a function.
- */
-void
-copy_attr_to_date(CK_ATTRIBUTE_PTR attr, CK_DATE **buf, CK_ULONG *buflen)
-{
- *buf = (CK_DATE *)attr->pValue;
- *buflen = attr->ulValueLen;
+ p[0] = '\0';
+
+ if (strcmp(arg, "IP") == 0)
+ *type = GENNAME_IPADDRESS;
+ else if (strcmp(arg, "DNS") == 0)
+ *type = GENNAME_DNSNAME;
+ else if (strcmp(arg, "EMAIL") == 0)
+ *type = GENNAME_RFC822NAME;
+ else if (strcmp(arg, "URI") == 0)
+ *type = GENNAME_URI;
+ else if (strcmp(arg, "DN") == 0)
+ *type = GENNAME_DIRECTORYNAME;
+ else if (strcmp(arg, "RID") == 0)
+ *type = GENNAME_REGISTEREDID;
+ else
+ rv = KMF_ERR_BAD_PARAMETER;
+
+ p[0] = '=';
+
+ return (rv);
}
-/*
- * Breaks out the getopt-style option string into a structure that can be
- * traversed later for calls to getopt_av(). Option string is NOT altered,
- * but the struct fields point to locations within option string.
- */
-static int
-populate_opts(char *optstring)
+int
+get_token_password(KMF_KEYSTORE_TYPE kstype,
+ char *token_spec, KMF_CREDENTIAL *cred)
{
- int i;
- av_opts *temp;
- char *marker;
-
- if (optstring == NULL || *optstring == '\0')
- return (0);
+ char prompt[1024];
+ char *p = NULL;
+ if (kstype == KMF_KEYSTORE_PK11TOKEN) {
+ p = strchr(token_spec, ':');
+ if (p != NULL)
+ *p = 0;
+ }
/*
- * This tries to imitate getopt(3c) Each option must conform to:
- * <short name char> [ ':' ] [ '(' <long name string> ')' ]
- * If long name is missing, the short name is used for long name.
+ * Login to the token first.
*/
- for (i = 0; *optstring != '\0'; i++) {
- if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
- realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
- free(opts_av);
- opts_av = NULL;
- return (0);
- } else
- opts_av = (av_opts *)temp;
-
- marker = optstring; /* may need optstring later */
-
- opts_av[i].shortnm = *marker++; /* set short name */
-
- if (*marker == ':') { /* check for opt arg */
- marker++;
- opts_av[i].has_arg = B_TRUE;
- }
+ (void) snprintf(prompt, sizeof (prompt),
+ gettext(DEFAULT_TOKEN_PROMPT),
+ token_spec);
- if (*marker == '(') { /* check and set long name */
- marker++;
- opts_av[i].longnm = marker;
- opts_av[i].longnm_len = strcspn(marker, ")");
- optstring = marker + opts_av[i].longnm_len + 1;
- } else {
- /* use short name option character */
- opts_av[i].longnm = optstring;
- opts_av[i].longnm_len = 1;
- optstring = marker;
- }
+ if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
+ (ulong_t *)&cred->credlen) != CKR_OK) {
+ cred->cred = NULL;
+ cred->credlen = 0;
}
- return (i);
+ if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL)
+ *p = ':';
+ return (KMF_OK);
}
-/*
- * getopt_av() is very similar to getopt(3c) in that the takes an option
- * string, compares command line arguments for matches, and returns a single
- * letter option when a match is found. However, getopt_av() differs from
- * getopt(3c) by requiring that only longname options and values be found
- * on the command line and all leading dashes are omitted. In other words,
- * it tries to enforce only longname "option=value" arguments on the command
- * line. Boolean options are not allowed either.
- */
-int
-getopt_av(int argc, char * const *argv, const char *optstring)
+KMF_RETURN
+verify_file(char *filename)
{
- int i;
- int len;
+ KMF_RETURN ret = KMF_OK;
+ int fd;
- if (optind_av >= argc)
- return (EOF);
+ /*
+ * Attempt to open with the EXCL flag so that if
+ * it already exists, the open will fail. It will
+ * also fail if the file cannot be created due to
+ * permissions on the parent directory, or if the
+ * parent directory itself does not exist.
+ */
+ fd = open(filename, O_CREAT | O_EXCL, 0600);
+ if (fd == -1)
+ return (KMF_ERR_OPEN_FILE);
- /* First time or when optstring changes from previous one */
- if (_save_optstr != optstring) {
- if (opts_av != NULL)
- free(opts_av);
- opts_av = NULL;
- _save_optstr = optstring;
- _save_numopts = populate_opts((char *)optstring);
- }
+ /* If we were able to create it, delete it. */
+ (void) close(fd);
+ (void) unlink(filename);
- for (i = 0; i < _save_numopts; i++) {
- if (strcmp(argv[optind_av], "--") == 0) {
- optind_av++;
- break;
- }
+ return (ret);
+}
- len = strcspn(argv[optind_av], "=");
+void
+display_error(void *handle, KMF_RETURN errcode, char *prefix)
+{
+ KMF_RETURN rv1, rv2;
+ char *plugin_errmsg = NULL;
+ char *kmf_errmsg = NULL;
- if (len == opts_av[i].longnm_len && strncmp(argv[optind_av],
- opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
- /* matched */
- if (!opts_av[i].has_arg) {
- optind_av++;
- return (opts_av[i].shortnm);
- }
+ rv1 = KMF_GetPluginErrorString(handle, &plugin_errmsg);
+ rv2 = KMF_GetKMFErrorString(errcode, &kmf_errmsg);
- /* needs optarg */
- if (argv[optind_av][len] == '=') {
- optarg_av = &(argv[optind_av][len+1]);
- optind_av++;
- return (opts_av[i].shortnm);
- }
+ cryptoerror(LOG_STDERR, "%s:", prefix);
+ if (rv1 == KMF_OK && plugin_errmsg) {
+ cryptoerror(LOG_STDERR,
+ gettext("keystore error: %s"),
+ plugin_errmsg);
+ KMF_FreeString(plugin_errmsg);
+ }
- optarg_av = NULL;
- optind_av++;
- return ((int)'?');
- }
+ if (rv2 == KMF_OK && kmf_errmsg) {
+ cryptoerror(LOG_STDERR,
+ gettext("libkmf error: %s"),
+ kmf_errmsg);
+ KMF_FreeString(kmf_errmsg);
}
- return (EOF);
+ if (rv1 != KMF_OK && rv2 != KMF_OK)
+ cryptoerror(LOG_STDERR, gettext("<unknown error>\n"));
+
}
diff --git a/usr/src/cmd/cmd-crypto/pktool/common.h b/usr/src/cmd/cmd-crypto/pktool/common.h
index 30e2890b4b..e15cee3282 100644
--- a/usr/src/cmd/cmd-crypto/pktool/common.h
+++ b/usr/src/cmd/cmd-crypto/pktool/common.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -39,14 +38,14 @@ extern "C" {
#endif
#include <cryptoutil.h>
-#include <biginteger.h>
/* I18N helpers. */
#include <libintl.h>
#include <locale.h>
+#include <errno.h>
+#include <kmfapi.h>
/* Defines used throughout */
-#define FULL_NAME_LEN 91 /* See full_token_name() for this number. */
/* Error codes */
#define PK_ERR_NONE 0
@@ -55,6 +54,7 @@ extern "C" {
#define PK_ERR_PK11 3
#define PK_ERR_SYSTEM 4
#define PK_ERR_OPENSSL 5
+#define PK_ERR_NSS 6
/* Types of objects for searches. */
#define PK_PRIVATE_OBJ 0x0001
@@ -62,11 +62,18 @@ extern "C" {
#define PK_CERT_OBJ 0x0010
#define PK_PRIKEY_OBJ 0x0020
#define PK_PUBKEY_OBJ 0x0040
-#define PK_SECKEY_OBJ 0x0080
+#define PK_SYMKEY_OBJ 0x0080
+#define PK_CRL_OBJ 0x0100
-#define PK_KEY_OBJ (PK_PRIKEY_OBJ|PK_PUBKEY_OBJ|PK_SECKEY_OBJ)
-#define PK_ALL_OBJ (PK_PRIVATE_OBJ|PK_PUBLIC_OBJ|\
- PK_CERT_OBJ|PK_KEY_OBJ)
+#define PK_KEY_OBJ (PK_PRIKEY_OBJ | PK_PUBKEY_OBJ | PK_SYMKEY_OBJ)
+#define PK_ALL_OBJ (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ |\
+ PK_CERT_OBJ| PK_CRL_OBJ | PK_KEY_OBJ)
+
+#define PK_DEFAULT_KEYTYPE "rsa"
+#define PK_DEFAULT_KEYLENGTH 1024
+#define PK_DEFAULT_DIRECTORY "."
+#define PK_DEFAULT_SERIALNUM 1
+#define PK_DEFAULT_PK11TOKEN SOFT_TOKEN_LABEL
/* Constants for attribute templates. */
extern CK_BBOOL pk_false;
@@ -77,18 +84,12 @@ extern CK_BBOOL pk_true;
extern CK_RV init_pk11(void);
extern void final_pk11(CK_SESSION_HANDLE sess);
-extern CK_RV open_sess(CK_SLOT_ID slot_id, CK_FLAGS sess_flags,
- CK_SESSION_HANDLE_PTR sess);
-extern void close_sess(CK_SESSION_HANDLE sess);
-
extern CK_RV login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin,
CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess);
-extern void logout_token(CK_SESSION_HANDLE sess);
extern CK_RV quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags,
CK_UTF8CHAR_PTR pin, CK_ULONG pinlen,
CK_SESSION_HANDLE_PTR sess);
-extern void quick_finish(CK_SESSION_HANDLE sess);
extern CK_RV get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin,
CK_ULONG *pinlen);
@@ -96,40 +97,35 @@ extern boolean_t yesno(char *prompt, char *invalid, boolean_t dflt);
extern CK_RV get_token_slots(CK_SLOT_ID_PTR *slot_list,
CK_ULONG *slot_count);
-extern CK_RV find_token_slot(char *token_name, char *manuf_id,
- char *serial_no, CK_SLOT_ID *slot_id, CK_FLAGS *pin_state);
-
-extern CK_RV find_obj_count(CK_SESSION_HANDLE sess, int obj_type,
- CK_BYTE *label, CK_ULONG *count);
-extern CK_RV find_objs(CK_SESSION_HANDLE sess, int obj_type,
- CK_BYTE *label, CK_OBJECT_HANDLE_PTR *obj, CK_ULONG *count);
-
-extern int parse_token_spec(char *spec, char **label, char **manuf,
- char **buf);
-extern void full_token_name(char *token, char *manuf, char *serial,
- char *buf);
-
-extern char *class_str(CK_OBJECT_CLASS class);
-extern char *keytype_str(CK_KEY_TYPE keytype);
-extern char *attr_str(CK_ATTRIBUTE_TYPE attrtype);
-
-extern void octetify(CK_BYTE *str, CK_ULONG str_sz, char *oct, int oct_sz,
- boolean_t stop_on_nul, boolean_t do_ascii, int limit,
- char *indent, char *blank);
-
-extern void copy_bigint_to_attr(biginteger_t big, CK_ATTRIBUTE_PTR attr);
-extern void copy_string_to_attr(CK_BYTE *buf, CK_ULONG buflen,
- CK_ATTRIBUTE_PTR attr);
-extern void copy_attr_to_bigint(CK_ATTRIBUTE_PTR attr, biginteger_t *big);
-extern void copy_attr_to_string(CK_ATTRIBUTE_PTR attr, CK_BYTE **buf,
- CK_ULONG *buflen);
-extern void copy_attr_to_date(CK_ATTRIBUTE_PTR attr, CK_DATE **buf,
- CK_ULONG *buflen);
+
+extern int get_subname(char **);
extern int getopt_av(int argc, char * const argv[], const char *optstring);
extern char *optarg_av;
extern int optind_av;
+int OT2Int(char *);
+int PK2Int(char *);
+KMF_KEYSTORE_TYPE KS2Int(char *);
+int Str2KeyType(char *, KMF_KEY_ALG *, KMF_ALGORITHM_INDEX *);
+int Str2SymKeyType(char *, KMF_KEY_ALG *);
+int Str2Lifetime(char *, uint32_t *);
+KMF_RETURN select_token(void *, char *, int);
+KMF_RETURN configure_nss(void *, char *, char *);
+
+KMF_ENCODE_FORMAT Str2Format(char *);
+KMF_RETURN get_pk12_password(KMF_CREDENTIAL *);
+KMF_RETURN hexstring2bytes(uchar_t *, uchar_t **, size_t *);
+KMF_RETURN verify_altname(char *arg, KMF_GENERALNAMECHOICES *, int *);
+KMF_RETURN verify_keyusage(char *arg, uint16_t *, int *);
+KMF_RETURN verify_file(char *);
+int get_token_password(KMF_KEYSTORE_TYPE, char *, KMF_CREDENTIAL *);
+void display_error(void *, KMF_RETURN, char *);
+#define DEFAULT_NSS_TOKEN "internal"
+#define DEFAULT_TOKEN_PROMPT "Enter pin for %s: "
+
+#define EMPTYSTRING(s) (s == NULL || !strlen((char *)s))
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/cmd/cmd-crypto/pktool/delete.c b/usr/src/cmd/cmd-crypto/pktool/delete.c
index ea550974c5..57d484cbe2 100644
--- a/usr/src/cmd/cmd-crypto/pktool/delete.c
+++ b/usr/src/cmd/cmd-crypto/pktool/delete.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -37,6 +36,382 @@
#include <cryptoutil.h>
#include <security/cryptoki.h>
#include "common.h"
+#include <kmfapi.h>
+
+static KMF_RETURN
+pk_destroy_keys(void *handle, KMF_KEY_HANDLE *keys,
+ KMF_FINDKEY_PARAMS *fkparams, uint32_t numkeys)
+{
+ int i;
+ KMF_RETURN rv = KMF_OK;
+ KMF_DELETEKEY_PARAMS dkparams;
+
+ (void) memset(&dkparams, 0, sizeof (dkparams));
+ dkparams.kstype = fkparams->kstype;
+
+ switch (fkparams->kstype) {
+ case KMF_KEYSTORE_NSS:
+ dkparams.nssparms = fkparams->nssparms;
+ dkparams.cred = fkparams->cred;
+ break;
+ case KMF_KEYSTORE_OPENSSL:
+ break;
+ case KMF_KEYSTORE_PK11TOKEN:
+ dkparams.cred = fkparams->cred;
+ break;
+ default:
+ return (PK_ERR_USAGE);
+ }
+
+ for (i = 0; rv == KMF_OK && i < numkeys; i++) {
+ rv = KMF_DeleteKeyFromKeystore(handle, &dkparams, &keys[i]);
+ }
+ return (rv);
+}
+
+static KMF_RETURN
+pk_delete_keys(KMF_HANDLE_T kmfhandle, KMF_FINDKEY_PARAMS *parms, char *desc,
+ int *keysdeleted)
+{
+ KMF_RETURN rv = KMF_OK;
+ uint32_t numkeys = 0;
+
+ *keysdeleted = 0;
+ numkeys = 0;
+ rv = KMF_FindKey(kmfhandle, parms, NULL, &numkeys);
+ if (rv == KMF_OK && numkeys > 0) {
+ KMF_KEY_HANDLE *keys = NULL;
+ char prompt[1024];
+
+ (void) snprintf(prompt, sizeof (prompt),
+ gettext("%d %s key(s) found, do you want "
+ "to delete them (y/N) ?"), numkeys,
+ (desc != NULL ? desc : ""));
+
+ if (!yesno(prompt,
+ gettext("Respond with yes or no.\n"),
+ B_FALSE)) {
+ return (KMF_OK);
+ }
+ keys = (KMF_KEY_HANDLE *)malloc(numkeys *
+ sizeof (KMF_KEY_HANDLE));
+ if (keys == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(keys, 0, numkeys *
+ sizeof (KMF_KEY_HANDLE));
+
+ rv = KMF_FindKey(kmfhandle, parms, keys, &numkeys);
+ if (rv == KMF_OK) {
+ rv = pk_destroy_keys(kmfhandle, keys,
+ parms, numkeys);
+ }
+
+ free(keys);
+ }
+
+ if (rv == KMF_ERR_KEY_NOT_FOUND) {
+ rv = KMF_OK;
+ }
+
+ *keysdeleted = numkeys;
+ return (rv);
+}
+
+static KMF_RETURN
+pk_delete_certs(KMF_HANDLE_T kmfhandle, KMF_FINDCERT_PARAMS *fcparms,
+ KMF_DELETECERT_PARAMS *dcparms)
+{
+ KMF_RETURN rv = KMF_OK;
+ uint32_t numcerts = 0;
+
+ rv = KMF_FindCert(kmfhandle, fcparms, NULL, &numcerts);
+ if (rv == KMF_OK && numcerts > 0) {
+ char prompt[1024];
+ (void) snprintf(prompt, sizeof (prompt),
+ gettext("%d certificate(s) found, do you want "
+ "to delete them (y/N) ?"), numcerts);
+
+ if (!yesno(prompt,
+ gettext("Respond with yes or no.\n"),
+ B_FALSE)) {
+ return (KMF_OK);
+ }
+
+ rv = KMF_DeleteCertFromKeystore(kmfhandle, dcparms);
+
+ } else if (rv == KMF_ERR_CERT_NOT_FOUND) {
+ rv = KMF_OK;
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+delete_nss_keys(KMF_HANDLE_T kmfhandle, char *dir, char *prefix,
+ char *token, int oclass, char *objlabel,
+ KMF_CREDENTIAL *tokencred)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_FINDKEY_PARAMS parms;
+ char *keytype = NULL;
+ int nk, numkeys = 0;
+
+ rv = configure_nss(kmfhandle, dir, prefix);
+ if (rv != KMF_OK)
+ return (rv);
+
+ (void) memset(&parms, 0, sizeof (parms));
+ parms.kstype = KMF_KEYSTORE_NSS;
+ parms.findLabel = objlabel;
+ parms.cred = *tokencred;
+ parms.nssparms.slotlabel = token;
+
+ if (oclass & PK_PRIKEY_OBJ) {
+ parms.keyclass = KMF_ASYM_PRI;
+ keytype = "private";
+ rv = pk_delete_keys(kmfhandle, &parms, keytype, &nk);
+ numkeys += nk;
+ }
+ if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) {
+ parms.keyclass = KMF_SYMMETRIC;
+ keytype = "symmetric";
+ rv = pk_delete_keys(kmfhandle, &parms, keytype, &nk);
+ numkeys += nk;
+ }
+ if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) {
+ parms.keyclass = KMF_ASYM_PUB;
+ keytype = "public";
+ rv = pk_delete_keys(kmfhandle, &parms, keytype, &nk);
+ numkeys += nk;
+ }
+ if (rv == KMF_OK && numkeys == 0)
+ rv = KMF_ERR_KEY_NOT_FOUND;
+
+ return (rv);
+}
+
+
+static KMF_RETURN
+delete_nss_certs(KMF_HANDLE_T kmfhandle,
+ char *dir, char *prefix,
+ char *token, char *objlabel,
+ KMF_BIGINT *serno, char *issuer, char *subject,
+ KMF_CERT_VALIDITY find_criteria_flag)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_DELETECERT_PARAMS dcparms;
+ KMF_FINDCERT_PARAMS fcargs;
+
+ rv = configure_nss(kmfhandle, dir, prefix);
+ if (rv != KMF_OK)
+ return (rv);
+
+ (void) memset(&dcparms, 0, sizeof (dcparms));
+ dcparms.kstype = KMF_KEYSTORE_NSS;
+ dcparms.certLabel = objlabel;
+ dcparms.issuer = issuer;
+ dcparms.subject = subject;
+ dcparms.serial = serno;
+ dcparms.find_cert_validity = find_criteria_flag;
+ dcparms.nssparms.slotlabel = token;
+
+ (void) memset(&fcargs, 0, sizeof (fcargs));
+ fcargs.kstype = KMF_KEYSTORE_NSS;
+ fcargs.certLabel = objlabel;
+ fcargs.issuer = issuer;
+ fcargs.subject = subject;
+ fcargs.serial = serno;
+ fcargs.find_cert_validity = find_criteria_flag;
+ fcargs.nssparms.slotlabel = token;
+
+ rv = pk_delete_certs(kmfhandle, &fcargs, &dcparms);
+
+ return (rv);
+}
+
+static KMF_RETURN
+delete_nss_crl(void *kmfhandle,
+ char *dir, char *prefix, char *token,
+ char *issuernickname, char *subject)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_DELETECRL_PARAMS dcrlparms;
+
+ rv = configure_nss(kmfhandle, dir, prefix);
+ if (rv != KMF_OK)
+ return (rv);
+
+ (void) memset(&dcrlparms, 0, sizeof (dcrlparms));
+
+ dcrlparms.kstype = KMF_KEYSTORE_NSS;
+ dcrlparms.nssparms.slotlabel = token;
+ dcrlparms.nssparms.crl_issuerName = issuernickname;
+ dcrlparms.nssparms.crl_subjName = subject;
+
+ rv = KMF_DeleteCRL(kmfhandle, &dcrlparms);
+
+ return (rv);
+}
+
+static KMF_RETURN
+delete_pk11_keys(KMF_HANDLE_T kmfhandle,
+ char *token, int oclass, char *objlabel,
+ KMF_CREDENTIAL *tokencred)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_FINDKEY_PARAMS parms;
+ int nk, numkeys = 0;
+
+ /*
+ * Symmetric keys and RSA/DSA private keys are always
+ * created with the "CKA_PRIVATE" field == TRUE, so
+ * make sure we search for them with it also set.
+ */
+ if (oclass & (PK_SYMKEY_OBJ | PK_PRIKEY_OBJ))
+ oclass |= PK_PRIVATE_OBJ;
+
+ rv = select_token(kmfhandle, token, FALSE);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ (void) memset(&parms, 0, sizeof (parms));
+ parms.kstype = KMF_KEYSTORE_PK11TOKEN;
+ parms.findLabel = (char *)objlabel;
+ parms.keytype = 0;
+ parms.pkcs11parms.private = ((oclass & PK_PRIVATE_OBJ) > 0);
+ parms.cred.cred = tokencred->cred;
+ parms.cred.credlen = tokencred->credlen;
+
+ if (oclass & PK_PRIKEY_OBJ) {
+ parms.keyclass = KMF_ASYM_PRI;
+ rv = pk_delete_keys(kmfhandle, &parms, "private", &nk);
+ numkeys += nk;
+ }
+
+ if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) {
+ parms.keyclass = KMF_SYMMETRIC;
+ rv = pk_delete_keys(kmfhandle, &parms, "symmetric", &nk);
+ numkeys += nk;
+ }
+
+ if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) {
+ parms.keyclass = KMF_ASYM_PUB;
+ rv = pk_delete_keys(kmfhandle, &parms, "public", &nk);
+ numkeys += nk;
+ }
+ if (rv == KMF_OK && numkeys == 0)
+ rv = KMF_ERR_KEY_NOT_FOUND;
+
+ return (rv);
+}
+
+static KMF_RETURN
+delete_pk11_certs(KMF_HANDLE_T kmfhandle,
+ char *token, char *objlabel,
+ KMF_BIGINT *serno, char *issuer, char *subject,
+ KMF_CERT_VALIDITY find_criteria_flag)
+{
+ KMF_RETURN kmfrv;
+ KMF_DELETECERT_PARAMS dparms;
+ KMF_FINDCERT_PARAMS fcargs;
+
+ kmfrv = select_token(kmfhandle, token, FALSE);
+
+ if (kmfrv != KMF_OK) {
+ return (kmfrv);
+ }
+
+ (void) memset(&dparms, 0, sizeof (dparms));
+ dparms.kstype = KMF_KEYSTORE_PK11TOKEN;
+ dparms.certLabel = objlabel;
+ dparms.issuer = issuer;
+ dparms.subject = subject;
+ dparms.serial = serno;
+ dparms.find_cert_validity = find_criteria_flag;
+
+ fcargs = dparms;
+ kmfrv = pk_delete_certs(kmfhandle, &fcargs, &dparms);
+
+ return (kmfrv);
+}
+
+static KMF_RETURN
+delete_file_certs(KMF_HANDLE_T kmfhandle,
+ char *dir, char *filename, KMF_BIGINT *serial, char *issuer,
+ char *subject, KMF_CERT_VALIDITY find_criteria_flag)
+{
+ KMF_RETURN rv;
+ KMF_DELETECERT_PARAMS dparms;
+ KMF_FINDCERT_PARAMS fcargs;
+
+ (void *)memset(&dparms, 0, sizeof (dparms));
+ (void *)memset(&fcargs, 0, sizeof (fcargs));
+ fcargs.kstype = KMF_KEYSTORE_OPENSSL;
+ fcargs.certLabel = NULL;
+ fcargs.issuer = issuer;
+ fcargs.subject = subject;
+ fcargs.serial = serial;
+ fcargs.sslparms.dirpath = dir;
+ fcargs.sslparms.certfile = filename;
+ fcargs.find_cert_validity = find_criteria_flag;
+
+ /* For now, delete parameters and find parameters are the same */
+ dparms = fcargs;
+
+ rv = pk_delete_certs(kmfhandle, &fcargs, &dparms);
+
+ return (rv);
+}
+
+static KMF_RETURN
+delete_file_keys(KMF_HANDLE_T kmfhandle, int oclass,
+ char *dir, char *infile)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_FINDKEY_PARAMS parms;
+ char *keytype = "";
+ int nk, numkeys = 0;
+
+ (void) memset(&parms, 0, sizeof (parms));
+ parms.kstype = KMF_KEYSTORE_OPENSSL;
+ parms.sslparms.dirpath = dir;
+ parms.sslparms.keyfile = infile;
+
+ if (oclass & (PK_PUBKEY_OBJ | PK_PRIKEY_OBJ)) {
+ parms.keyclass = KMF_ASYM_PRI;
+ keytype = "Asymmetric";
+ rv = pk_delete_keys(kmfhandle, &parms, keytype, &nk);
+ numkeys += nk;
+ }
+ if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) {
+ parms.keyclass = KMF_SYMMETRIC;
+ keytype = "symmetric";
+ rv = pk_delete_keys(kmfhandle, &parms, keytype, &nk);
+ numkeys += nk;
+ }
+ if (rv == KMF_OK && numkeys == 0)
+ rv = KMF_ERR_KEY_NOT_FOUND;
+
+ return (rv);
+}
+
+static KMF_RETURN
+delete_file_crl(void *kmfhandle, char *dir, char *filename)
+{
+ KMF_RETURN rv;
+ KMF_DELETECRL_PARAMS dcrlparms;
+
+ (void) memset(&dcrlparms, 0, sizeof (dcrlparms));
+
+ dcrlparms.kstype = KMF_KEYSTORE_OPENSSL;
+ dcrlparms.sslparms.dirpath = dir;
+ dcrlparms.sslparms.crlfile = filename;
+
+ rv = KMF_DeleteCRL(kmfhandle, &dcrlparms);
+
+ return (rv);
+}
/*
* Delete token objects.
@@ -48,31 +423,34 @@ pk_delete(int argc, char *argv[])
extern int optind_av;
extern char *optarg_av;
char *token_spec = NULL;
- char *token_name = NULL;
- char *manuf_id = NULL;
- char *serial_no = NULL;
- char *type_spec = NULL;
- char full_name[FULL_NAME_LEN];
- boolean_t public_objs = B_FALSE;
- boolean_t private_objs = B_FALSE;
- CK_BYTE *object_label = NULL;
- int obj_type = 0x00;
- CK_SLOT_ID slot_id;
- CK_FLAGS pin_state;
- CK_UTF8CHAR_PTR pin = NULL;
- CK_ULONG pinlen = 0;
- CK_SESSION_HANDLE sess;
- CK_OBJECT_HANDLE *objs;
- CK_ULONG num_objs;
- CK_ATTRIBUTE label = { CKA_LABEL, NULL, 0 };
- CK_RV rv = CKR_OK;
- int i;
-
- cryptodebug("inside pk_delete");
+ char *subject = NULL;
+ char *issuer = NULL;
+ char *dir = NULL;
+ char *prefix = NULL;
+ char *infile = NULL;
+ char *object_label = NULL;
+ char *serstr = NULL;
+
+ int oclass = 0;
+ KMF_BIGINT serial = { NULL, 0 };
+ KMF_HANDLE_T kmfhandle = NULL;
+ KMF_KEYSTORE_TYPE kstype = 0;
+ KMF_RETURN kmfrv;
+ int rv = 0;
+ char *find_criteria = NULL;
+ KMF_CERT_VALIDITY find_criteria_flag = KMF_ALL_CERTS;
+ KMF_CREDENTIAL tokencred = {NULL, 0};
/* Parse command line options. Do NOT i18n/l10n. */
while ((opt = getopt_av(argc, argv,
- "T:(token)y:(objtype)l:(label)")) != EOF) {
+ "T:(token)y:(objtype)l:(label)"
+ "k:(keystore)s:(subject)n:(nickname)"
+ "d:(dir)p:(prefix)S:(serial)i:(issuer)"
+ "c:(criteria)"
+ "f:(infile)")) != EOF) {
+
+ if (EMPTYSTRING(optarg_av))
+ return (PK_ERR_USAGE);
switch (opt) {
case 'T': /* token specifier */
if (token_spec)
@@ -80,14 +458,52 @@ pk_delete(int argc, char *argv[])
token_spec = optarg_av;
break;
case 'y': /* object type: public, private, both */
- if (type_spec)
+ if (oclass)
+ return (PK_ERR_USAGE);
+ oclass = OT2Int(optarg_av);
+ if (oclass == -1)
return (PK_ERR_USAGE);
- type_spec = optarg_av;
break;
case 'l': /* objects with specific label */
+ case 'n':
if (object_label)
return (PK_ERR_USAGE);
- object_label = (CK_BYTE *)optarg_av;
+ object_label = (char *)optarg_av;
+ break;
+ case 'k':
+ kstype = KS2Int(optarg_av);
+ if (kstype == 0)
+ return (PK_ERR_USAGE);
+ break;
+ case 's':
+ subject = optarg_av;
+ break;
+ case 'i':
+ issuer = optarg_av;
+ break;
+ case 'd':
+ dir = optarg_av;
+ break;
+ case 'p':
+ prefix = optarg_av;
+ break;
+ case 'S':
+ serstr = optarg_av;
+ break;
+ case 'f':
+ infile = optarg_av;
+ break;
+ case 'c':
+ find_criteria = optarg_av;
+ if (!strcasecmp(find_criteria, "valid"))
+ find_criteria_flag =
+ KMF_NONEXPIRED_CERTS;
+ else if (!strcasecmp(find_criteria, "expired"))
+ find_criteria_flag = KMF_EXPIRED_CERTS;
+ else if (!strcasecmp(find_criteria, "both"))
+ find_criteria_flag = KMF_ALL_CERTS;
+ else
+ return (PK_ERR_USAGE);
break;
default:
return (PK_ERR_USAGE);
@@ -95,55 +511,23 @@ pk_delete(int argc, char *argv[])
}
}
- /* If no token is specified, default is to use softtoken. */
- if (token_spec == NULL) {
- token_name = SOFT_TOKEN_LABEL;
- manuf_id = SOFT_MANUFACTURER_ID;
- serial_no = SOFT_TOKEN_SERIAL;
- } else {
- /*
- * Parse token specifier into token_name, manuf_id, serial_no.
- * Token_name is required; manuf_id and serial_no are optional.
- */
- if (parse_token_spec(token_spec, &token_name, &manuf_id,
- &serial_no) < 0)
- return (PK_ERR_USAGE);
- }
+ /* Assume keystore = PKCS#11 if not specified */
+ if (kstype == 0)
+ kstype = KMF_KEYSTORE_PK11TOKEN;
- /* If no object type specified, default is public objects. */
- if (!type_spec) {
- public_objs = B_TRUE;
- } else {
- /*
- * Otherwise, the object type must be "public", "private",
- * or "both".
- */
- if (strcmp(type_spec, "private") == 0) {
- private_objs = B_TRUE;
- } else if (strcmp(type_spec, "public") == 0) {
- public_objs = B_TRUE;
- } else if (strcmp(type_spec, "both") == 0) {
- private_objs = B_TRUE;
- public_objs = B_TRUE;
- } else
- return (PK_ERR_USAGE);
- }
-
- if (private_objs)
- obj_type |= PK_PRIVATE_OBJ;
- if (public_objs)
- obj_type |= PK_PUBLIC_OBJ;
+ /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */
+ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) &&
+ kstype != KMF_KEYSTORE_PK11TOKEN) {
- /* At least one of public, private, or object label is required. */
- if (!private_objs && !public_objs && object_label == NULL)
+ (void) fprintf(stderr, gettext("The objtype parameter "
+ "is only relevant if keystore=pkcs11\n"));
return (PK_ERR_USAGE);
+ }
- /*
- * If object label is given but neither public/private is specified,
- * delete all objects with that label.
- */
- if (!private_objs && !public_objs && object_label != NULL)
- obj_type = PK_ALL_OBJ;
+ /* If no object class specified, delete everything but CRLs */
+ if (oclass == 0)
+ oclass = PK_CERT_OBJ | PK_PUBKEY_OBJ | PK_PRIKEY_OBJ |
+ PK_SYMKEY_OBJ;
/* No additional args allowed. */
argc -= optind_av;
@@ -152,112 +536,129 @@ pk_delete(int argc, char *argv[])
return (PK_ERR_USAGE);
/* Done parsing command line options. */
- full_token_name(token_name, manuf_id, serial_no, full_name);
-
- /* Find the slot with token. */
- if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
- &pin_state)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to find token %s (%s)."), full_name,
- pkcs11_strerror(rv));
- return (PK_ERR_PK11);
+ if (kstype == KMF_KEYSTORE_PK11TOKEN && token_spec == NULL) {
+ token_spec = PK_DEFAULT_PK11TOKEN;
+ } else if (kstype == KMF_KEYSTORE_NSS && token_spec == NULL) {
+ token_spec = DEFAULT_NSS_TOKEN;
}
- /* Always get the user's PIN for delete operations. */
- if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin,
- &pinlen)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get token passphrase (%s)."),
- pkcs11_strerror(rv));
- quick_finish(NULL);
- return (PK_ERR_PK11);
- }
+ if (serstr != NULL) {
+ uchar_t *bytes = NULL;
+ size_t bytelen;
- /* Log the user R/W into the token. */
- if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to log into token (%s)."), pkcs11_strerror(rv));
- quick_finish(sess);
- return (PK_ERR_PK11);
+ rv = KMF_HexString2Bytes((uchar_t *)serstr, &bytes, &bytelen);
+ if (rv != KMF_OK || bytes == NULL) {
+ (void) fprintf(stderr, gettext("serial number "
+ "must be specified as a hex number "
+ "(ex: 0x0102030405ffeeddee)\n"));
+ return (PK_ERR_USAGE);
+ }
+ serial.val = bytes;
+ serial.len = bytelen;
}
- /* Find the object(s) with the given label and/or type. */
- if ((rv = find_objs(sess, obj_type, object_label, &objs, &num_objs)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to find token objects (%s)."), pkcs11_strerror(rv));
- quick_finish(sess);
- return (PK_ERR_PK11);
- }
+ if ((kstype == KMF_KEYSTORE_PK11TOKEN ||
+ kstype == KMF_KEYSTORE_NSS) &&
+ (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ))) {
- if (num_objs == 0) {
- (void) fprintf(stdout, gettext("No matching objects found.\n"));
- quick_finish(sess);
- return (0);
+ (void) get_token_password(kstype, token_spec,
+ &tokencred);
}
- if (num_objs != 1) {
- (void) fprintf(stdout, gettext(
- "Warning: %d matching objects found, deleting all.\n"),
- num_objs);
- if (yesno(gettext("Continue with delete? "),
- gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
- quick_finish(sess);
- return (0);
- }
- }
+ if ((kmfrv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK)
+ return (kmfrv);
- /* Destroy the objects if found. */
- for (i = 0; i < num_objs; i++) {
- /*
- * To give nice feedback to the user, get the object's
- * label before deleting it.
- */
- cryptodebug("calling C_GetAttributeValue for label");
- label.pValue = NULL;
- label.ulValueLen = 0;
- if (C_GetAttributeValue(sess, objs[i], &label, 1) == CKR_OK) {
- if (label.ulValueLen != (CK_ULONG)-1 &&
- label.ulValueLen != 0 &&
- (label.pValue = malloc(label.ulValueLen)) != NULL) {
- if (C_GetAttributeValue(sess, objs[i], &label,
- 1) != CKR_OK) {
- free(label.pValue);
- label.pValue = NULL;
- label.ulValueLen = 0;
- }
- } else {
- label.ulValueLen = 0;
+ switch (kstype) {
+ case KMF_KEYSTORE_PK11TOKEN:
+ if (oclass & PK_KEY_OBJ) {
+ kmfrv = delete_pk11_keys(kmfhandle,
+ token_spec, oclass,
+ object_label,
+ &tokencred);
+ /*
+ * If deleting groups of objects, it is OK
+ * to ignore the "key not found" case so that
+ * we can continue to find other objects.
+ */
+ if (kmfrv == KMF_ERR_KEY_NOT_FOUND &&
+ (oclass != PK_KEY_OBJ))
+ kmfrv = KMF_OK;
+ if (kmfrv != KMF_OK)
+ break;
}
- }
-
- cryptodebug("calling C_DestroyObject");
- if ((rv = C_DestroyObject(sess, objs[i])) != CKR_OK) {
- if (label.pValue != NULL)
- cryptoerror(LOG_STDERR, gettext(
- "Unable to delete object #%d \"%.*s\" "
- "(%s)."), i+1, label.ulValueLen,
- label.pValue, pkcs11_strerror(rv));
- else
- cryptoerror(LOG_STDERR, gettext(
- "Unable to delete object #%d (%s)."),
- i+1, pkcs11_strerror(rv));
- } else {
- if (label.pValue != NULL)
- (void) fprintf(stdout, gettext("Object #%d "
- "\"%.*s\" successfully deleted.\n"),
- i+1, label.ulValueLen, label.pValue);
- else
- (void) fprintf(stdout, gettext(
- "Object #%d successfully deleted.\n"), i+1);
- }
+ if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) {
+ kmfrv = delete_pk11_certs(kmfhandle,
+ token_spec,
+ object_label,
+ &serial, issuer,
+ subject, find_criteria_flag);
+ /*
+ * If cert delete failed, but we are looking at
+ * other objects, then it is OK.
+ */
+ if (kmfrv == KMF_ERR_CERT_NOT_FOUND &&
+ (oclass & (PK_CRL_OBJ | PK_KEY_OBJ)))
+ kmfrv = KMF_OK;
+ if (kmfrv != KMF_OK)
+ break;
+ }
+ if (oclass & PK_CRL_OBJ)
+ kmfrv = delete_file_crl(kmfhandle,
+ dir, infile);
+ break;
+ case KMF_KEYSTORE_NSS:
+ if (oclass & PK_KEY_OBJ) {
+ kmfrv = delete_nss_keys(kmfhandle,
+ dir, prefix, token_spec,
+ oclass, (char *)object_label,
+ &tokencred);
+ if (kmfrv != KMF_OK)
+ break;
+ }
+ if (oclass & PK_CERT_OBJ) {
+ kmfrv = delete_nss_certs(kmfhandle,
+ dir, prefix, token_spec,
+ (char *)object_label,
+ &serial, issuer, subject,
+ find_criteria_flag);
+ if (kmfrv != KMF_OK)
+ break;
+ }
+ if (oclass & PK_CRL_OBJ)
+ kmfrv = delete_nss_crl(kmfhandle,
+ dir, prefix, token_spec,
+ (char *)object_label, subject);
+ break;
+ case KMF_KEYSTORE_OPENSSL:
+ if (oclass & PK_KEY_OBJ) {
+ kmfrv = delete_file_keys(kmfhandle, oclass,
+ dir, infile);
+ if (kmfrv != KMF_OK)
+ break;
+ }
+ if (oclass & (PK_CERT_OBJ)) {
+ kmfrv = delete_file_certs(kmfhandle,
+ dir, infile, &serial, issuer,
+ subject, find_criteria_flag);
+ if (kmfrv != KMF_OK)
+ break;
+ }
+ if (oclass & PK_CRL_OBJ)
+ kmfrv = delete_file_crl(kmfhandle,
+ dir, infile);
+ break;
+ default:
+ rv = PK_ERR_USAGE;
+ break;
+ }
- if (label.pValue != NULL)
- free(label.pValue);
+ if (kmfrv != KMF_OK) {
+ display_error(kmfhandle, kmfrv,
+ gettext("Error deleting objects"));
}
- /* Clean up. */
- quick_finish(sess);
- return (0);
+ if (serial.val != NULL)
+ free(serial.val);
+ (void) KMF_Finalize(kmfhandle);
+ return (kmfrv);
}
diff --git a/usr/src/cmd/cmd-crypto/pktool/derparse.c b/usr/src/cmd/cmd-crypto/pktool/derparse.c
deleted file mode 100644
index cec607220a..0000000000
--- a/usr/src/cmd/cmd-crypto/pktool/derparse.c
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-/*
- * derparse.c - Functions for parsing DER-encoded data
- *
- * NOTE: This code was originally written by Cryptographic Products
- * Group at Sun Microsystems for the SCA 1000 "realmparse" program.
- * It is mostly intact except for necessary adaptaions to allow it to
- * compile in this environment.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <lber.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <strings.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <cryptoutil.h>
-#include "derparse.h"
-
-/* I18N helpers. */
-#include <libintl.h>
-#include <locale.h>
-
-/*
- * Some types that we need below.
- */
-typedef struct oidinfo {
- uint8_t *value; /* OID value in bytes */
- size_t length; /* Length of OID */
- char *strval; /* String rep. for OID in RDN */
-} oidinfo_t;
-
-/*
- * X.509 Issuer OIDs as recommended by RFC 3280
- * We might see these in certificates in their subject an issuer names.
- */
-static uint8_t common_name_oid[] = {0x55, 0x04, 0x03};
-static uint8_t surname_oid[] = {0x55, 0x04, 0x04};
-static uint8_t serial_number_oid[] = {0x55, 0x04, 0x05};
-static uint8_t country_name_oid[] = {0x55, 0x04, 0x06};
-static uint8_t locality_name_oid[] = {0x55, 0x04, 0x07};
-static uint8_t state_name_oid[] = {0x55, 0x04, 0x08};
-static uint8_t org_name_oid[] = {0x55, 0x04, 0x0a};
-static uint8_t org_unit_name_oid[] = {0x55, 0x04, 0x0b};
-static uint8_t title_oid[] = {0x55, 0x04, 0x0c};
-static uint8_t name_oid[] = {0x55, 0x04, 0x29};
-static uint8_t given_name_oid[] = {0x55, 0x04, 0x2a};
-static uint8_t initials_oid[] = {0x55, 0x04, 0x2b};
-static uint8_t gen_qual_oid[] = {0x55, 0x04, 0x2c};
-static uint8_t dn_qual_oid[] = {0x55, 0x04, 0x2e};
-static uint8_t pseudonym_oid[] = {0x55, 0x04, 0x31};
-static uint8_t uid_oid[] =
- {0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x01};
-static uint8_t domain_comp_oid[] =
- {0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19};
-static uint8_t email_addr_oid[] =
- {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01};
-
-/* Define this structure so we can match on a given oid */
-static oidinfo_t oids[] = {
- {common_name_oid, sizeof (common_name_oid), "CN"},
- {surname_oid, sizeof (surname_oid), "SN"},
- {serial_number_oid, sizeof (serial_number_oid), "SerialNum"},
- {country_name_oid, sizeof (country_name_oid), "C"},
- {locality_name_oid, sizeof (locality_name_oid), "L"},
- {state_name_oid, sizeof (state_name_oid), "ST"},
- {org_name_oid, sizeof (org_name_oid), "O"},
- {org_unit_name_oid, sizeof (org_unit_name_oid), "OU"},
- {title_oid, sizeof (title_oid), "Title"},
- {name_oid, sizeof (name_oid), "Name"},
- {given_name_oid, sizeof (given_name_oid), "GN"},
- {initials_oid, sizeof (initials_oid), "Initials"},
- {gen_qual_oid, sizeof (gen_qual_oid), "GenQual"},
- {dn_qual_oid, sizeof (dn_qual_oid), "DNQual"},
- {pseudonym_oid, sizeof (pseudonym_oid), "Pseudonym"},
- {uid_oid, sizeof (uid_oid), "UID"},
- {domain_comp_oid, sizeof (domain_comp_oid), "DC"},
- {email_addr_oid, sizeof (email_addr_oid), "E"}
-};
-static int oidblocklen = sizeof (oids) / sizeof (oidinfo_t);
-
-/* Local functions */
-static int oid_to_str(uint8_t *, size_t, char *, size_t);
-static int get_oid_type(char *);
-
-/*
- * An RDNSequence is what is handed to us when we get attributes like
- * CKA_ISSUER and CKA_SUBJECT_NAME. This function will take in a buffer
- * with the DER encoded bytes of an RDNSequence and print out the components.
- *
- * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
- *
- * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
- *
- * AttributeTypeAndValue ::= SEQUENCE {
- * type AttributeType,
- * value AttributeValue
- * }
- *
- * AttributeType ::= OBJECT IDENTIFIER
- *
- * AttributeValue ::= ANY DEFINED BY AttributeType
- */
-void
-rdnseq_to_str(uchar_t *derdata, size_t dersz, char *out, size_t outsz)
-{
-#define PKTOOL_LINEMAX 1024
- char oidout[PKTOOL_LINEMAX];
- BerElement *ber = NULL;
- BerValue ber_rdns;
- int tag;
- ber_len_t size;
- char *atv_type = NULL; /* Attribute Type */
- ber_len_t atv_type_size;
- char *atv_value = NULL; /* Attribute Value */
- ber_len_t atv_value_size;
- char *cookie = NULL;
- int idx;
- char *prndata = NULL;
- int prnsz;
- int offset = 0;
- boolean_t first = B_TRUE;
-
- cryptodebug("inside rdnseq_to_str");
-
- if (derdata == NULL || dersz == 0) {
- cryptodebug("nothing to parse");
- return;
- }
-
- /* Take the raw bytes and stuff them into a BerValue structure */
- ber_rdns.bv_val = (char *)derdata;
- ber_rdns.bv_len = dersz;
-
- /* Allocate the BerElement */
- if ((ber = ber_init(&ber_rdns)) == NULLBER) {
- cryptodebug("ber_init failed to return ber element");
- cryptoerror(LOG_STDERR, gettext(
- "Unable to begin parsing RDNSequence."));
- return;
- }
-
- /* Begin by parsing out the outer sequence */
- tag = ber_next_element(ber, &size, cookie);
- if (tag != LBER_SEQUENCE) {
- cryptodebug("ber_next_element tag is not SEQUENCE");
- cryptoerror(LOG_STDERR, gettext(
- "Expected RDNSequence SEQUENCE object, got tag [%02x]."),
- tag);
- return;
- }
- tag = ber_scanf(ber, "{");
-
- /* Parse the sequence of RelativeDistinguishedName objects */
- while ((tag = ber_next_element(ber, &size, cookie)) != -1) {
- if (tag != LBER_SET) {
- cryptodebug("ber_next_element tag is not SET");
- cryptoerror(LOG_STDERR, gettext(
- "Expected RelativeDistinguishedName SET object, "
- "got tag [%02x]."), tag);
- return;
- }
- tag = ber_scanf(ber, "[");
-
- /* AttributeTypeAndValue */
- tag = ber_next_element(ber, &size, cookie);
- if (tag != LBER_SEQUENCE) {
- cryptodebug("ber_next_element tag is not SEQUENCE");
- cryptoerror(LOG_STDERR, gettext(
- "Expected AttributeTypeAndValue SEQUENCE object, "
- "got tag [%02x]."), tag);
- return;
- }
- tag = ber_scanf(ber, "{");
-
- /* AttributeType OID */
- tag = ber_next_element(ber, &atv_type_size, cookie);
- atv_type_size++; /* Add room for null terminator */
- if (tag != LBER_OID) {
- cryptodebug("ber_next_element tag is not OID");
- cryptoerror(LOG_STDERR, gettext(
- "Expected an OID, got tag [%02x]."), tag);
- return;
- }
- /* Note: ber_scanf() allocates memory here for "a". */
- tag = ber_scanf(ber, "a", &atv_type, &atv_type_size);
-
- /* AttributeValue */
- tag = ber_next_element(ber, &atv_value_size, cookie);
- atv_value_size++;
- if ((tag != LBER_PRINTABLE_STRING) && (tag != LBER_IA5STRING)) {
- cryptodebug("ber_next_element tag is not "
- "PRINTABLE_STRING/IA5STRING");
- cryptoerror(LOG_STDERR, gettext("Expected a STRING, "
- "got tag [%02x]."), tag);
- free(atv_type);
- return;
- }
- /* Note: ber_scanf() allocates memory here for "a". */
- tag = ber_scanf(ber, "a", &atv_value, &atv_value_size);
-
- /*
- * Now go and turn the attribute type and value into
- * some kind of meaningful output.
- */
- if ((idx = get_oid_type(atv_type)) == -1) {
- if (oid_to_str((uint8_t *)atv_type, strlen(atv_type),
- oidout, sizeof (oidout)) < 0) {
- cryptodebug("oid_to_str failed");
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert OID to string."));
- free(atv_type);
- free(atv_value);
- return;
- }
- prndata = oidout;
- } else {
- prndata = oids[idx].strval;
- }
-
- if (!first)
- prnsz = snprintf(out + offset, outsz - offset,
- ", %s = %s", prndata, atv_value);
- else {
- prnsz = snprintf(out + offset, outsz - offset,
- "%s = %s", prndata, atv_value);
- first = B_FALSE;
- }
-
- free(atv_type);
- free(atv_value);
- atv_type = NULL;
- atv_value = NULL;
-
- offset += prnsz;
- if (offset >= outsz)
- break;
- }
-}
-
-/*
- * Convert OID to dotted notation string.
- */
-static int
-oid_to_str(uint8_t *oid, size_t oidlen, char *oidout, size_t oidout_len)
-{
- int count = 0;
- int offset = 0;
- int prnsz;
- uint_t firstnum;
- uint_t secondnum;
- uint64_t nextnum = 0;
-
- cryptodebug("inside oid_to_str");
-
- if (oidlen == 0)
- return (-1);
-
- /*
- * The first octet has a value of (40 x oidnum1) + oidnum2. We
- * will deconstruct it here and sanity check the result. According
- * to X.690, oidnum1 should never be more than 2 and oidnum2
- * shouldn't be greater than 39 when oidnum1 = 0 or 1.
- */
- firstnum = oid[count] / 40;
- if (firstnum > 2) /* force remainder to be > 39 */
- firstnum = 2;
- secondnum = oid[count] - (firstnum * 40);
-
- (void) memset(oidout, 0, oidout_len);
-
- prnsz = snprintf(oidout, oidout_len, "%d.%d", firstnum, secondnum);
- offset += prnsz;
- if (offset >= oidout_len)
- return (0);
-
- /* Start at the second byte and move our way forward */
- for (count = 1; count < oidlen; count++) {
- /* ORIGINAL COMMENT */
- /*
- * Each oid byte is taken as a 7-bit number. If bit 8 is
- * set, it means the next octet and this one are to be
- * chained together as a single bit string, and so forth.
- * We need to mask of bit 8, then shift over 7 bits in the
- * resulting integer, and then stuff the new 7 bits in
- * the low order byte, all the while making sure we don't
- * stomp bit 1 from the previous octet.
- * See X.690 or the layman's guide to ASN.1 for more.
- */
-
- /*
- * String together as many of the next octets if each of
- * their high order bits is set to 1. For example,
- * 1 1010111, 1 0010100, 1 0010110, 0 1101111, ...
- * (3 8-bit octets)
- * becomes
- * 1010111 0010100 0010110, 1101111, ...
- * (one 21 bit integer)
- * The high order bit functions as a "link" between octets.
- * Note that if there are more than 9 octets with their
- * high order bits set, it will overflow a 64-bit integer.
- */
- for (nextnum = 0; (oid[count] & 0x80) && (count < oidlen);
- count++) {
- nextnum <<= 7;
- nextnum |= (oid[count] & 0x7f);
- }
- if (count == oidlen) /* last number not terminated? */
- return (-1);
-
- /* We're done with this oid number, write it and move on */
- prnsz = snprintf(oidout + offset, oidout_len - offset,
- ".%lld", nextnum);
- offset += prnsz;
- if (offset >= oidout_len)
- return (0);
- }
-
- return (0);
-}
-
-/*
- * Returns the index in the oids[] array that matches the input type,
- * or -1 if it could not find a match.
- */
-static int
-get_oid_type(char *type)
-{
- int count;
-
- cryptodebug("inside get_oid_type");
-
- for (count = 0; count < oidblocklen; count++) {
- if (memcmp(oids[count].value, type, oids[count].length) == 0) {
- return (count);
- }
- }
-
- /* If we get here, we haven't found a match, so return -1 */
- return (-1);
-}
diff --git a/usr/src/cmd/cmd-crypto/pktool/download.c b/usr/src/cmd/cmd-crypto/pktool/download.c
new file mode 100644
index 0000000000..1eabc85ee3
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/download.c
@@ -0,0 +1,274 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <libgen.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <cryptoutil.h>
+#include "common.h"
+#include <kmfapi.h>
+
+int
+pk_download(int argc, char *argv[])
+{
+ int rv;
+ int opt;
+ extern int optind_av;
+ extern char *optarg_av;
+ int oclass = 0;
+ char *url = NULL;
+ char *http_proxy = NULL;
+ char *dir = NULL;
+ char *outfile = NULL;
+ char *proxy = NULL;
+ int proxy_port = 0;
+ KMF_HANDLE_T kmfhandle = NULL;
+ KMF_ENCODE_FORMAT format;
+ KMF_RETURN ch_rv = KMF_OK;
+ char *fullpath = NULL;
+ KMF_DATA cert = {NULL, 0};
+ KMF_DATA cert_der = {NULL, 0};
+
+ while ((opt = getopt_av(argc, argv,
+ "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) {
+
+ if (EMPTYSTRING(optarg_av))
+ return (PK_ERR_USAGE);
+ switch (opt) {
+ case 't':
+ if (oclass)
+ return (PK_ERR_USAGE);
+ oclass = OT2Int(optarg_av);
+ if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ)))
+ return (PK_ERR_USAGE);
+ break;
+ case 'u':
+ if (url)
+ return (PK_ERR_USAGE);
+ url = optarg_av;
+ break;
+ case 'h':
+ if (http_proxy)
+ return (PK_ERR_USAGE);
+ http_proxy = optarg_av;
+ break;
+ case 'o':
+ if (outfile)
+ return (PK_ERR_USAGE);
+ outfile = optarg_av;
+ break;
+ case 'd':
+ if (dir)
+ return (PK_ERR_USAGE);
+ dir = optarg_av;
+ break;
+ default:
+ cryptoerror(LOG_STDERR, gettext(
+ "unrecognized download option '%s'\n"),
+ argv[optind_av]);
+ return (PK_ERR_USAGE);
+ }
+ }
+
+ /* No additional args allowed. */
+ argc -= optind_av;
+ argv += optind_av;
+ if (argc) {
+ return (PK_ERR_USAGE);
+ }
+
+ /* Check the dir and outfile options */
+ if (outfile == NULL) {
+ /* If outfile is not specified, use the basename of URI */
+ outfile = basename(url);
+ }
+
+ fullpath = get_fullpath(dir, outfile);
+ if (fullpath == NULL) {
+ cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile "
+ "option value \n"));
+ return (PK_ERR_USAGE);
+ }
+ /* Check if the file exists and might be overwritten. */
+ if (access(fullpath, F_OK) == 0) {
+ cryptoerror(LOG_STDERR,
+ gettext("Warning: file \"%s\" exists, "
+ "will be overwritten."), fullpath);
+ if (yesno(gettext("Continue with download? "),
+ gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
+ return (0);
+ }
+ } else {
+ rv = verify_file(fullpath);
+ if (rv != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("The file (%s) "
+ "cannot be created.\n"), fullpath);
+ return (PK_ERR_USAGE);
+ }
+ }
+
+
+ /* URI MUST be specified */
+ if (url == NULL) {
+ cryptoerror(LOG_STDERR, gettext("A URL must be specified\n"));
+ rv = PK_ERR_USAGE;
+ goto end;
+ }
+
+ /*
+ * Get the http proxy from the command "http_proxy" option or the
+ * environment variable. The command option has a higher priority.
+ */
+ if (http_proxy == NULL)
+ http_proxy = getenv("http_proxy");
+
+ if (http_proxy != NULL) {
+ char *ptmp = http_proxy;
+ char *proxy_port_s;
+
+ if (strncasecmp(ptmp, "http://", 7) == 0)
+ ptmp += 7; /* skip the scheme prefix */
+
+ proxy = strtok(ptmp, ":");
+ proxy_port_s = strtok(NULL, "\0");
+ if (proxy_port_s != NULL)
+ proxy_port = strtol(proxy_port_s, NULL, 0);
+ else
+ proxy_port = 8080;
+ }
+
+ /* If objtype is not specified, default to CRL */
+ if (oclass == 0) {
+ oclass = PK_CRL_OBJ;
+ }
+
+ if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
+ rv = PK_ERR_USAGE;
+ goto end;
+ }
+
+ /* Now we are ready to download */
+ if (oclass & PK_CRL_OBJ) {
+ rv = KMF_DownloadCRL(kmfhandle, url, proxy, proxy_port, 30,
+ fullpath, &format);
+ } else if (oclass & PK_CERT_OBJ) {
+ rv = KMF_DownloadCert(kmfhandle, url, proxy, proxy_port, 30,
+ fullpath, &format);
+ }
+
+ if (rv != KMF_OK) {
+ switch (rv) {
+ case KMF_ERR_BAD_URI:
+ cryptoerror(LOG_STDERR,
+ gettext("Error in parsing URI\n"));
+ rv = PK_ERR_USAGE;
+ break;
+ case KMF_ERR_OPEN_FILE:
+ cryptoerror(LOG_STDERR,
+ gettext("Error in opening file\n"));
+ rv = PK_ERR_USAGE;
+ break;
+ case KMF_ERR_WRITE_FILE:
+ cryptoerror(LOG_STDERR,
+ gettext("Error in writing file\n"));
+ rv = PK_ERR_USAGE;
+ break;
+ case KMF_ERR_BAD_CRLFILE:
+ cryptoerror(LOG_STDERR, gettext("Not a CRL file\n"));
+ rv = PK_ERR_USAGE;
+ break;
+ case KMF_ERR_BAD_CERTFILE:
+ cryptoerror(LOG_STDERR,
+ gettext("Not a certificate file\n"));
+ rv = PK_ERR_USAGE;
+ break;
+ case KMF_ERR_MEMORY:
+ cryptoerror(LOG_STDERR,
+ gettext("Not enough memory\n"));
+ rv = PK_ERR_SYSTEM;
+ break;
+ default:
+ cryptoerror(LOG_STDERR,
+ gettext("Error in downloading the file.\n"));
+ rv = PK_ERR_SYSTEM;
+ break;
+ }
+ goto end;
+ }
+
+ /*
+ * If the file is successfully downloaded, we also check the date.
+ * If the downloaded file is outdated, give a warning.
+ */
+ if (oclass & PK_CRL_OBJ) {
+ KMF_CHECKCRLDATE_PARAMS params;
+
+ params.crl_name = fullpath;
+ ch_rv = KMF_CheckCRLDate(kmfhandle, &params);
+
+ } else { /* certificate */
+ ch_rv = KMF_ReadInputFile(kmfhandle, fullpath, &cert);
+ if (ch_rv != KMF_OK)
+ goto end;
+
+ if (format == KMF_FORMAT_PEM) {
+ int len;
+ ch_rv = KMF_Pem2Der(cert.Data, cert.Length,
+ &cert_der.Data, &len);
+ if (ch_rv != KMF_OK)
+ goto end;
+ cert_der.Length = (size_t)len;
+ }
+
+ ch_rv = KMF_CheckCertDate(kmfhandle,
+ format == KMF_FORMAT_ASN1 ? &cert : &cert_der);
+ }
+
+end:
+ if (ch_rv == KMF_ERR_VALIDITY_PERIOD) {
+ cryptoerror(LOG_STDERR,
+ gettext("Warning: the downloaded file is expired.\n"));
+ } else if (ch_rv != KMF_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Warning: failed to check the validity.\n"));
+ }
+
+ if (fullpath)
+ free(fullpath);
+
+ KMF_FreeData(&cert);
+ KMF_FreeData(&cert_der);
+
+ (void) KMF_Finalize(kmfhandle);
+ return (rv);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/export.c b/usr/src/cmd/cmd-crypto/pktool/export.c
index 46fbccb37e..9170a00468 100644
--- a/usr/src/cmd/cmd-crypto/pktool/export.c
+++ b/usr/src/cmd/cmd-crypto/pktool/export.c
@@ -17,8 +17,8 @@
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
- */
-/*
+ *
+ *
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -38,1170 +38,264 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include <cryptoutil.h>
-#include <security/cryptoki.h>
+#include <fcntl.h>
#include "common.h"
-#include "biginteger.h"
-#include "osslcommon.h"
-#include "p12common.h"
-#include <openssl/pkcs12.h>
-
-/*
- * Writes OpenSSL objects to PKCS#12 file. The PKCS#11 objects from
- * the soft token need to be converted to OpenSSL structures prior
- * to this call, since the PKCS#12 routines depend on that format.
- * This code is patterned from OpenSSL apps that write PKCS#12 files.
- *
- * Note: it's not clear from the usage of all the functions here by
- * OpenSSL apps whether these functions have return values or error
- * conditions that can be checked. This function may benefit from
- * a closer review at a later time.
- */
-static int
-write_objs_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen,
- CK_BYTE_PTR id, CK_ULONG id_len, EVP_PKEY *priv_key, X509 *cert,
- STACK_OF(X509) *ca_certs, int *successes, int *failures)
-/* ARGSUSED */
-{
- STACK_OF(PKCS12_SAFEBAG) *bag_stack = NULL;
- PKCS12_SAFEBAG *bag = NULL;
- X509 *ca = NULL;
- PKCS7 *cert_authsafe = NULL;
- PKCS8_PRIV_KEY_INFO *p8 = NULL;
- PKCS7 *key_authsafe = NULL;
- STACK_OF(PKCS7) *authsafe_stack = NULL;
- PKCS12 *p12_elem = NULL;
- unsigned char *lab = NULL;
- int lab_len = 0;
- int i;
- int n_writes = 0;
-
- cryptodebug("inside write_objs_pkcs12");
-
- /* Do not reset *successes or *failures -- keep running totals. */
-
- /* If there is nothing to write to the PKCS#12 file, leave. */
- if (cert == NULL && ca_certs == NULL && priv_key == NULL) {
- cryptodebug("nothing to write to export file");
- return (0);
- }
-
- /*
- * Section 1:
- *
- * The first PKCS#12 container (safebag) will hold the certificates
- * associated with this key. The result of this section is a
- * PIN-encrypted PKCS#7 container (authsafe). If there are no
- * certificates, there is no point in creating the "safebag" or the
- * "authsafe" so we go to the next section.
- */
- if (cert != NULL || ca_certs != NULL) {
- /* Start a PKCS#12 safebag container for the certificates. */
- cryptodebug("creating certificate PKCS#12 safebag");
- bag_stack = sk_PKCS12_SAFEBAG_new_null();
- if (bag_stack == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to create PKCS#12 certificate bag."));
- (*failures)++;
- return (-1);
- }
-
- /* Add the cert corresponding to private key to bag_stack. */
- if (cert) {
- /* Convert cert from X509 struct to PKCS#12 bag */
- cryptodebug("adding certificate to PKCS#12 safebag");
- bag = PKCS12_x5092certbag(cert);
- if (bag == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert certificate to "
- "PKCS#12 bag."));
- /* Cleanup the safebag. */
- sk_PKCS12_SAFEBAG_pop_free(bag_stack,
- PKCS12_SAFEBAG_free);
- (*failures)++;
- return (-1);
- }
-
- /* Add the key id to the certificate bag. */
- cryptodebug("add key id to PKCS#12 safebag");
- if (!PKCS12_add_localkeyid(bag, id, id_len))
- cryptodebug("error not caught");
-
- /* Add the friendly name to the certificate bag. */
- if ((lab = X509_alias_get0(cert, &lab_len)) != NULL) {
- cryptodebug(
- "label PKCS#12 safebag with friendly name");
- if (!PKCS12_add_friendlyname(bag, (char *)lab,
- lab_len))
- cryptodebug("error not caught");
- }
-
- /* Pile it on the bag_stack. */
- if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag))
- cryptodebug("error not caught");
-
- n_writes++;
- }
-
- /* Add all the CA chain certs to the bag_stack. */
- if (ca_certs) {
- cryptodebug("adding CA certificate chain to PKCS#12 "
- "safebag");
- /*
- * Go through the stack of CA certs, converting each
- * one to a PKCS#12 bag and piling them onto the
- * bag_stack.
- */
- for (i = 0; i < sk_X509_num(ca_certs); i++) {
- /*
- * sk_X509_value() is macro that embeds a
- * cast to (X509 *). Here it translates
- * into ((X509 *)sk_value((ca_certs), (i))).
- * Lint is complaining about the embedded
- * casting, and to fix it, you need to fix
- * openssl header files.
- */
- /* LINTED E_BAD_PTR_CAST_ALIGN */
- ca = sk_X509_value(ca_certs, i);
-
- /* Convert CA cert to PKCS#12 bag. */
- cryptodebug("adding CA certificate #%d "
- "to PKCS#12 safebag", i+1);
- bag = PKCS12_x5092certbag(ca);
- if (bag == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert CA certificate "
- "#%d to PKCS#12 bag."), i+1);
- /* Cleanup the safebag. */
- sk_PKCS12_SAFEBAG_pop_free(bag_stack,
- PKCS12_SAFEBAG_free);
- (*failures)++;
- return (-1);
- }
-
- /* Note CA certs do not have friendly name. */
-
- /* Pile it onto the bag_stack. */
- if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag))
- cryptodebug("error not caught");
-
- n_writes++;
- }
- }
-
- /* Turn bag_stack of certs into encrypted authsafe. */
- cryptodebug("encrypt certificate PKCS#12 bag into "
- "PKCS#7 authsafe");
- cert_authsafe = PKCS12_pack_p7encdata(
- NID_pbe_WithSHA1And40BitRC2_CBC, (char *)pin, -1, NULL,
- 0, PKCS12_DEFAULT_ITER, bag_stack);
-
- /* Clear away this bag_stack, we're done with it. */
- sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
- bag_stack = NULL;
-
- if (cert_authsafe == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to PKCS#7-encrypt certificate bag."));
- (*failures)++;
- return (-1);
- }
- }
-
- /*
- * Section 2:
- *
- * The second PKCS#12 container (safebag) will hold the private key
- * that goes with the certificates above. The results of this section
- * is an unencrypted PKCS#7 container (authsafe). If there is no
- * private key, there is no point in creating the "safebag" or the
- * "authsafe" so we go to the next section.
- */
- if (priv_key != NULL) {
- /* Make a PKCS#8 shrouded key bag. */
- cryptodebug("create PKCS#8 shrouded key out of private key");
- p8 = EVP_PKEY2PKCS8(priv_key);
- if (p8 == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to create PKCS#8 shrouded key for "
- "private key."));
- (*failures)++;
- return (-1);
- }
-
- /* Put the shrouded key into a PKCS#12 bag. */
- cryptodebug("convert shrouded key to PKCS#12 bag");
- bag = PKCS12_MAKE_SHKEYBAG(
- NID_pbe_WithSHA1And3_Key_TripleDES_CBC, (char *)pin,
- -1, NULL, 0, PKCS12_DEFAULT_ITER, p8);
-
- /* Clean up the PKCS#8 shrouded key, don't need it now. */
- PKCS8_PRIV_KEY_INFO_free(p8);
- p8 = NULL;
-
- if (bag == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert private key to PKCS#12 bag."));
- (*failures)++;
- return (-1);
- }
-
- /* Add the key id to the certificate bag. */
- cryptodebug("add key id to PKCS#12 safebag");
- if (!PKCS12_add_localkeyid(bag, id, id_len))
- cryptodebug("error not caught");
-
- /* Add the cert friendly name to the private key bag. */
- if (lab != NULL) {
- cryptodebug("label PKCS#12 safebag with friendly name");
- if (!PKCS12_add_friendlyname(bag, (char *)lab, lab_len))
- cryptodebug("error not caught");
- }
-
- /* Start a PKCS#12 safebag container for the private key. */
- cryptodebug("creating private key PKCS#12 safebag");
- bag_stack = sk_PKCS12_SAFEBAG_new_null();
- if (bag_stack == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to create PKCS#12 private key bag."));
- (*failures)++;
- return (-1);
- }
-
- /* Pile on the private key on the bag_stack. */
- if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag))
- cryptodebug("error not caught");
- /* Turn bag_stack with private key into unencrypted authsafe. */
- cryptodebug("put private PKCS#12 bag into PKCS#7 authsafe");
- key_authsafe = PKCS12_pack_p7data(bag_stack);
+#include <kmfapi.h>
- /* Clear away this bag_stack, we're done with it. */
- sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
- bag_stack = NULL;
-
- if (key_authsafe == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to PKCS#7-convert private key bag."));
- (*failures)++;
- return (-1);
- }
-
- n_writes++;
- }
-
- /*
- * Section 3:
- *
- * This is where the two PKCS#7 containers, one for the certificates
- * and one for the private key, are put together into a PKCS#12
- * element. This final PKCS#12 element is written to the export file.
- */
- /* Start a PKCS#7 stack. */
- cryptodebug("create PKCS#7 authsafe for private key and certificates");
- authsafe_stack = sk_PKCS7_new_null();
- if (authsafe_stack == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to create PKCS#7 container for private key "
- "and certificates."));
- (*failures)++;
- return (-1);
- }
-
- /* Put certificates and private key into PKCS#7 stack. */
- if (key_authsafe != NULL) {
- cryptodebug("put private key authsafe into PKCS#7 container");
- if (!sk_PKCS7_push(authsafe_stack, key_authsafe))
- cryptodebug("error not caught");
- }
- if (cert_authsafe != NULL) {
- cryptodebug("put certificate authsafe into PKCS#7 container");
- if (!sk_PKCS7_push(authsafe_stack, cert_authsafe))
- cryptodebug("error not caught");
- }
-
- /* Create PKCS#12 element out of PKCS#7 stack. */
- cryptodebug("create PKCS#12 element for export file");
- p12_elem = PKCS12_init(NID_pkcs7_data);
- if (p12_elem == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to create PKCS#12 element for export file."));
- sk_PKCS7_pop_free(authsafe_stack, PKCS7_free);
- (*failures)++;
- return (-1);
- }
-
- /* Put the PKCS#7 stack into the PKCS#12 element. */
- if (!PKCS12_pack_authsafes(p12_elem, authsafe_stack))
- cryptodebug("error not caught");
-
- /* Clear away the PKCS#7 stack, we're done with it. */
- sk_PKCS7_pop_free(authsafe_stack, PKCS7_free);
- authsafe_stack = NULL;
-
- /* Set the integrity MAC on the PKCS#12 element. */
- cryptodebug("setting MAC for PKCS#12 element");
- if (!PKCS12_set_mac(p12_elem, (char *)pin, -1, NULL, 0,
- PKCS12_DEFAULT_ITER, NULL))
- cryptodebug("error not caught");
-
- /* Write the PKCS#12 element to the export file. */
- cryptodebug("writing PKCS#12 element to export file");
- if (!i2d_PKCS12_bio(fbio, p12_elem))
- cryptodebug("error not caught");
-
- (*successes) += n_writes;
-
- /* Clear away the PKCS#12 element. */
- PKCS12_free(p12_elem);
- return (0);
-}
-
-/*
- * Get token objects: private key, its cert, and its cert chain.
- */
-static CK_RV
-get_token_objs(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj,
- CK_OBJECT_HANDLE *mate, CK_OBJECT_HANDLE_PTR *chain,
- CK_ULONG *chain_len, CK_BYTE_PTR *id, CK_ULONG *id_len)
+static KMF_RETURN
+pk_find_export_cert(KMF_HANDLE_T kmfhandle, KMF_FINDCERT_PARAMS *parms,
+ KMF_X509_DER_CERT *cert)
{
- CK_RV rv = CKR_OK;
- CK_ATTRIBUTE keyid_attr[1] = {
- { CKA_ID, NULL, 0 }
- };
- static CK_OBJECT_CLASS class = CKO_CERTIFICATE;
- static CK_CERTIFICATE_TYPE certtype = CKC_X_509;
- CK_ATTRIBUTE cert_attr[4] = {
- { CKA_CLASS, &class, sizeof (CK_OBJECT_CLASS) },
- { CKA_CERTIFICATE_TYPE, &certtype, sizeof (certtype) },
- { CKA_TOKEN, &pk_true, sizeof (pk_true) },
- { CKA_ID, NULL, 0 }
- };
- CK_ULONG num_attr = sizeof (cert_attr) / sizeof (CK_ATTRIBUTE);
- CK_OBJECT_HANDLE cert = ~0UL;
- CK_ULONG num = 0;
-
- cryptodebug("inside get_token_objs");
-
- /* Get the size of the object's CKA_ID field first. */
- cryptodebug("getting CKA_ID size for object 0x%x", obj);
- if ((rv = C_GetAttributeValue(sess, obj, keyid_attr, 1)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext("Unable to get size of object"
- " key id (%s)."), pkcs11_strerror(rv));
- return (rv);
- }
-
- /* Allocate the space needed for the key id. */
- if ((keyid_attr[0].pValue = malloc(keyid_attr[0].ulValueLen)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- return (CKR_HOST_MEMORY);
- }
+ KMF_RETURN rv = KMF_OK;
+ uint32_t numcerts = 0;
- /* Get the CKA_ID field to match obj with its cert. */
- cryptodebug("getting CKA_ID attribute for object 0x%x", obj);
- if ((rv = C_GetAttributeValue(sess, obj, keyid_attr, 1)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext("Unable to get object "
- "key id (%s)."), pkcs11_strerror(rv));
- free(keyid_attr[0].pValue);
+ numcerts = 0;
+ (void) memset(cert, 0, sizeof (KMF_X509_DER_CERT));
+ rv = KMF_FindCert(kmfhandle, parms, NULL, &numcerts);
+ if (rv != KMF_OK) {
return (rv);
}
+ if (numcerts == 0) {
+ cryptoerror(LOG_STDERR,
+ gettext("No matching certificates found."));
+ return (KMF_ERR_CERT_NOT_FOUND);
- /* Now try to find any certs that have the same id. */
- cryptodebug("searching for certificates with same CKA_ID");
- cert_attr[3].pValue = keyid_attr[0].pValue;
- cert_attr[3].ulValueLen = keyid_attr[0].ulValueLen;
- if ((rv = C_FindObjectsInit(sess, cert_attr, num_attr)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext("Unable to initialize "
- "certificate search (%s)."), pkcs11_strerror(rv));
- free(keyid_attr[0].pValue);
- return (rv);
- }
+ } else if (numcerts == 1) {
+ rv = KMF_FindCert(kmfhandle, parms, cert, &numcerts);
- /* Find the first cert that matches the key id. */
- if ((rv = C_FindObjects(sess, &cert, 1, &num)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext("Certificate search failed "
- "(%s)."), pkcs11_strerror(rv));
- free(keyid_attr[0].pValue);
- return (rv);
+ } else if (numcerts > 1) {
+ cryptoerror(LOG_STDERR,
+ gettext("%d certificates found, refine the "
+ "search parameters to eliminate ambiguity\n"),
+ numcerts);
+ return (KMF_ERR_BAD_PARAMETER);
}
-
- (void) C_FindObjectsFinal(sess);
-
- *id = keyid_attr[0].pValue;
- *id_len = keyid_attr[0].ulValueLen;
-
- *mate = (num == 1) ? cert : ~0UL;
-
- /* We currently do not find all the certs in the chain. */
- *chain_len = 0;
- *chain = NULL;
-
- return (CKR_OK);
+ return (rv);
}
-/*
- * Converts PKCS#11 biginteger_t format to OpenSSL BIGNUM.
- * "to" should be the address of a ptr init'ed to NULL to
- * receive the BIGNUM, e.g.,
- * biginteger_t from;
- * BIGNUM *foo = NULL;
- * cvt_bigint2bn(&from, &foo);
- */
-static int
-cvt_bigint2bn(biginteger_t *from, BIGNUM **to)
+static KMF_RETURN
+pk_export_file_objects(KMF_HANDLE_T kmfhandle, int oclass,
+ char *issuer, char *subject, KMF_BIGINT *serial,
+ KMF_ENCODE_FORMAT ofmt,
+ char *dir, char *infile, char *filename)
{
- BIGNUM *temp = NULL;
-
- cryptodebug("inside cvt_bigint2bn");
-
- if (from == NULL || to == NULL)
- return (-1);
-
- cryptodebug("calling BN_bin2bn");
- if ((temp = BN_bin2bn(from->big_value, from->big_value_len, *to)) ==
- NULL)
- return (-1);
-
- *to = temp;
- return (0);
+ KMF_RETURN rv = KMF_OK;
+ KMF_STORECERT_PARAMS scparms;
+ KMF_X509_DER_CERT kmfcert;
+
+ /* If searching for public objects or certificates, find certs now */
+ if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) {
+ KMF_FINDCERT_PARAMS fcargs;
+
+ (void) memset(&fcargs, 0, sizeof (fcargs));
+ fcargs.kstype = KMF_KEYSTORE_OPENSSL;
+ fcargs.certLabel = NULL;
+ fcargs.issuer = issuer;
+ fcargs.subject = subject;
+ fcargs.serial = serial;
+ fcargs.sslparms.dirpath = dir;
+ fcargs.sslparms.certfile = infile;
+ fcargs.sslparms.format = ofmt;
+
+ rv = pk_find_export_cert(kmfhandle, &fcargs, &kmfcert);
+ if (rv == KMF_OK) {
+ (void) memset(&scparms, 0, sizeof (scparms));
+ scparms.kstype = KMF_KEYSTORE_OPENSSL;
+ scparms.sslparms.certfile = filename;
+ rv = KMF_StoreCert(kmfhandle, &scparms,
+ &kmfcert.certificate);
+
+ KMF_FreeKMFCert(kmfhandle, &kmfcert);
+ }
+ }
+ return (rv);
}
-/*
- * Convert PKCS#11 RSA private key to OpenSSL EVP_PKEY structure.
- */
-static CK_RV
-cvt_rsa2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk)
+static KMF_RETURN
+pk_export_pk12_nss(KMF_HANDLE_T kmfhandle,
+ char *token_spec, char *dir, char *prefix,
+ char *certlabel, char *issuer, char *subject,
+ KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred,
+ char *filename)
{
- CK_RV rv = CKR_OK;
- EVP_PKEY *key = NULL; /* OpenSSL representation */
- RSA *rsa = NULL; /* OpenSSL representation */
- biginteger_t mod = { NULL, 0 }; /* required */
- biginteger_t pubexp = { NULL, 0 }; /* required */
- biginteger_t priexp = { NULL, 0 }; /* optional */
- biginteger_t prime1 = { NULL, 0 }; /* optional */
- biginteger_t prime2 = { NULL, 0 }; /* optional */
- biginteger_t exp1 = { NULL, 0 }; /* optional */
- biginteger_t exp2 = { NULL, 0 }; /* optional */
- biginteger_t coef = { NULL, 0 }; /* optional */
- CK_ATTRIBUTE rsa_pri_attrs[8] = {
- { CKA_MODULUS, NULL, 0 },
- { CKA_PUBLIC_EXPONENT, NULL, 0 },
- { CKA_PRIVATE_EXPONENT, NULL, 0 }, /* optional */
- { CKA_PRIME_1, NULL, 0 }, /* | */
- { CKA_PRIME_2, NULL, 0 }, /* | */
- { CKA_EXPONENT_1, NULL, 0 }, /* | */
- { CKA_EXPONENT_2, NULL, 0 }, /* | */
- { CKA_COEFFICIENT, NULL, 0 } /* V */
- };
- CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
- int i;
-
- cryptodebug("inside cvt_rsa2evp_pkey");
-
- cryptodebug("calling RSA_new");
- if ((rsa = RSA_new()) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to allocate internal RSA structure."));
- return (CKR_HOST_MEMORY);
- }
+ KMF_RETURN rv = KMF_OK;
+ KMF_EXPORTP12_PARAMS p12parms;
- /* Get the sizes of the attributes we need. */
- cryptodebug("calling C_GetAttributeValue for size info");
- if ((rv = C_GetAttributeValue(sess, obj, rsa_pri_attrs, count)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get RSA private key attribute sizes (%s)."),
- pkcs11_strerror(rv));
+ rv = configure_nss(kmfhandle, dir, prefix);
+ if (rv != KMF_OK)
return (rv);
- }
- /* Allocate memory for each attribute. */
- for (i = 0; i < count; i++) {
- if (rsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 ||
- rsa_pri_attrs[i].ulValueLen == 0) {
- cryptodebug("cvt_rsa2evp_pkey: *** should not happen");
- rsa_pri_attrs[i].ulValueLen = 0;
- continue;
- }
- if ((rsa_pri_attrs[i].pValue =
- malloc(rsa_pri_attrs[i].ulValueLen)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- return (CKR_HOST_MEMORY);
- }
- }
+ (void) memset(&p12parms, 0, sizeof (p12parms));
+ if (token_spec == NULL)
+ token_spec = DEFAULT_NSS_TOKEN;
- /* Now really get the attributes. */
- cryptodebug("calling C_GetAttributeValue for attribute info");
- if ((rv = C_GetAttributeValue(sess, obj, rsa_pri_attrs, count)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get RSA private key attributes (%s)."),
- pkcs11_strerror(rv));
- return (rv);
- }
+ p12parms.kstype = KMF_KEYSTORE_NSS;
+ p12parms.certLabel = certlabel;
+ p12parms.issuer = issuer;
+ p12parms.subject = subject;
+ p12parms.serial = serial;
+ p12parms.idstr = NULL;
+ if (tokencred != NULL)
+ p12parms.cred = *tokencred;
+ p12parms.nssparms.slotlabel = token_spec;
- /*
- * Fill in all the temp variables. Modulus and public exponent
- * are required. The rest are optional.
- */
- i = 0;
- copy_attr_to_bigint(&(rsa_pri_attrs[i++]), &mod);
- copy_attr_to_bigint(&(rsa_pri_attrs[i++]), &pubexp);
-
- if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
- rsa_pri_attrs[i].ulValueLen != 0)
- copy_attr_to_bigint(&(rsa_pri_attrs[i]), &priexp);
- i++;
-
- if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
- rsa_pri_attrs[i].ulValueLen != 0)
- copy_attr_to_bigint(&(rsa_pri_attrs[i]), &prime1);
- i++;
-
- if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
- rsa_pri_attrs[i].ulValueLen != 0)
- copy_attr_to_bigint(&(rsa_pri_attrs[i]), &prime2);
- i++;
-
- if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
- rsa_pri_attrs[i].ulValueLen != 0)
- copy_attr_to_bigint(&(rsa_pri_attrs[i]), &exp1);
- i++;
-
- if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
- rsa_pri_attrs[i].ulValueLen != 0)
- copy_attr_to_bigint(&(rsa_pri_attrs[i]), &exp2);
- i++;
-
- if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
- rsa_pri_attrs[i].ulValueLen != 0)
- copy_attr_to_bigint(&(rsa_pri_attrs[i]), &coef);
- i++;
-
- /* Start the conversion to internal OpenSSL RSA structure. */
-
- /* Modulus n */
- if (cvt_bigint2bn(&mod, &(rsa->n)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key modulus."));
- return (CKR_GENERAL_ERROR);
- }
+ (void) get_pk12_password(&p12parms.p12cred);
- /* Public exponent e */
- if (cvt_bigint2bn(&pubexp, &(rsa->e)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key public exponent."));
- return (CKR_GENERAL_ERROR);
- }
+ rv = KMF_ExportPK12(kmfhandle, &p12parms, filename);
+ if (p12parms.p12cred.cred)
+ free(p12parms.p12cred.cred);
- /* Private exponent e */
- if (priexp.big_value != NULL) {
- if (cvt_bigint2bn(&priexp, &(rsa->d)) < 0) {
- cryptoerror(LOG_STDERR, gettext("Unable to convert "
- "RSA private key private exponent."));
- return (CKR_GENERAL_ERROR);
- }
- } else
- cryptodebug("no RSA private key private exponent");
-
- /* Prime p */
- if (prime1.big_value != NULL) {
- if (cvt_bigint2bn(&prime1, &(rsa->p)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key prime 1."));
- return (CKR_GENERAL_ERROR);
- }
- } else
- cryptodebug("no RSA private key prime 1");
-
- /* Prime q */
- if (prime2.big_value != NULL) {
- if (cvt_bigint2bn(&prime2, &(rsa->q)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key prime 2."));
- return (CKR_GENERAL_ERROR);
- }
- } else
- cryptodebug("no RSA private key prime 2");
-
- /* Private exponent d modulo p-1 */
- if (exp1.big_value != NULL) {
- if (cvt_bigint2bn(&exp1, &(rsa->dmp1)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key exponent 1."));
- return (CKR_GENERAL_ERROR);
- }
- } else
- cryptodebug("no RSA private key exponent 1");
-
- /* Private exponent d modulo q-1 */
- if (exp2.big_value != NULL) {
- if (cvt_bigint2bn(&exp2, &(rsa->dmq1)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key exponent 2."));
- return (CKR_GENERAL_ERROR);
- }
- } else
- cryptodebug("no RSA private key exponent 2");
-
- /* CRT coefficient q-inverse mod p */
- if (coef.big_value != NULL) {
- if (cvt_bigint2bn(&coef, &(rsa->iqmp)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key coefficient."));
- return (CKR_GENERAL_ERROR);
- }
- } else
- cryptodebug("no RSA private key coefficient");
-
- /* Create OpenSSL EVP_PKEY struct in which to stuff RSA struct. */
- cryptodebug("calling EVP_PKEY_new");
- if ((key = EVP_PKEY_new()) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to allocate internal EVP_PKEY structure."));
- return (CKR_HOST_MEMORY);
- }
-
- /* Put the RSA struct into the EVP_PKEY struct and return it. */
- cryptodebug("calling EVP_PKEY_set1_RSA");
- (void) EVP_PKEY_set1_RSA(key, rsa);
-
- *pk = key;
- return (CKR_OK);
+ return (rv);
}
-/*
- * Convert PKCS#11 DSA private key to OpenSSL EVP_PKEY structure.
- */
-static CK_RV
-cvt_dsa2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk)
+static KMF_RETURN
+pk_export_pk12_files(KMF_HANDLE_T kmfhandle,
+ char *certfile, char *keyfile, char *dir,
+ char *outfile)
{
- CK_RV rv = CKR_OK;
- EVP_PKEY *key = NULL; /* OpenSSL representation */
- DSA *dsa = NULL; /* OpenSSL representation */
- biginteger_t prime = { NULL, 0 }; /* required */
- biginteger_t subprime = { NULL, 0 }; /* required */
- biginteger_t base = { NULL, 0 }; /* required */
- biginteger_t value = { NULL, 0 }; /* required */
- CK_ATTRIBUTE dsa_pri_attrs[4] = {
- { CKA_PRIME, NULL, 0 },
- { CKA_SUBPRIME, NULL, 0 },
- { CKA_BASE, NULL, 0 },
- { CKA_VALUE, NULL, 0 }
- };
- CK_ULONG count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
- int i;
-
- cryptodebug("inside cvt_dsa2evp_pkey");
-
- cryptodebug("calling DSA_new");
- if ((dsa = DSA_new()) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to allocate internal DSA structure."));
- return (CKR_HOST_MEMORY);
- }
-
- /* Get the sizes of the attributes we need. */
- cryptodebug("calling C_GetAttributeValue for size info");
- if ((rv = C_GetAttributeValue(sess, obj, dsa_pri_attrs, count)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get DSA private key object attributes (%s)."),
- pkcs11_strerror(rv));
- return (rv);
- }
-
- /* Allocate memory for each attribute. */
- for (i = 0; i < count; i++) {
- if (dsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 ||
- dsa_pri_attrs[i].ulValueLen == 0) {
- cryptodebug("cvt_dsa2evp_pkey: *** should not happen");
- dsa_pri_attrs[i].ulValueLen = 0;
- continue;
- }
- if ((dsa_pri_attrs[i].pValue =
- malloc(dsa_pri_attrs[i].ulValueLen)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- return (CKR_HOST_MEMORY);
- }
- }
-
- /* Now really get the attributes. */
- cryptodebug("calling C_GetAttributeValue for attribute info");
- if ((rv = C_GetAttributeValue(sess, obj, dsa_pri_attrs, count)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get DSA private key attributes (%s)."),
- pkcs11_strerror(rv));
- return (rv);
- }
-
- /* Fill in all the temp variables. They are all required. */
- i = 0;
- copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &prime);
- copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &subprime);
- copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &base);
- copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &value);
-
- /* Start the conversion to internal OpenSSL DSA structure. */
+ KMF_RETURN rv;
+ KMF_EXPORTP12_PARAMS p12parms;
- /* Prime p */
- if (cvt_bigint2bn(&prime, &(dsa->p)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DSA private key prime."));
- return (CKR_GENERAL_ERROR);
- }
+ (void) memset(&p12parms, 0, sizeof (p12parms));
- /* Subprime q */
- if (cvt_bigint2bn(&subprime, &(dsa->q)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DSA private key subprime."));
- return (CKR_GENERAL_ERROR);
- }
+ p12parms.kstype = KMF_KEYSTORE_OPENSSL;
+ p12parms.certLabel = NULL;
+ p12parms.issuer = NULL;
+ p12parms.subject = NULL;
+ p12parms.serial = 0;
+ p12parms.idstr = NULL;
+ p12parms.sslparms.dirpath = dir;
+ p12parms.sslparms.certfile = certfile;
+ p12parms.sslparms.keyfile = keyfile;
- /* Base g */
- if (cvt_bigint2bn(&base, &(dsa->g)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DSA private key base."));
- return (CKR_GENERAL_ERROR);
- }
+ (void) get_pk12_password(&p12parms.p12cred);
- /* Private key x */
- if (cvt_bigint2bn(&value, &(dsa->priv_key)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DSA private key value."));
- return (CKR_GENERAL_ERROR);
- }
+ rv = KMF_ExportPK12(kmfhandle, &p12parms, outfile);
- /* Create OpenSSL EVP PKEY struct in which to stuff DSA struct. */
- cryptodebug("calling EVP_PKEY_new");
- if ((key = EVP_PKEY_new()) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to allocate internal EVP_PKEY structure."));
- return (CKR_HOST_MEMORY);
- }
-
- /* Put the DSA struct into the EVP_PKEY struct and return it. */
- cryptodebug("calling EVP_PKEY_set1_DSA");
- (void) EVP_PKEY_set1_DSA(key, dsa);
+ if (p12parms.p12cred.cred)
+ free(p12parms.p12cred.cred);
- *pk = key;
- return (CKR_OK);
+ return (rv);
}
-/*
- * Convert PKCS#11 DH private key to OpenSSL EVP_PKEY structure.
- */
-static CK_RV
-cvt_dh2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk)
+static KMF_RETURN
+pk_export_nss_objects(KMF_HANDLE_T kmfhandle, char *token_spec,
+ int oclass, char *certlabel, char *issuer, char *subject,
+ KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt, char *dir,
+ char *prefix, char *filename)
{
- CK_RV rv = CKR_OK;
- EVP_PKEY *key = NULL; /* OpenSSL representation */
- DH *dh = NULL; /* OpenSSL representation */
- biginteger_t prime = { NULL, 0 }; /* required */
- biginteger_t base = { NULL, 0 }; /* required */
- biginteger_t value = { NULL, 0 }; /* required */
- CK_ATTRIBUTE dh_pri_attrs[3] = {
- { CKA_PRIME, NULL, 0 },
- { CKA_BASE, NULL, 0 },
- { CKA_VALUE, NULL, 0 }
- };
- CK_ULONG count = sizeof (dh_pri_attrs) / sizeof (CK_ATTRIBUTE);
- int i;
-
- cryptodebug("inside cvt_dh2evp_pkey");
-
- cryptodebug("calling DH_new");
- if ((dh = DH_new()) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to allocate internal DH structure."));
- return (CKR_HOST_MEMORY);
- }
+ KMF_RETURN rv = KMF_OK;
+ KMF_STORECERT_PARAMS scparms;
+ KMF_X509_DER_CERT kmfcert;
- /* Get the sizes of the attributes we need. */
- cryptodebug("calling C_GetAttributeValue for size info");
- if ((rv = C_GetAttributeValue(sess, obj, dh_pri_attrs, count)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get DH private key object attributes (%s)."),
- pkcs11_strerror(rv));
+ rv = configure_nss(kmfhandle, dir, prefix);
+ if (rv != KMF_OK)
return (rv);
- }
- /* Allocate memory for each attribute. */
- for (i = 0; i < count; i++) {
- if (dh_pri_attrs[i].ulValueLen == (CK_ULONG)-1 ||
- dh_pri_attrs[i].ulValueLen == 0) {
- cryptodebug("cvt_dh2evp_pkey: ***should not happen");
- dh_pri_attrs[i].ulValueLen = 0;
- continue;
- }
- if ((dh_pri_attrs[i].pValue =
- malloc(dh_pri_attrs[i].ulValueLen)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- return (CKR_HOST_MEMORY);
+ /* If searching for public objects or certificates, find certs now */
+ if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) {
+ KMF_FINDCERT_PARAMS fcargs;
+
+ (void) memset(&fcargs, 0, sizeof (fcargs));
+ fcargs.kstype = KMF_KEYSTORE_NSS;
+ fcargs.certLabel = certlabel;
+ fcargs.issuer = issuer;
+ fcargs.subject = subject;
+ fcargs.serial = serial;
+ fcargs.nssparms.slotlabel = token_spec;
+
+ rv = pk_find_export_cert(kmfhandle, &fcargs, &kmfcert);
+ if (rv == KMF_OK) {
+ (void) memset(&scparms, 0, sizeof (scparms));
+ scparms.kstype = KMF_KEYSTORE_OPENSSL;
+ scparms.sslparms.certfile = filename;
+ scparms.sslparms.format = kfmt;
+
+ rv = KMF_StoreCert(kmfhandle, &scparms,
+ &kmfcert.certificate);
+
+ KMF_FreeKMFCert(kmfhandle, &kmfcert);
}
}
+ return (rv);
+}
- /* Now really get the attributes. */
- cryptodebug("calling C_GetAttributeValue for attribute info");
- if ((rv = C_GetAttributeValue(sess, obj, dh_pri_attrs, count)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get DH private key attributes (%s)."),
- pkcs11_strerror(rv));
- return (rv);
- }
-
- /* Fill in all the temp variables. They are all required. */
- i = 0;
- copy_attr_to_bigint(&(dh_pri_attrs[i++]), &prime);
- copy_attr_to_bigint(&(dh_pri_attrs[i++]), &base);
- copy_attr_to_bigint(&(dh_pri_attrs[i++]), &value);
-
- /* Start the conversion to internal OpenSSL DH structure. */
+static KMF_RETURN
+pk_export_pk12_pk11(KMF_HANDLE_T kmfhandle, char *token_spec,
+ char *certlabel, char *issuer, char *subject,
+ KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred, char *filename)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_EXPORTP12_PARAMS p12parms;
- /* Prime p */
- if (cvt_bigint2bn(&prime, &(dh->p)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DH private key prime."));
- return (CKR_GENERAL_ERROR);
+ rv = select_token(kmfhandle, token_spec, TRUE);
+ if (rv != KMF_OK) {
+ return (rv);
}
- /* Base g */
- if (cvt_bigint2bn(&base, &(dh->g)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DH private key base."));
- return (CKR_GENERAL_ERROR);
- }
+ (void) memset(&p12parms, 0, sizeof (p12parms));
- /* Private value x */
- if (cvt_bigint2bn(&value, &(dh->priv_key)) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DH private key value."));
- return (CKR_GENERAL_ERROR);
- }
+ p12parms.kstype = KMF_KEYSTORE_PK11TOKEN;
+ p12parms.certLabel = certlabel;
+ p12parms.issuer = issuer;
+ p12parms.subject = subject;
+ p12parms.serial = serial;
+ p12parms.idstr = NULL;
+ if (tokencred != NULL)
+ p12parms.cred = *tokencred;
+ (void) get_pk12_password(&p12parms.p12cred);
- /* Create OpenSSL EVP PKEY struct in which to stuff DH struct. */
- cryptodebug("calling EVP_PKEY_new");
- if ((key = EVP_PKEY_new()) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to allocate internal EVP_PKEY structure."));
- return (CKR_HOST_MEMORY);
- }
+ rv = KMF_ExportPK12(kmfhandle, &p12parms, filename);
- /* Put the DH struct into the EVP_PKEY struct and return it. */
- cryptodebug("calling EVP_PKEY_set1_DH");
- (void) EVP_PKEY_set1_DH(key, dh);
+ if (p12parms.p12cred.cred)
+ free(p12parms.p12cred.cred);
- *pk = key;
- return (CKR_OK);
+ return (rv);
}
-/*
- * Convert PKCS#11 private key object to OpenSSL EVP_PKEY structure.
- */
-static CK_RV
-cvt_obj2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk)
+static KMF_RETURN
+pk_export_pk11_objects(KMF_HANDLE_T kmfhandle, char *token_spec,
+ char *certlabel, char *issuer, char *subject,
+ KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt,
+ char *filename)
{
- CK_RV rv = CKR_OK;
- static CK_KEY_TYPE keytype = 0;
- CK_ATTRIBUTE keytype_attr[1] = {
- { CKA_KEY_TYPE, &keytype, sizeof (keytype) }
- };
-
- cryptodebug("inside cvt_obj2evp_pkey");
-
- /* Find out the key type to do the right conversion. */
- cryptodebug("calling C_GetAttributeValue");
- if ((rv = C_GetAttributeValue(sess, obj, keytype_attr, 1)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get token object key type (%s)."),
- pkcs11_strerror(rv));
- return (rv);
- }
+ KMF_RETURN rv = KMF_OK;
+ KMF_FINDCERT_PARAMS fcparms;
+ KMF_STORECERT_PARAMS scparms;
+ KMF_X509_DER_CERT kmfcert;
- switch (keytype) {
- case CKK_RSA:
- cryptodebug("converting RSA key");
- return (cvt_rsa2evp_pkey(sess, obj, pk));
- case CKK_DSA:
- cryptodebug("converting DSA key");
- return (cvt_dsa2evp_pkey(sess, obj, pk));
- case CKK_DH:
- cryptodebug("converting DH key");
- return (cvt_dh2evp_pkey(sess, obj, pk));
- default:
- cryptoerror(LOG_STDERR, gettext(
- "Private key type 0x%02x conversion not supported."),
- keytype);
- return (CKR_GENERAL_ERROR);
- }
-}
-
-/*
- * Convert PKCS#11 certificate object to OpenSSL X509 structure.
- */
-static CK_RV
-cvt_cert2x509(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, X509 **c)
-{
- CK_RV rv = CKR_OK;
- X509 *cert = NULL; /* OpenSSL representation */
- X509 *temp_cert = NULL;
- CK_BYTE *subject = NULL;
- CK_ULONG subject_len = 0;
- CK_BYTE *value = NULL;
- CK_ULONG value_len = 0;
- CK_BYTE *label = NULL;
- CK_ULONG label_len = 0;
- CK_BYTE *id = NULL;
- CK_ULONG id_len = 0;
- CK_BYTE *issuer = NULL;
- CK_ULONG issuer_len = 0;
- CK_BYTE *serial = NULL;
- CK_ULONG serial_len = 0;
- CK_ATTRIBUTE cert_attrs[6] = {
- { CKA_SUBJECT, NULL, 0 }, /* required */
- { CKA_VALUE, NULL, 0 }, /* required */
- { CKA_LABEL, NULL, 0 }, /* optional */
- { CKA_ID, NULL, 0 }, /* optional */
- { CKA_ISSUER, NULL, 0 }, /* optional */
- { CKA_SERIAL_NUMBER, NULL, 0 } /* optional */
- };
- CK_ULONG count = sizeof (cert_attrs) / sizeof (CK_ATTRIBUTE);
- int i = 0;
- X509_NAME *ssl_subject = NULL;
- X509_NAME *ssl_issuer = NULL;
- ASN1_INTEGER *ssl_serial = NULL;
-
- cryptodebug("inside cvt_cert2x509");
-
- cryptodebug("calling X509_new");
- if ((cert = X509_new()) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to allocate internal X509 structure."));
- return (CKR_HOST_MEMORY);
- }
+ rv = select_token(kmfhandle, token_spec, TRUE);
- /* Get the sizes of the attributes we need. */
- cryptodebug("calling C_GetAttributeValue for size info");
- if ((rv = C_GetAttributeValue(sess, obj, cert_attrs, count)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get certificate attribute sizes (%s)."),
- pkcs11_strerror(rv));
+ if (rv != KMF_OK) {
return (rv);
}
- /* Allocate memory for each attribute. */
- for (i = 0; i < count; i++) {
- if (cert_attrs[i].ulValueLen == (CK_ULONG)-1 ||
- cert_attrs[i].ulValueLen == 0) {
- cryptodebug("cvt_cert2x509: *** should not happen");
- cert_attrs[i].ulValueLen = 0;
- continue;
- }
- if ((cert_attrs[i].pValue = malloc(cert_attrs[i].ulValueLen))
- == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- return (CKR_HOST_MEMORY);
- }
- }
+ (void) memset(&fcparms, 0, sizeof (fcparms));
+ fcparms.kstype = KMF_KEYSTORE_PK11TOKEN;
+ fcparms.certLabel = certlabel;
+ fcparms.issuer = issuer;
+ fcparms.subject = subject;
+ fcparms.serial = serial;
- /* Now really get the attributes. */
- cryptodebug("calling C_GetAttributeValue for attribute info");
- if ((rv = C_GetAttributeValue(sess, obj, cert_attrs, count)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get certificate attributes (%s)."),
- pkcs11_strerror(rv));
- return (rv);
- }
-
- /*
- * Fill in all the temp variables. Subject and value are required.
- * The rest are optional.
- */
- i = 0;
- copy_attr_to_string(&(cert_attrs[i++]), &subject, &subject_len);
- copy_attr_to_string(&(cert_attrs[i++]), &value, &value_len);
-
- if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 &&
- cert_attrs[i].ulValueLen != 0)
- copy_attr_to_string(&(cert_attrs[i]), &label, &label_len);
- i++;
-
- if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 &&
- cert_attrs[i].ulValueLen != 0)
- copy_attr_to_string(&(cert_attrs[i]), &id, &id_len);
- i++;
-
- if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 &&
- cert_attrs[i].ulValueLen != 0)
- copy_attr_to_string(&(cert_attrs[i]), &issuer, &issuer_len);
- i++;
-
- if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 &&
- cert_attrs[i].ulValueLen != 0)
- copy_attr_to_string(&(cert_attrs[i]), &serial, &serial_len);
- i++;
-
- /* Start the conversion to internal OpenSSL X509 structure. */
-
- /* Subject name (required) */
- cryptodebug("calling d2i_X509_NAME for subject name");
- if ((ssl_subject = d2i_X509_NAME(NULL,
- (const unsigned char **) &subject, subject_len)) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert certificate subject name."));
- return (CKR_GENERAL_ERROR);
- }
- cryptodebug("calling X509_set_subject_name");
- if (!X509_set_subject_name(cert, ssl_subject)) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to pack certificate subject name entries."));
- return (CKR_GENERAL_ERROR);
- }
-
- /* Label (optional) */
- cryptodebug("calling X509_alias_set1");
- if (!X509_alias_set1(cert, label, label_len))
- cryptodebug("error not caught");
-
- /* Id (optional) */
- cryptodebug("calling X509_keyid_set1");
- if (!X509_keyid_set1(cert, id, id_len))
- cryptodebug("error not caught");
-
- /* Issuer name (optional) */
- cryptodebug("calling d2i_X509_NAME for issuer name");
- if ((ssl_issuer = d2i_X509_NAME(NULL, (const unsigned char **) &issuer,
- issuer_len)) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert certificate issuer name."));
- return (CKR_GENERAL_ERROR);
- }
- cryptodebug("calling X509_set_issuer_name");
- if (!X509_set_issuer_name(cert, ssl_issuer)) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to pack certificate issuer name entries."));
- return (CKR_GENERAL_ERROR);
- }
-
- /* Serial number (optional) */
- cryptodebug("calling OPENSSL_malloc() for serial number");
- if ((ssl_serial = OPENSSL_malloc(sizeof (ASN1_INTEGER))) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert certificate serial number."));
- return (CKR_HOST_MEMORY);
- }
- ssl_serial->length = serial_len;
- ssl_serial->type = (serial[0] & 0x80) ? V_ASN1_NEG_INTEGER :
- V_ASN1_INTEGER;
- ssl_serial->data = serial;
- ssl_serial->flags = 0;
- cryptodebug("calling X509_set_serialNumber");
- if (!X509_set_serialNumber(cert, ssl_serial))
- cryptodebug("error not caught");
-
- /*
- * Value (required)
- *
- * The rest of this code takes the CKA_VALUE attribute, converts
- * it into a temp OpenSSL X509 structure and picks out the rest
- * of the fields we need to convert it back into the current X509
- * structure that will get exported. The reason we don't just
- * start with CKA_VALUE is because while the object was in the
- * softtoken, it is possible that some of its attributes changed.
- * Those changes would not appear in CKA_VALUE and would be lost
- * if we started with CKA_VALUE that was saved originally.
- */
- cryptodebug("calling d2i_X509 for cert value");
- if ((temp_cert = d2i_X509(NULL, (const unsigned char **) &value,
- value_len)) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert main certificate values."));
- return (CKR_GENERAL_ERROR);
- }
-
- /* Transfer these values from temp_cert to cert. */
- cryptodebug("calling X509_set_version/X509_get_version");
- if (!X509_set_version(cert, X509_get_version(temp_cert)))
- cryptodebug("error not caught");
-
- cryptodebug("calling X509_set_notBefore/X509_get_notBefore");
- if (!X509_set_notBefore(cert, X509_get_notBefore(temp_cert)))
- cryptodebug("error not caught");
-
- cryptodebug("calling X509_set_notAfter/X509_get_notAfter");
- if (!X509_set_notAfter(cert, X509_get_notAfter(temp_cert)))
- cryptodebug("error not caught");
-
- cryptodebug("calling X509_set_pubkey/X509_get_pubkey");
- if (!X509_set_pubkey(cert, X509_get_pubkey(temp_cert)))
- cryptodebug("error not caught");
-
- /*
- * These don't get transfered from temp_cert to cert.
- * It -appears- that they may get regenerated as needed.
- *
- * cert->cert_info->signature = dup(temp_cert->cert_info->signature);
- * cert->sig_alg = dup(temp_cert->sig_alg);
- * cert->signature = dup(temp_cert->signature);
- * cert->skid = dup(temp_cert->skid);
- * cert->akid = dup(temp_cert->akid);
- */
-
- *c = cert;
- return (CKR_OK);
-}
-
-static CK_RV
-convert_token_objs(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj,
- CK_OBJECT_HANDLE mate, CK_OBJECT_HANDLE *chain, CK_ULONG chain_len,
- EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca)
-{
- CK_RV rv = CKR_OK;
- EVP_PKEY *pk = NULL;
- X509 *c = NULL;
- X509 *one_ca = NULL;
- STACK_OF(X509) *ch = NULL;
- int i;
+ rv = pk_find_export_cert(kmfhandle, &fcparms, &kmfcert);
- cryptodebug("inside convert_token_objs");
+ if (rv == KMF_OK) {
+ (void) memset(&scparms, 0, sizeof (scparms));
+ scparms.kstype = KMF_KEYSTORE_OPENSSL;
+ scparms.sslparms.certfile = filename;
+ scparms.sslparms.format = kfmt;
- if ((rv = cvt_obj2evp_pkey(sess, obj, &pk)) != CKR_OK)
- return (rv);
-
- if (mate != ~0UL) {
- cryptodebug("converting cert corresponding to private key");
- if ((rv = cvt_cert2x509(sess, mate, &c)) != CKR_OK)
- return (rv);
- }
+ rv = KMF_StoreCert(kmfhandle, &scparms,
+ &kmfcert.certificate);
- if (chain_len != 0) {
- cryptodebug("converting ca chain of %d certs corresponding "
- "to private key", chain_len);
- ch = sk_X509_new_null();
- for (i = 0; i < chain_len; i++) {
- if ((rv = cvt_cert2x509(sess, chain[i], &one_ca)) !=
- CKR_OK) {
- return (rv);
- }
- if (!sk_X509_push(ch, one_ca))
- cryptodebug("error not caught");
- }
+ KMF_FreeKMFCert(kmfhandle, &kmfcert);
}
-
- *priv_key = pk;
- *cert = (mate != ~0UL) ? c : NULL;
- *ca = (chain_len != 0) ? ch : NULL;
- return (CKR_OK);
+ return (rv);
}
/*
- * Export objects from token to PKCS#12 file.
+ * Export objects from one keystore to a file.
*/
int
pk_export(int argc, char *argv[])
@@ -1210,231 +304,263 @@ pk_export(int argc, char *argv[])
extern int optind_av;
extern char *optarg_av;
char *token_spec = NULL;
- char *token_name = NULL;
- char *manuf_id = NULL;
- char *serial_no = NULL;
- char full_name[FULL_NAME_LEN];
char *filename = NULL;
- CK_SLOT_ID slot_id;
- CK_FLAGS pin_state;
- CK_UTF8CHAR_PTR pin = NULL;
- CK_ULONG pinlen = 0;
- CK_UTF8CHAR_PTR pk12pin = NULL;
- CK_ULONG pk12pinlen = 0;
- CK_SESSION_HANDLE sess;
- BIO *fbio = NULL;
- EVP_PKEY *priv_key = NULL;
- X509 *cert = NULL;
- STACK_OF(X509) *ca = NULL;
- CK_RV rv = CKR_OK;
- CK_OBJECT_HANDLE *objs = NULL;
- CK_ULONG num_objs = 0;
- CK_OBJECT_HANDLE mate = ~0UL;
- CK_OBJECT_HANDLE *chain = NULL;
- CK_ULONG chain_len;
- CK_BYTE *id = NULL;
- CK_ULONG id_len = 0;
- int i = 0;
- int good_ones = 0, bad_ones = 0; /* running totals */
-
- cryptodebug("inside pk_export");
+ char *dir = NULL;
+ char *prefix = NULL;
+ char *certlabel = NULL;
+ char *subject = NULL;
+ char *issuer = NULL;
+ char *infile = NULL;
+ char *keyfile = NULL;
+ char *certfile = NULL;
+ char *serstr = NULL;
+ KMF_KEYSTORE_TYPE kstype = 0;
+ KMF_ENCODE_FORMAT kfmt = KMF_FORMAT_PKCS12;
+ KMF_RETURN rv = KMF_OK;
+ int oclass = PK_CERT_OBJ;
+ KMF_BIGINT serial = { NULL, 0 };
+ KMF_HANDLE_T kmfhandle = NULL;
+ KMF_CREDENTIAL tokencred = {NULL, 0};
/* Parse command line options. Do NOT i18n/l10n. */
- while ((opt = getopt_av(argc, argv, "T:(token)o:(outfile)")) != EOF) {
+ while ((opt = getopt_av(argc, argv,
+ "k:(keystore)y:(objtype)T:(token)"
+ "d:(dir)p:(prefix)"
+ "l:(label)n:(nickname)s:(subject)"
+ "i:(issuer)S:(serial)"
+ "K:(keyfile)c:(certfile)"
+ "F:(outformat)"
+ "I:(infile)o:(outfile)")) != EOF) {
+ if (EMPTYSTRING(optarg_av))
+ return (PK_ERR_USAGE);
switch (opt) {
+ case 'k':
+ kstype = KS2Int(optarg_av);
+ if (kstype == 0)
+ return (PK_ERR_USAGE);
+ break;
+ case 'y':
+ oclass = OT2Int(optarg_av);
+ if (oclass == -1)
+ return (PK_ERR_USAGE);
+ break;
case 'T': /* token specifier */
if (token_spec)
return (PK_ERR_USAGE);
token_spec = optarg_av;
break;
+ case 'd':
+ if (dir)
+ return (PK_ERR_USAGE);
+ dir = optarg_av;
+ break;
+ case 'p':
+ if (prefix)
+ return (PK_ERR_USAGE);
+ prefix = optarg_av;
+ break;
+ case 'n':
+ case 'l':
+ if (certlabel)
+ return (PK_ERR_USAGE);
+ certlabel = optarg_av;
+ break;
+ case 's':
+ if (subject)
+ return (PK_ERR_USAGE);
+ subject = optarg_av;
+ break;
+ case 'i':
+ if (issuer)
+ return (PK_ERR_USAGE);
+ issuer = optarg_av;
+ break;
+ case 'S':
+ serstr = optarg_av;
+ break;
+ case 'F':
+ kfmt = Str2Format(optarg_av);
+ if (kfmt == KMF_FORMAT_UNDEF)
+ return (PK_ERR_USAGE);
+ break;
+ case 'I': /* output file name */
+ if (infile)
+ return (PK_ERR_USAGE);
+ infile = optarg_av;
+ break;
case 'o': /* output file name */
if (filename)
return (PK_ERR_USAGE);
filename = optarg_av;
break;
+ case 'c': /* input cert file name */
+ if (certfile)
+ return (PK_ERR_USAGE);
+ certfile = optarg_av;
+ break;
+ case 'K': /* input key file name */
+ if (keyfile)
+ return (PK_ERR_USAGE);
+ keyfile = optarg_av;
+ break;
default:
return (PK_ERR_USAGE);
break;
}
}
- /* If nothing is specified, default is to use softtoken. */
- if (token_spec == NULL) {
- token_name = SOFT_TOKEN_LABEL;
- manuf_id = SOFT_MANUFACTURER_ID;
- serial_no = SOFT_TOKEN_SERIAL;
- } else {
- /*
- * Parse token specifier into token_name, manuf_id, serial_no.
- * Token_name is required; manuf_id and serial_no are optional.
- */
- if (parse_token_spec(token_spec, &token_name, &manuf_id,
- &serial_no) < 0)
- return (PK_ERR_USAGE);
- }
+ /* Assume keystore = PKCS#11 if not specified */
+ if (kstype == 0)
+ kstype = KMF_KEYSTORE_PK11TOKEN;
/* Filename arg is required. */
- if (filename == NULL)
+ if (EMPTYSTRING(filename)) {
+ cryptoerror(LOG_STDERR, gettext("You must specify "
+ "an 'outfile' parameter when exporting.\n"));
return (PK_ERR_USAGE);
+ }
/* No additional args allowed. */
argc -= optind_av;
argv += optind_av;
if (argc)
return (PK_ERR_USAGE);
- /* Done parsing command line options. */
+
+ /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */
+ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) &&
+ kstype != KMF_KEYSTORE_PK11TOKEN) {
+
+ (void) fprintf(stderr, gettext("The objtype parameter "
+ "is only relevant if keystore=pkcs11\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec))
+ token_spec = PK_DEFAULT_PK11TOKEN;
+ else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec))
+ token_spec = DEFAULT_NSS_TOKEN;
+
+ if (kstype == KMF_KEYSTORE_OPENSSL) {
+ if (kfmt != KMF_FORMAT_PKCS12) {
+ cryptoerror(LOG_STDERR, gettext("PKCS12 "
+ "is the only export format "
+ "supported for the 'file' "
+ "keystore.\n"));
+ return (PK_ERR_USAGE);
+ }
+ if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) {
+ cryptoerror(LOG_STDERR, gettext("A cert file"
+ "and a key file must be specified "
+ "when exporting to PKCS12 from the "
+ "'file' keystore.\n"));
+ return (PK_ERR_USAGE);
+ }
+ }
/* Check if the file exists and might be overwritten. */
if (access(filename, F_OK) == 0) {
- cryptoerror(LOG_STDERR, gettext("Warning: file \"%s\" exists, "
- "will be overwritten."), filename);
+ cryptoerror(LOG_STDERR,
+ gettext("Warning: file \"%s\" exists, "
+ "will be overwritten."), filename);
if (yesno(gettext("Continue with export? "),
gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
return (0);
}
+ } else {
+ rv = verify_file(filename);
+ if (rv != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("The file (%s) "
+ "cannot be created.\n"), filename);
+ return (PK_ERR_USAGE);
+ }
}
- full_token_name(token_name, manuf_id, serial_no, full_name);
-
- /* Find the slot with token. */
- if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
- &pin_state)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to find token %s (%s)."), full_name,
- pkcs11_strerror(rv));
- return (PK_ERR_PK11);
- }
-
- /* Get the user's PIN. */
- if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin,
- &pinlen)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get token passphrase (%s)."),
- pkcs11_strerror(rv));
- quick_finish(NULL);
- return (PK_ERR_PK11);
- }
-
- /* Assume user must be logged in R/W to export objects from token. */
- if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR,
- gettext("Unable to log into token (%s)."),
- pkcs11_strerror(rv));
- quick_finish(sess);
- return (PK_ERR_PK11);
- }
+ if (serstr != NULL) {
+ uchar_t *bytes = NULL;
+ size_t bytelen;
- /* Collect all private keys first. */
- if ((rv = find_objs(sess, PK_PRIVATE_OBJ|PK_KEY_OBJ, NULL,
- &objs, &num_objs)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to retrieve private key token objects (%s)."),
- pkcs11_strerror(rv));
- quick_finish(sess);
- return (PK_ERR_PK11);
+ rv = KMF_HexString2Bytes((uchar_t *)serstr, &bytes, &bytelen);
+ if (rv != KMF_OK || bytes == NULL) {
+ (void) fprintf(stderr, gettext("serial number "
+ "must be specified as a hex number "
+ "(ex: 0x0102030405ffeeddee)\n"));
+ return (PK_ERR_USAGE);
+ }
+ serial.val = bytes;
+ serial.len = bytelen;
}
- /* Nothing to do? */
- if (num_objs == 0) {
- cryptoerror(LOG_STDERR, gettext("No objects found."));
- quick_finish(sess);
- return (0);
+ if ((kstype == KMF_KEYSTORE_PK11TOKEN ||
+ kstype == KMF_KEYSTORE_NSS) &&
+ (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ) ||
+ kfmt == KMF_FORMAT_PKCS12)) {
+ (void) get_token_password(kstype, token_spec,
+ &tokencred);
}
- /* Setup OpenSSL context. */
- PKTOOL_setup_openssl();
-
- /* Create PKCS#12 file. */
- if ((create_pkcs12(filename, &fbio)) < 0) {
- cryptoerror(LOG_STDERR, gettext("No export file created."));
- quick_finish(sess);
- return (PK_ERR_SYSTEM);
+ if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("Error initializing "
+ "KMF: 0x%02x\n"), rv);
+ return (rv);
}
- /* Get the PIN for the PKCS#12 export file. */
- if ((rv = get_pin(gettext("Create export file passphrase:"), gettext(
- "Re-enter export file passphrase:"), &pk12pin, &pk12pinlen)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR,
- gettext("Unable to get export file passphrase (%s)."),
- pkcs11_strerror(rv));
- close_pkcs12(fbio);
- quick_finish(sess);
- return (PK_ERR_PK11);
+ switch (kstype) {
+ case KMF_KEYSTORE_PK11TOKEN:
+ if (kfmt == KMF_FORMAT_PKCS12)
+ rv = pk_export_pk12_pk11(
+ kmfhandle,
+ token_spec,
+ certlabel,
+ issuer, subject,
+ &serial, &tokencred,
+ filename);
+ else
+ rv = pk_export_pk11_objects(kmfhandle,
+ token_spec,
+ certlabel,
+ issuer, subject,
+ &serial, kfmt,
+ filename);
+ break;
+ case KMF_KEYSTORE_NSS:
+ if (dir == NULL)
+ dir = PK_DEFAULT_DIRECTORY;
+ if (kfmt == KMF_FORMAT_PKCS12)
+ rv = pk_export_pk12_nss(kmfhandle,
+ token_spec, dir, prefix,
+ certlabel, issuer,
+ subject, &serial,
+ &tokencred, filename);
+ else
+ rv = pk_export_nss_objects(kmfhandle,
+ token_spec,
+ oclass, certlabel, issuer, subject,
+ &serial, kfmt, dir, prefix, filename);
+ break;
+ case KMF_KEYSTORE_OPENSSL:
+ if (kfmt == KMF_FORMAT_PKCS12)
+ rv = pk_export_pk12_files(kmfhandle,
+ certfile, keyfile, dir,
+ filename);
+ else
+ rv = pk_export_file_objects(kmfhandle, oclass,
+ issuer, subject, &serial, kfmt,
+ dir, infile, filename);
+ break;
+ default:
+ rv = PK_ERR_USAGE;
+ break;
}
- for (i = 0; i < num_objs; i++) {
- /* Get a private key and its certificate and CA chain. */
- if ((rv = get_token_objs(sess, objs[i], &mate, &chain,
- &chain_len, &id, &id_len)) != CKR_OK) {
- /*
- * Note this "rv" is either CKR_OK or !CKR_OK. The
- * real error codes/messages are handled inside
- * read_token_objs().
- */
- cryptoerror(LOG_STDERR,
- gettext("Unable to get token objects."));
- free(id);
- close_pkcs12(fbio);
- quick_finish(sess);
- return (PK_ERR_PK11);
- }
-
- /* Convert to OpenSSL equivalents. */
- if ((rv = convert_token_objs(sess, objs[i], mate, chain,
- chain_len, &priv_key, &cert, &ca)) != CKR_OK) {
- /*
- * Note this "rv" is either CKR_OK or !CKR_OK. The
- * real error codes/messages are handled inside
- * read_token_objs().
- */
- cryptoerror(LOG_STDERR,
- gettext("Unable to convert token objects."));
- free(id);
- close_pkcs12(fbio);
- quick_finish(sess);
- return (PK_ERR_PK11);
- }
-
- /*
- * When exporting of cert chains is implemented, these
- * messages should be updated accordingly.
- */
- if (mate == ~0UL)
- (void) fprintf(stdout, gettext(
- "Writing object #%d...\n"), i+1);
- else
- (void) fprintf(stdout, gettext("Writing object #%d "
- "and its certificate...\n"), i+1);
-
- /* Write object and its certs to the PKCS#12 export file. */
- if (write_objs_pkcs12(fbio, pk12pin, pk12pinlen, id, id_len,
- priv_key, cert, ca, &good_ones, &bad_ones) < 0) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to write object #%d to export file."), i+1);
- sk_X509_pop_free(ca, X509_free);
- free(id);
- close_pkcs12(fbio);
- quick_finish(sess);
- return (PK_ERR_OPENSSL);
- }
-
- /* Destroy key id and CA cert chain, done with them. */
- free(id);
- id = NULL;
- sk_X509_pop_free(ca, X509_free);
- ca = NULL;
+ if (rv != KMF_OK) {
+ display_error(kmfhandle, rv,
+ gettext("Error exporting objects"));
}
- (void) fprintf(stdout, gettext(
- "%d token objects exported, %d errors occurred.\n"),
- good_ones, bad_ones);
+ if (serial.val != NULL)
+ free(serial.val);
- /* Close PKCS#12 file. */
- close_pkcs12(fbio);
+ (void) KMF_Finalize(kmfhandle);
- /* Clean up. */
- quick_finish(sess);
- return (0);
+ return (rv);
}
diff --git a/usr/src/cmd/cmd-crypto/pktool/gencert.c b/usr/src/cmd/cmd-crypto/pktool/gencert.c
new file mode 100644
index 0000000000..ae79c579a4
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/gencert.c
@@ -0,0 +1,729 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <libgen.h>
+#include <errno.h>
+#include <cryptoutil.h>
+#include <security/cryptoki.h>
+#include "common.h"
+
+#include <kmfapi.h>
+
+#define SET_VALUE(f, s) \
+ kmfrv = f; \
+ if (kmfrv != KMF_OK) { \
+ cryptoerror(LOG_STDERR, \
+ gettext("Failed to set %s: 0x%02x\n"), \
+ s, kmfrv); \
+ goto cleanup; \
+ }
+
+static int
+gencert_pkcs11(KMF_HANDLE_T kmfhandle,
+ char *token, char *subject, char *altname,
+ KMF_GENERALNAMECHOICES alttype, int altcrit,
+ char *certlabel, KMF_KEY_ALG keyAlg,
+ KMF_ALGORITHM_INDEX sigAlg,
+ int keylen, uint32_t ltime, KMF_BIGINT *serial,
+ uint16_t kubits, int kucrit, KMF_CREDENTIAL *tokencred)
+{
+ KMF_RETURN kmfrv = KMF_OK;
+ KMF_CREATEKEYPAIR_PARAMS kp_params;
+ KMF_STORECERT_PARAMS sc_params;
+ KMF_KEY_HANDLE pubk, prik;
+ KMF_X509_CERTIFICATE signedCert;
+ KMF_X509_NAME certSubject;
+ KMF_X509_NAME certIssuer;
+ KMF_DATA x509DER;
+
+ (void) memset(&signedCert, 0, sizeof (signedCert));
+ (void) memset(&certSubject, 0, sizeof (certSubject));
+ (void) memset(&certIssuer, 0, sizeof (certIssuer));
+ (void) memset(&x509DER, 0, sizeof (x509DER));
+ (void) memset(&kp_params, 0, sizeof (kp_params));
+
+ /* If the subject name cannot be parsed, flag it now and exit */
+ if (KMF_DNParser(subject, &certSubject) != KMF_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Subject name cannot be parsed.\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ /* For a self-signed cert, the issuser and subject are the same */
+ if (KMF_DNParser(subject, &certIssuer) != KMF_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Subject name cannot be parsed.\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ kp_params.kstype = KMF_KEYSTORE_PK11TOKEN;
+ kp_params.keylabel = certlabel;
+ kp_params.keylength = keylen; /* bits */
+ kp_params.keytype = keyAlg;
+ kp_params.cred.cred = tokencred->cred;
+ kp_params.cred.credlen = tokencred->credlen;
+
+ /* Select a PKCS11 token */
+ kmfrv = select_token(kmfhandle, token, FALSE);
+
+ if (kmfrv != KMF_OK) {
+ return (kmfrv);
+ }
+
+ kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk);
+ if (kmfrv != KMF_OK) {
+ return (kmfrv);
+ }
+
+ SET_VALUE(KMF_SetCertPubKey(kmfhandle, &pubk, &signedCert),
+ "keypair");
+
+ SET_VALUE(KMF_SetCertVersion(&signedCert, 2), "version number");
+
+ SET_VALUE(KMF_SetCertSerialNumber(&signedCert, serial),
+ "serial number");
+
+ SET_VALUE(KMF_SetCertValidityTimes(&signedCert, NULL, ltime),
+ "validity time");
+
+ SET_VALUE(KMF_SetCertSignatureAlgorithm(&signedCert, sigAlg),
+ "signature algorithm");
+
+ SET_VALUE(KMF_SetCertSubjectName(&signedCert, &certSubject),
+ "subject name");
+
+ SET_VALUE(KMF_SetCertIssuerName(&signedCert, &certIssuer),
+ "issuer name");
+
+ if (altname != NULL)
+ SET_VALUE(KMF_SetCertSubjectAltName(&signedCert, altcrit,
+ alttype, altname), "subjectAltName");
+
+ if (kubits != 0)
+ SET_VALUE(KMF_SetCertKeyUsage(&signedCert, kucrit, kubits),
+ "KeyUsage");
+
+ if ((kmfrv = KMF_SignCertRecord(kmfhandle, &prik,
+ &signedCert, &x509DER)) != KMF_OK) {
+ goto cleanup;
+ }
+
+ (void) memset(&sc_params, 0, sizeof (sc_params));
+ sc_params.kstype = KMF_KEYSTORE_PK11TOKEN;
+ sc_params.certLabel = certlabel;
+
+ /*
+ * Store the cert in the DB.
+ */
+ kmfrv = KMF_StoreCert(kmfhandle, &sc_params, &x509DER);
+
+cleanup:
+ KMF_FreeData(&x509DER);
+ KMF_FreeDN(&certSubject);
+ KMF_FreeDN(&certIssuer);
+ return (kmfrv);
+}
+
+static int
+gencert_file(KMF_HANDLE_T kmfhandle,
+ KMF_KEY_ALG keyAlg, KMF_ALGORITHM_INDEX sigAlg,
+ int keylen, KMF_ENCODE_FORMAT fmt,
+ uint32_t ltime, char *subject, char *altname,
+ KMF_GENERALNAMECHOICES alttype, int altcrit,
+ KMF_BIGINT *serial, uint16_t kubits, int kucrit,
+ char *dir, char *outcert, char *outkey)
+{
+ KMF_RETURN kmfrv;
+ KMF_CREATEKEYPAIR_PARAMS kp_params;
+ KMF_STORECERT_PARAMS sc_params;
+ KMF_KEY_HANDLE pubk, prik;
+ KMF_X509_CERTIFICATE signedCert;
+ KMF_X509_NAME certSubject;
+ KMF_X509_NAME certIssuer;
+ KMF_DATA x509DER;
+ char *fullcertpath = NULL;
+ char *fullkeypath = NULL;
+
+ (void) memset(&signedCert, 0, sizeof (signedCert));
+ (void) memset(&certSubject, 0, sizeof (certSubject));
+ (void) memset(&certIssuer, 0, sizeof (certIssuer));
+ (void) memset(&x509DER, 0, sizeof (x509DER));
+ (void) memset(&kp_params, 0, sizeof (kp_params));
+ (void) memset(&sc_params, 0, sizeof (sc_params));
+
+ if (EMPTYSTRING(outcert) || EMPTYSTRING(outkey)) {
+ cryptoerror(LOG_STDERR,
+ gettext("No output file was specified for "
+ "the cert or key\n"));
+ return (PK_ERR_USAGE);
+ }
+ if (dir != NULL) {
+ fullcertpath = get_fullpath(dir, outcert);
+ if (fullcertpath == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("Cannot create file %s in "
+ "directory %s\n"), dir, outcert);
+ return (PK_ERR_USAGE);
+ }
+ } else {
+ fullcertpath = strdup(outcert);
+ }
+ if (verify_file(fullcertpath)) {
+ cryptoerror(LOG_STDERR,
+ gettext("Cannot write the indicated output "
+ "certificate file (%s).\n"),
+ fullcertpath);
+ free(fullcertpath);
+ return (PK_ERR_USAGE);
+ }
+ if (dir != NULL) {
+ fullkeypath = get_fullpath(dir, outkey);
+ if (fullkeypath == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("Cannot create file %s in "
+ "directory %s\n"), dir, outkey);
+ free(fullcertpath);
+ return (PK_ERR_USAGE);
+ }
+ } else {
+ fullkeypath = strdup(outkey);
+ }
+ if (verify_file(fullkeypath)) {
+ cryptoerror(LOG_STDERR,
+ gettext("Cannot write the indicated output "
+ "key file (%s).\n"),
+ fullkeypath);
+ free(fullkeypath);
+ free(fullcertpath);
+ return (PK_ERR_USAGE);
+ }
+
+ /* If the subject name cannot be parsed, flag it now and exit */
+ if (KMF_DNParser(subject, &certSubject) != KMF_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Subject name cannot be parsed (%s)\n"),
+ subject);
+ return (PK_ERR_USAGE);
+ }
+
+ /* For a self-signed cert, the issuser and subject are the same */
+ if (KMF_DNParser(subject, &certIssuer) != KMF_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Subject name cannot be parsed (%s)\n"),
+ subject);
+ KMF_FreeDN(&certSubject);
+ return (PK_ERR_USAGE);
+ }
+
+ kp_params.kstype = KMF_KEYSTORE_OPENSSL;
+ kp_params.keylength = keylen; /* bits */
+ kp_params.keytype = keyAlg;
+
+ kp_params.sslparms.keyfile = fullkeypath;
+ kp_params.sslparms.format = fmt;
+
+ kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk);
+ if (kmfrv != KMF_OK) {
+ goto cleanup;
+ }
+ SET_VALUE(KMF_SetCertPubKey(kmfhandle, &pubk, &signedCert),
+ "keypair");
+
+ SET_VALUE(KMF_SetCertVersion(&signedCert, 2), "version number");
+
+ SET_VALUE(KMF_SetCertSerialNumber(&signedCert, serial),
+ "serial number");
+
+ SET_VALUE(KMF_SetCertValidityTimes(&signedCert, NULL, ltime),
+ "validity time");
+
+ SET_VALUE(KMF_SetCertSignatureAlgorithm(&signedCert, sigAlg),
+ "signature algorithm");
+
+ SET_VALUE(KMF_SetCertSubjectName(&signedCert, &certSubject),
+ "subject name");
+
+ SET_VALUE(KMF_SetCertIssuerName(&signedCert, &certIssuer),
+ "issuer name");
+
+ if (altname != NULL)
+ SET_VALUE(KMF_SetCertSubjectAltName(&signedCert, altcrit,
+ alttype, altname), "subjectAltName");
+
+ if (kubits != 0)
+ SET_VALUE(KMF_SetCertKeyUsage(&signedCert, kucrit, kubits),
+ "KeyUsage");
+
+ if ((kmfrv = KMF_SignCertRecord(kmfhandle, &prik,
+ &signedCert, &x509DER)) != KMF_OK) {
+ goto cleanup;
+ }
+
+ sc_params.kstype = KMF_KEYSTORE_OPENSSL;
+ sc_params.sslparms.certfile = fullcertpath;
+ sc_params.sslparms.keyfile = fullkeypath;
+ sc_params.sslparms.format = fmt;
+ /*
+ * Store the cert in the DB.
+ */
+ kmfrv = KMF_StoreCert(kmfhandle, &sc_params, &x509DER);
+
+cleanup:
+ if (fullkeypath != NULL)
+ free(fullkeypath);
+ if (fullcertpath != NULL)
+ free(fullcertpath);
+
+ KMF_FreeData(&x509DER);
+ KMF_FreeDN(&certSubject);
+ KMF_FreeDN(&certIssuer);
+ return (kmfrv);
+}
+
+static KMF_RETURN
+gencert_nss(KMF_HANDLE_T kmfhandle,
+ char *token, char *subject, char *altname,
+ KMF_GENERALNAMECHOICES alttype, int altcrit,
+ char *nickname, char *dir, char *prefix,
+ KMF_KEY_ALG keyAlg,
+ KMF_ALGORITHM_INDEX sigAlg,
+ int keylen, char *trust,
+ uint32_t ltime, KMF_BIGINT *serial, uint16_t kubits,
+ int kucrit, KMF_CREDENTIAL *tokencred)
+{
+ KMF_RETURN kmfrv;
+ KMF_CREATEKEYPAIR_PARAMS kp_params;
+ KMF_STORECERT_PARAMS sc_params;
+ KMF_KEY_HANDLE pubk, prik;
+ KMF_X509_CERTIFICATE signedCert;
+ KMF_X509_NAME certSubject;
+ KMF_X509_NAME certIssuer;
+ KMF_DATA x509DER;
+
+ if (token == NULL)
+ token = DEFAULT_NSS_TOKEN;
+
+ kmfrv = configure_nss(kmfhandle, dir, prefix);
+ if (kmfrv != KMF_OK)
+ return (kmfrv);
+
+ (void) memset(&signedCert, 0, sizeof (signedCert));
+ (void) memset(&certSubject, 0, sizeof (certSubject));
+ (void) memset(&certIssuer, 0, sizeof (certIssuer));
+ (void) memset(&x509DER, 0, sizeof (x509DER));
+
+ /* If the subject name cannot be parsed, flag it now and exit */
+ if (KMF_DNParser(subject, &certSubject) != KMF_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Subject name cannot be parsed.\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ /* For a self-signed cert, the issuser and subject are the same */
+ if (KMF_DNParser(subject, &certIssuer) != KMF_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Subject name cannot be parsed.\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ (void) memset(&kp_params, 0, sizeof (kp_params));
+
+ kp_params.kstype = KMF_KEYSTORE_NSS;
+ kp_params.keylabel = nickname;
+ kp_params.keylength = keylen; /* bits */
+ kp_params.keytype = keyAlg;
+ kp_params.cred.cred = tokencred->cred;
+ kp_params.cred.credlen = tokencred->credlen;
+ kp_params.nssparms.slotlabel = token;
+
+ kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk);
+ if (kmfrv != KMF_OK) {
+ return (kmfrv);
+ }
+
+ SET_VALUE(KMF_SetCertPubKey(kmfhandle, &pubk, &signedCert),
+ "keypair");
+
+ SET_VALUE(KMF_SetCertVersion(&signedCert, 2), "version number");
+
+ SET_VALUE(KMF_SetCertSerialNumber(&signedCert, serial),
+ "serial number");
+
+ SET_VALUE(KMF_SetCertValidityTimes(&signedCert, NULL, ltime),
+ "validity time");
+
+ SET_VALUE(KMF_SetCertSignatureAlgorithm(&signedCert, sigAlg),
+ "signature algorithm");
+
+ SET_VALUE(KMF_SetCertSubjectName(&signedCert, &certSubject),
+ "subject name");
+
+ SET_VALUE(KMF_SetCertIssuerName(&signedCert, &certIssuer),
+ "issuer name");
+
+ if (altname != NULL)
+ SET_VALUE(KMF_SetCertSubjectAltName(&signedCert, altcrit,
+ alttype, altname), "subjectAltName");
+
+ if (kubits)
+ SET_VALUE(KMF_SetCertKeyUsage(&signedCert, kucrit, kubits),
+ "subjectAltName");
+
+ if ((kmfrv = KMF_SignCertRecord(kmfhandle, &prik,
+ &signedCert, &x509DER)) != KMF_OK) {
+ goto cleanup;
+ }
+
+ sc_params.kstype = KMF_KEYSTORE_NSS;
+ sc_params.certLabel = nickname;
+ sc_params.nssparms.trustflag = trust;
+ sc_params.nssparms.slotlabel = token;
+
+ /*
+ * Store the cert in the DB.
+ */
+ kmfrv = KMF_StoreCert(kmfhandle, &sc_params, &x509DER);
+
+cleanup:
+ KMF_FreeData(&x509DER);
+ KMF_FreeDN(&certSubject);
+ KMF_FreeDN(&certIssuer);
+ return (kmfrv);
+}
+
+int
+pk_gencert(int argc, char *argv[])
+{
+ int rv;
+ int opt;
+ extern int optind_av;
+ extern char *optarg_av;
+ KMF_KEYSTORE_TYPE kstype = 0;
+ char *subject = NULL;
+ char *tokenname = NULL;
+ char *dir = NULL;
+ char *prefix = NULL;
+ char *keytype = PK_DEFAULT_KEYTYPE;
+ int keylen = PK_DEFAULT_KEYLENGTH;
+ char *trust = NULL;
+ char *lifetime = NULL;
+ char *certlabel = NULL;
+ char *outcert = NULL;
+ char *outkey = NULL;
+ char *format = NULL;
+ char *serstr = NULL;
+ char *altname = NULL;
+ char *keyusagestr = NULL;
+ KMF_GENERALNAMECHOICES alttype = 0;
+ KMF_BIGINT serial = { NULL, 0 };
+ uint32_t ltime;
+ KMF_HANDLE_T kmfhandle = NULL;
+ KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1;
+ KMF_KEY_ALG keyAlg = KMF_RSA;
+ KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_MD5WithRSA;
+ boolean_t interactive = B_FALSE;
+ char *subname = NULL;
+ KMF_CREDENTIAL tokencred = {NULL, 0};
+ uint16_t kubits = 0;
+ int altcrit = 0, kucrit = 0;
+
+ while ((opt = getopt_av(argc, argv,
+ "ik:(keystore)s:(subject)n:(nickname)A:(altname)"
+ "T:(token)d:(dir)p:(prefix)t:(keytype)y:(keylen)"
+ "r:(trust)L:(lifetime)l:(label)c:(outcert)"
+ "K:(outkey)S:(serial)F:(format)u:(keyusage)")) != EOF) {
+
+ if (opt != 'i' && EMPTYSTRING(optarg_av))
+ return (PK_ERR_USAGE);
+
+ switch (opt) {
+ case 'A':
+ altname = optarg_av;
+ break;
+ case 'i':
+ if (interactive || subject)
+ return (PK_ERR_USAGE);
+ else
+ interactive = B_TRUE;
+ break;
+ case 'k':
+ kstype = KS2Int(optarg_av);
+ if (kstype == 0)
+ return (PK_ERR_USAGE);
+ break;
+ case 's':
+ if (interactive || subject)
+ return (PK_ERR_USAGE);
+ else
+ subject = optarg_av;
+ break;
+ case 'l':
+ case 'n':
+ if (certlabel)
+ return (PK_ERR_USAGE);
+ certlabel = optarg_av;
+ break;
+ case 'T':
+ if (tokenname)
+ return (PK_ERR_USAGE);
+ tokenname = optarg_av;
+ break;
+ case 'd':
+ if (dir)
+ return (PK_ERR_USAGE);
+ dir = optarg_av;
+ break;
+ case 'p':
+ if (prefix)
+ return (PK_ERR_USAGE);
+ prefix = optarg_av;
+ break;
+ case 't':
+ keytype = optarg_av;
+ break;
+ case 'u':
+ keyusagestr = optarg_av;
+ break;
+ case 'y':
+ if (sscanf(optarg_av, "%d",
+ &keylen) != 1) {
+ cryptoerror(LOG_STDERR,
+ gettext("key length must be"
+ "a numeric value (%s)\n"),
+ optarg_av);
+ return (PK_ERR_USAGE);
+ }
+ break;
+ case 'r':
+ if (trust)
+ return (PK_ERR_USAGE);
+ trust = optarg_av;
+ break;
+ case 'L':
+ if (lifetime)
+ return (PK_ERR_USAGE);
+ lifetime = optarg_av;
+ break;
+ case 'c':
+ if (outcert)
+ return (PK_ERR_USAGE);
+ outcert = optarg_av;
+ break;
+ case 'K':
+ if (outkey)
+ return (PK_ERR_USAGE);
+ outkey = optarg_av;
+ break;
+ case 'S':
+ serstr = optarg_av;
+ break;
+ case 'F':
+ if (format)
+ return (PK_ERR_USAGE);
+ format = optarg_av;
+ break;
+ default:
+ return (PK_ERR_USAGE);
+ }
+ }
+
+ /* No additional args allowed. */
+ argc -= optind_av;
+ argv += optind_av;
+ if (argc) {
+ return (PK_ERR_USAGE);
+ }
+
+ if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ /* Assume keystore = PKCS#11 if not specified. */
+ if (kstype == 0)
+ kstype = KMF_KEYSTORE_PK11TOKEN;
+
+ if ((kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) &&
+ EMPTYSTRING(certlabel)) {
+ cryptoerror(LOG_STDERR, gettext("A label must be specified "
+ "to create a self-signed certificate.\n"));
+ return (PK_ERR_USAGE);
+ } else if (kstype == KMF_KEYSTORE_OPENSSL && EMPTYSTRING(outcert)) {
+ cryptoerror(LOG_STDERR, gettext("A certificate filename must "
+ "be specified to create a self-signed certificate.\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) {
+ cryptoerror(LOG_STDERR,
+ gettext("Error parsing format string (%s).\n"),
+ format);
+ return (PK_ERR_USAGE);
+ }
+
+ if (Str2Lifetime(lifetime, &ltime) != 0) {
+ cryptoerror(LOG_STDERR,
+ gettext("Error parsing lifetime string\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ if (Str2KeyType(keytype, &keyAlg, &sigAlg) != 0) {
+ cryptoerror(LOG_STDERR, gettext("Unrecognized keytype (%s).\n"),
+ keytype);
+ return (PK_ERR_USAGE);
+ }
+
+
+ /*
+ * Check the subject name.
+ * If interactive is true, get it now interactively.
+ */
+ if (interactive) {
+ if (get_subname(&subname) != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("Failed to get the "
+ "subject name interactively.\n"));
+ return (PK_ERR_USAGE);
+ }
+ } else {
+ if (EMPTYSTRING(subject)) {
+ cryptoerror(LOG_STDERR, gettext("A subject name or "
+ "-i must be specified to create a self-signed "
+ "certificate.\n"));
+ return (PK_ERR_USAGE);
+ } else {
+ subname = strdup(subject);
+ if (subname == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("Out of memory.\n"));
+ return (PK_ERR_SYSTEM);
+ }
+ }
+ }
+
+ if (serstr == NULL) {
+ (void) fprintf(stderr, gettext("A serial number "
+ "must be specified as a hex number when creating"
+ " a self-signed certificate "
+ "(ex: serno=0x0102030405feedface)\n"));
+ rv = PK_ERR_USAGE;
+ goto end;
+ } else {
+ uchar_t *bytes = NULL;
+ size_t bytelen;
+
+ rv = KMF_HexString2Bytes((uchar_t *)serstr, &bytes, &bytelen);
+ if (rv != KMF_OK || bytes == NULL) {
+ (void) fprintf(stderr, gettext("serial number "
+ "must be specified as a hex number "
+ "(ex: 0x0102030405ffeeddee)\n"));
+ rv = PK_ERR_USAGE;
+ goto end;
+ }
+ serial.val = bytes;
+ serial.len = bytelen;
+ }
+
+ if (altname != NULL) {
+ rv = verify_altname(altname, &alttype, &altcrit);
+ if (rv != KMF_OK) {
+ (void) fprintf(stderr, gettext("Subject AltName "
+ "must be specified as a name=value pair. "
+ "See the man page for details.\n"));
+ rv = PK_ERR_USAGE;
+ goto end;
+ } else {
+ /* advance the altname past the '=' sign */
+ char *p = strchr(altname, '=');
+ if (p != NULL)
+ altname = p + 1;
+ }
+ }
+
+ if (keyusagestr != NULL) {
+ rv = verify_keyusage(keyusagestr, &kubits, &kucrit);
+ if (rv != KMF_OK) {
+ (void) fprintf(stderr, gettext("KeyUsage "
+ "must be specified as a comma-separated list. "
+ "See the man page for details.\n"));
+ rv = PK_ERR_USAGE;
+ goto end;
+ }
+ }
+
+ if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) {
+ if (tokenname == NULL || !strlen(tokenname)) {
+ if (kstype == KMF_KEYSTORE_NSS) {
+ tokenname = "internal";
+ } else {
+ tokenname = PK_DEFAULT_PK11TOKEN;
+ }
+ }
+
+ (void) get_token_password(kstype, tokenname, &tokencred);
+ }
+
+ if (kstype == KMF_KEYSTORE_NSS) {
+ if (dir == NULL)
+ dir = PK_DEFAULT_DIRECTORY;
+
+ rv = gencert_nss(kmfhandle,
+ tokenname, subname, altname, alttype, altcrit,
+ certlabel, dir, prefix, keyAlg, sigAlg, keylen,
+ trust, ltime, &serial, kubits, kucrit, &tokencred);
+
+ } else if (kstype == KMF_KEYSTORE_PK11TOKEN) {
+ rv = gencert_pkcs11(kmfhandle,
+ tokenname, subname, altname, alttype, altcrit,
+ certlabel, keyAlg, sigAlg, keylen, ltime,
+ &serial, kubits, kucrit, &tokencred);
+
+ } else if (kstype == KMF_KEYSTORE_OPENSSL) {
+ rv = gencert_file(kmfhandle,
+ keyAlg, sigAlg, keylen, fmt,
+ ltime, subname, altname, alttype, altcrit,
+ &serial, kubits, kucrit, dir, outcert, outkey);
+ }
+
+ if (rv != KMF_OK)
+ display_error(kmfhandle, rv,
+ gettext("Error creating certificate and keypair"));
+end:
+ if (subname)
+ free(subname);
+ if (tokencred.cred != NULL)
+ free(tokencred.cred);
+
+ if (serial.val != NULL)
+ free(serial.val);
+
+ (void) KMF_Finalize(kmfhandle);
+ return (rv);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/gencsr.c b/usr/src/cmd/cmd-crypto/pktool/gencsr.c
new file mode 100644
index 0000000000..fcc00d01c8
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/gencsr.c
@@ -0,0 +1,631 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <libgen.h>
+#include <errno.h>
+#include <cryptoutil.h>
+#include <security/cryptoki.h>
+#include "common.h"
+
+#include <kmfapi.h>
+
+#define SET_VALUE(f, s) \
+ kmfrv = f; \
+ if (kmfrv != KMF_OK) { \
+ cryptoerror(LOG_STDERR, \
+ gettext("Failed to %s: 0x%02\n"), \
+ s, kmfrv); \
+ goto cleanup; \
+ }
+
+static KMF_RETURN
+gencsr_pkcs11(KMF_HANDLE_T kmfhandle,
+ char *token, char *subject, char *altname,
+ KMF_GENERALNAMECHOICES alttype, int altcrit,
+ char *certlabel, KMF_KEY_ALG keyAlg,
+ int keylen,
+ uint16_t kubits, int kucrit,
+ KMF_ENCODE_FORMAT fmt, char *csrfile,
+ KMF_CREDENTIAL *tokencred)
+{
+ KMF_RETURN kmfrv = KMF_OK;
+ KMF_CREATEKEYPAIR_PARAMS kp_params;
+ KMF_DELETEKEY_PARAMS dk_params;
+ KMF_KEY_HANDLE pubk, prik;
+ KMF_X509_NAME csrSubject;
+ KMF_CSR_DATA csr;
+ KMF_ALGORITHM_INDEX sigAlg;
+ KMF_DATA signedCsr = {NULL, 0};
+
+ (void) memset(&csr, 0, sizeof (csr));
+ (void) memset(&csrSubject, 0, sizeof (csrSubject));
+ (void) memset(&kp_params, 0, sizeof (kp_params));
+
+ if (keyAlg == KMF_DSA)
+ sigAlg = KMF_ALGID_SHA1WithDSA;
+ else
+ sigAlg = KMF_ALGID_MD5WithRSA;
+
+
+ /* If the subject name cannot be parsed, flag it now and exit */
+ if ((kmfrv = KMF_DNParser(subject, &csrSubject)) != KMF_OK) {
+ return (kmfrv);
+ }
+
+ kp_params.kstype = KMF_KEYSTORE_PK11TOKEN;
+ kp_params.keylabel = certlabel;
+ kp_params.keylength = keylen; /* bits */
+ kp_params.keytype = keyAlg;
+ kp_params.cred.cred = tokencred->cred;
+ kp_params.cred.credlen = tokencred->credlen;
+
+ /* Select a PKCS11 token */
+ kmfrv = select_token(kmfhandle, token, FALSE);
+ if (kmfrv != KMF_OK) {
+ return (kmfrv);
+ }
+
+ kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk);
+ if (kmfrv != KMF_OK) {
+ return (kmfrv);
+ }
+
+ 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 (altname != NULL) {
+ SET_VALUE(KMF_SetCSRSubjectAltName(&csr, altname, altcrit,
+ alttype), "SetCSRSubjectAltName");
+ }
+
+ if (kubits != 0) {
+ SET_VALUE(KMF_SetCSRKeyUsage(&csr, kucrit, kubits),
+ "SetCSRKeyUsage");
+ }
+
+ if ((kmfrv = KMF_SignCSR(kmfhandle, &csr, &prik, &signedCsr)) ==
+ KMF_OK) {
+ kmfrv = KMF_CreateCSRFile(&signedCsr, fmt, csrfile);
+ }
+
+cleanup:
+ (void) KMF_FreeData(&signedCsr);
+ (void) KMF_FreeKMFKey(kmfhandle, &prik);
+ /* delete the key */
+ (void) memset(&dk_params, 0, sizeof (dk_params));
+ dk_params.kstype = KMF_KEYSTORE_PK11TOKEN;
+ (void) KMF_DeleteKeyFromKeystore(kmfhandle, &dk_params, &pubk);
+ (void) KMF_FreeSignedCSR(&csr);
+
+ return (kmfrv);
+}
+
+static KMF_RETURN
+gencsr_file(KMF_HANDLE_T kmfhandle,
+ KMF_KEY_ALG keyAlg,
+ int keylen, KMF_ENCODE_FORMAT fmt,
+ char *subject, char *altname, KMF_GENERALNAMECHOICES alttype,
+ int altcrit, uint16_t kubits, int kucrit,
+ char *dir, char *outcsr, char *outkey)
+{
+ KMF_RETURN kmfrv;
+ KMF_CREATEKEYPAIR_PARAMS kp_params;
+ KMF_KEY_HANDLE pubk, prik;
+ KMF_X509_NAME csrSubject;
+ KMF_CSR_DATA csr;
+ KMF_ALGORITHM_INDEX sigAlg;
+ KMF_DATA signedCsr = {NULL, 0};
+ char *fullcsrpath = NULL;
+ char *fullkeypath = NULL;
+
+ (void) memset(&csr, 0, sizeof (csr));
+ (void) memset(&csrSubject, 0, sizeof (csrSubject));
+ (void) memset(&kp_params, 0, sizeof (kp_params));
+
+ if (EMPTYSTRING(outcsr) || EMPTYSTRING(outkey)) {
+ cryptoerror(LOG_STDERR,
+ gettext("No output file was specified for "
+ "the csr or key\n"));
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ if (dir != NULL) {
+ fullcsrpath = get_fullpath(dir, outcsr);
+ if (fullcsrpath == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("Cannot create file %s in "
+ "directory %s\n"), dir, outcsr);
+ return (PK_ERR_USAGE);
+ }
+ } else {
+ fullcsrpath = strdup(outcsr);
+ }
+ if (verify_file(fullcsrpath)) {
+ cryptoerror(LOG_STDERR,
+ gettext("Cannot write the indicated output "
+ "certificate file (%s).\n"), fullcsrpath);
+ free(fullcsrpath);
+ return (PK_ERR_USAGE);
+ }
+ if (dir != NULL) {
+ fullkeypath = get_fullpath(dir, outkey);
+ if (fullkeypath == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("Cannot create file %s in "
+ "directory %s\n"), dir, outkey);
+ free(fullcsrpath);
+ return (PK_ERR_USAGE);
+ }
+ } else {
+ fullkeypath = strdup(outkey);
+ }
+ if (verify_file(fullcsrpath)) {
+ cryptoerror(LOG_STDERR,
+ gettext("Cannot write the indicated output "
+ "key file (%s).\n"), fullkeypath);
+ free(fullcsrpath);
+ return (PK_ERR_USAGE);
+ }
+
+ if (keyAlg == KMF_DSA)
+ sigAlg = KMF_ALGID_SHA1WithDSA;
+ else
+ sigAlg = KMF_ALGID_MD5WithRSA;
+
+ /* If the subject name cannot be parsed, flag it now and exit */
+ if ((kmfrv = KMF_DNParser(subject, &csrSubject)) != KMF_OK) {
+ return (kmfrv);
+ }
+
+ kp_params.kstype = KMF_KEYSTORE_OPENSSL;
+ kp_params.keylength = keylen; /* bits */
+ kp_params.keytype = keyAlg;
+
+ kp_params.sslparms.keyfile = fullkeypath;
+ kp_params.sslparms.format = fmt;
+
+ kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk);
+ if (kmfrv != KMF_OK) {
+ goto cleanup;
+ }
+ SET_VALUE(KMF_SetCSRPubKey(kmfhandle, &pubk, &csr),
+ "SetCSRPubKey");
+
+ SET_VALUE(KMF_SetCSRVersion(&csr, 2), "SetCSRVersion");
+
+ SET_VALUE(KMF_SetCSRSubjectName(&csr, &csrSubject),
+ "SetCSRSubjectName");
+
+ SET_VALUE(KMF_SetCSRSignatureAlgorithm(&csr, sigAlg),
+ "SetCSRSignatureAlgorithm");
+
+ if (altname != NULL) {
+ SET_VALUE(KMF_SetCSRSubjectAltName(&csr, altname, altcrit,
+ alttype), "SetCSRSubjectAltName");
+ }
+ if (kubits != NULL) {
+ SET_VALUE(KMF_SetCSRKeyUsage(&csr, kucrit, kubits),
+ "SetCSRKeyUsage");
+ }
+ if ((kmfrv = KMF_SignCSR(kmfhandle, &csr, &prik, &signedCsr)) ==
+ KMF_OK) {
+ kmfrv = KMF_CreateCSRFile(&signedCsr, fmt, fullcsrpath);
+ }
+
+cleanup:
+ if (fullkeypath)
+ free(fullkeypath);
+ if (fullcsrpath)
+ free(fullcsrpath);
+
+ KMF_FreeData(&signedCsr);
+ KMF_FreeKMFKey(kmfhandle, &prik);
+ KMF_FreeSignedCSR(&csr);
+
+ return (kmfrv);
+}
+
+static KMF_RETURN
+gencsr_nss(KMF_HANDLE_T kmfhandle,
+ char *token, char *subject, char *altname,
+ KMF_GENERALNAMECHOICES alttype, int altcrit,
+ char *nickname, char *dir, char *prefix,
+ KMF_KEY_ALG keyAlg, int keylen,
+ uint16_t kubits, int kucrit,
+ KMF_ENCODE_FORMAT fmt, char *csrfile,
+ KMF_CREDENTIAL *tokencred)
+{
+ KMF_RETURN kmfrv;
+ KMF_CREATEKEYPAIR_PARAMS kp_params;
+ KMF_KEY_HANDLE pubk, prik;
+ KMF_X509_NAME csrSubject;
+ KMF_CSR_DATA csr;
+ KMF_ALGORITHM_INDEX sigAlg;
+ KMF_DATA signedCsr = {NULL, 0};
+ KMF_DELETEKEY_PARAMS dk_params;
+
+ if (token == NULL)
+ token = DEFAULT_NSS_TOKEN;
+
+ if (keyAlg == KMF_DSA)
+ sigAlg = KMF_ALGID_SHA1WithDSA;
+ else
+ sigAlg = KMF_ALGID_MD5WithRSA;
+
+ kmfrv = configure_nss(kmfhandle, dir, prefix);
+ if (kmfrv != KMF_OK)
+ return (kmfrv);
+
+ (void) memset(&csr, 0, sizeof (csr));
+ (void) memset(&csrSubject, 0, sizeof (csrSubject));
+
+ /* If the subject name cannot be parsed, flag it now and exit */
+ if ((kmfrv = KMF_DNParser(subject, &csrSubject)) != KMF_OK) {
+ return (kmfrv);
+ }
+
+ (void) memset(&kp_params, 0, sizeof (kp_params));
+
+ kp_params.kstype = KMF_KEYSTORE_NSS;
+ kp_params.keylabel = nickname;
+ kp_params.keylength = keylen; /* bits */
+ kp_params.keytype = keyAlg;
+ kp_params.cred.cred = tokencred->cred;
+ kp_params.cred.credlen = tokencred->credlen;
+ kp_params.nssparms.slotlabel = token;
+
+ kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk);
+ if (kmfrv != KMF_OK) {
+ goto cleanup;
+ }
+
+ SET_VALUE(KMF_SetCSRPubKey(kmfhandle, &pubk, &csr), "SetCSRPubKey");
+ SET_VALUE(KMF_SetCSRVersion(&csr, 2), "SetCSRVersion");
+ SET_VALUE(KMF_SetCSRSubjectName(&csr, &csrSubject),
+ "SetCSRSubjectName");
+ SET_VALUE(KMF_SetCSRSignatureAlgorithm(&csr, sigAlg),
+ "SetCSRSignatureAlgorithm");
+
+ if (altname != NULL) {
+ SET_VALUE(KMF_SetCSRSubjectAltName(&csr, altname, altcrit,
+ alttype), "SetCSRSubjectAltName");
+ }
+ if (kubits != NULL) {
+ SET_VALUE(KMF_SetCSRKeyUsage(&csr, kucrit, kubits),
+ "SetCSRKeyUsage");
+ }
+ if ((kmfrv = KMF_SignCSR(kmfhandle, &csr, &prik, &signedCsr)) ==
+ KMF_OK) {
+ kmfrv = KMF_CreateCSRFile(&signedCsr, fmt, csrfile);
+ }
+
+cleanup:
+ (void) KMF_FreeData(&signedCsr);
+ (void) KMF_FreeKMFKey(kmfhandle, &prik);
+ /* delete the key */
+ (void) memset(&dk_params, 0, sizeof (dk_params));
+ dk_params.kstype = KMF_KEYSTORE_NSS;
+ dk_params.cred.cred = tokencred->cred;
+ dk_params.cred.credlen = tokencred->credlen;
+ dk_params.nssparms.slotlabel = token;
+ (void) KMF_DeleteKeyFromKeystore(kmfhandle, &dk_params, &pubk);
+ (void) KMF_FreeSignedCSR(&csr);
+
+ return (kmfrv);
+}
+
+int
+pk_gencsr(int argc, char *argv[])
+{
+ KMF_RETURN rv;
+ int opt;
+ extern int optind_av;
+ extern char *optarg_av;
+ KMF_KEYSTORE_TYPE kstype = 0;
+ char *subject = NULL;
+ char *tokenname = NULL;
+ char *dir = NULL;
+ char *prefix = NULL;
+ int keylen = PK_DEFAULT_KEYLENGTH;
+ char *certlabel = NULL;
+ char *outcsr = NULL;
+ char *outkey = NULL;
+ char *format = NULL;
+ char *altname = NULL;
+ char *kustr = NULL;
+ uint16_t kubits = 0;
+ char *keytype = PK_DEFAULT_KEYTYPE;
+ KMF_HANDLE_T kmfhandle = NULL;
+ KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1;
+ KMF_KEY_ALG keyAlg = KMF_RSA;
+ KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_MD5WithRSA;
+ boolean_t interactive = B_FALSE;
+ char *subname = NULL;
+ KMF_CREDENTIAL tokencred = {NULL, 0};
+ KMF_GENERALNAMECHOICES alttype = 0;
+ int altcrit = 0, kucrit = 0;
+
+ while ((opt = getopt_av(argc, argv,
+ "ik:(keystore)s:(subject)n:(nickname)A:(altname)"
+ "u:(keyusage)T:(token)d:(dir)p:(prefix)t:(keytype)"
+ "y:(keylen)l:(label)c:(outcsr)"
+ "K:(outkey)F:(format)")) != EOF) {
+
+ if (opt != 'i' && EMPTYSTRING(optarg_av))
+ return (PK_ERR_USAGE);
+
+ switch (opt) {
+ case 'A':
+ altname = optarg_av;
+ break;
+ case 'i':
+ if (interactive || subject)
+ return (PK_ERR_USAGE);
+ else
+ interactive = B_TRUE;
+ break;
+ case 'k':
+ kstype = KS2Int(optarg_av);
+ if (kstype == 0)
+ return (PK_ERR_USAGE);
+ break;
+ case 's':
+ if (interactive || subject)
+ return (PK_ERR_USAGE);
+ else
+ subject = optarg_av;
+ break;
+ case 'l':
+ case 'n':
+ if (certlabel)
+ return (PK_ERR_USAGE);
+ certlabel = optarg_av;
+ break;
+ case 'T':
+ if (tokenname)
+ return (PK_ERR_USAGE);
+ tokenname = optarg_av;
+ break;
+ case 'd':
+ dir = optarg_av;
+ break;
+ case 'p':
+ if (prefix)
+ return (PK_ERR_USAGE);
+ prefix = optarg_av;
+ break;
+ case 't':
+ keytype = optarg_av;
+ break;
+ case 'u':
+ kustr = optarg_av;
+ break;
+ case 'y':
+ if (sscanf(optarg_av, "%d",
+ &keylen) != 1) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unrecognized "
+ "key length (%s)\n"),
+ optarg_av);
+ return (PK_ERR_USAGE);
+ }
+ break;
+ case 'c':
+ if (outcsr)
+ return (PK_ERR_USAGE);
+ outcsr = optarg_av;
+ break;
+ case 'K':
+ if (outkey)
+ return (PK_ERR_USAGE);
+ outkey = optarg_av;
+ break;
+ case 'F':
+ if (format)
+ return (PK_ERR_USAGE);
+ format = optarg_av;
+ break;
+ default:
+ cryptoerror(LOG_STDERR, gettext(
+ "unrecognized gencsr option '%s'\n"),
+ argv[optind_av]);
+ return (PK_ERR_USAGE);
+ }
+ }
+ /* No additional args allowed. */
+ argc -= optind_av;
+ argv += optind_av;
+ if (argc) {
+ return (PK_ERR_USAGE);
+ }
+
+ if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ /* Assume keystore = PKCS#11 if not specified. */
+ if (kstype == 0)
+ kstype = KMF_KEYSTORE_PK11TOKEN;
+
+ if (EMPTYSTRING(outcsr)) {
+ (void) printf(gettext("A filename must be specified to hold"
+ "the final certificate request data.\n"));
+ return (PK_ERR_USAGE);
+ } else {
+ /*
+ * verify that the outcsr file does not already exist
+ * and that it can be created.
+ */
+ rv = verify_file(outcsr);
+ if (rv != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("output file (%s) "
+ "cannot be created.\n"), outcsr);
+ return (PK_ERR_USAGE);
+ }
+ }
+
+ if ((kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) &&
+ EMPTYSTRING(certlabel)) {
+ cryptoerror(LOG_STDERR, gettext("A label must be specified "
+ "to create a certificate request.\n"));
+ return (PK_ERR_USAGE);
+ } else if (kstype == KMF_KEYSTORE_OPENSSL && EMPTYSTRING(outkey)) {
+ cryptoerror(LOG_STDERR, gettext("A key filename must be "
+ "specified to create a certificate request.\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) {
+ cryptoerror(LOG_STDERR,
+ gettext("Error parsing format string (%s).\n"),
+ format);
+ return (PK_ERR_USAGE);
+ }
+ if (format && fmt != KMF_FORMAT_ASN1 && fmt != KMF_FORMAT_PEM) {
+ cryptoerror(LOG_STDERR,
+ gettext("CSR must be DER or PEM format.\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ /*
+ * Check the subject name.
+ * If interactive is true, get it now interactively.
+ */
+ if (interactive) {
+ if (get_subname(&subname) != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("Failed to get the "
+ "subject name interactively.\n"));
+ return (PK_ERR_USAGE);
+ }
+ } else {
+ if (EMPTYSTRING(subject)) {
+ cryptoerror(LOG_STDERR, gettext("A subject name or "
+ "-i must be specified to create a certificate "
+ "request.\n"));
+ return (PK_ERR_USAGE);
+ } else {
+ subname = strdup(subject);
+ if (subname == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("Out of memory.\n"));
+ return (PK_ERR_SYSTEM);
+ }
+ }
+ }
+ if (altname != NULL) {
+ rv = verify_altname(altname, &alttype, &altcrit);
+ if (rv != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("Subject AltName "
+ "must be specified as a name=value pair. "
+ "See the man page for details."));
+ goto end;
+ } else {
+ /* advance the altname past the '=' sign */
+ char *p = strchr(altname, '=');
+ if (p != NULL)
+ altname = p + 1;
+ }
+ }
+
+ if (kustr != NULL) {
+ rv = verify_keyusage(kustr, &kubits, &kucrit);
+ if (rv != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("KeyUsage "
+ "must be specified as a comma-separated list. "
+ "See the man page for details."));
+ goto end;
+ }
+ }
+ if ((rv = Str2KeyType(keytype, &keyAlg, &sigAlg)) != 0) {
+ cryptoerror(LOG_STDERR, gettext("Unrecognized keytype (%s).\n"),
+ keytype);
+ goto end;
+ }
+
+ if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) {
+ if (tokenname == NULL || !strlen(tokenname)) {
+ if (kstype == KMF_KEYSTORE_NSS) {
+ tokenname = "internal";
+ } else {
+ tokenname = PK_DEFAULT_PK11TOKEN;
+ }
+ }
+
+ (void) get_token_password(kstype, tokenname, &tokencred);
+ }
+
+ if (kstype == KMF_KEYSTORE_NSS) {
+ if (dir == NULL)
+ dir = PK_DEFAULT_DIRECTORY;
+
+ rv = gencsr_nss(kmfhandle,
+ tokenname, subname, altname, alttype, altcrit,
+ certlabel, dir, prefix,
+ keyAlg, keylen, kubits, kucrit,
+ fmt, outcsr, &tokencred);
+
+ } else if (kstype == KMF_KEYSTORE_PK11TOKEN) {
+ rv = gencsr_pkcs11(kmfhandle,
+ tokenname, subname, altname, alttype, altcrit,
+ certlabel, keyAlg, keylen,
+ kubits, kucrit, fmt, outcsr, &tokencred);
+
+ } else if (kstype == KMF_KEYSTORE_OPENSSL) {
+ rv = gencsr_file(kmfhandle,
+ keyAlg, keylen, fmt, subname, altname,
+ alttype, altcrit, kubits, kucrit,
+ dir, outcsr, outkey);
+ }
+
+end:
+ if (rv != KMF_OK)
+ display_error(kmfhandle, rv,
+ gettext("Error creating CSR or keypair"));
+
+ if (subname)
+ free(subname);
+
+ if (tokencred.cred != NULL)
+ free(tokencred.cred);
+
+ (void) KMF_Finalize(kmfhandle);
+ if (rv != KMF_OK)
+ return (PK_ERR_USAGE);
+
+ return (0);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/genkey.c b/usr/src/cmd/cmd-crypto/pktool/genkey.c
new file mode 100644
index 0000000000..f94093029e
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/genkey.c
@@ -0,0 +1,450 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <libgen.h>
+#include <errno.h>
+#include <cryptoutil.h>
+#include <security/cryptoki.h>
+#include "common.h"
+#include <kmfapi.h>
+
+
+static KMF_RETURN
+genkey_nss(KMF_HANDLE_T kmfhandle, char *token, char *dir, char *prefix,
+ char *keylabel, KMF_KEY_ALG keyAlg, int keylen, KMF_CREDENTIAL *tokencred)
+{
+ KMF_RETURN kmfrv = KMF_OK;
+ KMF_CREATESYMKEY_PARAMS csk_params;
+ KMF_KEY_HANDLE key;
+
+ if (keylabel == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("A key label must be specified \n"));
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ kmfrv = configure_nss(kmfhandle, dir, prefix);
+ if (kmfrv != KMF_OK)
+ return (kmfrv);
+
+ (void) memset(&key, 0, sizeof (KMF_KEY_HANDLE));
+ csk_params.kstype = KMF_KEYSTORE_NSS;
+ csk_params.nssparms.slotlabel = token;
+ csk_params.keytype = keyAlg;
+ csk_params.keylength = keylen;
+ csk_params.keylabel = keylabel;
+ csk_params.cred.cred = tokencred->cred;
+ csk_params.cred.credlen = tokencred->credlen;
+ kmfrv = KMF_CreateSymKey(kmfhandle, &csk_params, &key);
+
+ return (kmfrv);
+}
+
+static KMF_RETURN
+genkey_pkcs11(KMF_HANDLE_T kmfhandle, char *token,
+ char *keylabel, KMF_KEY_ALG keyAlg, int keylen,
+ char *senstr, char *extstr, boolean_t print_hex,
+ KMF_CREDENTIAL *tokencred)
+{
+ KMF_RETURN kmfrv = KMF_OK;
+ KMF_CREATESYMKEY_PARAMS params;
+ KMF_KEY_HANDLE key;
+ KMF_RAW_SYM_KEY *rkey = NULL;
+ boolean_t sensitive = B_FALSE;
+ boolean_t not_extractable = B_FALSE;
+ char *hexstr = NULL;
+ int hexstrlen;
+
+ if (keylabel == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("A key label must be specified \n"));
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* Check the sensitive option value if specified. */
+ if (senstr != NULL) {
+ if (tolower(senstr[0]) == 'y')
+ sensitive = B_TRUE;
+ else if (tolower(senstr[0]) == 'n')
+ sensitive = B_FALSE;
+ else {
+ cryptoerror(LOG_STDERR,
+ gettext("Incorrect sensitive option value.\n"));
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ }
+
+ /* Check the extractable option value if specified. */
+ if (extstr != NULL) {
+ if (tolower(extstr[0]) == 'y')
+ not_extractable = B_FALSE;
+ else if (tolower(extstr[0]) == 'n')
+ not_extractable = B_TRUE;
+ else {
+ cryptoerror(LOG_STDERR,
+ gettext("Incorrect extractable option value.\n"));
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ }
+
+ /* Select a PKCS11 token first */
+ kmfrv = select_token(kmfhandle, token, FALSE);
+ if (kmfrv != KMF_OK) {
+ return (kmfrv);
+ }
+
+ (void) memset(&key, 0, sizeof (KMF_KEY_HANDLE));
+ params.kstype = KMF_KEYSTORE_PK11TOKEN;
+ params.keytype = keyAlg;
+ params.keylength = keylen; /* bits */
+ params.keylabel = keylabel;
+ params.pkcs11parms.sensitive = sensitive;
+ params.pkcs11parms.not_extractable = not_extractable;
+ params.cred.cred = tokencred->cred;
+ params.cred.credlen = tokencred->credlen;
+ kmfrv = KMF_CreateSymKey(kmfhandle, &params, &key);
+ if (kmfrv != KMF_OK) {
+ goto out;
+ }
+
+ if (print_hex) {
+ if (sensitive == B_TRUE || not_extractable == B_TRUE) {
+ cryptoerror(LOG_STDERR,
+ gettext("Warning: can not reveal the key value "
+ "for a sensitive or non-extractable key.\n"));
+ goto out;
+ } else {
+ rkey = malloc(sizeof (KMF_RAW_SYM_KEY));
+ if (rkey == NULL) {
+ kmfrv = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY));
+ kmfrv = KMF_GetSymKeyValue(kmfhandle, &key, rkey);
+ if (kmfrv != KMF_OK) {
+ goto out;
+ }
+ hexstrlen = 2 * rkey->keydata.len + 1;
+ hexstr = malloc(hexstrlen);
+ if (hexstr == NULL) {
+ kmfrv = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ tohexstr(rkey->keydata.val, rkey->keydata.len, hexstr,
+ hexstrlen);
+ (void) printf(gettext("\tKey Value =\"%s\"\n"), hexstr);
+ }
+ }
+
+out:
+ KMF_FreeRawSymKey(rkey);
+
+ if (hexstr != NULL)
+ free(hexstr);
+
+ return (kmfrv);
+}
+
+
+static KMF_RETURN
+genkey_file(KMF_HANDLE_T kmfhandle, KMF_KEY_ALG keyAlg, int keylen, char *dir,
+ char *outkey, boolean_t print_hex)
+{
+ KMF_RETURN kmfrv = KMF_OK;
+ KMF_CREATESYMKEY_PARAMS csk_params;
+ KMF_KEY_HANDLE key;
+ KMF_RAW_SYM_KEY *rkey = NULL;
+ char *hexstr = NULL;
+ int hexstrlen;
+
+ if (EMPTYSTRING(outkey)) {
+ cryptoerror(LOG_STDERR,
+ gettext("No output key file was specified for the key\n"));
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (verify_file(outkey)) {
+ cryptoerror(LOG_STDERR,
+ gettext("Cannot write the indicated output "
+ "key file (%s).\n"), outkey);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ (void) memset(&key, 0, sizeof (KMF_KEY_HANDLE));
+ csk_params.kstype = KMF_KEYSTORE_OPENSSL;
+ csk_params.keytype = keyAlg;
+ csk_params.keylength = keylen;
+ csk_params.cred.cred = NULL;
+ csk_params.cred.credlen = 0;
+ csk_params.sslparms.dirpath = (dir == NULL) ? "." : dir;
+ csk_params.sslparms.keyfile = outkey;
+
+ kmfrv = KMF_CreateSymKey(kmfhandle, &csk_params, &key);
+ if (kmfrv != KMF_OK) {
+ goto out;
+ }
+
+ if (print_hex) {
+ rkey = malloc(sizeof (KMF_RAW_SYM_KEY));
+ if (rkey == NULL) {
+ kmfrv = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY));
+ kmfrv = KMF_GetSymKeyValue(kmfhandle, &key, rkey);
+ if (kmfrv != KMF_OK) {
+ goto out;
+ }
+
+ hexstrlen = 2 * rkey->keydata.len + 1;
+ hexstr = malloc(hexstrlen);
+ if (hexstr == NULL) {
+ kmfrv = KMF_ERR_MEMORY;
+ goto out;
+ }
+ tohexstr(rkey->keydata.val, rkey->keydata.len, hexstr,
+ hexstrlen);
+ (void) printf(gettext("\tKey Value =\"%s\"\n"), hexstr);
+ }
+
+out:
+ KMF_FreeRawSymKey(rkey);
+
+ if (hexstr != NULL)
+ free(hexstr);
+
+ return (kmfrv);
+}
+
+int
+pk_genkey(int argc, char *argv[])
+{
+ int rv;
+ int opt;
+ extern int optind_av;
+ extern char *optarg_av;
+ KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
+ char *tokenname = NULL;
+ char *dir = NULL;
+ char *prefix = NULL;
+ char *keytype = "AES";
+ char *keylenstr = NULL;
+ int keylen = 0;
+ char *keylabel = NULL;
+ char *outkey = NULL;
+ char *senstr = NULL;
+ char *extstr = NULL;
+ char *printstr = NULL;
+ KMF_HANDLE_T kmfhandle = NULL;
+ KMF_KEY_ALG keyAlg = KMF_AES;
+ boolean_t print_hex = B_FALSE;
+ KMF_CREDENTIAL tokencred = {NULL, 0};
+
+ while ((opt = getopt_av(argc, argv,
+ "k:(keystore)l:(label)T:(token)d:(dir)p:(prefix)"
+ "t:(keytype)y:(keylen)K:(outkey)P:(print)"
+ "s:(sensitive)e:(extractable)")) != EOF) {
+ if (EMPTYSTRING(optarg_av))
+ return (PK_ERR_USAGE);
+ switch (opt) {
+ case 'k':
+ kstype = KS2Int(optarg_av);
+ if (kstype == 0)
+ return (PK_ERR_USAGE);
+ break;
+ case 'l':
+ if (keylabel)
+ return (PK_ERR_USAGE);
+ keylabel = optarg_av;
+ break;
+ case 'T':
+ if (tokenname)
+ return (PK_ERR_USAGE);
+ tokenname = optarg_av;
+ break;
+ case 'd':
+ if (dir)
+ return (PK_ERR_USAGE);
+ dir = optarg_av;
+ break;
+ case 'p':
+ if (prefix)
+ return (PK_ERR_USAGE);
+ prefix = optarg_av;
+ break;
+ case 't':
+ keytype = optarg_av;
+ break;
+ case 'y':
+ if (keylenstr)
+ return (PK_ERR_USAGE);
+ keylenstr = optarg_av;
+ break;
+ case 'K':
+ if (outkey)
+ return (PK_ERR_USAGE);
+ outkey = optarg_av;
+ break;
+ case 'P':
+ if (printstr)
+ return (PK_ERR_USAGE);
+ printstr = optarg_av;
+ break;
+ case 's':
+ if (senstr)
+ return (PK_ERR_USAGE);
+ senstr = optarg_av;
+ break;
+ case 'e':
+ if (extstr)
+ return (PK_ERR_USAGE);
+ extstr = optarg_av;
+ break;
+ default:
+ return (PK_ERR_USAGE);
+ }
+ }
+
+ /* No additional args allowed. */
+ argc -= optind_av;
+ argv += optind_av;
+ if (argc) {
+ return (PK_ERR_USAGE);
+ }
+
+ /* Check keytype. If not specified, default to AES */
+ if (keytype != NULL && Str2SymKeyType(keytype, &keyAlg) != 0) {
+ cryptoerror(LOG_STDERR, gettext("Unrecognized keytype(%s).\n"),
+ keytype);
+ return (PK_ERR_USAGE);
+ }
+
+ /*
+ * Check and set the key length.
+ * - For DES and 3DES, the key size are fixed. Ingore the keylen
+ * option, even if it is specified.
+ * - For AES and ARCFOUR, if keylen is not specified, default to
+ * 128 bits.
+ */
+ if (keyAlg == KMF_DES)
+ keylen = 64; /* fixed size; ignore input */
+ else if (keyAlg == KMF_DES3)
+ keylen = 192; /* fixed size; ignore input */
+ else /* AES or ARCFOUR */ {
+ if (keylenstr == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("Key length must be specified "
+ "for AES and ARCFOUR symmetric keys.\n"));
+ return (PK_ERR_USAGE);
+ }
+ if (sscanf(keylenstr, "%d", &keylen) != 1) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unrecognized key length (%s).\n"),
+ keytype);
+ return (PK_ERR_USAGE);
+ }
+ if (keylen == 0 || (keylen % 8) != 0) {
+ cryptoerror(LOG_STDERR,
+ gettext("Key length bitlength must be a "
+ "multiple of 8.\n"));
+ return (PK_ERR_USAGE);
+ }
+ }
+
+ /* check the print option */
+ if (printstr != NULL) {
+ if (kstype == KMF_KEYSTORE_NSS) {
+ cryptoerror(LOG_STDERR,
+ gettext("The print option does not apply "
+ "to the NSS keystore.\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ if (tolower(printstr[0]) == 'y')
+ print_hex = B_TRUE;
+ else if (tolower(printstr[0]) == 'n')
+ print_hex = B_FALSE;
+ else {
+ cryptoerror(LOG_STDERR,
+ gettext("Incorrect print option value.\n"));
+ return (PK_ERR_USAGE);
+ }
+ }
+
+ /* check the sensitive and extractable options */
+ if ((senstr != NULL || extstr != NULL) &&
+ (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_OPENSSL)) {
+ cryptoerror(LOG_STDERR,
+ gettext("The sensitive or extractable option applies "
+ "to the PKCS11 keystore only.\n"));
+ return (PK_ERR_USAGE);
+ }
+
+ if (kstype == KMF_KEYSTORE_PK11TOKEN && tokenname == NULL) {
+ tokenname = PK_DEFAULT_PK11TOKEN;
+ } else if (kstype == KMF_KEYSTORE_NSS && tokenname == NULL) {
+ tokenname = DEFAULT_NSS_TOKEN;
+ }
+
+ if (kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS)
+ (void) get_token_password(kstype, tokenname, &tokencred);
+
+ if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
+ goto end;
+ }
+
+ if (kstype == KMF_KEYSTORE_NSS) {
+ rv = genkey_nss(kmfhandle, tokenname, dir, prefix,
+ keylabel, keyAlg, keylen, &tokencred);
+ } else if (kstype == KMF_KEYSTORE_OPENSSL) {
+ rv = genkey_file(kmfhandle, keyAlg, keylen, dir, outkey,
+ print_hex);
+ } else {
+ rv = genkey_pkcs11(kmfhandle, tokenname, keylabel, keyAlg,
+ keylen, senstr, extstr, print_hex, &tokencred);
+ }
+
+end:
+ if (rv != KMF_OK)
+ display_error(kmfhandle, rv,
+ gettext("Error generating key"));
+
+ if (tokencred.cred != NULL)
+ free(tokencred.cred);
+
+ (void) KMF_Finalize(kmfhandle);
+ if (rv != KMF_OK)
+ return (PK_ERR_USAGE);
+
+ return (0);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/import.c b/usr/src/cmd/cmd-crypto/pktool/import.c
index 0afba0ef2e..ac706b82ab 100644
--- a/usr/src/cmd/cmd-crypto/pktool/import.c
+++ b/usr/src/cmd/cmd-crypto/pktool/import.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -37,754 +36,354 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <cryptoutil.h>
-#include <security/cryptoki.h>
#include "common.h"
-#include "biginteger.h"
-#include "osslcommon.h"
-#include "p12common.h"
-#include <openssl/pkcs12.h>
-#include <openssl/err.h>
-/*
- * Helper function decrypt and parse PKCS#12 import file.
- */
-static CK_RV
-extract_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen,
- EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca)
-/* ARGSUSED */
+#include <kmfapi.h>
+
+static KMF_RETURN
+pk_import_pk12_files(KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *cred,
+ char *outfile, char *certfile, char *keyfile,
+ char *dir, char *keydir, KMF_ENCODE_FORMAT outformat)
{
- PKCS12 *pk12, *pk12_tmp;
- EVP_PKEY *temp_pkey = NULL;
- X509 *temp_cert = NULL;
- STACK_OF(X509) *temp_ca = NULL;
-
- cryptodebug("inside extract_pkcs12");
-
- cryptodebug("calling PKCS12_new");
- if ((pk12 = PKCS12_new()) == NULL) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to create PKCS#12 context."));
- return (CKR_GENERAL_ERROR);
+ KMF_RETURN rv = KMF_OK;
+ KMF_DATA *certs = NULL;
+ KMF_RAW_KEY_DATA *keys = NULL;
+ int ncerts = 0;
+ int nkeys = 0;
+ int i;
+
+ rv = KMF_ImportPK12(kmfhandle, outfile, cred,
+ &certs, &ncerts, &keys, &nkeys);
+
+ if (rv == KMF_OK) {
+ (void) printf(gettext("Found %d certificate(s) and %d "
+ "key(s) in %s\n"), ncerts, nkeys, outfile);
+ }
+
+ if (rv == KMF_OK && ncerts > 0) {
+ KMF_STORECERT_PARAMS params;
+ char newcertfile[MAXPATHLEN];
+
+ (void) memset(&params, 0, sizeof (KMF_STORECERT_PARAMS));
+ params.kstype = KMF_KEYSTORE_OPENSSL;
+ params.sslparms.dirpath = dir;
+ params.sslparms.format = outformat;
+
+ for (i = 0; rv == KMF_OK && i < ncerts; i++) {
+ /*
+ * If storing more than 1 cert, gotta change
+ * the name so we don't overwrite the previous one.
+ * Just append a _# to the name.
+ */
+ if (i > 0) {
+ (void) snprintf(newcertfile,
+ sizeof (newcertfile),
+ "%s_%d", certfile, i);
+ params.sslparms.certfile = newcertfile;
+ } else {
+ params.sslparms.certfile = certfile;
+ }
+ rv = KMF_StoreCert(kmfhandle, &params, &certs[i]);
+ }
}
-
- cryptodebug("calling d2i_PKCS12_bio");
- if ((pk12_tmp = d2i_PKCS12_bio(fbio, &pk12)) == NULL) {
- /* This is ok; it seems to mean there is no more to read. */
- if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_ASN1 &&
- ERR_GET_REASON(ERR_peek_error()) == ASN1_R_HEADER_TOO_LONG)
- goto end_extract_pkcs12;
-
- cryptoerror(LOG_STDERR, gettext(
- "Unable to populate PKCS#12 context."));
- PKCS12_free(pk12);
- return (CKR_GENERAL_ERROR);
+ if (rv == KMF_OK && nkeys > 0) {
+ KMF_STOREKEY_PARAMS skparms;
+ char newkeyfile[MAXPATHLEN];
+
+ (void) memset(&skparms, 0, sizeof (skparms));
+
+ /* The order of certificates and keys should match */
+ for (i = 0; rv == KMF_OK && i < nkeys; i++) {
+ skparms.kstype = KMF_KEYSTORE_OPENSSL;
+ skparms.sslparms.dirpath = keydir;
+ skparms.sslparms.format = outformat;
+ skparms.cred = *cred;
+ skparms.certificate = &certs[i];
+
+ if (i > 0) {
+ (void) snprintf(newkeyfile,
+ sizeof (newkeyfile),
+ "%s_%d", keyfile, i);
+ skparms.sslparms.keyfile = newkeyfile;
+ } else {
+ skparms.sslparms.keyfile = keyfile;
+ }
+
+ rv = KMF_StorePrivateKey(kmfhandle, &skparms,
+ &keys[i]);
+ }
}
- pk12 = pk12_tmp;
-
- cryptodebug("calling PKCS12_parse");
- if (PKCS12_parse(pk12, (char *)pin, &temp_pkey, &temp_cert,
- &temp_ca) <= 0) {
- cryptoerror(LOG_STDERR,
- gettext("Unable to parse import file."));
- PKCS12_free(pk12);
- return (CKR_GENERAL_ERROR);
+ /*
+ * Cleanup memory.
+ */
+ if (certs) {
+ for (i = 0; i < ncerts; i++)
+ KMF_FreeData(&certs[i]);
+ free(certs);
+ }
+ if (keys) {
+ for (i = 0; i < nkeys; i++)
+ KMF_FreeRawKey(&keys[i]);
+ free(keys);
}
-end_extract_pkcs12:
-
- *priv_key = temp_pkey;
- *cert = temp_cert;
- *ca = temp_ca;
- PKCS12_free(pk12);
- return (CKR_OK);
+ return (rv);
}
-/*
- * Converts OpenSSL BIGNUM into PKCS#11 biginteger_t format.
- */
-static CK_RV
-cvt_bn2bigint(BIGNUM *from, biginteger_t *to)
+
+static KMF_RETURN
+pk_import_pk12_nss(
+ KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *kmfcred,
+ KMF_CREDENTIAL *tokencred,
+ char *token_spec, char *dir, char *prefix,
+ char *nickname, char *trustflags, char *filename)
{
- CK_BYTE *temp;
- CK_ULONG temp_alloc_sz, temp_cvt_sz;
+ KMF_RETURN rv = KMF_OK;
+ KMF_DATA *certs = NULL;
+ KMF_RAW_KEY_DATA *keys = NULL;
+ int ncerts = 0;
+ int nkeys = 0;
+ int i;
+
+ rv = configure_nss(kmfhandle, dir, prefix);
+ if (rv != KMF_OK)
+ return (rv);
- cryptodebug("inside cvt_bn2bigint");
+ rv = KMF_ImportPK12(kmfhandle, filename, kmfcred,
+ &certs, &ncerts, &keys, &nkeys);
- if (from == NULL || to == NULL)
- return (CKR_ARGUMENTS_BAD);
+ if (rv == KMF_OK)
+ (void) printf(gettext("Found %d certificate(s) and %d "
+ "key(s) in %s\n"), ncerts, nkeys, filename);
- cryptodebug("calling BN_num_bytes");
- temp_alloc_sz = BN_num_bytes(from);
- if ((temp = malloc(temp_alloc_sz)) == NULL)
- return (CKR_HOST_MEMORY);
+ if (rv == KMF_OK) {
+ KMF_STORECERT_PARAMS params;
- cryptodebug("calling BN_bn2bin");
- temp_cvt_sz = BN_bn2bin(from, (unsigned char *)temp);
- if (temp_cvt_sz != temp_alloc_sz)
- return (CKR_GENERAL_ERROR);
+ (void) memset(&params, 0, sizeof (KMF_STORECERT_PARAMS));
+ params.kstype = KMF_KEYSTORE_NSS;
+ params.nssparms.slotlabel = token_spec;
+ params.nssparms.trustflag = trustflags;
- to->big_value = temp;
- to->big_value_len = temp_cvt_sz;
- return (CKR_OK);
-}
+ for (i = 0; rv == KMF_OK && i < ncerts; i++) {
+ if (i == 0)
+ params.certLabel = nickname;
+ else
+ params.certLabel = NULL;
-/*
- * Write RSA private key to token.
- */
-static CK_RV
-write_rsa_private(CK_SESSION_HANDLE sess, RSA *rsa, X509 *cert)
-{
- CK_RV rv = CKR_OK;
- int i = 0;
- static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY;
- static CK_KEY_TYPE keytype = CKK_RSA;
- CK_BYTE *label = NULL;
- CK_ULONG label_len = 0;
- CK_BYTE *id = NULL;
- CK_ULONG id_len = 0;
- CK_DATE startdate = { "", "", "" };
- CK_DATE enddate = { "", "", "" };
- char tmpdate[8];
- biginteger_t mod = { NULL, 0 }; /* required */
- biginteger_t pubexp = { NULL, 0 }; /* required */
- biginteger_t priexp = { NULL, 0 }; /* optional */
- biginteger_t prime1 = { NULL, 0 }; /* optional */
- biginteger_t prime2 = { NULL, 0 }; /* optional */
- biginteger_t exp1 = { NULL, 0 }; /* optional */
- biginteger_t exp2 = { NULL, 0 }; /* optional */
- biginteger_t coef = { NULL, 0 }; /* optional */
- CK_ATTRIBUTE rsa_pri_attrs[16] = {
- { CKA_CLASS, &objclass, sizeof (objclass) },
- { CKA_KEY_TYPE, &keytype, sizeof (keytype) },
- { CKA_PRIVATE, &pk_true, sizeof (pk_true) },
- { CKA_TOKEN, &pk_true, sizeof (pk_true) },
- { CKA_LABEL, NULL, 0 },
- { CKA_ID, NULL, 0 },
- { CKA_START_DATE, NULL, 0 },
- { CKA_END_DATE, NULL, 0 },
- { CKA_MODULUS, NULL, 0 },
- { CKA_PUBLIC_EXPONENT, NULL, 0 },
- { 0 /* CKA_PRIVATE_EXPONENT */, NULL, 0 }, /* optional */
- { 0 /* CKA_PRIME_1 */, NULL, 0 }, /* | */
- { 0 /* CKA_PRIME_2 */, NULL, 0 }, /* | */
- { 0 /* CKA_EXPONENT_1 */, NULL, 0 }, /* | */
- { 0 /* CKA_EXPONENT_2 */, NULL, 0 }, /* | */
- { 0 /* CKA_COEFFICIENT */, NULL, 0 } /* V */
- };
- CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
- CK_OBJECT_HANDLE obj;
-
- cryptodebug("inside write_rsa_private");
-
- /* Attributes start at array index 4. */
- i = 4;
-
- /* Recycle the certificate label for the private key label. */
- cryptodebug("calling X509_alias_get0");
- if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
- label = (CK_BYTE *)gettext("no label");
- label_len = strlen((char *)label);
- }
- copy_string_to_attr(label, label_len, &(rsa_pri_attrs[i++]));
-
- /* Recycle the certificate id for the private key id. */
- cryptodebug("calling PKTOOL_X509_keyid_get0");
- if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
- id = (CK_BYTE *)gettext("no id");
- id_len = strlen((char *)id);
- }
- copy_string_to_attr(id, id_len, &(rsa_pri_attrs[i++]));
-
- /* Recycle the certificate start and end dates for private key. */
- cryptodebug("calling X509_get_notBefore");
- if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
- (void) memcpy(&startdate, tmpdate, sizeof (startdate));
- copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
- &(rsa_pri_attrs[i++]));
- }
-
- cryptodebug("calling X509_get_notAfter");
- if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
- (void) memcpy(&enddate, tmpdate, sizeof (enddate));
- copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
- &(rsa_pri_attrs[i++]));
- }
-
- /* Modulus n */
- cryptodebug("converting RSA private key modulus");
- if ((rv = cvt_bn2bigint(rsa->n, &mod)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key modulus."));
- return (rv);
- }
- copy_bigint_to_attr(mod, &(rsa_pri_attrs[i++]));
-
- /* Public exponent e */
- cryptodebug("converting RSA private key public exponent");
- if ((rv = cvt_bn2bigint(rsa->e, &pubexp)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key public exponent."));
- return (rv);
- }
- copy_bigint_to_attr(pubexp, &(rsa_pri_attrs[i++]));
-
- /* Private exponent d */
- if (rsa->d != NULL) {
- cryptodebug("converting RSA private key private exponent");
- if ((rv = cvt_bn2bigint(rsa->d, &priexp)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext("Unable to convert "
- "RSA private key private exponent."));
- return (rv);
- }
- rsa_pri_attrs[i].type = CKA_PRIVATE_EXPONENT;
- copy_bigint_to_attr(priexp, &(rsa_pri_attrs[i++]));
- } else
- cryptodebug("no RSA private key private exponent");
-
- /* Prime p */
- if (rsa->p != NULL) {
- cryptodebug("converting RSA private key prime 1");
- if ((rv = cvt_bn2bigint(rsa->p, &prime1)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key prime 1."));
- return (rv);
- }
- rsa_pri_attrs[i].type = CKA_PRIME_1;
- copy_bigint_to_attr(prime1, &(rsa_pri_attrs[i++]));
- } else
- cryptodebug("no RSA private key prime 1");
-
- /* Prime q */
- if (rsa->q != NULL) {
- cryptodebug("converting RSA private key prime 2");
- if ((rv = cvt_bn2bigint(rsa->q, &prime2)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key prime 2."));
- return (rv);
- }
- rsa_pri_attrs[i].type = CKA_PRIME_2;
- copy_bigint_to_attr(prime2, &(rsa_pri_attrs[i++]));
- } else
- cryptodebug("no RSA private key prime 2");
-
- /* Private exponent d modulo p-1 */
- if (rsa->dmp1 != NULL) {
- cryptodebug("converting RSA private key exponent 1");
- if ((rv = cvt_bn2bigint(rsa->dmp1, &exp1)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key exponent 1."));
- return (rv);
- }
- rsa_pri_attrs[i].type = CKA_EXPONENT_1;
- copy_bigint_to_attr(exp1, &(rsa_pri_attrs[i++]));
- } else
- cryptodebug("no RSA private key exponent 1");
-
- /* Private exponent d modulo q-1 */
- if (rsa->dmq1 != NULL) {
- cryptodebug("converting RSA private key exponent 2");
- if ((rv = cvt_bn2bigint(rsa->dmq1, &exp2)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key exponent 2."));
- return (rv);
+ rv = KMF_StoreCert(kmfhandle, &params, &certs[i]);
}
- rsa_pri_attrs[i].type = CKA_EXPONENT_2;
- copy_bigint_to_attr(exp2, &(rsa_pri_attrs[i++]));
- } else
- cryptodebug("no RSA private key exponent 2");
-
- /* CRT coefficient q-inverse mod p */
- if (rsa->iqmp != NULL) {
- cryptodebug("converting RSA private key coefficient");
- if ((rv = cvt_bn2bigint(rsa->iqmp, &coef)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert RSA private key coefficient."));
- return (rv);
+ if (rv != KMF_OK) {
+ display_error(kmfhandle, rv,
+ gettext("Error storing certificate "
+ "in PKCS11 token"));
}
- rsa_pri_attrs[i].type = CKA_COEFFICIENT;
- copy_bigint_to_attr(coef, &(rsa_pri_attrs[i++]));
- } else
- cryptodebug("no RSA private key coefficient");
-
- /* Indicates programming error: attributes overran the template */
- if (i > count) {
- cryptodebug("error: more attributes found than accounted for");
- i = count;
}
- cryptodebug("calling C_CreateObject");
- if ((rv = C_CreateObject(sess, rsa_pri_attrs, i, &obj)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to create RSA private key object."));
- return (rv);
- }
+ if (rv == KMF_OK) {
+ KMF_STOREKEY_PARAMS skparms;
- return (CKR_OK);
-}
+ /* The order of certificates and keys should match */
+ for (i = 0; i < nkeys; i++) {
+ (void) memset(&skparms, 0,
+ sizeof (KMF_STOREKEY_PARAMS));
+ skparms.kstype = KMF_KEYSTORE_NSS;
+ skparms.cred = *tokencred;
+ skparms.label = nickname;
+ skparms.certificate = &certs[i];
+ skparms.nssparms.slotlabel = token_spec;
-/*
- * Write DSA private key to token.
- */
-static CK_RV
-write_dsa_private(CK_SESSION_HANDLE sess, DSA *dsa, X509 *cert)
-{
- CK_RV rv = CKR_OK;
- int i = 0;
- static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY;
- static CK_KEY_TYPE keytype = CKK_DSA;
- CK_BYTE *label = NULL;
- CK_ULONG label_len = 0;
- CK_BYTE *id = NULL;
- CK_ULONG id_len = 0;
- CK_DATE startdate = { "", "", "" };
- CK_DATE enddate = { "", "", "" };
- char tmpdate[8];
- biginteger_t prime = { NULL, 0 }; /* required */
- biginteger_t subprime = { NULL, 0 }; /* required */
- biginteger_t base = { NULL, 0 }; /* required */
- biginteger_t value = { NULL, 0 }; /* required */
- CK_ATTRIBUTE dsa_pri_attrs[12] = {
- { CKA_CLASS, &objclass, sizeof (objclass) },
- { CKA_KEY_TYPE, &keytype, sizeof (keytype) },
- { CKA_PRIVATE, &pk_true, sizeof (pk_true) },
- { CKA_TOKEN, &pk_true, sizeof (pk_true) },
- { CKA_LABEL, NULL, 0 },
- { CKA_ID, NULL, 0 },
- { CKA_START_DATE, NULL, 0 },
- { CKA_END_DATE, NULL, 0 },
- { CKA_PRIME, NULL, 0 },
- { CKA_SUBPRIME, NULL, 0 },
- { CKA_BASE, NULL, 0 },
- { CKA_VALUE, NULL, 0 }
- };
- CK_ULONG count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
- CK_OBJECT_HANDLE obj;
-
- cryptodebug("inside write_dsa_private");
-
- /* Attributes start at array index 4. */
- i = 4;
-
- /* Recycle the certificate label for the private key label. */
- cryptodebug("calling X509_alias_get0");
- if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
- label = (CK_BYTE *)gettext("no label");
- label_len = strlen((char *)label);
+ rv = KMF_StorePrivateKey(kmfhandle, &skparms, &keys[i]);
+ }
}
- copy_string_to_attr(label, label_len, &(dsa_pri_attrs[i++]));
- /* Recycle the certificate id for the private key id. */
- cryptodebug("calling PKTOOL_X509_keyid_get0");
- if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
- id = (CK_BYTE *)gettext("no id");
- id_len = strlen((char *)id);
+ /*
+ * Cleanup memory.
+ */
+ if (certs) {
+ for (i = 0; i < ncerts; i++)
+ KMF_FreeData(&certs[i]);
+ free(certs);
}
- copy_string_to_attr(id, id_len, &(dsa_pri_attrs[i++]));
-
- /* Recycle the certificate start and end dates for private key. */
- cryptodebug("calling X509_get_notBefore");
- if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
- (void) memcpy(&startdate, tmpdate, sizeof (startdate));
- copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
- &(dsa_pri_attrs[i++]));
+ if (keys) {
+ for (i = 0; i < nkeys; i++)
+ KMF_FreeRawKey(&keys[i]);
+ free(keys);
}
- cryptodebug("calling X509_get_notAfter");
- if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
- (void) memcpy(&enddate, tmpdate, sizeof (enddate));
- copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
- &(dsa_pri_attrs[i++]));
- }
+ return (rv);
+}
- /* Prime p */
- cryptodebug("converting DSA private key prime");
- if ((rv = cvt_bn2bigint(dsa->p, &prime)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DSA private key prime."));
- return (rv);
- }
- copy_bigint_to_attr(prime, &(dsa_pri_attrs[i++]));
+static KMF_RETURN
+pk_import_cert(
+ KMF_HANDLE_T kmfhandle,
+ KMF_KEYSTORE_TYPE kstype,
+ char *label, char *token_spec, char *filename,
+ char *dir, char *prefix, char *trustflags)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_IMPORTCERT_PARAMS params;
- /* Subprime q */
- cryptodebug("converting DSA private key subprime");
- if ((rv = cvt_bn2bigint(dsa->q, &subprime)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DSA private key subprime."));
- return (rv);
- }
- copy_bigint_to_attr(subprime, &(dsa_pri_attrs[i++]));
+ if (kstype == KMF_KEYSTORE_PK11TOKEN) {
+ rv = select_token(kmfhandle, token_spec, FALSE);
- /* Base g */
- cryptodebug("converting DSA private key base");
- if ((rv = cvt_bn2bigint(dsa->g, &base)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DSA private key base."));
- return (rv);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
}
- copy_bigint_to_attr(base, &(dsa_pri_attrs[i++]));
- /* Private key x */
- cryptodebug("converting DSA private key value");
- if ((rv = cvt_bn2bigint(dsa->priv_key, &value)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DSA private key value."));
- return (rv);
- }
- copy_bigint_to_attr(value, &(dsa_pri_attrs[i++]));
+ (void) memset(&params, 0, sizeof (params));
+ params.kstype = kstype;
+ params.certfile = filename;
+ params.certLabel = label;
- /* Indicates programming error: attributes overran the template */
- if (i > count) {
- cryptodebug("error: more attributes found than accounted for");
- i = count;
+ if (kstype == KMF_KEYSTORE_NSS) {
+ rv = configure_nss(kmfhandle, dir, prefix);
+ if (rv != KMF_OK)
+ return (rv);
+ params.nssparms.trustflag = trustflags;
+ params.nssparms.slotlabel = token_spec;
}
- cryptodebug("calling C_CreateObject");
- if ((rv = C_CreateObject(sess, dsa_pri_attrs, i, &obj)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to create DSA private key object."));
- return (rv);
- }
+ rv = KMF_ImportCert(kmfhandle, &params);
- return (CKR_OK);
+ return (rv);
}
-/*
- * Write DH private key to token.
- */
-static CK_RV
-write_dh_private(CK_SESSION_HANDLE sess, DH *dh, X509 *cert)
+static KMF_RETURN
+pk_import_file_crl(void *kmfhandle,
+ char *infile,
+ char *outfile,
+ char *outdir,
+ KMF_ENCODE_FORMAT outfmt)
{
- CK_RV rv = CKR_OK;
- int i = 0;
- static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY;
- static CK_KEY_TYPE keytype = CKK_DH;
- CK_BYTE *label = NULL;
- CK_ULONG label_len = 0;
- CK_BYTE *id = NULL;
- CK_ULONG id_len = 0;
- CK_DATE startdate = { "", "", "" };
- CK_DATE enddate = { "", "", "" };
- char tmpdate[8];
- biginteger_t prime = { NULL, 0 }; /* required */
- biginteger_t base = { NULL, 0 }; /* required */
- biginteger_t value = { NULL, 0 }; /* required */
- CK_ATTRIBUTE dh_pri_attrs[11] = {
- { CKA_CLASS, &objclass, sizeof (objclass) },
- { CKA_KEY_TYPE, &keytype, sizeof (keytype) },
- { CKA_PRIVATE, &pk_true, sizeof (pk_true) },
- { CKA_TOKEN, &pk_true, sizeof (pk_true) },
- { CKA_LABEL, NULL, 0 },
- { CKA_ID, NULL, 0 },
- { CKA_START_DATE, NULL, 0 },
- { CKA_END_DATE, NULL, 0 },
- { CKA_PRIME, NULL, 0 },
- { CKA_BASE, NULL, 0 },
- { CKA_VALUE, NULL, 0 }
- };
- CK_ULONG count = sizeof (dh_pri_attrs) / sizeof (CK_ATTRIBUTE);
- CK_OBJECT_HANDLE obj;
-
- cryptodebug("inside write_dh_private");
-
- /* Attributes start at array index 4. */
- i = 4;
-
- /* Recycle the certificate label for the private key label. */
- cryptodebug("calling X509_alias_get0");
- if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
- label = (CK_BYTE *)gettext("no label");
- label_len = strlen((char *)label);
- }
- copy_string_to_attr(label, label_len, &(dh_pri_attrs[i++]));
+ KMF_IMPORTCRL_PARAMS icrl_params;
+ KMF_OPENSSL_PARAMS sslparams;
- /* Recycle the certificate id for the private key id. */
- cryptodebug("PKTOOL_X509_keyid_get0");
- if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
- id = (CK_BYTE *)gettext("no id");
- id_len = strlen((char *)id);
- }
- copy_string_to_attr(id, id_len, &(dh_pri_attrs[i++]));
-
- /* Recycle the certificate start and end dates for private key. */
- cryptodebug("calling X509_get_notBefore");
- if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
- (void) memcpy(&startdate, tmpdate, sizeof (startdate));
- copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
- &(dh_pri_attrs[i++]));
- }
+ sslparams.crlfile = infile;
+ sslparams.dirpath = outdir;
+ sslparams.outcrlfile = outfile;
+ sslparams.format = outfmt;
+ sslparams.crl_check = B_FALSE;
- cryptodebug("calling X509_get_notAfter");
- if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
- (void) memcpy(&enddate, tmpdate, sizeof (enddate));
- copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
- &(dh_pri_attrs[i++]));
- }
+ icrl_params.kstype = KMF_KEYSTORE_OPENSSL;
+ icrl_params.sslparms = sslparams;
- /* Prime p */
- cryptodebug("converting DH private key prime");
- if ((rv = cvt_bn2bigint(dh->p, &prime)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DH private key prime."));
- return (rv);
- }
- copy_bigint_to_attr(prime, &(dh_pri_attrs[i++]));
+ return (KMF_ImportCRL(kmfhandle, &icrl_params));
- /* Base g */
- cryptodebug("converting DH private key base");
- if ((rv = cvt_bn2bigint(dh->g, &base)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DH private key base."));
- return (rv);
- }
- copy_bigint_to_attr(base, &(dh_pri_attrs[i++]));
+}
- /* Private value x */
- cryptodebug("converting DH private key value");
- if ((rv = cvt_bn2bigint(dh->priv_key, &value)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to convert DH private key value."));
+static KMF_RETURN
+pk_import_nss_crl(void *kmfhandle,
+ boolean_t verify_crl_flag,
+ char *infile,
+ char *outdir,
+ char *prefix)
+{
+ KMF_IMPORTCRL_PARAMS icrl_params;
+ KMF_RETURN rv;
+
+ rv = configure_nss(kmfhandle, outdir, prefix);
+ if (rv != KMF_OK)
return (rv);
- }
- copy_bigint_to_attr(value, &(dh_pri_attrs[i++]));
- /* Indicates programming error: attributes overran the template */
- if (i > count) {
- cryptodebug("error: more attributes found than accounted for");
- i = count;
- }
+ icrl_params.kstype = KMF_KEYSTORE_NSS;
+ icrl_params.nssparms.slotlabel = NULL;
+ icrl_params.nssparms.crlfile = infile;
+ icrl_params.nssparms.crl_check = verify_crl_flag;
- cryptodebug("calling C_CreateObject");
- if ((rv = C_CreateObject(sess, dh_pri_attrs, i, &obj)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to create DH private key object."));
- return (rv);
- }
+ return (KMF_ImportCRL(kmfhandle, &icrl_params));
- return (CKR_OK);
}
-/*
- * Write certificate to token.
- */
-static CK_RV
-write_cert(CK_SESSION_HANDLE sess, X509 *cert)
+static KMF_RETURN
+pk_import_pk12_pk11(
+ KMF_HANDLE_T kmfhandle,
+ KMF_CREDENTIAL *p12cred,
+ KMF_CREDENTIAL *tokencred,
+ char *label, char *token_spec,
+ char *filename)
{
- CK_RV rv = CKR_OK;
- int i = 0;
- static CK_OBJECT_CLASS objclass = CKO_CERTIFICATE;
- static CK_CERTIFICATE_TYPE certtype = CKC_X_509;
- CK_BYTE *subject = NULL;
- CK_ULONG subject_len = 0;
- CK_BYTE *value = NULL;
- CK_ULONG value_len = 0;
- CK_BYTE *label = NULL;
- CK_ULONG label_len = 0;
- CK_BYTE *id = NULL;
- CK_ULONG id_len = 0;
- CK_BYTE *issuer = NULL;
- CK_ULONG issuer_len = 0;
- CK_BYTE *serial = NULL;
- CK_ULONG serial_len = 0;
- CK_ATTRIBUTE cert_attrs[9] = {
- { CKA_CLASS, &objclass, sizeof (objclass) },
- { CKA_CERTIFICATE_TYPE, &certtype, sizeof (certtype) },
- { CKA_TOKEN, &pk_true, sizeof (pk_true) },
- { CKA_SUBJECT, NULL, 0 }, /* required */
- { CKA_VALUE, NULL, 0 }, /* required */
- { 0 /* CKA_LABEL */, NULL, 0 }, /* optional */
- { 0 /* CKA_ID */, NULL, 0 }, /* optional */
- { 0 /* CKA_ISSUER */, NULL, 0 }, /* optional */
- { 0 /* CKA_SERIAL_NUMBER */, NULL, 0 } /* optional */
- };
- CK_ULONG count = sizeof (cert_attrs) / sizeof (CK_ATTRIBUTE);
- CK_OBJECT_HANDLE obj;
-
- cryptodebug("inside write_cert");
-
- /* Attributes start at array index 3. */
- i = 3;
+ KMF_RETURN rv = KMF_OK;
+ KMF_DATA *certs = NULL;
+ KMF_RAW_KEY_DATA *keys = NULL;
+ int ncerts = 0;
+ int nkeys = 0;
+ int i;
- /*
- * OpenSSL subject name and issuer (a little further below) are
- * actually stack structures that contain individual ASN.1
- * components. This stack of entries is packed into one DER string.
- */
- cryptodebug("calling PKTOOL_X509_subject_name");
- if ((subject = PKTOOL_X509_subject_name(cert, (int *)&subject_len)) ==
- NULL) {
- subject = (CK_BYTE *)gettext("no subject name");
- subject_len = strlen((char *)subject);
- }
- copy_string_to_attr(subject, subject_len, &(cert_attrs[i++]));
+ rv = select_token(kmfhandle, token_spec, FALSE);
- /* Get cert value, but it has to be reconstructed from cert. */
- cryptodebug("calling PKTOOL_X509_cert_value");
- if ((value = PKTOOL_X509_cert_value(cert, (int *)&value_len)) == NULL) {
- value = (CK_BYTE *)gettext("no value");
- value_len = strlen((char *)value);
- }
- copy_string_to_attr(value, value_len, &(cert_attrs[i++]));
-
- /*
- * Get certificate label which is "friendlyName" Netscape,
- * "alias" in OpenSSL.
- */
- if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
- cryptodebug("no certificate label");
- } else {
- cert_attrs[i].type = CKA_LABEL;
- copy_string_to_attr(label, label_len, &(cert_attrs[i++]));
+ if (rv != KMF_OK) {
+ return (rv);
}
- /* Get the keyid for the cert. */
- if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
- cryptodebug("no certificate id");
- } else {
- cert_attrs[i].type = CKA_ID;
- copy_string_to_attr(id, id_len, &(cert_attrs[i++]));
- }
+ rv = KMF_ImportPK12(kmfhandle, filename, p12cred,
+ &certs, &ncerts, &keys, &nkeys);
- /* Get the issuer name for the cert. */
- if ((issuer = PKTOOL_X509_issuer_name(cert, (int *)&issuer_len)) ==
- NULL) {
- cryptodebug("no certificate issuer name");
- } else {
- cert_attrs[i].type = CKA_ISSUER;
- copy_string_to_attr(issuer, issuer_len, &(cert_attrs[i++]));
- }
+ if (rv == KMF_OK) {
+ KMF_STOREKEY_PARAMS skparms;
- /* Get the cert serial number. */
- if ((serial = PKTOOL_X509_serial_number(cert, (int *)&serial_len)) ==
- NULL) {
- cryptodebug("no certificate serial number");
- } else {
- cert_attrs[i].type = CKA_SERIAL_NUMBER;
- copy_string_to_attr(serial, serial_len, &(cert_attrs[i++]));
- }
+ /* The order of certificates and keys should match */
+ for (i = 0; i < nkeys; i++) {
+ (void) memset(&skparms, 0,
+ sizeof (KMF_STOREKEY_PARAMS));
+ skparms.kstype = KMF_KEYSTORE_PK11TOKEN;
+ skparms.certificate = &certs[i];
+ if (tokencred != NULL)
+ skparms.cred = *tokencred;
+ if (i == 0)
+ skparms.label = label;
+ else
+ skparms.label = NULL;
- /* Indicates programming error: attributes overran the template */
- if (i > count) {
- cryptodebug("error: more attributes found than accounted for");
- i = count;
- }
-
- cryptodebug("calling C_CreateObject");
- if ((rv = C_CreateObject(sess, cert_attrs, i, &obj)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to create X.509 certificate object."));
- return (rv);
+ rv = KMF_StorePrivateKey(kmfhandle, &skparms,
+ &keys[i]);
+ }
}
- return (CKR_OK);
-}
+ if (rv == KMF_OK) {
+ KMF_STORECERT_PARAMS params;
-/*
- * Helper function to write PKCS#12 items to token. Returns CKR_OK
- * or CKR_GENERAL_ERROR
- */
-static CK_RV
-write_token_objs(CK_SESSION_HANDLE sess, EVP_PKEY *priv_key, X509 *cert,
- STACK_OF(X509) *ca, int *successes, int *failures)
-{
- int i;
- X509 *c;
- CK_RV rv = CKR_OK;
+ (void) printf(gettext("Found %d certificate(s) and %d "
+ "key(s) in %s\n"), ncerts, nkeys, filename);
+ (void) memset(&params, 0, sizeof (KMF_STORECERT_PARAMS));
- cryptodebug("inside write_token_objs");
+ params.kstype = KMF_KEYSTORE_PK11TOKEN;
- /* Do not reset *successes or *failures -- keep running totals. */
+ for (i = 0; rv == KMF_OK && i < ncerts; i++) {
+ if (i == 0)
+ params.certLabel = label;
+ else
+ params.certLabel = NULL;
- /* Import user key. */
- switch (priv_key->type) {
- case EVP_PKEY_RSA:
- (void) fprintf(stdout, gettext("Writing RSA private key...\n"));
- if ((rv = write_rsa_private(sess,
- EVP_PKEY_get1_RSA(priv_key), cert)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to write RSA private key (%s)."),
- pkcs11_strerror(rv));
- (*failures)++;
- } else
- (*successes)++;
- break;
- case EVP_PKEY_DSA:
- (void) fprintf(stdout, gettext("Writing DSA private key...\n"));
- if ((rv = write_dsa_private(sess,
- EVP_PKEY_get1_DSA(priv_key), cert)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to write DSA private key (%s)."),
- pkcs11_strerror(rv));
- (*failures)++;
- } else
- (*successes)++;
- break;
- case EVP_PKEY_DH:
- (void) fprintf(stdout, gettext("Writing DH private key...\n"));
- if ((rv = write_dh_private(sess,
- EVP_PKEY_get1_DH(priv_key), cert)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to write DH private key (%s)."),
- pkcs11_strerror(rv));
- (*failures)++;
- } else
- (*successes)++;
- break;
-
- default:
- /*
- * Note that EVP_PKEY_DH for X9.42 is not implemented
- * in the OpenSSL library.
- */
- cryptoerror(LOG_STDERR, gettext(
- "Private key type 0x%02x import not supported."),
- priv_key->type);
- (*failures)++;
- break;
+ rv = KMF_StoreCert(kmfhandle, &params, &certs[i]);
+ }
}
- /* Import user certificate. */
- (void) fprintf(stdout, gettext("Writing user certificate...\n"));
- if ((rv = write_cert(sess, cert)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to write user certificate (%s)."),
- pkcs11_strerror(rv));
- (*failures)++;
- } else
- (*successes)++;
-
- /* Import as many stacks of authority certificates as possible. */
- for (i = 0; i != sk_X509_num(ca); i++) {
- /*
- * sk_X509_value() is macro that embeds a cast to (X509 *).
- * Here it translates into ((X509 *)sk_value((ca), (i))).
- * Lint is complaining about the embedded casting, and
- * to fix it, you need to fix openssl header files.
- */
- /* LINTED E_BAD_PTR_CAST_ALIGN */
- c = sk_X509_value(ca, i);
- (void) fprintf(stdout, gettext(
- "Writing authority certificate...\n"));
- if ((rv = write_cert(sess, c)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to write authority certificate (%s)."),
- pkcs11_strerror(rv));
- (*failures)++;
- } else
- (*successes)++;
+ /*
+ * Cleanup memory.
+ */
+ if (certs) {
+ for (i = 0; i < ncerts; i++)
+ KMF_FreeData(&certs[i]);
+ free(certs);
+ }
+ if (keys) {
+ for (i = 0; i < nkeys; i++)
+ KMF_FreeRawKey(&keys[i]);
+ free(keys);
}
- (void) fprintf(stdout, gettext("PKCS#12 element scan completed.\n"));
- return (*failures != 0 ? CKR_GENERAL_ERROR : CKR_OK);
+ return (rv);
}
/*
- * Import objects from PKCS#12 file into token.
+ * Import objects from into KMF repositories.
*/
int
pk_import(int argc, char *argv[])
@@ -793,184 +392,320 @@ pk_import(int argc, char *argv[])
extern int optind_av;
extern char *optarg_av;
char *token_spec = NULL;
- char *token_name = NULL;
- char *manuf_id = NULL;
- char *serial_no = NULL;
- char full_name[FULL_NAME_LEN];
char *filename = NULL;
- struct stat statbuf;
- CK_SLOT_ID slot_id;
- CK_FLAGS pin_state;
- CK_UTF8CHAR_PTR pin = NULL;
- CK_ULONG pinlen = 0;
- CK_UTF8CHAR_PTR pk12pin = NULL;
- CK_ULONG pk12pinlen = 0;
- CK_SESSION_HANDLE sess;
- BIO *fbio = NULL;
- EVP_PKEY *priv_key = NULL;
- X509 *cert = NULL;
- STACK_OF(X509) *ca = NULL;
- CK_RV rv = CKR_OK;
- int i;
- int good_count = 0, bad_count = 0; /* running totals */
-
- cryptodebug("inside pk_import");
+ char *keyfile = NULL;
+ char *certfile = NULL;
+ char *crlfile = NULL;
+ char *certlabel = NULL;
+ char *dir = NULL;
+ char *keydir = NULL;
+ char *prefix = NULL;
+ char *trustflags = NULL;
+ char *verify_crl = NULL;
+ boolean_t verify_crl_flag = B_FALSE;
+ int oclass = 0;
+ KMF_KEYSTORE_TYPE kstype = 0;
+ KMF_ENCODE_FORMAT kfmt = 0;
+ KMF_ENCODE_FORMAT okfmt = KMF_FORMAT_ASN1;
+ KMF_RETURN rv = KMF_OK;
+ KMF_CREDENTIAL pk12cred = { NULL, 0 };
+ KMF_CREDENTIAL tokencred = { NULL, 0 };
+ KMF_HANDLE_T kmfhandle = NULL;
/* Parse command line options. Do NOT i18n/l10n. */
- while ((opt = getopt_av(argc, argv, "T:(token)i:(infile)")) != EOF) {
+ while ((opt = getopt_av(argc, argv,
+ "T:(token)i:(infile)"
+ "k:(keystore)y:(objtype)"
+ "d:(dir)p:(prefix)"
+ "n:(certlabel)N:(label)"
+ "K:(outkey)c:(outcert)"
+ "v:(verifycrl)l:(outcrl)"
+ "t:(trust)D:(keydir)F:(outformat)")) != EOF) {
+ if (EMPTYSTRING(optarg_av))
+ return (PK_ERR_USAGE);
switch (opt) {
case 'T': /* token specifier */
if (token_spec)
return (PK_ERR_USAGE);
token_spec = optarg_av;
break;
+ case 'c': /* output cert file name */
+ if (certfile)
+ return (PK_ERR_USAGE);
+ certfile = optarg_av;
+ break;
+ case 'l': /* output CRL file name */
+ if (crlfile)
+ return (PK_ERR_USAGE);
+ crlfile = optarg_av;
+ break;
+ case 'K': /* output key file name */
+ if (keyfile)
+ return (PK_ERR_USAGE);
+ keyfile = optarg_av;
+ break;
case 'i': /* input file name */
if (filename)
return (PK_ERR_USAGE);
filename = optarg_av;
break;
+ case 'k':
+ kstype = KS2Int(optarg_av);
+ if (kstype == 0)
+ return (PK_ERR_USAGE);
+ break;
+ case 'y':
+ oclass = OT2Int(optarg_av);
+ if (oclass == -1)
+ return (PK_ERR_USAGE);
+ break;
+ case 'd':
+ dir = optarg_av;
+ break;
+ case 'D':
+ keydir = optarg_av;
+ break;
+ case 'p':
+ if (prefix)
+ return (PK_ERR_USAGE);
+ prefix = optarg_av;
+ break;
+ case 'n':
+ case 'N':
+ if (certlabel)
+ return (PK_ERR_USAGE);
+ certlabel = optarg_av;
+ break;
+ case 'F':
+ okfmt = Str2Format(optarg_av);
+ if (okfmt == KMF_FORMAT_UNDEF)
+ return (PK_ERR_USAGE);
+ break;
+ case 't':
+ if (trustflags)
+ return (PK_ERR_USAGE);
+ trustflags = optarg_av;
+ break;
+ case 'v':
+ verify_crl = optarg_av;
+ if (tolower(verify_crl[0]) == 'y')
+ verify_crl_flag = B_TRUE;
+ else if (tolower(verify_crl[0]) == 'n')
+ verify_crl_flag = B_FALSE;
+ else
+ return (PK_ERR_USAGE);
+ break;
default:
return (PK_ERR_USAGE);
break;
}
}
- /* If nothing is specified, default is to use softtoken. */
- if (token_spec == NULL) {
- token_name = SOFT_TOKEN_LABEL;
- manuf_id = SOFT_MANUFACTURER_ID;
- serial_no = SOFT_TOKEN_SERIAL;
- } else {
- /*
- * Parse token specifier into token_name, manuf_id, serial_no.
- * Token_name is required; manuf_id and serial_no are optional.
- */
- if (parse_token_spec(token_spec, &token_name, &manuf_id,
- &serial_no) < 0)
- return (PK_ERR_USAGE);
- }
+ /* Assume keystore = PKCS#11 if not specified */
+ if (kstype == 0)
+ kstype = KMF_KEYSTORE_PK11TOKEN;
/* Filename arg is required. */
- if (filename == NULL)
+ if (EMPTYSTRING(filename)) {
+ cryptoerror(LOG_STDERR, gettext("The 'infile' parameter"
+ "is required for the import operation.\n"));
return (PK_ERR_USAGE);
+ }
/* No additional args allowed. */
argc -= optind_av;
argv += optind_av;
if (argc)
return (PK_ERR_USAGE);
- /* Done parsing command line options. */
- /* Check that the file exists and is non-empty. */
- if (access(filename, R_OK) < 0) {
- cryptoerror(LOG_STDERR, gettext("File \"%s\" is unreadable "
- "(%s)."), filename, strerror(errno));
- return (CKR_OK);
- }
- if (stat(filename, &statbuf) < 0) {
- cryptoerror(LOG_STDERR, gettext("Unable to get size of "
- "file \"%s\" (%s)."), filename, strerror(errno));
- return (CKR_OK);
- }
- if (statbuf.st_size == 0) {
- cryptoerror(LOG_STDERR, gettext("File \"%s\" is empty."),
- filename);
- return (CKR_OK);
- }
+ /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */
+ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) &&
+ kstype != KMF_KEYSTORE_PK11TOKEN) {
- full_token_name(token_name, manuf_id, serial_no, full_name);
+ (void) fprintf(stderr, gettext("The objtype parameter "
+ "is only relevant if keystore=pkcs11\n"));
+ return (PK_ERR_USAGE);
+ }
- /* Find the slot with token. */
- if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
- &pin_state)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to find token %s (%s)."), full_name,
- pkcs11_strerror(rv));
- return (PK_ERR_PK11);
+ /*
+ * You must specify a certlabel (cert label) when importing
+ * into NSS or PKCS#11.
+ */
+ if (kstype == KMF_KEYSTORE_NSS &&
+ (oclass != PK_CRL_OBJ) && EMPTYSTRING(certlabel)) {
+ cryptoerror(LOG_STDERR, gettext("The 'label' argument "
+ "is required for this operation\n"));
+ return (PK_ERR_USAGE);
}
- /* Get the user's PIN. */
- if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin,
- &pinlen)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get token passphrase (%s)."),
- pkcs11_strerror(rv));
- quick_finish(NULL);
- return (PK_ERR_PK11);
+ /*
+ * PKCS11 only imports PKCS#12 files or PEM/DER Cert files.
+ */
+ if (kstype == KMF_KEYSTORE_PK11TOKEN) {
+ /* we do not import private keys except in PKCS12 bundles */
+ if (oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)) {
+ cryptoerror(LOG_STDERR, gettext(
+ "The PKCS11 keystore only imports PKCS12 "
+ "files or raw certificate data files "
+ " or CRL file.\n"));
+ return (PK_ERR_USAGE);
+ }
}
- /* Assume user must be logged in R/W to import objects into token. */
- if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) !=
- CKR_OK) {
+ if ((rv = KMF_GetFileFormat(filename, &kfmt)) != KMF_OK) {
cryptoerror(LOG_STDERR,
- gettext("Unable to log into token (%s)."),
- pkcs11_strerror(rv));
- quick_finish(sess);
- return (PK_ERR_PK11);
+ gettext("File format not recognized."));
+ return (rv);
}
+ if (oclass == 0 && (kfmt == KMF_FORMAT_ASN1 ||
+ kfmt == KMF_FORMAT_PEM))
+ oclass = PK_CERT_OBJ;
- /* Setup OpenSSL context. */
- PKTOOL_setup_openssl();
+ if (kstype == KMF_KEYSTORE_NSS) {
+ if (oclass == PK_CRL_OBJ &&
+ (kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) {
+ cryptoerror(LOG_STDERR, gettext(
+ "CRL data can only be imported as DER or "
+ "PEM format"));
+ return (PK_ERR_USAGE);
+ }
- /* Open PKCS#12 file. */
- if ((open_pkcs12(filename, &fbio)) < 0) {
- cryptoerror(LOG_STDERR, gettext("Unable to open import file."));
- quick_finish(sess);
- return (PK_ERR_SYSTEM);
- }
+ if (oclass == PK_CERT_OBJ &&
+ (kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Certificates can only be imported as DER or "
+ "PEM format"));
+ return (PK_ERR_USAGE);
+ }
- /* Get the PIN for the PKCS#12 import file. */
- if ((rv = get_pin(gettext("Enter import file passphrase:"), NULL,
- &pk12pin, &pk12pinlen)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get import file passphrase (%s)."),
- pkcs11_strerror(rv));
- close_pkcs12(fbio);
- quick_finish(sess);
- return (PK_ERR_PK11);
+ /* we do not import private keys except in PKCS12 bundles */
+ if (oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Private key data can only be imported as part "
+ "of a PKCS12 file.\n"));
+ return (PK_ERR_USAGE);
+ }
}
- /* PKCS#12 import file may have multiple elements, loop until done. */
- for (i = 0; /* */; i++) {
- /* Extract the contents of the PKCS#12 import file. */
- if ((rv = extract_pkcs12(fbio, pk12pin, pk12pinlen, &priv_key,
- &cert, &ca)) != CKR_OK) {
+ if (kstype == KMF_KEYSTORE_OPENSSL && oclass != PK_CRL_OBJ) {
+ if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) {
cryptoerror(LOG_STDERR, gettext(
- "Unable to parse PKCS#12 element #%d "
- "in import file (%s)."), i+1, pkcs11_strerror(rv));
- close_pkcs12(fbio);
- quick_finish(sess);
- return (PK_ERR_OPENSSL);
+ "The 'outkey' and 'outcert' parameters "
+ "are required for the import operation "
+ "when the 'file' keystore is used.\n"));
+ return (PK_ERR_USAGE);
}
+ }
- /* Reached end of import file? */
- if (rv == CKR_OK && priv_key == NULL && cert == NULL &&
- ca == NULL)
+ if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec))
+ token_spec = PK_DEFAULT_PK11TOKEN;
+ else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec))
+ token_spec = DEFAULT_NSS_TOKEN;
+
+ if (kfmt == KMF_FORMAT_PKCS12) {
+ (void) get_pk12_password(&pk12cred);
+
+ if (kstype == KMF_KEYSTORE_PK11TOKEN ||
+ kstype == KMF_KEYSTORE_NSS)
+ (void) get_token_password(kstype, token_spec,
+ &tokencred);
+ }
+
+ if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
+ cryptoerror(LOG_STDERR, gettext("Error initializing "
+ "KMF: 0x%02x\n"), rv);
+ goto end;
+ }
+
+ switch (kstype) {
+ case KMF_KEYSTORE_PK11TOKEN:
+ if (kfmt == KMF_FORMAT_PKCS12)
+ rv = pk_import_pk12_pk11(
+ kmfhandle,
+ &pk12cred,
+ &tokencred,
+ certlabel,
+ token_spec,
+ filename);
+ else if (oclass == PK_CERT_OBJ)
+ rv = pk_import_cert(
+ kmfhandle,
+ kstype,
+ certlabel,
+ token_spec,
+ filename,
+ NULL, NULL, NULL);
+ else if (oclass == PK_CRL_OBJ)
+ rv = pk_import_file_crl(
+ kmfhandle,
+ filename,
+ crlfile,
+ dir,
+ okfmt);
break;
+ case KMF_KEYSTORE_NSS:
+ if (dir == NULL)
+ dir = PK_DEFAULT_DIRECTORY;
+ if (kfmt == KMF_FORMAT_PKCS12)
+ rv = pk_import_pk12_nss(
+ kmfhandle, &pk12cred,
+ &tokencred,
+ token_spec, dir, prefix,
+ certlabel, trustflags, filename);
+ else if (oclass == PK_CERT_OBJ) {
+ rv = pk_import_cert(
+ kmfhandle, kstype,
+ certlabel, token_spec,
+ filename, dir, prefix, trustflags);
+ } else if (oclass == PK_CRL_OBJ) {
+ rv = pk_import_nss_crl(
+ kmfhandle,
+ verify_crl_flag,
+ filename,
+ dir,
+ prefix);
+ }
+ break;
+ case KMF_KEYSTORE_OPENSSL:
+ if (kfmt == KMF_FORMAT_PKCS12)
+ rv = pk_import_pk12_files(
+ kmfhandle, &pk12cred,
+ filename, certfile, keyfile,
+ dir, keydir, okfmt);
+ else if (oclass == PK_CRL_OBJ) {
+ rv = pk_import_file_crl(
+ kmfhandle,
+ filename,
+ crlfile,
+ dir,
+ okfmt);
+ } else
+ /*
+ * It doesn't make sense to import anything
+ * else for the files plugin.
+ */
+ return (PK_ERR_USAGE);
+ break;
+ default:
+ rv = PK_ERR_USAGE;
+ break;
+ }
- (void) fprintf(stdout, gettext(
- "Scanning PKCS#12 element #%d for objects...\n"), i+1);
+end:
+ if (rv != KMF_OK)
+ display_error(kmfhandle, rv,
+ gettext("Error importing objects"));
- /* Write the objects to the token. */
- if ((rv = write_token_objs(sess, priv_key, cert, ca,
- &good_count, &bad_count)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to write PKCS#12 element #%d to token %s."),
- i+1, full_name);
- close_pkcs12(fbio);
- quick_finish(sess);
- return (PK_ERR_PK11);
- }
- }
+ if (tokencred.cred != NULL)
+ free(tokencred.cred);
- (void) fprintf(stdout, gettext("%d PKCS#12 elements scanned: "
- "%d objects imported, %d errors occurred.\n"), i,
- good_count, bad_count);
+ if (pk12cred.cred != NULL)
+ free(pk12cred.cred);
- /* Close PKCS#12 file. */
- close_pkcs12(fbio);
+ (void) KMF_Finalize(kmfhandle);
+
+ if (rv != KMF_OK)
+ return (PK_ERR_USAGE);
- /* Clean up. */
- quick_finish(sess);
return (0);
}
diff --git a/usr/src/cmd/cmd-crypto/pktool/list.c b/usr/src/cmd/cmd-crypto/pktool/list.c
index 496642c8da..2a427dfc36 100644
--- a/usr/src/cmd/cmd-crypto/pktool/list.c
+++ b/usr/src/cmd/cmd-crypto/pktool/list.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -39,794 +38,482 @@
#include <cryptoutil.h>
#include <security/cryptoki.h>
#include "common.h"
-#include "derparse.h"
-/*
- * Get key size based on the key type.
- */
-static CK_ULONG
-get_key_size(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, CK_KEY_TYPE key_type)
+#include <kmfapi.h>
+
+static void
+pk_show_certs(KMF_HANDLE_T kmfhandle, KMF_X509_DER_CERT *certs, int num_certs)
{
- CK_RV rv = CKR_OK;
- CK_ULONG key_size;
- CK_ATTRIBUTE modulus_sz =
- { CKA_MODULUS, NULL, 0 }; /* RSA */
- CK_ATTRIBUTE prime_sz =
- { CKA_PRIME, NULL, 0 }; /* DSA, DH X9.42 */
- CK_ATTRIBUTE value_sz =
- { CKA_VALUE, NULL_PTR, 0 }; /* DH, DES/DES3, AES, GENERIC */
-
- cryptodebug("inside get_key_size");
-
- switch (key_type) {
- case CKK_RSA:
- if ((rv = C_GetAttributeValue(sess, obj, &modulus_sz, 1)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get modulus attribute size (%s)."),
- pkcs11_strerror(rv));
- } else
- /* Convert key size to bits. */
- key_size = modulus_sz.ulValueLen * 8;
- break;
- case CKK_DH:
- if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get value attribute size (%s)."),
- pkcs11_strerror(rv));
- } else
- /* Convert key size to bits. */
- key_size = value_sz.ulValueLen * 8;
- break;
- case CKK_X9_42_DH:
- case CKK_DSA:
- if ((rv = C_GetAttributeValue(sess, obj, &prime_sz, 1)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get prime attribute size (%s)."),
- pkcs11_strerror(rv));
- } else
- /* Convert key size to bits. */
- key_size = prime_sz.ulValueLen * 8;
- break;
- case CKK_DES:
- case CKK_DES3:
- if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get value attribute size (%s)."),
- pkcs11_strerror(rv));
- } else
- /* Convert key size to bits -- omitting parity bit. */
- key_size = value_sz.ulValueLen * 7;
- break;
- case CKK_AES:
- case CKK_GENERIC_SECRET:
- if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get value attribute size (%s)."),
- pkcs11_strerror(rv));
- } else
- /* Convert key size to bits. */
- key_size = value_sz.ulValueLen * 8;
- break;
- default:
- cryptoerror(LOG_STDERR, gettext(
- "Unknown object key type (0x%02x)."), key_type);
- break;
- }
+ int i;
+ char *subject, *issuer, *serial, *id, *altname;
+
+ for (i = 0; i < num_certs; i++) {
+ subject = NULL;
+ issuer = NULL;
+ serial = NULL;
+ id = NULL;
+ altname = NULL;
+
+ (void) fprintf(stdout,
+ gettext("%d. (X.509 certificate)\n"), i + 1);
+ if (certs[i].kmf_private.label != NULL)
+ (void) fprintf(stdout, gettext("\t%s: %s\n"),
+ (certs[i].kmf_private.keystore_type ==
+ KMF_KEYSTORE_OPENSSL ? "Filename" : "Label"),
+ certs[i].kmf_private.label);
+ if (KMF_GetCertIDString(&certs[i].certificate,
+ &id) == KMF_OK)
+ (void) fprintf(stdout, gettext("\tID: %s\n"), id);
+ if (KMF_GetCertSubjectNameString(kmfhandle,
+ &certs[i].certificate, &subject) == KMF_OK)
+ (void) fprintf(stdout, gettext("\tSubject: %s\n"),
+ subject);
+ if (KMF_GetCertIssuerNameString(kmfhandle,
+ &certs[i].certificate, &issuer) == KMF_OK)
+ (void) fprintf(stdout, gettext("\tIssuer: %s\n"),
+ issuer);
+ if (KMF_GetCertSerialNumberString(kmfhandle,
+ &certs[i].certificate, &serial) == KMF_OK)
+ (void) fprintf(stdout, gettext("\tSerial: %s\n"),
+ serial);
+
+ if (KMF_GetCertExtensionString(kmfhandle,
+ &certs[i].certificate, KMF_X509_EXT_SUBJ_ALTNAME,
+ &altname) == KMF_OK) {
+ (void) fprintf(stdout, gettext("\t%s\n"),
+ altname);
+ }
- return (key_size);
+ KMF_FreeString(subject);
+ KMF_FreeString(issuer);
+ KMF_FreeString(serial);
+ KMF_FreeString(id);
+ KMF_FreeString(altname);
+ (void) fprintf(stdout, "\n");
+ }
}
-/*
- * Display private key.
- */
-static CK_RV
-display_prikey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
+static char *
+describeKey(KMF_KEY_HANDLE *key)
{
- CK_RV rv = CKR_OK;
- static CK_BBOOL private;
- static CK_BBOOL modifiable;
- static CK_KEY_TYPE key_type;
- CK_ULONG key_size;
- CK_BYTE *label = NULL;
- CK_ULONG label_len = 0;
- CK_BYTE *id = NULL;
- CK_ULONG id_len = 0;
- CK_BYTE *subject = NULL;
- CK_ULONG subject_len = 0;
- CK_DATE *start_date = NULL;
- CK_ULONG start_date_len = 0;
- CK_DATE *end_date = NULL;
- CK_ULONG end_date_len = 0;
- CK_ATTRIBUTE attrs[18] = {
- /* 0 to 2 */
- { CKA_PRIVATE, &private, sizeof (private) },
- { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
- { CKA_KEY_TYPE, &key_type, sizeof (key_type) },
- /* 3 to 12 */
- { CKA_DERIVE, NULL, 0 },
- { CKA_LOCAL, NULL, 0 },
- { CKA_DECRYPT, NULL, 0 },
- { CKA_SIGN, NULL, 0 },
- { CKA_SIGN_RECOVER, NULL, 0 },
- { CKA_UNWRAP, NULL, 0 },
- { CKA_SENSITIVE, NULL, 0 },
- { CKA_ALWAYS_SENSITIVE, NULL, 0 },
- { CKA_EXTRACTABLE, NULL, 0 },
- { CKA_NEVER_EXTRACTABLE, NULL, 0 },
- /* 13 to 17 */
- { CKA_LABEL, NULL, 0 }, /* optional */
- { CKA_ID, NULL, 0 }, /* optional */
- { CKA_SUBJECT, NULL, 0 }, /* optional */
- { CKA_START_DATE, NULL, 0 }, /* optional */
- { CKA_END_DATE, NULL, 0 } /* optional */
- /* not displaying CKA_KEY_GEN_MECHANISM */
- };
- CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
- int i;
- char *hex_id = NULL;
- int hex_id_len = 0;
- char *hex_subject = NULL;
- int hex_subject_len = 0;
-
- cryptodebug("inside display_prikey");
-
- /* Get the sizes of the attributes we need. */
- cryptodebug("calling C_GetAttributeValue for size info");
- if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get private key attribute sizes (%s)."),
- pkcs11_strerror(rv));
- return (rv);
- }
-
- /* Allocate memory for each variable-length attribute. */
- for (i = 3; i < n_attrs; i++) {
- if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
- attrs[i].ulValueLen == 0) {
- cryptodebug("display_prikey: *** should not happen");
- attrs[i].ulValueLen = 0;
- continue;
- }
- if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_prikey;
+ if (key->keyclass == KMF_ASYM_PUB) {
+ if (key->keyalg == KMF_RSA)
+ return (gettext("RSA public key"));
+ if (key->keyalg == KMF_DSA)
+ return (gettext("DSA public key"));
+ }
+ if (key->keyclass == KMF_ASYM_PRI) {
+ if (key->keyalg == KMF_RSA)
+ return ("RSA private key");
+ if (key->keyalg == KMF_DSA)
+ return ("DSA private key");
+ }
+ if (key->keyclass == KMF_SYMMETRIC) {
+ switch (key->keyalg) {
+ case KMF_AES:
+ return (gettext("AES"));
+ break;
+ case KMF_RC4:
+ return (gettext("ARCFOUR"));
+ break;
+ case KMF_DES:
+ return (gettext("DES"));
+ break;
+ case KMF_DES3:
+ return (gettext("Triple-DES"));
+ break;
+ default:
+ return (gettext("symmetric"));
+ break;
}
}
- /* Now really get the attributes. */
- cryptodebug("calling C_GetAttributeValue for attribute info");
- if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get private key attributes (%s)."),
- pkcs11_strerror(rv));
- goto free_display_prikey;
+ return (gettext("unrecognized key object"));
+
+}
+
+static char *
+keybitstr(KMF_KEY_HANDLE *key)
+{
+ KMF_RAW_SYM_KEY *rkey;
+ char keystr[256];
+ char *p;
+
+ if (key == NULL || (key->keyclass != KMF_SYMMETRIC))
+ return ("");
+
+ rkey = (KMF_RAW_SYM_KEY *)key->keyp;
+ (void) memset(keystr, 0, sizeof (keystr));
+ if (rkey != NULL) {
+ (void) snprintf(keystr, sizeof (keystr),
+ " (%d bits)", rkey->keydata.len * 8);
+ p = keystr;
+ } else {
+ return ("");
}
- /* Fill in all the optional temp variables. */
- i = 13;
- copy_attr_to_string(&(attrs[i++]), &label, &label_len);
- copy_attr_to_string(&(attrs[i++]), &id, &id_len);
- copy_attr_to_string(&(attrs[i++]), &subject, &subject_len);
- copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len);
- copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len);
-
- /* Get the key size for the object. */
- key_size = get_key_size(sess, obj, key_type);
-
- /* Display the object ... */
- /* ... the label and what it is (and key size in bits) ... */
- (void) fprintf(stdout, gettext("%d. \"%.*s\" (%d-bit %s %s)\n"),
- counter, label_len, label_len > 0 ? (char *)label :
- gettext("<no label>"), key_size, keytype_str(key_type),
- class_str(CKO_PRIVATE_KEY));
-
- /* ... the id ... */
- if (id_len == (CK_ULONG)-1 || id_len == 0)
- (void) fprintf(stdout, gettext("\tId: --\n"));
- else {
- hex_id_len = 3 * id_len + 1;
- if ((hex_id = malloc(hex_id_len)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_prikey;
+ return (p);
+}
+
+static void
+pk_show_keys(void *handle, KMF_KEY_HANDLE *keys, int numkeys)
+{
+ int i;
+
+ for (i = 0; i < numkeys; i++) {
+ (void) fprintf(stdout, gettext("Key #%d - %s: %s%s"),
+ i+1, describeKey(&keys[i]),
+ keys[i].keylabel ? keys[i].keylabel :
+ gettext("No label"),
+ (keys[i].keyclass == KMF_SYMMETRIC ?
+ keybitstr(&keys[i]) : ""));
+
+ if (keys[i].keyclass == KMF_SYMMETRIC) {
+ KMF_RETURN rv;
+ KMF_RAW_SYM_KEY rkey;
+ rv = KMF_GetSymKeyValue(handle, &keys[i],
+ &rkey);
+ if (rv == KMF_OK) {
+ (void) fprintf(stdout, "\t %d bits",
+ rkey.keydata.len * 8);
+ KMF_FreeRawSymKey(&rkey);
+ }
}
- octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
- "\n\t\t", "");
- (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id);
- free(hex_id);
+ (void) fprintf(stdout, "\n");
}
+}
- /* ... the subject name ... */
- if (subject_len == (CK_ULONG)-1 || subject_len == 0)
- (void) fprintf(stdout, gettext("\tSubject: --\n"));
- else {
- hex_subject_len = 2 * subject_len + 1; /* best guesstimate */
- if ((hex_subject = malloc(hex_subject_len)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_prikey;
+/*
+ * Generic routine used by all "list cert" operations to find
+ * all matching certificates.
+ */
+static KMF_RETURN
+pk_find_certs(KMF_HANDLE_T kmfhandle, KMF_FINDCERT_PARAMS *params)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_X509_DER_CERT *certlist = NULL;
+ uint32_t numcerts = 0;
+
+ numcerts = 0;
+ rv = KMF_FindCert(kmfhandle, params, NULL, &numcerts);
+ if (rv == KMF_OK && numcerts > 0) {
+ (void) printf(gettext("Found %d certificates.\n"),
+ numcerts);
+ certlist = (KMF_X509_DER_CERT *)malloc(numcerts *
+ sizeof (KMF_X509_DER_CERT));
+ if (certlist == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(certlist, 0, numcerts *
+ sizeof (KMF_X509_DER_CERT));
+
+ rv = KMF_FindCert(kmfhandle, params, certlist, &numcerts);
+ if (rv == KMF_OK) {
+ int i;
+ (void) pk_show_certs(kmfhandle, certlist,
+ numcerts);
+ for (i = 0; i < numcerts; i++)
+ KMF_FreeKMFCert(kmfhandle, &certlist[i]);
}
- rdnseq_to_str(subject, subject_len, hex_subject,
- hex_subject_len);
- (void) fprintf(stdout, gettext("\tSubject: %.*s\n"),
- hex_subject_len, hex_subject);
- free(hex_subject);
+ free(certlist);
}
+ if (rv == KMF_ERR_CERT_NOT_FOUND &&
+ params->kstype != KMF_KEYSTORE_OPENSSL)
+ rv = KMF_OK;
- /* ... the start date ... */
- if (start_date_len == (CK_ULONG)-1 || start_date_len == 0)
- (void) fprintf(stdout, gettext("\tStart Date: --\n"));
- else
- (void) fprintf(stdout, gettext(
- "\tStart Date: %02.2s/%02.2s/%04.4s\n"),
- start_date->month, start_date->day, start_date->year);
-
- /* ... the end date ... */
- if (end_date_len == (CK_ULONG)-1 || end_date_len == 0)
- (void) fprintf(stdout, gettext("\tEnd Date: --\n"));
- else
- (void) fprintf(stdout, gettext(
- "\tEnd Date: %02.2s/%02.2s/%04.4s\n"),
- end_date->month, end_date->day, end_date->year);
-
- /* ... and its capabilities */
- (void) fprintf(stdout, "\t(%s, %s",
- private != pk_false ? gettext("private") : gettext("public"),
- modifiable == B_TRUE ? gettext("modifiable") :
- gettext("not modifiable"));
- for (i = 3; i <= 12; i++) {
- if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
- attrs[i].ulValueLen != 0 &&
- *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE)
- (void) fprintf(stdout, ", %s", attr_str(attrs[i].type));
- }
- (void) fprintf(stdout, ")\n");
+ return (rv);
+}
-free_display_prikey:
- for (i = 3; i < n_attrs; i++)
- if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
- attrs[i].ulValueLen != 0)
- free(attrs[i].pValue);
+static KMF_RETURN
+pk_list_keys(void *handle, KMF_FINDKEY_PARAMS *parms)
+{
+ KMF_RETURN rv;
+ KMF_KEY_HANDLE *keys;
+ uint32_t numkeys = 0;
+
+ numkeys = 0;
+ rv = KMF_FindKey(handle, parms, NULL, &numkeys);
+ if (rv == KMF_OK && numkeys > 0) {
+ int i;
+ (void) printf(gettext("Found %d keys.\n"), numkeys);
+ keys = (KMF_KEY_HANDLE *)malloc(numkeys *
+ sizeof (KMF_KEY_HANDLE));
+ if (keys == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(keys, 0, numkeys *
+ sizeof (KMF_KEY_HANDLE));
+
+ rv = KMF_FindKey(handle, parms, keys, &numkeys);
+ if (rv == KMF_OK)
+ pk_show_keys(handle, keys, numkeys);
+ for (i = 0; i < numkeys; i++)
+ KMF_FreeKMFKey(handle, &keys[i]);
+ free(keys);
+ }
+ if (rv == KMF_ERR_KEY_NOT_FOUND &&
+ parms->kstype != KMF_KEYSTORE_OPENSSL)
+ rv = KMF_OK;
return (rv);
}
-/*
- * Display public key.
- */
-static CK_RV
-display_pubkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
+static KMF_RETURN
+list_pk11_objects(KMF_HANDLE_T kmfhandle, char *token, int oclass,
+ char *objlabel, KMF_BIGINT *serial, char *issuer, char *subject,
+ char *dir, char *filename, KMF_CREDENTIAL *tokencred,
+ KMF_CERT_VALIDITY find_criteria_flag)
{
- CK_RV rv = CKR_OK;
- static CK_BBOOL private;
- static CK_BBOOL modifiable;
- static CK_BBOOL trusted;
- static CK_KEY_TYPE key_type;
- CK_ULONG key_size;
- CK_BYTE *label = NULL;
- CK_ULONG label_len = 0;
- CK_BYTE *id = NULL;
- CK_ULONG id_len = 0;
- CK_BYTE *subject = NULL;
- CK_ULONG subject_len = 0;
- CK_DATE *start_date = NULL;
- CK_ULONG start_date_len = 0;
- CK_DATE *end_date = NULL;
- CK_ULONG end_date_len = 0;
- CK_ATTRIBUTE attrs[15] = {
- /* 0 to 3 */
- { CKA_PRIVATE, &private, sizeof (private) },
- { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
- { CKA_TRUSTED, &trusted, sizeof (trusted) },
- { CKA_KEY_TYPE, &key_type, sizeof (key_type) },
- /* 4 to 9 */
- { CKA_DERIVE, NULL, 0 },
- { CKA_LOCAL, NULL, 0 },
- { CKA_ENCRYPT, NULL, 0 },
- { CKA_VERIFY, NULL, 0 },
- { CKA_VERIFY_RECOVER, NULL, 0 },
- { CKA_WRAP, NULL, 0 },
- /* 10 to 14 */
- { CKA_LABEL, NULL, 0 }, /* optional */
- { CKA_ID, NULL, 0 }, /* optional */
- { CKA_SUBJECT, NULL, 0 }, /* optional */
- { CKA_START_DATE, NULL, 0 }, /* optional */
- { CKA_END_DATE, NULL, 0 } /* optional */
- /* not displaying CKA_KEY_GEN_MECHANISM */
- };
- CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
- int i;
- char *hex_id = NULL;
- int hex_id_len = 0;
- char *hex_subject = NULL;
- int hex_subject_len = 0;
-
- cryptodebug("inside display_pubkey");
-
- /* Get the sizes of the attributes we need. */
- cryptodebug("calling C_GetAttributeValue for size info");
- if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get public key attribute sizes (%s)."),
- pkcs11_strerror(rv));
+ KMF_RETURN rv;
+ KMF_LISTCRL_PARAMS lcrlargs;
+
+ /*
+ * Symmetric keys and RSA/DSA private keys are always
+ * created with the "CKA_PRIVATE" field == TRUE, so
+ * make sure we search for them with it also set.
+ */
+ if (oclass & (PK_SYMKEY_OBJ | PK_PRIKEY_OBJ))
+ oclass |= PK_PRIVATE_OBJ;
+
+ rv = select_token(kmfhandle, token,
+ !(oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)));
+
+ if (rv != KMF_OK) {
return (rv);
}
- /* Allocate memory for each variable-length attribute. */
- for (i = 4; i < n_attrs; i++) {
- if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
- attrs[i].ulValueLen == 0) {
- cryptodebug("display_pubkey: *** should not happen");
- attrs[i].ulValueLen = 0;
- continue;
+ if (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ)) {
+ KMF_FINDKEY_PARAMS parms;
+
+ (void) memset(&parms, 0, sizeof (parms));
+ parms.kstype = KMF_KEYSTORE_PK11TOKEN;
+
+ if (oclass & PK_PRIKEY_OBJ) {
+ parms.keyclass = KMF_ASYM_PRI;
+ parms.findLabel = objlabel;
+ parms.cred = *tokencred;
+ parms.pkcs11parms.private =
+ ((oclass & PK_PRIVATE_OBJ) > 0);
+
+ /* list asymmetric private keys */
+ rv = pk_list_keys(kmfhandle, &parms);
}
- if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_pubkey;
+
+ if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) {
+ parms.keyclass = KMF_SYMMETRIC;
+ parms.findLabel = objlabel;
+ parms.cred = *tokencred;
+ parms.format = KMF_FORMAT_RAWKEY;
+ parms.pkcs11parms.private =
+ ((oclass & PK_PRIVATE_OBJ) > 0);
+
+ /* list symmetric keys */
+ rv = pk_list_keys(kmfhandle, &parms);
}
- }
- /* Now really get the attributes. */
- cryptodebug("calling C_GetAttributeValue for attribute info");
- if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get public key attributes (%s)."),
- pkcs11_strerror(rv));
- goto free_display_pubkey;
- }
+ if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) {
+ parms.keyclass = KMF_ASYM_PUB;
+ parms.findLabel = objlabel;
+ parms.pkcs11parms.private =
+ ((oclass & PK_PRIVATE_OBJ) > 0);
- /* Fill in all the optional temp variables. */
- i = 10;
- copy_attr_to_string(&(attrs[i++]), &label, &label_len);
- copy_attr_to_string(&(attrs[i++]), &id, &id_len);
- copy_attr_to_string(&(attrs[i++]), &subject, &subject_len);
- copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len);
- copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len);
-
- /* Get the key size for the object. */
- key_size = get_key_size(sess, obj, key_type);
-
- /* Display the object ... */
- /* ... the label and what it is (and key size in bits) ... */
- (void) fprintf(stdout, gettext("%d. \"%.*s\" (%d-bit %s %s)\n"),
- counter, label_len, label_len > 0 ? (char *)label :
- gettext("<no label>"), key_size, keytype_str(key_type),
- class_str(CKO_PUBLIC_KEY));
-
- /* ... the id ... */
- if (id_len == (CK_ULONG)-1 || id_len == 0)
- (void) fprintf(stdout, gettext("\tId: --\n"));
- else {
- hex_id_len = 3 * id_len + 1;
- if ((hex_id = malloc(hex_id_len)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_pubkey;
+ /* list asymmetric public keys (if any) */
+ rv = pk_list_keys(kmfhandle, &parms);
}
- octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
- "\n\t\t", "");
- (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id);
- free(hex_id);
+
+ if (rv != KMF_OK)
+ return (rv);
}
- /* ... the subject name ... */
- if (subject_len == (CK_ULONG)-1 || subject_len == 0)
- (void) fprintf(stdout, gettext("\tSubject: --\n"));
- else {
- hex_subject_len = 2 * subject_len + 1; /* best guesstimate */
- if ((hex_subject = malloc(hex_subject_len)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_pubkey;
- }
- rdnseq_to_str(subject, subject_len, hex_subject,
- hex_subject_len);
- (void) fprintf(stdout, gettext("\tSubject: %.*s\n"),
- hex_subject_len, hex_subject);
- free(hex_subject);
+ if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) {
+ KMF_FINDCERT_PARAMS parms;
+
+ (void) memset(&parms, 0, sizeof (parms));
+ parms.kstype = KMF_KEYSTORE_PK11TOKEN;
+ parms.certLabel = objlabel;
+ parms.issuer = issuer;
+ parms.subject = subject;
+ parms.serial = serial;
+ parms.pkcs11parms.private = FALSE;
+ parms.find_cert_validity = find_criteria_flag;
+
+ rv = pk_find_certs(kmfhandle, &parms);
+ if (rv != KMF_OK)
+ return (rv);
}
- /* ... the start date ... */
- if (start_date_len == (CK_ULONG)-1 || start_date_len == 0)
- (void) fprintf(stdout, gettext("\tStart Date: --\n"));
- else
- (void) fprintf(stdout, gettext(
- "\tStart Date: %02.2s/%02.2s/%04.4s\n"),
- start_date->month, start_date->day, start_date->year);
-
- /* ... the end date ... */
- if (end_date_len == (CK_ULONG)-1 || end_date_len == 0)
- (void) fprintf(stdout, gettext("\tEnd Date: --\n"));
- else
- (void) fprintf(stdout, gettext(
- "\tEnd Date: %02.2s/%02.2s/%04.4s\n"),
- end_date->month, end_date->day, end_date->year);
-
- /* ... and its capabilities */
- (void) fprintf(stdout, "\t(%s, %s, %s",
- private == B_TRUE ? gettext("private") : gettext("public"),
- modifiable == B_TRUE ? gettext("modifiable") :
- gettext("not modifiable"),
- trusted == B_TRUE ? gettext("trusted") : gettext("untrusted"));
- for (i = 4; i <= 9; i++) {
- if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
- attrs[i].ulValueLen != 0 &&
- *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE)
- (void) fprintf(stdout, ", %s", attr_str(attrs[i].type));
+ if (oclass & PK_CRL_OBJ) {
+ char *crldata;
+
+ (void) memset(&lcrlargs, 0, sizeof (lcrlargs));
+ lcrlargs.kstype = KMF_KEYSTORE_OPENSSL;
+ lcrlargs.sslparms.dirpath = dir;
+ lcrlargs.sslparms.crlfile = filename;
+
+ rv = KMF_ListCRL(kmfhandle, &lcrlargs, &crldata);
+ if (rv == KMF_OK) {
+ (void) printf("%s\n", crldata);
+ free(crldata);
+ }
}
- (void) fprintf(stdout, ")\n");
-free_display_pubkey:
- for (i = 4; i < n_attrs; i++)
- if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
- attrs[i].ulValueLen != 0)
- free(attrs[i].pValue);
return (rv);
}
-/*
- * Display secret key.
- */
-static CK_RV
-display_seckey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
+static int
+list_file_objects(KMF_HANDLE_T kmfhandle, int oclass,
+ char *dir, char *filename, KMF_BIGINT *serial,
+ char *issuer, char *subject,
+ KMF_CERT_VALIDITY find_criteria_flag)
{
- CK_RV rv = CKR_OK;
- static CK_BBOOL private;
- static CK_BBOOL modifiable;
- static CK_KEY_TYPE key_type;
- static CK_ULONG key_size;
- CK_BYTE *label = NULL;
- CK_ULONG label_len = 0;
- CK_BYTE *id = NULL;
- CK_ULONG id_len = 0;
- CK_DATE *start_date = NULL;
- CK_ULONG start_date_len = 0;
- CK_DATE *end_date = NULL;
- CK_ULONG end_date_len = 0;
- CK_ATTRIBUTE attrs[19] = {
- /* 0 to 2 */
- { CKA_PRIVATE, &private, sizeof (private) },
- { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
- { CKA_KEY_TYPE, &key_type, sizeof (key_type) },
- /* 3 to 14 */
- { CKA_DERIVE, NULL, 0 },
- { CKA_LOCAL, NULL, 0 },
- { CKA_ENCRYPT, NULL, 0 },
- { CKA_DECRYPT, NULL, 0 },
- { CKA_SIGN, NULL, 0 },
- { CKA_VERIFY, NULL, 0 },
- { CKA_WRAP, NULL, 0 },
- { CKA_UNWRAP, NULL, 0 },
- { CKA_SENSITIVE, NULL, 0 },
- { CKA_ALWAYS_SENSITIVE, NULL, 0 },
- { CKA_EXTRACTABLE, NULL, 0 },
- { CKA_NEVER_EXTRACTABLE, 0 },
- /* 15 to 18 */
- { CKA_LABEL, NULL, 0 }, /* optional */
- { CKA_ID, NULL, 0 }, /* optional */
- { CKA_START_DATE, NULL, 0 }, /* optional */
- { CKA_END_DATE, NULL, 0 } /* optional */
- /* not displaying CKA_KEY_GEN_MECHANISM */
- };
- CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
- int i;
- char *hex_id = NULL;
- int hex_id_len = 0;
-
- cryptodebug("inside display_seckey");
-
- /* Get the sizes of the attributes we need. */
- cryptodebug("calling C_GetAttributeValue for size info");
- if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get secret key attribute sizes (%s)."),
- pkcs11_strerror(rv));
- return (rv);
- }
-
- /* Allocate memory for each variable-length attribute. */
- for (i = 3; i < n_attrs; i++) {
- if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
- attrs[i].ulValueLen == 0) {
- cryptodebug("display_seckey: *** should not happen");
- attrs[i].ulValueLen = 0;
- continue;
+ int rv;
+ KMF_FINDCERT_PARAMS fcargs;
+ KMF_FINDKEY_PARAMS fkargs;
+ KMF_LISTCRL_PARAMS lcrlargs;
+
+ if (oclass & PK_KEY_OBJ) {
+ (void) memset(&fkargs, 0, sizeof (fkargs));
+ fkargs.kstype = KMF_KEYSTORE_OPENSSL;
+ fkargs.sslparms.dirpath = dir;
+ fkargs.sslparms.keyfile = filename;
+ if (oclass & PK_PRIKEY_OBJ) {
+ fkargs.keyclass = KMF_ASYM_PRI;
+
+ rv = pk_list_keys(kmfhandle, &fkargs);
}
- if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_seckey;
- }
- }
+ if (rv == KMF_ERR_KEY_NOT_FOUND)
+ rv = KMF_OK;
- /* Now really get the attributes. */
- cryptodebug("calling C_GetAttributeValue for attribute info");
- if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get secret key attributes (%s)."),
- pkcs11_strerror(rv));
- goto free_display_seckey;
- }
+ if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) {
+ fkargs.keyclass = KMF_SYMMETRIC;
+ fkargs.format = KMF_FORMAT_RAWKEY;
- /* Fill in all the optional temp variables. */
- i = 15;
- copy_attr_to_string(&(attrs[i++]), &label, &label_len);
- copy_attr_to_string(&(attrs[i++]), &id, &id_len);
- copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len);
- copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len);
-
- /* Get the key size for the object. */
- key_size = get_key_size(sess, obj, key_type);
-
- /* Display the object ... */
- /* ... the label and what it is (and key size in bytes) ... */
- (void) fprintf(stdout, gettext("%d. \"%.*s\" (%d-bit %s %s)\n"),
- counter, label_len, label_len > 0 ? (char *)label :
- gettext("<no label>"), key_size, keytype_str(key_type),
- class_str(CKO_SECRET_KEY));
-
- /* ... the id ... */
- if (id_len == (CK_ULONG)-1 || id_len == 0)
- (void) fprintf(stdout, gettext("\tId: --\n"));
- else {
- hex_id_len = 3 * id_len + 1;
- if ((hex_id = malloc(hex_id_len)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_seckey;
+ rv = pk_list_keys(kmfhandle, &fkargs);
+ }
+ if (rv == KMF_ERR_KEY_NOT_FOUND)
+ rv = KMF_OK;
+ if (rv != KMF_OK)
+ return (rv);
+ }
+
+ if (oclass & PK_CERT_OBJ) {
+ (void) memset(&fcargs, 0, sizeof (fcargs));
+ fcargs.kstype = KMF_KEYSTORE_OPENSSL;
+ fcargs.certLabel = NULL;
+ fcargs.issuer = issuer;
+ fcargs.subject = subject;
+ fcargs.serial = serial;
+ fcargs.sslparms.dirpath = dir;
+ fcargs.sslparms.certfile = filename;
+ fcargs.find_cert_validity = find_criteria_flag;
+
+ rv = pk_find_certs(kmfhandle, &fcargs);
+ if (rv != KMF_OK)
+ return (rv);
+ }
+
+ if (oclass & PK_CRL_OBJ) {
+ char *crldata;
+
+ (void) memset(&lcrlargs, 0, sizeof (lcrlargs));
+ lcrlargs.kstype = KMF_KEYSTORE_OPENSSL;
+ lcrlargs.sslparms.dirpath = dir;
+ lcrlargs.sslparms.crlfile = filename;
+
+ rv = KMF_ListCRL(kmfhandle, &lcrlargs, &crldata);
+ if (rv == KMF_OK) {
+ (void) printf("%s\n", crldata);
+ free(crldata);
}
- octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
- "\n\t\t", "");
- (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id);
- free(hex_id);
- }
-
- /* ... the start date ... */
- if (start_date_len == (CK_ULONG)-1 || start_date_len == 0)
- (void) fprintf(stdout, gettext("\tStart Date: --\n"));
- else
- (void) fprintf(stdout, gettext(
- "\tStart Date: %02.2s/%02.2s/%04.4s\n"),
- start_date->month, start_date->day, start_date->year);
-
- /* ... the end date ... */
- if (end_date_len == (CK_ULONG)-1 || end_date_len == 0)
- (void) fprintf(stdout, gettext("\tEnd Date: --\n"));
- else
- (void) fprintf(stdout, gettext(
- "\tEnd Date: %02.2s/%02.2s/%04.4s\n"),
- end_date->month, end_date->day, end_date->year);
-
- /* ... and its capabilities */
- (void) fprintf(stdout, "\t(%s, %s",
- private == B_TRUE ? gettext("private") : gettext("public"),
- modifiable == B_TRUE ? gettext("modifiable") :
- gettext("not modifiable"));
- for (i = 3; i <= 14; i++) {
- if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
- attrs[i].ulValueLen != 0 &&
- *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE)
- (void) fprintf(stdout, ", %s", attr_str(attrs[i].type));
}
- (void) fprintf(stdout, ")\n");
-free_display_seckey:
- for (i = 3; i < n_attrs; i++)
- if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
- attrs[i].ulValueLen != 0)
- free(attrs[i].pValue);
return (rv);
}
-/*
- * Display certificate.
- */
-static CK_RV
-display_cert(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
+static int
+list_nss_objects(KMF_HANDLE_T kmfhandle,
+ int oclass, char *token_spec, char *dir, char *prefix,
+ char *nickname, KMF_BIGINT *serial, char *issuer, char *subject,
+ KMF_CREDENTIAL *tokencred,
+ KMF_CERT_VALIDITY find_criteria_flag)
{
- CK_RV rv = CKR_OK;
- static CK_BBOOL private;
- static CK_BBOOL modifiable;
- static CK_BBOOL trusted;
- CK_BYTE *subject = NULL;
- CK_ULONG subject_len = 0;
- CK_BYTE *value = NULL;
- CK_ULONG value_len = 0;
- CK_BYTE *label = NULL;
- CK_ULONG label_len = 0;
- CK_BYTE *id = NULL;
- CK_ULONG id_len = 0;
- CK_BYTE *issuer = NULL;
- CK_ULONG issuer_len = 0;
- CK_BYTE *serial = NULL;
- CK_ULONG serial_len = 0;
- CK_ATTRIBUTE attrs[9] = {
- { CKA_PRIVATE, &private, sizeof (private) },
- { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
- { CKA_TRUSTED, &trusted, sizeof (trusted) },
- { CKA_SUBJECT, NULL, 0 }, /* required */
- { CKA_VALUE, NULL, 0 }, /* required */
- { CKA_LABEL, NULL, 0 }, /* optional */
- { CKA_ID, NULL, 0 }, /* optional */
- { CKA_ISSUER, NULL, 0 }, /* optional */
- { CKA_SERIAL_NUMBER, NULL, 0 } /* optional */
- };
- CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
- int i;
- char *hex_id = NULL;
- int hex_id_len = 0;
- char *hex_subject = NULL;
- int hex_subject_len = 0;
- char *hex_issuer = NULL;
- int hex_issuer_len = 0;
- char *hex_serial = NULL;
- int hex_serial_len = NULL;
- uint32_t serial_value = 0;
- char *hex_value = NULL;
- int hex_value_len = 0;
-
- cryptodebug("inside display_cert");
-
- /* Get the sizes of the attributes we need. */
- cryptodebug("calling C_GetAttributeValue for size info");
- if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get certificate attribute sizes (%s)."),
- pkcs11_strerror(rv));
+ KMF_RETURN rv = KMF_OK;
+ KMF_FINDKEY_PARAMS fkargs;
+
+ rv = configure_nss(kmfhandle, dir, prefix);
+ if (rv != KMF_OK)
return (rv);
- }
- /* Allocate memory for each variable-length attribute. */
- for (i = 3; i < n_attrs; i++) {
- if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
- attrs[i].ulValueLen == 0) {
- cryptodebug("display_cert: *** should not happen");
- attrs[i].ulValueLen = 0;
- continue;
- }
- if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_cert;
- }
+ if (oclass & PK_KEY_OBJ) {
+ (void) memset(&fkargs, 0, sizeof (fkargs));
+ fkargs.kstype = KMF_KEYSTORE_NSS;
+ fkargs.findLabel = nickname;
+ fkargs.cred = *tokencred;
+ fkargs.nssparms.slotlabel = token_spec;
}
- /* Now really get the attributes. */
- cryptodebug("calling C_GetAttributeValue for attribute info");
- if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get certificate attributes (%s)."),
- pkcs11_strerror(rv));
- goto free_display_cert;
+ if (oclass & PK_PRIKEY_OBJ) {
+ fkargs.keyclass = KMF_ASYM_PRI;
+ rv = pk_list_keys(kmfhandle, &fkargs);
}
-
- /*
- * Fill in all the temp variables. Subject and value are required.
- * The rest are optional.
- */
- i = 3;
- copy_attr_to_string(&(attrs[i++]), &subject, &subject_len);
- copy_attr_to_string(&(attrs[i++]), &value, &value_len);
- copy_attr_to_string(&(attrs[i++]), &label, &label_len);
- copy_attr_to_string(&(attrs[i++]), &id, &id_len);
- copy_attr_to_string(&(attrs[i++]), &issuer, &issuer_len);
- copy_attr_to_string(&(attrs[i++]), &serial, &serial_len);
-
- /* Display the object ... */
- /* ... the label and what it is ... */
- (void) fprintf(stdout, gettext("%d. \"%.*s\" (%s %s)\n"),
- counter, label_len, label_len > 0 ? (char *)label :
- gettext("<no label>"), "X.509", class_str(CKO_CERTIFICATE));
-
- /* ... its capabilities ... */
- (void) fprintf(stdout, gettext("\t(%s, %s, %s)\n"),
- private == B_TRUE ? gettext("private") : gettext("public"),
- modifiable == B_TRUE ? gettext("modifiable") :
- gettext("not modifiable"),
- trusted == B_TRUE ? gettext("trusted") : gettext("untrusted"));
-
- /* ... the id ... */
- if (id_len == (CK_ULONG)-1 || id_len == 0)
- (void) fprintf(stdout, gettext("\tId: --\n"));
- else {
- hex_id_len = 3 * id_len + 1;
- if ((hex_id = malloc(hex_id_len)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_cert;
- }
- octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
- "\n\t\t", "");
- (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id);
- free(hex_id);
+ if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) {
+ fkargs.keyclass = KMF_SYMMETRIC;
+ fkargs.format = KMF_FORMAT_RAWKEY;
+ rv = pk_list_keys(kmfhandle, &fkargs);
}
-
- /* ... the subject name ... */
- if (subject_len == (CK_ULONG)-1 || subject_len == 0)
- (void) fprintf(stdout, gettext("\tSubject: --\n"));
- else {
- hex_subject_len = 2 * subject_len + 1; /* best guesstimate */
- if ((hex_subject = malloc(hex_subject_len)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_cert;
- }
- rdnseq_to_str(subject, subject_len, hex_subject,
- hex_subject_len);
- (void) fprintf(stdout, gettext("\tSubject: %.*s\n"),
- hex_subject_len, hex_subject);
- free(hex_subject);
+ if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) {
+ fkargs.keyclass = KMF_ASYM_PUB;
+ rv = pk_list_keys(kmfhandle, &fkargs);
}
- /* ... the issuer name ... */
- if (issuer_len == (CK_ULONG)-1 || issuer_len == 0)
- (void) fprintf(stdout, gettext("\tIssuer: --\n"));
- else {
- hex_issuer_len = 2 * issuer_len + 1; /* best guesstimate */
- if ((hex_issuer = malloc(hex_issuer_len)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_cert;
- }
- rdnseq_to_str(issuer, issuer_len, hex_issuer, hex_issuer_len);
- (void) fprintf(stdout, gettext("\tIssuer: %.*s\n"),
- hex_issuer_len, hex_issuer);
- free(hex_issuer);
- }
+ /* If searching for public objects or certificates, find certs now */
+ if (rv == KMF_OK && (oclass & PK_CERT_OBJ)) {
+ KMF_FINDCERT_PARAMS fcargs;
- /* ... the serial number ... */
- if (serial_len == (CK_ULONG)-1 || serial_len == 0)
- (void) fprintf(stdout, gettext("\tSerial: --\n"));
- else {
- hex_serial_len = 3 * serial_len + 1;
- if ((hex_serial = malloc(hex_serial_len)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_cert;
- }
- octetify(serial, serial_len, hex_serial, hex_serial_len,
- B_FALSE, B_FALSE, 60, "\n\t\t", "");
- if (serial_len > 4)
- (void) fprintf(stdout, gettext("\tSerial: %s\n"),
- hex_serial);
- else {
- for (i = 0; i < serial_len; i++) {
- serial_value <<= 8;
- serial_value |= (serial[i] & 0xff);
- }
- (void) fprintf(stdout, gettext("\tSerial: %s (%d)\n"),
- hex_serial, serial_value);
- }
- free(hex_serial);
+ (void) memset(&fcargs, 0, sizeof (fcargs));
+ fcargs.kstype = KMF_KEYSTORE_NSS;
+ fcargs.certLabel = nickname;
+ fcargs.issuer = issuer;
+ fcargs.subject = subject;
+ fcargs.serial = serial;
+ fcargs.nssparms.slotlabel = token_spec;
+ fcargs.find_cert_validity = find_criteria_flag;
+
+ rv = pk_find_certs(kmfhandle, &fcargs);
}
- /* ... and the value */
- if (value_len == (CK_ULONG)-1 || value_len == 0)
- (void) fprintf(stdout, gettext("\tValue: --\n"));
- else {
- hex_value_len = 3 * value_len + 1;
- if ((hex_value = malloc(hex_value_len)) == NULL) {
- cryptoerror(LOG_STDERR, "%s.", strerror(errno));
- rv = CKR_HOST_MEMORY;
- goto free_display_cert;
+ if (rv == KMF_OK && (oclass & PK_CRL_OBJ)) {
+ int numcrls;
+ KMF_FINDCRL_PARAMS fcrlargs;
+
+ (void) memset(&fcrlargs, 0, sizeof (fcrlargs));
+ fcrlargs.kstype = KMF_KEYSTORE_NSS;
+ fcrlargs.nssparms.slotlabel = token_spec;
+
+ rv = KMF_FindCRL(kmfhandle, &fcrlargs, NULL, &numcrls);
+ if (rv == KMF_OK) {
+ char **p;
+ if (numcrls == 0) {
+ (void) printf(gettext("No CRLs found in "
+ "NSS keystore.\n"));
+
+ return (KMF_OK);
+ }
+ p = malloc(numcrls * sizeof (char *));
+ if (p == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+ (void) memset(p, 0, numcrls * sizeof (char *));
+ rv = KMF_FindCRL(kmfhandle, &fcrlargs,
+ p, &numcrls);
+ if (rv == KMF_OK) {
+ int i;
+ for (i = 0; i < numcrls; i++) {
+ (void) printf("%d. Name = %s\n",
+ i + 1, p[i]);
+ free(p[i]);
+ }
+ }
+ free(p);
}
- octetify(value, value_len, hex_value, hex_value_len,
- B_FALSE, B_FALSE, 60, "\n\t\t", "");
- (void) fprintf(stdout, gettext("\tValue: %s\n"), hex_value);
- free(hex_value);
}
-
-free_display_cert:
- for (i = 3; i < n_attrs; i++)
- if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
- attrs[i].ulValueLen != 0)
- free(attrs[i].pValue);
return (rv);
}
@@ -840,207 +527,189 @@ pk_list(int argc, char *argv[])
extern int optind_av;
extern char *optarg_av;
char *token_spec = NULL;
- char *token_name = NULL;
- char *manuf_id = NULL;
- char *serial_no = NULL;
- char *type_spec = NULL;
- char full_name[FULL_NAME_LEN];
- boolean_t public_objs = B_FALSE;
- boolean_t private_objs = B_FALSE;
- CK_BYTE *list_label = NULL;
- int obj_type = 0x00;
- CK_SLOT_ID slot_id;
- CK_FLAGS pin_state;
- CK_UTF8CHAR_PTR pin = NULL;
- CK_ULONG pinlen = 0;
- CK_SESSION_HANDLE sess;
- CK_OBJECT_HANDLE *objs;
- CK_ULONG num_objs;
- CK_RV rv = CKR_OK;
- int i;
- static CK_OBJECT_CLASS objclass;
- CK_ATTRIBUTE class_attr =
- { CKA_CLASS, &objclass, sizeof (objclass) };
-
- cryptodebug("inside pk_list");
+ char *subject = NULL;
+ char *issuer = NULL;
+ char *dir = NULL;
+ char *prefix = NULL;
+ char *filename = NULL;
+ char *serstr = NULL;
+ KMF_BIGINT serial = { NULL, 0 };
+
+ char *list_label = NULL;
+ int oclass = 0;
+ KMF_KEYSTORE_TYPE kstype = 0;
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE_T kmfhandle = NULL;
+ char *find_criteria = NULL;
+ KMF_CERT_VALIDITY find_criteria_flag = KMF_ALL_CERTS;
+ KMF_CREDENTIAL tokencred = {NULL, 0};
/* Parse command line options. Do NOT i18n/l10n. */
while ((opt = getopt_av(argc, argv,
- "T:(token)y:(objtype)l:(label)")) != EOF) {
+ "k:(keystore)t:(objtype)T:(token)d:(dir)"
+ "p:(prefix)n:(nickname)S:(serial)s:(subject)"
+ "c:(criteria)"
+ "i:(issuer)l:(label)f:(infile)")) != EOF) {
+ if (EMPTYSTRING(optarg_av))
+ return (PK_ERR_USAGE);
switch (opt) {
- case 'T': /* token specifier */
- if (token_spec)
+ case 'k':
+ if (kstype != 0)
+ return (PK_ERR_USAGE);
+ kstype = KS2Int(optarg_av);
+ if (kstype == 0)
+ return (PK_ERR_USAGE);
+ break;
+ case 't':
+ if (oclass != 0)
+ return (PK_ERR_USAGE);
+ oclass = OT2Int(optarg_av);
+ if (oclass == -1)
+ return (PK_ERR_USAGE);
+ break;
+ case 's':
+ if (subject)
+ return (PK_ERR_USAGE);
+ subject = optarg_av;
+ break;
+ case 'i':
+ if (issuer)
+ return (PK_ERR_USAGE);
+ issuer = optarg_av;
+ break;
+ case 'd':
+ if (dir)
+ return (PK_ERR_USAGE);
+ dir = optarg_av;
+ break;
+ case 'p':
+ if (prefix)
+ return (PK_ERR_USAGE);
+ prefix = optarg_av;
+ break;
+ case 'S':
+ serstr = optarg_av;
+ break;
+ case 'f':
+ if (filename)
+ return (PK_ERR_USAGE);
+ filename = optarg_av;
+ break;
+ case 'T': /* token specifier */
+ if (token_spec)
+ return (PK_ERR_USAGE);
+ token_spec = optarg_av;
+ break;
+ case 'n':
+ case 'l': /* object with specific label */
+ if (list_label)
+ return (PK_ERR_USAGE);
+ list_label = optarg_av;
+ break;
+ case 'c':
+ find_criteria = optarg_av;
+ if (!strcasecmp(find_criteria, "valid"))
+ find_criteria_flag =
+ KMF_NONEXPIRED_CERTS;
+ else if (!strcasecmp(find_criteria, "expired"))
+ find_criteria_flag = KMF_EXPIRED_CERTS;
+ else if (!strcasecmp(find_criteria, "both"))
+ find_criteria_flag = KMF_ALL_CERTS;
+ else
+ return (PK_ERR_USAGE);
+ break;
+ default:
return (PK_ERR_USAGE);
- token_spec = optarg_av;
- break;
- case 'y': /* object type: public, private, both */
- if (type_spec)
- return (PK_ERR_USAGE);
- type_spec = optarg_av;
- break;
- case 'l': /* object with specific label */
- if (list_label)
- return (PK_ERR_USAGE);
- list_label = (CK_BYTE *)optarg_av;
- break;
- default:
- return (PK_ERR_USAGE);
- break;
}
}
+ /* No additional args allowed. */
+ argc -= optind_av;
+ argv += optind_av;
+ if (argc)
+ return (PK_ERR_USAGE);
- /* If no token is specified, default is to use softtoken. */
- if (token_spec == NULL) {
- token_name = SOFT_TOKEN_LABEL;
- manuf_id = SOFT_MANUFACTURER_ID;
- serial_no = SOFT_TOKEN_SERIAL;
- } else {
- /*
- * Parse token specifier into token_name, manuf_id, serial_no.
- * Token_name is required; manuf_id and serial_no are optional.
- */
- if (parse_token_spec(token_spec, &token_name, &manuf_id,
- &serial_no) < 0)
- return (PK_ERR_USAGE);
+ if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
+ /* Error message ? */
+ return (rv);
}
- /* If no object type specified, default is public objects. */
- if (!type_spec) {
- public_objs = B_TRUE;
- } else {
- /*
- * Otherwise, the object type must be "public", "private",
- * or "both".
- */
- if (strcmp(type_spec, "private") == 0) {
- private_objs = B_TRUE;
- } else if (strcmp(type_spec, "public") == 0) {
- public_objs = B_TRUE;
- } else if (strcmp(type_spec, "both") == 0) {
- private_objs = B_TRUE;
- public_objs = B_TRUE;
- } else
- return (PK_ERR_USAGE);
- }
+ /* Assume keystore = PKCS#11 if not specified. */
+ if (kstype == 0)
+ kstype = KMF_KEYSTORE_PK11TOKEN;
- if (private_objs)
- obj_type |= PK_PRIVATE_OBJ;
- if (public_objs)
- obj_type |= PK_PUBLIC_OBJ;
+ /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */
+ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) &&
+ kstype != KMF_KEYSTORE_PK11TOKEN) {
- /* No additional args allowed. */
- argc -= optind_av;
- argv += optind_av;
- if (argc)
+ (void) fprintf(stderr, gettext("The objtype parameter "
+ "is only relevant if keystore=pkcs11\n"));
return (PK_ERR_USAGE);
- /* Done parsing command line options. */
+ }
- full_token_name(token_name, manuf_id, serial_no, full_name);
+ /* If no object class specified, list certificate objects. */
+ if (oclass == 0)
+ oclass = PK_CERT_OBJ;
- /* Find the slot with token. */
- if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
- &pin_state)) != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to find token %s (%s)."), full_name,
- pkcs11_strerror(rv));
- return (PK_ERR_PK11);
+ if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) {
+ token_spec = PK_DEFAULT_PK11TOKEN;
+ } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) {
+ token_spec = DEFAULT_NSS_TOKEN;
}
- /* If private objects are to be listed, user must be logged in. */
- if (private_objs) {
- /* Get the user's PIN. */
- if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
- &pin, &pinlen)) != CKR_OK) {
- cryptoerror(LOG_STDERR,
- gettext("Unable to get token passphrase (%s)."),
- pkcs11_strerror(rv));
- quick_finish(NULL);
- return (PK_ERR_PK11);
- }
+ if (serstr != NULL) {
+ uchar_t *bytes = NULL;
+ size_t bytelen;
- /* Logging in user R/O into the token is sufficient. */
- cryptodebug("logging in with readonly session");
- if ((rv = quick_start(slot_id, 0, pin, pinlen, &sess)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR,
- gettext("Unable to log into token (%s)."),
- pkcs11_strerror(rv));
- quick_finish(sess);
- return (PK_ERR_PK11);
- }
- /* Otherwise, just create a session. */
- } else {
- cryptodebug("opening a readonly session");
- if ((rv = open_sess(slot_id, 0, &sess)) != CKR_OK) {
- cryptoerror(LOG_STDERR,
- gettext("Unable to open token session (%s)."),
- pkcs11_strerror(rv));
- quick_finish(sess);
- return (PK_ERR_PK11);
+ rv = KMF_HexString2Bytes((uchar_t *)serstr, &bytes, &bytelen);
+ if (rv != KMF_OK || bytes == NULL) {
+ (void) fprintf(stderr, gettext("serial number "
+ "must be specified as a hex number "
+ "(ex: 0x0102030405ffeeddee)\n"));
+ return (PK_ERR_USAGE);
}
+ serial.val = bytes;
+ serial.len = bytelen;
}
- /* Find the object(s) with the given label and/or type. */
- if ((rv = find_objs(sess, obj_type, list_label, &objs, &num_objs)) !=
- CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to find token objects (%s)."), pkcs11_strerror(rv));
- quick_finish(sess);
- return (PK_ERR_PK11);
- }
+ if ((kstype == KMF_KEYSTORE_PK11TOKEN ||
+ kstype == KMF_KEYSTORE_NSS) &&
+ (oclass & (PK_PRIKEY_OBJ | PK_PRIVATE_OBJ))) {
- if (num_objs == 0) {
- cryptoerror(LOG_STDERR, gettext("No objects found."));
- quick_finish(sess);
- return (0);
+ (void) get_token_password(kstype, token_spec,
+ &tokencred);
}
+ if (kstype == KMF_KEYSTORE_PK11TOKEN) {
+ rv = list_pk11_objects(kmfhandle, token_spec,
+ oclass, list_label, &serial,
+ issuer, subject, dir, filename,
+ &tokencred, find_criteria_flag);
- /* List the objects found. */
- for (i = 0; i < num_objs; i++) {
- /* Get object class first, then decide what is next. */
- cryptodebug("calling C_GetAttributeValue for object class");
- if ((rv = C_GetAttributeValue(sess, objs[i], &class_attr, 1))
- != CKR_OK) {
- cryptoerror(LOG_STDERR, gettext(
- "Unable to get object #%d class attribute (%s)."),
- i+1, pkcs11_strerror(rv));
- continue;
- }
+ } else if (kstype == KMF_KEYSTORE_NSS) {
+ if (dir == NULL)
+ dir = PK_DEFAULT_DIRECTORY;
+ rv = list_nss_objects(kmfhandle,
+ oclass, token_spec, dir, prefix,
+ list_label, &serial, issuer, subject,
+ &tokencred, find_criteria_flag);
- /* Display based on the type of object. */
- switch (objclass) {
- case CKO_CERTIFICATE:
- if ((rv = display_cert(sess, objs[i], i+1)) != CKR_OK)
- cryptoerror(LOG_STDERR,
- gettext("Unable to display certificate."));
- break;
- case CKO_PUBLIC_KEY:
- if ((rv = display_pubkey(sess, objs[i], i+1)) != CKR_OK)
- cryptoerror(LOG_STDERR,
- gettext("Unable to display public key."));
- break;
- case CKO_PRIVATE_KEY:
- if ((rv = display_prikey(sess, objs[i], i+1)) != CKR_OK)
- cryptoerror(LOG_STDERR,
- gettext("Unable to display private key."));
- break;
- case CKO_SECRET_KEY:
- if ((rv = display_seckey(sess, objs[i], i+1)) != CKR_OK)
- cryptoerror(LOG_STDERR,
- gettext("Unable to display secret key."));
- break;
- case CKO_DATA:
- cryptoerror(LOG_STDERR,
- gettext("Data object display not implemented."));
- break;
- default:
- cryptoerror(LOG_STDERR, gettext(
- "Unknown token object class (0x%02x)."), objclass);
- break;
- }
+ } else if (kstype == KMF_KEYSTORE_OPENSSL) {
+
+ rv = list_file_objects(kmfhandle,
+ oclass, dir, filename,
+ &serial, issuer, subject, find_criteria_flag);
+ }
+
+ if (rv != KMF_OK) {
+ display_error(kmfhandle, rv,
+ gettext("Error listing objects"));
}
- /* Clean up. */
- quick_finish(sess);
- return (0);
+ if (serial.val != NULL)
+ free(serial.val);
+
+ if (tokencred.cred != NULL)
+ free(tokencred.cred);
+
+ (void) KMF_Finalize(kmfhandle);
+ return (rv);
}
diff --git a/usr/src/cmd/cmd-crypto/pktool/osslcommon.c b/usr/src/cmd/cmd-crypto/pktool/osslcommon.c
deleted file mode 100644
index 84b4fdbdce..0000000000
--- a/usr/src/cmd/cmd-crypto/pktool/osslcommon.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-/*
- * This file implements some "missing" routines that should
- * be part of the OpenSSL library but are not there yet.
- */
-
-#include <cryptoutil.h>
-#include "osslcommon.h"
-#include <openssl/pkcs12.h>
-#include <openssl/engine.h>
-
-/*
- * OpenSSL usage needs algorithms (ciphers and digests), strings,
- * and engines loaded first to be useful.
- */
-void
-PKTOOL_setup_openssl(void)
-{
- cryptodebug("inside PKTOOL_setup_openssl");
-
- /* Add all ciphers and digests. */
- OpenSSL_add_all_algorithms();
-
- /* Load up error message strings. */
- ERR_load_crypto_strings();
-
- /* Load up PKCS#11 engine. */
- /* ENGINE_load_pk11(); */
-
- /* Load up builtin crypto engines. */
- /*
- * This function is actually defined in OpenSSL libcrypto
- * library. However it doesn't make its lint library correctly
- * which is why this lint error occurs. OpenSSL needs fixing.
- * Do not put a LINTED comment here because lint will complain
- * that the directive is ununsed.
- */
- ENGINE_load_builtin_engines();
-
- /* U/I methods are not necessary here. */
- /* setup_ui_method(); */
-}
-
-/*
- * This should be an OpenSSL function, but they haven't added it yet.
- * See <openssl>/crypto/asn1/x_x509a.c:X509_alias_get0() for the model.
- */
-unsigned char *
-PKTOOL_X509_keyid_get0(X509 *x, int *len)
-{
- cryptodebug("inside PKTOOL_setup_openssl");
-
- if (x->aux == NULL || x->aux->keyid == NULL) {
- cryptodebug("certificate aux or aux->keyid is null");
- return (NULL);
- }
- if (len)
- *len = x->aux->keyid->length;
- return (x->aux->keyid->data);
-}
-
-/*
- * This should be an OpenSSL function, but couldn't find it yet.
- * It gets the subject name safely without dereferencing null pointers.
- * If it is ever found in OpenSSL, this should be removed and all
- * calls to it need to be replaced with right OpenSSL function.
- */
-unsigned char *
-PKTOOL_X509_subject_name(X509 *x, int *len)
-{
- X509_NAME *temp;
-
- cryptodebug("inside PKTOOL_X509_subject_name");
-
- if ((temp = X509_get_subject_name(x)) == NULL) {
- cryptodebug("certificate subject name stack is null");
- return (NULL);
- }
- if (temp->bytes == NULL) {
- cryptodebug("certificate subject name stack bytes is null");
- return (NULL);
- }
- if (len)
- *len = temp->bytes->length;
- return ((unsigned char *)temp->bytes->data);
-}
-
-/*
- * This should be an OpenSSL function, but couldn't find it yet.
- * It gets the issuer name safely without dereferencing null pointers.
- * If it is ever found in OpenSSL, this should be removed and all
- * calls to it need to be replaced with right OpenSSL function.
- */
-unsigned char *
-PKTOOL_X509_issuer_name(X509 *x, int *len)
-{
- X509_NAME *temp;
-
- cryptodebug("inside PKTOOL_X509_issuer_name");
-
- if ((temp = X509_get_issuer_name(x)) == NULL) {
- cryptodebug("certificate issuer name stack is null");
- return (NULL);
- }
- if (temp->bytes == NULL) {
- cryptodebug("certificate issuer name stack bytes is null");
- return (NULL);
- }
- if (len)
- *len = temp->bytes->length;
- return ((unsigned char *)temp->bytes->data);
-}
-
-/*
- * This should be an OpenSSL function, but couldn't find it yet.
- * It gets the serial number safely without dereferencing null pointers.
- * If it is ever found in OpenSSL, this should be removed and all
- * calls to it need to be replaced with right OpenSSL function.
- */
-unsigned char *
-PKTOOL_X509_serial_number(X509 *x, int *len)
-{
- ASN1_INTEGER *temp;
-
- cryptodebug("inside PKTOOL_X509_serial_number");
-
- if ((temp = X509_get_serialNumber(x)) == NULL) {
- cryptodebug("certificate serial number is null");
- return (NULL);
- }
- if (len)
- *len = temp->length;
- return (temp->data);
-}
-
-/*
- * This should be an OpenSSL function, but couldn't find it yet.
- * It gets the cert value safely without dereferencing null pointers.
- * If it is ever found in OpenSSL, this should be removed and all
- * calls to it need to be replaced with right OpenSSL function.
- */
-unsigned char *
-PKTOOL_X509_cert_value(X509 *x, int *len)
-{
- PKCS12_SAFEBAG *bag;
-
- cryptodebug("inside PKTOOL_X509_cert_value");
-
- if ((bag = PKCS12_x5092certbag(x)) == NULL) {
- cryptodebug("unable to convert cert to PKCS#12 bag");
- return (NULL);
- }
- if (bag->value.bag == NULL || bag->value.bag->value.x509cert == NULL) {
- cryptodebug("PKCS#12 bag value or cert inside it is null");
- return (NULL);
- }
- if (len)
- *len = bag->value.bag->value.x509cert->length;
- return (bag->value.bag->value.x509cert->data);
-}
-
-/*
- * Convert OpenSSL's ASN1_TIME format into a character buffer that
- * can then be converted into PKCS#11 format. The buffer must be
- * at least 8 bytes long. The length of the result will be 8 bytes.
- * Return value of 0 indicates failure, 1 indicates success.
- */
-int
-PKTOOL_cvt_ossltime(ASN1_TIME *t, char *buf)
-{
- cryptodebug("inside PKTOOL_cvt_ossltime");
-
- if (t == NULL) {
- cryptodebug("time string is empty");
- buf[0] = '\0';
- return (0);
- }
-
- if (t->length == 15) { /* generalized time: YYYYMMDDmmhhssZ */
- cryptodebug("time string is in generalized format");
- (void) snprintf(buf, 8, "%08.8s", t->data);
- return (1);
- }
-
- if (t->length == 13) { /* UTC time: YYMMDDmmhhssZ */
- cryptodebug("time string is in UTC format");
- /* Guess whether its a 197x to 199x date, or a 20xx date. */
- (void) snprintf(buf, 8, "%s%06.6s",
- ('7' <= t->data[0] && t->data[0] <= '9') ? "19" : "20",
- t->data);
- return (1);
- }
-
- cryptodebug("time string is in unknown format");
- buf[0] = '\0';
- return (0);
-}
diff --git a/usr/src/cmd/cmd-crypto/pktool/osslcommon.h b/usr/src/cmd/cmd-crypto/pktool/osslcommon.h
deleted file mode 100644
index 098d0e1f6a..0000000000
--- a/usr/src/cmd/cmd-crypto/pktool/osslcommon.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _PKTOOL_OSSLCOMMON_H
-#define _PKTOOL_OSSLCOMMON_H
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <openssl/x509.h>
-
-extern void PKTOOL_setup_openssl(void);
-extern unsigned char *PKTOOL_X509_keyid_get0(X509 *x, int *len);
-extern unsigned char *PKTOOL_X509_subject_name(X509 *x, int *len);
-extern unsigned char *PKTOOL_X509_issuer_name(X509 *x, int *len);
-extern unsigned char *PKTOOL_X509_serial_number(X509 *x, int *len);
-extern unsigned char *PKTOOL_X509_cert_value(X509 *x, int *len);
-extern int PKTOOL_cvt_ossltime(ASN1_TIME *t, char *buf);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PKTOOL_OSSLCOMMON_H */
diff --git a/usr/src/cmd/cmd-crypto/pktool/p12common.c b/usr/src/cmd/cmd-crypto/pktool/p12common.c
deleted file mode 100644
index 4e164ea911..0000000000
--- a/usr/src/cmd/cmd-crypto/pktool/p12common.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-/*
- * This file implements some of the common PKCS#12 routines.
- */
-
-#include <errno.h>
-#include <string.h>
-#include <cryptoutil.h>
-#include "p12common.h"
-#include <openssl/pkcs12.h>
-
-/* I18N helpers. */
-#include <libintl.h>
-#include <locale.h>
-
-/*
- * Common function to create/open PKCS#12 files.
- */
-static int
-pkcs12_file(char *filename, boolean_t create, BIO **fbio)
-{
- cryptodebug("inside pkcs12_file");
-
- if (fbio == NULL) {
- cryptoerror(LOG_STDERR, create ?
- gettext("Error creating file \"%s\", invalid input.") :
- gettext("Error opening file \"%s\", invalid input."),
- filename);
- return (-1);
- }
-
- cryptodebug(create ? "creating %s for binary writes" :
- "opening %s for binary reads", filename);
- if ((*fbio = BIO_new_file(filename, create ? "wb" : "rb")) == NULL) {
- cryptoerror(LOG_STDERR, create ?
- gettext("Error creating file \"%s\" (%s).") :
- gettext("Error opening file \"%s\" (%s)."),
- filename, strerror(errno));
- return (-1);
- }
-
- return (0);
-}
-
-/*
- * Create PKCS#12 export file.
- */
-int
-create_pkcs12(char *filename, BIO **fbio)
-{
- cryptodebug("inside create_pkcs12");
-
- return (pkcs12_file(filename, B_TRUE, fbio));
-}
-
-/*
- * Opens PKCS#12 import file.
- */
-int
-open_pkcs12(char *filename, BIO **fbio)
-{
- cryptodebug("inside open_pkcs12");
-
- return (pkcs12_file(filename, B_FALSE, fbio));
-}
-
-/*
- * Closes PKCS#12 export file.
- */
-void
-close_pkcs12(BIO *fbio)
-{
- cryptodebug("inside close_pkcs12");
-
- BIO_free_all(fbio);
-}
diff --git a/usr/src/cmd/cmd-crypto/pktool/pktool.c b/usr/src/cmd/cmd-crypto/pktool/pktool.c
index ce7a26235c..c97cf80063 100644
--- a/usr/src/cmd/cmd-crypto/pktool/pktool.c
+++ b/usr/src/cmd/cmd-crypto/pktool/pktool.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -62,6 +61,10 @@ extern int pk_delete(int argc, char *argv[]);
extern int pk_import(int argc, char *argv[]);
extern int pk_export(int argc, char *argv[]);
extern int pk_tokens(int argc, char *argv[]);
+extern int pk_gencert(int argc, char *argv[]);
+extern int pk_gencsr(int argc, char *argv[]);
+extern int pk_download(int argc, char *argv[]);
+extern int pk_genkey(int argc, char *argv[]);
/* Forward declarations for "built-in" verb actions. */
static int pk_help(int argc, char *argv[]);
@@ -70,45 +73,353 @@ static int pk_help(int argc, char *argv[]);
static verbcmd cmds[] = {
{ "tokens", pk_tokens, 0, "tokens" },
{ "setpin", pk_setpin, 0,
- "setpin [token=<token>[:<manuf>[:<serial>]]]" },
+ "setpin [ keystore=pkcs11 ]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t"
+
+ "setpin keystore=nss\n\t\t"
+ "[ token=token ]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t"
+ },
{ "list", pk_list, 0,
- "list [token=<token>[:<manuf>[:<serial>]]] "
- "[objtype=private|public|both] [label=<label>]" },
+
+ "list [ token=token[:manuf[:serial]]]\n\t\t"
+ "[ objtype=private|public|both ]\n\t\t"
+ "[ label=label ]\n\t"
+
+ "list objtype=cert[:[public | private | both ]]\n\t\t"
+ "[ subject=subject-DN ]\n\t\t"
+ "[ keystore=pkcs11 ]\n\t\t"
+ "[ issuer=issuer-DN ]\n\t\t"
+ "[ serial=serial number]\n\t\t"
+ "[ label=cert-label ]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ criteria=valid|expired|both ]\n\t"
+
+ "list objtype=key[:[public | private | both ]]\n\t\t"
+ "[ keystore=pkcs11 ]\n\t\t"
+ "[ subject=subject-DN ]\n\t\t"
+ "[ label=key-label ]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t"
+
+ "list keystore=pkcs11 objtype=crl\n\t\t"
+ "infile=crl-fn\n\t\t"
+ "[ dir=directory-path ]\n\t"
+
+ "list keystore=nss objtype=cert\n\t\t"
+ "[ subject=subject-DN ]\n\t\t"
+ "[ issuer=issuer-DN ]\n\t\t"
+ "[ serial=serial number]\n\t\t"
+ "[ nickname=cert-nickname ]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t\t"
+ "[ criteria=valid|expired|both ]\n\t"
+
+ "list keystore=nss objtype=key\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t\t"
+ "[ nickname=key-nickname ]\n\t"
+
+ "list keystore=file objtype=cert\n\t\t"
+ "[ subject=subject-DN ]\n\t\t"
+ "[ issuer=issuer-DN ]\n\t\t"
+ "[ serial=serial number]\n\t\t"
+ "[ infile=cert-fn ]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ criteria=valid|expired|both ]\n\t"
+
+ "list keystore=file objtype=key\n\t\t"
+ "[ infile=key-fn ]\n\t\t"
+ "[ dir=directory-path ]\n\t"
+
+ "list keystore=file objtype=crl\n\t\t"
+ "infile=crl-fn\n\t\t"
+ "[ dir=directory-path ]\n\t"
+ },
+
{ "delete", pk_delete, 0,
- "delete [token=<token>[:<manuf>[:<serial>]]] "
- "{ [objtype=private|public|both] [label=<label>] }" },
+
+ "delete [ token=token[:manuf[:serial]]]\n\t\t"
+ "[ objtype=private|public|both ]\n\t\t"
+ "[ label=object-label ]\n\t"
+
+ "delete keystore=nss objtype=cert\n\t\t"
+ "[ subject=subject-DN ]\n\t\t"
+ "[ issuer=issuer-DN ]\n\t\t"
+ "[ serial=serial number]\n\t\t"
+ "[ nickname=cert-nickname ]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t\t"
+ "[ criteria=valid|expired|both ]\n\t"
+
+ "delete keystore=nss objtype=key\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t\t"
+ "[ nickname=key-nickname ]\n\t\t"
+
+ "delete keystore=nss objtype=crl\n\t\t"
+ "[ nickname=issuer-nickname ]\n\t\t"
+ "[ subject=subject-DN ]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t"
+
+ "delete keystore=pkcs11 objtype=cert[:[public | private | both]]\n\t\t"
+ "[ subject=subject-DN ]\n\t\t"
+ "[ issuer=issuer-DN ]\n\t\t"
+ "[ serial=serial number]\n\t\t"
+ "[ label=cert-label ]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ criteria=valid|expired|both ]\n\t"
+
+ "delete keystore=pkcs11 objtype=key[:[public | private | both]]\n\t\t"
+ "[ subject=subject-DN ]\n\t\t"
+ "[ label=key-label ]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t"
+
+ "delete keystore=pkcs11 objtype=crl\n\t\t"
+ "infile=crl-fn\n\t\t"
+ "[ dir=directory-path ]\n\t"
+
+ "delete keystore=file objtype=cert\n\t\t"
+ "[ subject=subject-DN ]\n\t\t"
+ "[ issuer=issuer-DN ]\n\t\t"
+ "[ serial=serial number]\n\t\t"
+ "[ infile=cert-fn ]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ criteria=valid|expired|both ]\n\t"
+
+ "delete keystore=file objtype=key\n\t\t"
+ "[ infile=key-fn ]\n\t\t"
+ "[ dir=directory-path ]\n\t"
+
+ "delete keystore=file objtype=crl\n\t\t"
+ "infile=crl-fn\n\t\t"
+ "[ dir=directory-path ]\n\t"
+ },
{ "import", pk_import, 0,
- "import [token=<token>[:<manuf>[:<serial>]]] infile=<file>" },
+
+ "import [token=token[:manuf[:serial]]]\n\t\t"
+ "infile=input-fn\n\t"
+
+ "import keystore=nss objtype=cert\n\t\t"
+ "infile=input-fn\n\t\t"
+ "nickname=cert-nickname\n\t\t"
+ "[ trust=trust-value ]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t"
+
+ "import keystore=nss objtype=crl\n\t\t"
+ "infile=input-fn\n\t\t"
+ "[ verifycrl=y|n ]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t"
+
+ "import keystore=pkcs11\n\t\t"
+ "infile=input-fn\n\t\t"
+ "label=cert-label\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t"
+
+ "import keystore=pkcs11 objtype=crl\n\t\t"
+ "infile=input-crl-fn\n\t\t"
+ "outcrl=output-crl-fn\n\t\t"
+ "outformat=pem|der\n\t\t"
+ "[ dir=output-crl-directory-path ]\n\t"
+
+ "import keystore=file\n\t\t"
+ "infile=input-fn\n\t\t"
+ "outkey=output-key-fn\n\t\t"
+ "outcert=output-cert-fn\n\t\t"
+ "[ dir=output-cert-dir-path ]\n\t\t"
+ "[ keydir=output-key-dir-path ]\n\t\t"
+ "[ outformat=pem|der|pkcs12 ]\n\t"
+
+ "import keystore=file objtype=crl\n\t\t"
+ "infile=input-crl-fn\n\t\t"
+ "outcrl=output-crl-fn\n\t\t"
+ "outformat=pem|der\n\t\t"
+ "[ dir=output-crl-directory-path ]\n\t"
+ },
+
{ "export", pk_export, 0,
- "export [token=<token>[:<manuf>[:<serial>]]] outfile=<file>" },
- { "-?", pk_help, 0, "help\t(help and usage)" },
+
+ "export [token=token[:manuf[:serial]]]\n\t\t"
+ "outfile=output-fn\n\t"
+
+ "export keystore=nss\n\t\t"
+ "outfile=output-fn\n\t\t"
+ "[ objtype=cert|key ]\n\t\t"
+ "[ subject=subject-DN ]\n\t\t"
+ "[ issuer=issuer-DN ]\n\t\t"
+ "[ serial=serial number]\n\t\t"
+ "[ nickname=cert-nickname]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBPrefix ]\n\t\t"
+ "[ outformat=pem|der|pkcs12 ]\n\t"
+
+ "export keystore=pkcs11\n\t\t"
+ "outfile=output-fn\n\t\t"
+ "[ label=cert-label]\n\t\t"
+ "[ subject=subject-DN ]\n\t\t"
+ "[ issuer=issuer-DN ]\n\t\t"
+ "[ serial=serial number]\n\t\t"
+ "[ outformat=pem|der|pkcs12]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t"
+
+ "export keystore=file\n\t\t"
+ "certfile=cert-input-fn\n\t\t"
+ "keyfile=key-input-fn\n\t\t"
+ "outfile=output-pkcs12-fn\n\t\t"
+ "[ dir=directory-path ]\n\t"
+ },
+
+ { "gencert", pk_gencert, 0,
+ "gencert [-i] keystore=nss\n\t\t"
+ "label=cert-nickname\n\t\t"
+ "serial=serial number hex string]\n\t\t"
+ "subject=subject-DN\n\t\t"
+ "[ altname=[critical:]SubjectAltName ]\n\t\t"
+ "[ keyusage=[critical:]usage,usage,...]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t\t"
+ "[ keytype=rsa|dsa ]\n\t\t"
+ "[ keylen=key-size ]\n\t\t"
+ "[ trust=trust-value ]\n\t\t"
+ "[ lifetime=number-hour|number-day|number-year ]\n\t"
+
+ "gencert [-i] [ keystore=pkcs11 ]\n\t\t"
+ "label=key/cert-label\n\t\t"
+ "subject=subject-DN\n\t\t"
+ "serial=serial number hex string\n\t\t"
+ "[ altname=[critical:]SubjectAltName ]\n\t\t"
+ "[ keyusage=[critical:]usage,usage,...]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ keytype=rsa|dsa ]\n\t\t"
+ "[ keylen=key-size ]\n\t\t"
+ "[ lifetime=number-hour|number-day|number-year ]\n\t"
+
+ "gencert [-i] keystore=file\n\t\t"
+ "outcert=cert_filename\n\t\t"
+ "outkey=key_filename\n\t\t"
+ "subject=subject-DN\n\t\t"
+ "serial=serial number hex string\n\t\t"
+ "[ altname=[critical:]SubjectAltName ]\n\t\t"
+ "[ keyusage=[critical:]usage,usage,...]\n\t\t"
+ "[ format=der|pem ]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t\t"
+ "[ keytype=rsa|dsa ]\n\t\t"
+ "[ keylen=key-size ]\n\t\t"
+ "[ lifetime=number-hour|number-day|number-year ]\n\t"
+ },
+ { "gencsr", pk_gencsr, 0,
+ "gencsr [-i] keystore=nss \n\t\t"
+ "nickname=cert-nickname\n\t\t"
+ "outcsr=csr-fn\n\t\t"
+ "subject=subject-DN\n\t\t"
+ "[ altname=[critical:]SubjectAltName ]\n\t\t"
+ "[ keyusage=[critical:]usage,usage,...]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t\t"
+ "[ keytype=rsa|dsa ]\n\t\t"
+ "[ keylen=key-size ]\n\t\t"
+ "[ format=pem|der]\n\t"
+ "gencsr [-i] [ keystore=pkcs11 ]\n\t\t"
+ "label=key-label\n\t\t"
+ "outcsr=csr-fn\n\t\t"
+ "subject=subject-DN\n\t\t"
+ "[ altname=[critical:]SubjectAltName ]\n\t\t"
+ "[ keyusage=[critical:]usage,usage,...]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ keytype=rsa|dsa ]\n\t\t"
+ "[ keylen=key-size ]\n\t\t"
+ "[ format=pem|der]\n\t"
+ "gencsr [-i] keystore=file\n\t\t"
+ "outcsr=csr-fn\n\t\t"
+ "outkey=key-fn\n\t\t"
+ "subject=subject-DN\n\t\t"
+ "[ altname=[critical:]SubjectAltName ]\n\t\t"
+ "[ keyusage=[critical:]usage,usage,...]\n\t\t"
+ "[ keytype=rsa|dsa ]\n\t\t"
+ "[ keylen=key-size ]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ format=pem|der]\n\t"
+ },
+
+ { "download", pk_download, 0,
+ "download url=url_str\n\t\t"
+ "[ objtype=crl|cert ]\n\t\t"
+ "[ http_proxy=proxy_str ]\n\t\t"
+ "[ outfile = outfile ]\n\t\t"
+ },
+
+ { "genkey", pk_genkey, 0,
+ "genkey [ keystore=pkcs11 ]\n\t\t"
+ "label=key-label\n\t\t"
+ "[ keytype=aes|arcfour|des|3des ]\n\t\t"
+ "[ keylen=key-size (AES or ARCFOUR only)]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ sensitive=y|n ]\n\t\t"
+ "[ extractable=y|n ]\n\t\t"
+ "[ print=y|n ]\n\t"
+
+ "genkey keystore=nss\n\t\t"
+ "label=key-label\n\t\t"
+ "[ keytype=aes|arcfour|des|3des ]\n\t\t"
+ "[ keylen=key-size (AES or ARCFOUR only)]\n\t\t"
+ "[ token=token[:manuf[:serial]]]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ prefix=DBprefix ]\n\t"
+
+ "genkey keystore=file\n\t\t"
+ "outkey=key-fn\n\t\t"
+ "[ keytype=aes|arcfour|des|3des ]\n\t\t"
+ "[ keylen=key-size (AES or ARCFOUR only)]\n\t\t"
+ "[ dir=directory-path ]\n\t\t"
+ "[ print=y|n ]\n\t"
+ },
+
+ { "-?", pk_help, 0, "help\t(help and usage)" },
+ { "-f", pk_help, 0, "-f option_file" }
};
static int num_cmds = sizeof (cmds) / sizeof (verbcmd);
static char *prog;
-static void usage(void);
+static void usage(int);
/*
* Usage information. This function must be updated when new verbs or
* options are added.
*/
static void
-usage(void)
+usage(int idx)
{
int i;
- cryptodebug("inside usage");
-
/* Display this block only in command-line mode. */
(void) fprintf(stdout, gettext("Usage:\n"));
(void) fprintf(stdout, gettext("\t%s -?\t(help and usage)\n"), prog);
+ (void) fprintf(stdout, gettext("\t%s -f option_file\n"), prog);
(void) fprintf(stdout, gettext("\t%s subcommand [options...]\n"), prog);
(void) fprintf(stdout, gettext("where subcommands may be:\n"));
/* Display only those verbs that match the current tool mode. */
- for (i = 0; i < num_cmds; i++) {
- /* Do NOT i18n/l10n. */
- (void) fprintf(stdout, "\t%s\n", cmds[i].synopsis);
+ if (idx == -1) {
+ for (i = 0; i < num_cmds; i++) {
+ /* Do NOT i18n/l10n. */
+ (void) fprintf(stdout, "\t%s\n", cmds[i].synopsis);
+ }
+ } else {
+ (void) fprintf(stdout, "\t%s\n", cmds[idx].synopsis);
}
}
@@ -119,9 +430,59 @@ static int
pk_help(int argc, char *argv[])
/* ARGSUSED */
{
- cryptodebug("inside pk_help");
+ usage(-1);
+ return (0);
+}
+
+/*
+ * Process arguments from the argfile and create a new
+ * argv/argc list to be processed later.
+ */
+static int
+process_arg_file(char *argfile, char ***argv, int *argc)
+{
+ FILE *fp;
+ char argline[2 * BUFSIZ]; /* 2048 bytes should be plenty */
+ char *p;
+ int nargs = 0;
+
+ if ((fp = fopen(argfile, "rF")) == NULL) {
+ (void) fprintf(stderr,
+ gettext("Cannot read argfile %s: %s\n"),
+ argfile, strerror(errno));
+ return (errno);
+ }
- usage();
+ while (fgets(argline, sizeof (argline), fp) != NULL) {
+ int j;
+ /* remove trailing whitespace */
+ j = strlen(argline) - 1;
+ while (j >= 0 && isspace(argline[j])) {
+ argline[j] = 0;
+ j--;
+ }
+ /* If it was a blank line, get the next one. */
+ if (!strlen(argline))
+ continue;
+
+ (*argv) = realloc((*argv),
+ (nargs + 1) * sizeof (char *));
+ if ((*argv) == NULL) {
+ perror("memory error");
+ (void) fclose(fp);
+ return (errno);
+ }
+ p = (char *)strdup(argline);
+ if (p == NULL) {
+ perror("memory error");
+ (void) fclose(fp);
+ return (errno);
+ }
+ (*argv)[nargs] = p;
+ nargs++;
+ }
+ *argc = nargs;
+ (void) fclose(fp);
return (0);
}
@@ -150,26 +511,24 @@ main(int argc, char *argv[], char *envp[])
argv++, argc--;
/* Set up for debug and error output. */
- cryptodebug_init(prog);
-
if (argc == 0) {
- usage();
+ usage(-1);
return (1);
}
/* Check for help options. For CLIP-compliance. */
- if (argc == 1 && argv[0][0] == '-') {
- switch (argv[0][1]) {
- case '?':
- return (pk_help(argc, argv));
- default:
- usage();
- return (1);
- }
+ if (strcmp(argv[0], "-?") == 0) {
+ return (pk_help(argc, argv));
+ } else if (strcmp(argv[0], "-f") == 0 && argc == 2) {
+ rv = process_arg_file(argv[1], &pk_argv, &pk_argc);
+ if (rv)
+ return (rv);
+ } else if (argc >= 1 && argv[0][0] == '-') {
+ usage(-1);
+ return (1);
}
/* Always turns off Metaslot so that we can see softtoken. */
- cryptodebug("disabling Metaslot");
if (setenv("METASLOT_ENABLED", "false", 1) < 0) {
save_errno = errno;
cryptoerror(LOG_STDERR,
@@ -179,21 +538,18 @@ main(int argc, char *argv[], char *envp[])
}
/* Begin parsing command line. */
- cryptodebug("begin parsing command line");
- pk_argc = argc;
- pk_argv = argv;
+ if (pk_argc == 0 && pk_argv == NULL) {
+ pk_argc = argc;
+ pk_argv = argv;
+ }
/* Check for valid verb (or an abbreviation of it). */
found = -1;
for (i = 0; i < num_cmds; i++) {
if (strcmp(cmds[i].verb, pk_argv[0]) == 0) {
if (found < 0) {
- cryptodebug("found cmd %s", cmds[i].verb);
found = i;
break;
- } else {
- cryptodebug("also found cmd %s, skipping",
- cmds[i].verb);
}
}
}
@@ -205,36 +561,21 @@ main(int argc, char *argv[], char *envp[])
}
/* Get to work! */
- cryptodebug("begin executing cmd action");
rv = (*cmds[found].action)(pk_argc, pk_argv);
- cryptodebug("end executing cmd action");
switch (rv) {
case PK_ERR_NONE:
- cryptodebug("subcommand succeeded");
break; /* Command succeeded, do nothing. */
case PK_ERR_USAGE:
- cryptodebug("usage error detected");
- usage();
+ usage(found);
break;
case PK_ERR_QUIT:
- cryptodebug("quit command received");
exit(0);
/* NOTREACHED */
case PK_ERR_PK11:
- cryptoerror(LOG_STDERR, "%s",
- gettext("Command failed due to PKCS#11 error."));
- break;
case PK_ERR_SYSTEM:
- cryptoerror(LOG_STDERR, "%s",
- gettext("Command failed due to system error."));
- break;
case PK_ERR_OPENSSL:
- cryptoerror(LOG_STDERR, "%s",
- gettext("Command failed due to OpenSSL error."));
- break;
+ case PK_ERR_NSS:
default:
- cryptoerror(LOG_STDERR, "%s (%d).",
- gettext("Unknown error value"), rv);
break;
}
return (rv);
diff --git a/usr/src/cmd/cmd-crypto/pktool/setpin.c b/usr/src/cmd/cmd-crypto/pktool/setpin.c
index 038f57169e..62416e8c7d 100644
--- a/usr/src/cmd/cmd-crypto/pktool/setpin.c
+++ b/usr/src/cmd/cmd-crypto/pktool/setpin.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -41,76 +40,90 @@
#include <security/cryptoki.h>
#include "common.h"
-/*
- * Changes the token's PIN.
- */
-int
-pk_setpin(int argc, char *argv[])
-/* ARGSUSED */
+static int
+setpin_nss(KMF_HANDLE_T handle,
+ char *token_spec, char *dir, char *prefix)
{
- int opt;
- extern int optind_av;
- extern char *optarg_av;
- char *token_spec = NULL;
- char *token_name = NULL;
- char *manuf_id = NULL;
- char *serial_no = NULL;
- CK_SLOT_ID slot_id;
- CK_FLAGS pin_state;
- CK_SESSION_HANDLE sess;
+ int rv = 0;
+ KMF_SETPIN_PARAMS params;
+ KMF_CREDENTIAL newpincred = { NULL, 0 };
CK_UTF8CHAR_PTR old_pin = NULL, new_pin = NULL;
CK_ULONG old_pinlen = 0, new_pinlen = 0;
- CK_RV rv = CKR_OK;
- char full_name[FULL_NAME_LEN];
- cryptodebug("inside pk_setpin");
+ rv = configure_nss(handle, dir, prefix);
+ if (rv != KMF_OK)
+ return (rv);
- /* Parse command line options. Do NOT i18n/l10n. */
- while ((opt = getopt_av(argc, argv, "T:(token)")) != EOF) {
- switch (opt) {
- case 'T': /* token specifier */
- if (token_spec)
- return (PK_ERR_USAGE);
- token_spec = optarg_av;
- break;
- default:
- return (PK_ERR_USAGE);
- break;
- }
+ (void) memset(&params, 0, sizeof (params));
+ params.kstype = KMF_KEYSTORE_NSS;
+ params.tokenname = token_spec;
+ params.nssparms.slotlabel = token_spec;
+
+ if ((rv = get_pin(gettext("Enter current token passphrase "
+ "(<CR> if not set):"), NULL, &old_pin, &old_pinlen)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to get token passphrase."));
+ return (PK_ERR_NSS);
}
+ /* Get the user's new PIN. */
+ if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
+ "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
+ if (rv == CKR_PIN_INCORRECT)
+ cryptoerror(LOG_STDERR, gettext(
+ "Passphrases do not match."));
+ else
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get and confirm new passphrase."));
+ if (old_pin != NULL)
+ free(old_pin);
+ return (PK_ERR_NSS);
+ }
+
+ params.cred.cred = (char *)old_pin;
+ params.cred.credlen = old_pinlen;
+
+ newpincred.cred = (char *)new_pin;
+ newpincred.credlen = new_pinlen;
+
+ rv = KMF_SetTokenPin(handle, &params, &newpincred);
+
+ if (new_pin)
+ free(new_pin);
+ if (old_pin)
+ free(old_pin);
+
+ return (rv);
+}
+
+static int
+setpin_pkcs11(KMF_HANDLE_T handle, char *token_spec)
+{
+ CK_SLOT_ID slot_id;
+ CK_FLAGS pin_state;
+ CK_UTF8CHAR_PTR old_pin = NULL, new_pin = NULL;
+ CK_ULONG old_pinlen = 0, new_pinlen = 0;
+ CK_RV rv = CKR_OK;
+ char *token_name = NULL;
+ KMF_SETPIN_PARAMS params;
+ CK_TOKEN_INFO token_info;
+ KMF_CREDENTIAL newpincred = { NULL, 0 };
/* If nothing is specified, default is to use softtoken. */
if (token_spec == NULL) {
+ token_spec = SOFT_TOKEN_LABEL ":" SOFT_MANUFACTURER_ID;
token_name = SOFT_TOKEN_LABEL;
- manuf_id = SOFT_MANUFACTURER_ID;
- serial_no = SOFT_TOKEN_SERIAL;
- } else {
- /*
- * Parse token specifier into token_name, manuf_id, serial_no.
- * Token_name is required; manuf_id and serial_no are optional.
- */
- if (parse_token_spec(token_spec, &token_name, &manuf_id,
- &serial_no) < 0)
- return (PK_ERR_USAGE);
}
- /* No additional args allowed. */
- argc -= optind_av;
- argv += optind_av;
- if (argc != 0)
- return (PK_ERR_USAGE);
- /* Done parsing command line options. */
-
- full_token_name(token_name, manuf_id, serial_no, full_name);
+ rv = KMF_PK11TokenLookup(NULL, token_spec, &slot_id);
+ if (rv == KMF_OK) {
+ /* find the pin state for the selected token */
+ if (C_GetTokenInfo(slot_id, &token_info) != CKR_OK)
+ return (PK_ERR_PK11);
- /* Find the slot with token. */
- if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
- &pin_state)) != CKR_OK) {
- cryptoerror(LOG_STDERR,
- gettext("Unable to find token %s (%s)."), full_name,
- pkcs11_strerror(rv));
- final_pk11(NULL);
- return (PK_ERR_PK11);
+ pin_state = token_info.flags & CKF_USER_PIN_TO_BE_CHANGED;
+ if (token_name == NULL)
+ token_name = (char *)token_info.label;
}
/*
@@ -121,7 +134,6 @@ pk_setpin(int argc, char *argv[])
*/
if (pin_state == CKF_USER_PIN_TO_BE_CHANGED &&
strcmp(token_name, SOFT_TOKEN_LABEL) == 0) {
- cryptodebug("pin_state: first time passphrase is being set");
if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) ==
NULL) {
cryptoerror(LOG_STDERR, "%s.", strerror(errno));
@@ -130,7 +142,6 @@ pk_setpin(int argc, char *argv[])
}
old_pinlen = strlen(SOFT_DEFAULT_PIN);
} else {
- cryptodebug("pin_state: changing an existing pin ");
if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
&old_pin, &old_pinlen)) != CKR_OK) {
cryptoerror(LOG_STDERR,
@@ -156,36 +167,117 @@ pk_setpin(int argc, char *argv[])
return (PK_ERR_PK11);
}
- /* Open a R/W session to the token to change the PIN. */
- if ((rv = open_sess(slot_id, CKF_RW_SESSION, &sess)) != CKR_OK) {
- cryptoerror(LOG_STDERR,
- gettext("Unable to open token session (%s)."),
- pkcs11_strerror(rv));
+ (void) memset(&params, 0, sizeof (params));
+ params.kstype = KMF_KEYSTORE_PK11TOKEN;
+ params.tokenname = (char *)token_info.label;
+ params.cred.cred = (char *)old_pin;
+ params.cred.credlen = old_pinlen;
+ params.pkcs11parms.slot = slot_id;
+
+ newpincred.cred = (char *)new_pin;
+ newpincred.credlen = new_pinlen;
+
+ rv = KMF_SetTokenPin(handle, &params, &newpincred);
+
+ /* Clean up. */
+ if (old_pin != NULL)
free(old_pin);
- final_pk11(NULL);
- return (PK_ERR_PK11);
+ if (new_pin != NULL)
+ free(new_pin);
+
+ return (rv);
+}
+
+/*
+ * Changes the token's PIN.
+ */
+int
+pk_setpin(int argc, char *argv[])
+/* ARGSUSED */
+{
+ int opt;
+ int rv;
+ extern int optind_av;
+ extern char *optarg_av;
+ char *token_spec = NULL;
+ char *dir = NULL;
+ char *prefix = NULL;
+ KMF_HANDLE_T handle;
+ KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
+
+ /* Parse command line options. Do NOT i18n/l10n. */
+ while ((opt = getopt_av(argc, argv,
+ "T:(token)k:(keystore)d:(dir)"
+ "p:(prefix)")) != EOF) {
+ switch (opt) {
+ case 'k':
+ kstype = KS2Int(optarg_av);
+ if (kstype == 0)
+ return (PK_ERR_USAGE);
+ break;
+ case 'T': /* token specifier */
+ if (token_spec)
+ return (PK_ERR_USAGE);
+ token_spec = optarg_av;
+ break;
+ case 'd':
+ if (dir)
+ return (PK_ERR_USAGE);
+ dir = optarg_av;
+ break;
+ case 'p':
+ if (prefix)
+ return (PK_ERR_USAGE);
+ prefix = optarg_av;
+ break;
+ default:
+ return (PK_ERR_USAGE);
+ break;
+ }
}
- /* Change the PIN if possible. */
- cryptodebug("calling C_SetPIN");
- rv = C_SetPIN(sess, old_pin, old_pinlen, new_pin, new_pinlen);
- /* Clean up. */
- free(old_pin);
- free(new_pin);
- quick_finish(sess);
+ /* No additional args allowed. */
+ argc -= optind_av;
+ argv += optind_av;
+ if (argc != 0)
+ return (PK_ERR_USAGE);
- if (rv != CKR_OK) {
- if (rv == CKR_PIN_INCORRECT)
- cryptoerror(LOG_STDERR,
- gettext("Incorrect passphrase."));
- else
+ /* Done parsing command line options. */
+ if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) {
+ token_spec = PK_DEFAULT_PK11TOKEN;
+ } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) {
+ token_spec = DEFAULT_NSS_TOKEN;
+ }
+
+ if ((rv = KMF_Initialize(&handle, NULL, NULL)) != KMF_OK)
+ return (rv);
+
+ switch (kstype) {
+ case KMF_KEYSTORE_PK11TOKEN:
+ rv = setpin_pkcs11(handle, token_spec);
+ break;
+ case KMF_KEYSTORE_NSS:
+ rv = setpin_nss(handle, token_spec, dir, prefix);
+ break;
+ default:
cryptoerror(LOG_STDERR,
- gettext("Unable to change passphrase (%s)."),
- pkcs11_strerror(rv));
- return (PK_ERR_PK11);
+ gettext("incorrect keystore."));
+ return (PK_ERR_USAGE);
}
- (void) fprintf(stdout, gettext("Passphrase changed.\n"));
+ (void) KMF_Finalize(handle);
+
+ if (rv == KMF_ERR_AUTH_FAILED) {
+ cryptoerror(LOG_STDERR,
+ gettext("Incorrect passphrase."));
+ return (PK_ERR_SYSTEM);
+ } else if (rv != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to change passphrase."));
+ return (PK_ERR_SYSTEM);
+ } else {
+ (void) fprintf(stdout, gettext("Passphrase changed.\n"));
+ }
return (0);
}
diff --git a/usr/src/cmd/cmd-crypto/pktool/tokens.c b/usr/src/cmd/cmd-crypto/pktool/tokens.c
index e6345c77b8..ea9d556caa 100644
--- a/usr/src/cmd/cmd-crypto/pktool/tokens.c
+++ b/usr/src/cmd/cmd-crypto/pktool/tokens.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -51,7 +50,6 @@ pk_tokens(int argc, char *argv[])
CK_RV rv = CKR_OK;
int i;
- cryptodebug("inside pk_tokens");
/* Get rid of subcommand word "tokens". */
argc--;
@@ -81,13 +79,10 @@ pk_tokens(int argc, char *argv[])
(void) fprintf(stdout, fmt, gettext("Token Label"), gettext("Manuf ID"),
gettext("Serial No"), gettext("PIN State"));
for (i = 0; i < slot_count; i++) {
- cryptodebug("calling C_GetTokenInfo");
if ((rv = C_GetTokenInfo(slots[i], &token_info)) != CKR_OK) {
cryptoerror(LOG_STDERR,
gettext("Unable to get slot %d token info (%s)."),
i, pkcs11_strerror(rv));
- cryptodebug("token info error, slot %d (%s)", i,
- pkcs11_strerror(rv));
continue;
}
@@ -99,6 +94,6 @@ pk_tokens(int argc, char *argv[])
/* Clean up. */
free(slots);
- quick_finish(NULL);
+ (void) C_Finalize(NULL);
return (0);
}
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index b08aa23cd9..1515a356cb 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -108,6 +108,7 @@ SUBDIRS += \
libinetcfg \
libinetutil \
libipmp \
+ libkmf \
libkstat \
libkvm \
liblaadm \
@@ -466,6 +467,7 @@ libfstyp: libnvpair
$(CLOSED_BUILD)$(CLOSED)/lib/libelfsign: \
$(CLOSED)/lib/libike libcryptoutil pkcs11
libinetcfg: libnsl libsocket libdevinfo
+libkmf: libcryptoutil pkcs11 openssl
libnsl: libmd5 libscf
libmapid: libresolv
libmacadm: libdevinfo
diff --git a/usr/src/lib/libcryptoutil/Makefile.com b/usr/src/lib/libcryptoutil/Makefile.com
index 2beda723bb..cffe48fc23 100644
--- a/usr/src/lib/libcryptoutil/Makefile.com
+++ b/usr/src/lib/libcryptoutil/Makefile.com
@@ -34,7 +34,8 @@ OBJECTS= \
config_parsing.o \
tohexstr.o \
mechkeytype.o\
- pkcserror.o
+ pkcserror.o \
+ util.o
include $(SRC)/lib/Makefile.lib
diff --git a/usr/src/lib/libcryptoutil/common/config_parsing.c b/usr/src/lib/libcryptoutil/common/config_parsing.c
index 1c01db6de5..92eccf35dd 100644
--- a/usr/src/lib/libcryptoutil/common/config_parsing.c
+++ b/usr/src/lib/libcryptoutil/common/config_parsing.c
@@ -211,7 +211,7 @@ parse_policylist(char *buf, uentry_t *pent)
if (value = strpbrk(buf, SEP_EQUAL)) {
value++; /* get rid of = */
(void) strlcpy((char *)pent->metaslot_ks_token, value,
- TOKEN_LABEL_SIZE);
+ sizeof (pent->metaslot_ks_token));
return (SUCCESS);
} else {
cryptoerror(LOG_ERR, "failed to parse %s.\n",
@@ -223,7 +223,7 @@ parse_policylist(char *buf, uentry_t *pent)
if (value = strpbrk(buf, SEP_EQUAL)) {
value++; /* get rid of = */
(void) strlcpy((char *)pent->metaslot_ks_slot, value,
- SLOT_DESCRIPTION_SIZE);
+ sizeof (pent->metaslot_ks_slot));
return (SUCCESS);
} else {
cryptoerror(LOG_ERR, "failed to parse %s.\n",
@@ -376,3 +376,174 @@ free_uentrylist(uentrylist_t *entrylist)
entrylist = pnext;
}
}
+
+
+
+/*
+ * Duplicate an UEF mechanism list. A NULL pointer is returned if out of
+ * memory or the input argument is NULL.
+ */
+static umechlist_t *
+dup_umechlist(umechlist_t *plist)
+{
+ umechlist_t *pres = NULL;
+ umechlist_t *pcur;
+ umechlist_t *ptmp;
+ int rc = SUCCESS;
+
+ while (plist != NULL) {
+ if (!(ptmp = create_umech(plist->name))) {
+ rc = FAILURE;
+ break;
+ }
+
+ if (pres == NULL) {
+ pres = pcur = ptmp;
+ } else {
+ pcur->next = ptmp;
+ pcur = pcur->next;
+ }
+ plist = plist->next;
+ }
+
+ if (rc != SUCCESS) {
+ free_umechlist(pres);
+ return (NULL);
+ }
+
+ return (pres);
+}
+
+
+/*
+ * Duplicate an uentry. A NULL pointer is returned if out of memory
+ * or the input argument is NULL.
+ */
+static uentry_t *
+dup_uentry(uentry_t *puent1)
+{
+ uentry_t *puent2 = NULL;
+
+ if (puent1 == NULL) {
+ return (NULL);
+ }
+
+ if ((puent2 = malloc(sizeof (uentry_t))) == NULL) {
+ cryptoerror(LOG_STDERR, gettext("out of memory."));
+ return (NULL);
+ } else {
+ (void) strlcpy(puent2->name, puent1->name,
+ sizeof (puent2->name));
+ puent2->flag_norandom = puent1->flag_norandom;
+ puent2->flag_enabledlist = puent1->flag_enabledlist;
+ puent2->policylist = dup_umechlist(puent1->policylist);
+ puent2->flag_metaslot_enabled = puent1->flag_metaslot_enabled;
+ puent2->flag_metaslot_auto_key_migrate
+ = puent1->flag_metaslot_auto_key_migrate;
+ (void) memcpy(puent2->metaslot_ks_slot,
+ puent1->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE);
+ (void) memcpy(puent2->metaslot_ks_token,
+ puent1->metaslot_ks_token, TOKEN_LABEL_SIZE);
+ puent2->count = puent1->count;
+ return (puent2);
+ }
+}
+
+/*
+ * Find the entry in the "pkcs11.conf" file with "libname" as the provider
+ * name. Return the entry if found, otherwise return NULL.
+ */
+uentry_t *
+getent_uef(char *libname)
+{
+ uentrylist_t *pliblist = NULL;
+ uentrylist_t *plib = NULL;
+ uentry_t *puent = NULL;
+ boolean_t found = B_FALSE;
+
+ if (libname == NULL) {
+ return (NULL);
+ }
+
+ if ((get_pkcs11conf_info(&pliblist)) == FAILURE) {
+ return (NULL);
+ }
+
+ plib = pliblist;
+ while (plib) {
+ if (strcmp(plib->puent->name, libname) == 0) {
+ found = B_TRUE;
+ break;
+ } else {
+ plib = plib->next;
+ }
+ }
+
+ if (found) {
+ puent = dup_uentry(plib->puent);
+ }
+
+ free_uentrylist(pliblist);
+ return (puent);
+}
+
+
+
+/*
+ * Retrieve the metaslot information from the pkcs11.conf file.
+ * This function returns SUCCESS if successfully done; otherwise it returns
+ * FAILURE. If successful, the caller is responsible to free the space
+ * allocated for objectstore_slot_info and objectstore_token_info.
+ */
+int
+get_metaslot_info(boolean_t *status_enabled, boolean_t *migrate_enabled,
+ char **objectstore_slot_info, char **objectstore_token_info)
+{
+
+ int rc = SUCCESS;
+ uentry_t *puent;
+ char *buf1 = NULL;
+ char *buf2 = NULL;
+
+ if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) {
+ /* metaslot entry doesn't exist */
+ return (FAILURE);
+ }
+
+ *status_enabled = puent->flag_metaslot_enabled;
+ *migrate_enabled = puent->flag_metaslot_auto_key_migrate;
+
+ buf1 = malloc(SLOT_DESCRIPTION_SIZE);
+ if (buf1 == NULL) {
+ cryptoerror(LOG_ERR, "get_metaslot_info() - out of memory.\n");
+ rc = FAILURE;
+ goto out;
+ }
+ (void) strcpy(buf1, (const char *) puent->metaslot_ks_slot);
+ *objectstore_slot_info = buf1;
+
+ buf2 = malloc(TOKEN_LABEL_SIZE);
+ if (objectstore_slot_info == NULL) {
+ cryptoerror(LOG_ERR, "get_metaslot_info() - out of memory.\n");
+ rc = FAILURE;
+ goto out;
+ }
+ (void) strcpy(buf2, (const char *) puent->metaslot_ks_token);
+ *objectstore_token_info = buf2;
+
+out:
+ if (puent != NULL) {
+ free_uentry(puent);
+ }
+
+ if (rc == FAILURE) {
+ if (buf1 != NULL) {
+ free(buf1);
+ }
+ if (buf2 != NULL) {
+ free(buf2);
+ }
+ }
+
+ return (rc);
+}
diff --git a/usr/src/lib/libcryptoutil/common/cryptoutil.h b/usr/src/lib/libcryptoutil/common/cryptoutil.h
index 18a82bcdc0..c322ea76af 100644
--- a/usr/src/lib/libcryptoutil/common/cryptoutil.h
+++ b/usr/src/lib/libcryptoutil/common/cryptoutil.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -121,12 +120,20 @@ extern umechlist_t *create_umech(char *);
extern void free_umechlist(umechlist_t *);
extern void free_uentrylist(uentrylist_t *);
extern void free_uentry(uentry_t *);
+extern uentry_t *getent_uef(char *);
extern void tohexstr(uchar_t *bytes, size_t blen, char *hexstr, size_t hexlen);
extern CK_RV pkcs11_mech2keytype(CK_MECHANISM_TYPE mech_type,
CK_KEY_TYPE *ktype);
extern char *pkcs11_strerror(CK_RV rv);
+extern int
+get_metaslot_info(boolean_t *status_enabled, boolean_t *migrate_enabled,
+ char **objectstore_slot_info, char **objectstore_token_info);
+
+extern char *get_fullpath(char *dir, char *filepath);
+extern int str2lifetime(char *ltimestr, uint32_t *ltime);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libcryptoutil/common/mapfile-vers b/usr/src/lib/libcryptoutil/common/mapfile-vers
index 92e53197af..9ff8c3eec6 100644
--- a/usr/src/lib/libcryptoutil/common/mapfile-vers
+++ b/usr/src/lib/libcryptoutil/common/mapfile-vers
@@ -34,11 +34,15 @@ SUNWprivate_1.1 {
free_uentry;
free_uentrylist;
free_umechlist;
+ getent_uef;
+ get_fullpath;
+ get_metaslot_info;
get_pkcs11conf_info;
pkcs11_mech2keytype;
pkcs11_mech2str;
pkcs11_str2mech;
pkcs11_strerror;
+ str2lifetime;
tohexstr;
local:
*;
diff --git a/usr/src/lib/libcryptoutil/common/util.c b/usr/src/lib/libcryptoutil/common/util.c
new file mode 100644
index 0000000000..6fbf175d77
--- /dev/null
+++ b/usr/src/lib/libcryptoutil/common/util.c
@@ -0,0 +1,116 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <cryptoutil.h>
+#include <strings.h>
+#include <stdio.h>
+#include <tzfile.h>
+
+/*
+ * This function returns a fullpath based on the "dir" and "filepath" input
+ * arugments.
+ * - If the filepath specified does not start with a "/" and the directory
+ * is also given, prepend the directory to the filename.
+ * - If only dir or filepath is given, this function returns a copy of the
+ * given argument.
+ * - If the filepath is fully qualified already and the "dir" is also
+ * given, return NULL to indicate an error.
+ */
+char *
+get_fullpath(char *dir, char *filepath)
+{
+ char *fullpath = NULL;
+ int pathlen = 0;
+ int dirlen = 0;
+
+ if (filepath != NULL)
+ pathlen = strlen(filepath);
+
+ if (dir != NULL)
+ dirlen = strlen(dir);
+
+ if (pathlen > 0 && dirlen > 0) {
+ if (filepath[0] != '/') {
+ int len = pathlen + dirlen + 2;
+ fullpath = (char *)malloc(len);
+ if (fullpath != NULL)
+ (void) snprintf(fullpath, len, "%s/%s",
+ dir, filepath);
+ } else {
+ return (NULL);
+ }
+ } else if (pathlen > 0) {
+ fullpath = (char *)strdup(filepath);
+ } else if (dirlen > 0) {
+ fullpath = (char *)strdup(dir);
+ }
+
+ return (fullpath);
+}
+
+/*
+ * This function converts the input string to the value of time
+ * in seconds.
+ * - If the input string is NULL, return zero second.
+ * - The input string needs to be in the form of:
+ * number-second(s), number-minute(s), number-hour(s) or
+ * number-day(s).
+ */
+int
+str2lifetime(char *ltimestr, uint32_t *ltime)
+{
+ int num;
+ char timetok[10];
+
+ if (ltimestr == NULL || !strlen(ltimestr)) {
+ *ltime = 0;
+ return (0);
+ }
+
+ (void) memset(timetok, 0, sizeof (timetok));
+ if (sscanf(ltimestr, "%d-%08s", &num, timetok) != 2)
+ return (-1);
+
+ if (!strcasecmp(timetok, "second") ||
+ !strcasecmp(timetok, "seconds")) {
+ *ltime = num;
+ } else if (!strcasecmp(timetok, "minute") ||
+ !strcasecmp(timetok, "minutes")) {
+ *ltime = num * SECSPERMIN;
+ } else if (!strcasecmp(timetok, "day") ||
+ !strcasecmp(timetok, "days")) {
+ *ltime = num * SECSPERDAY;
+ } else if (!strcasecmp(timetok, "hour") ||
+ !strcasecmp(timetok, "hours")) {
+ *ltime = num * SECSPERHOUR;
+ } else {
+ *ltime = 0;
+ return (-1);
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libkmf/Makefile b/usr/src/lib/libkmf/Makefile
new file mode 100644
index 0000000000..d300caefb5
--- /dev/null
+++ b/usr/src/lib/libkmf/Makefile
@@ -0,0 +1,56 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# KMF Prototype Makefile
+#
+include ../Makefile.lib
+
+LIBRARY= libkmf.a
+VERS= 1
+
+SUBDIRS = ber_der libkmf plugins
+
+HDRS= kmfapi.h kmftypes.h
+HDRDIR= include
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+install_h := TARGET= install_h
+
+all clean clobber install lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRDIR) $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): install_h FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/ber_der/Makefile b/usr/src/lib/libkmf/ber_der/Makefile
new file mode 100644
index 0000000000..d81be42e84
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/Makefile
@@ -0,0 +1,49 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS= $(MACH)
+
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+check := TARGET= check
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/ber_der/Makefile.com b/usr/src/lib/libkmf/ber_der/Makefile.com
new file mode 100644
index 0000000000..9c8c5657de
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/Makefile.com
@@ -0,0 +1,57 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY= libkmfberder.a
+VERS= .1
+
+OBJECTS=\
+ encode.o \
+ decode.o \
+ io.o \
+ clasn1.o
+
+include $(SRC)/lib/Makefile.lib
+
+SRCDIR= ../common
+INCDIR= ../inc
+
+LIBS= $(DYNLIB) $(LINTLIB)
+
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+CFLAGS += $(CCVERBOSE) -xCC
+CFLAGS64 += $(CCVERBOSE) -xCC
+CPPFLAGS += -I/usr/include/libxml2 -I$(INCDIR) -I../../include
+CPPFLAGS64 += -I/usr/include/libxml2 -I$(INCDIR) -I../../include
+LDLIBS += -lc
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/ber_der/amd64/Makefile b/usr/src/lib/libkmf/ber_der/amd64/Makefile
new file mode 100644
index 0000000000..6093af918f
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libkmf/ber_der/common/clasn1.c b/usr/src/lib/libkmf/ber_der/common/clasn1.c
new file mode 100644
index 0000000000..3aa1c7b68d
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/common/clasn1.c
@@ -0,0 +1,2452 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ *
+ * File: CLASN1.C
+ *
+ * Copyright (c) 1995-1999 Intel Corporation. All rights reserved.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <strings.h>
+#include <kmftypes.h>
+#include <ber_der.h>
+#include <kmfapi.h>
+#include <kmfapiP.h>
+
+#include <stdio.h>
+
+#define DSA_RAW_SIG_LEN 40
+
+static uint8_t OID_ExtensionRequest[] = { OID_PKCS_9, 14 };
+const KMF_OID extension_request_oid = {OID_PKCS_9_LENGTH + 1,
+ OID_ExtensionRequest};
+
+static KMF_RETURN
+encode_algoid(BerElement *asn1, KMF_X509_ALGORITHM_IDENTIFIER *algoid)
+{
+ KMF_RETURN ret = KMF_OK;
+
+ if (kmfber_printf(asn1, "{D", &algoid->algorithm) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ }
+ if (algoid->parameters.Data == NULL ||
+ algoid->parameters.Length == 0) {
+ if (kmfber_printf(asn1, "n}") == -1)
+ return (KMF_ERR_BAD_CERT_FORMAT);
+ } else {
+ /*
+ * The algorithm data can be anything, so we just write it
+ * straight into the buffer. It is already DER encoded.
+ */
+ (void) kmfber_write(asn1, (char *)algoid->parameters.Data,
+ algoid->parameters.Length, 0);
+ if (kmfber_printf(asn1, "}") == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ }
+ }
+
+ return (ret);
+}
+
+static void
+free_data(KMF_DATA *data)
+{
+ if (data == NULL || data->Data == NULL)
+ return;
+
+ free(data->Data);
+ data->Data = NULL;
+ data->Length = 0;
+}
+
+static void
+free_algoid(KMF_X509_ALGORITHM_IDENTIFIER *algoid)
+{
+ free_data(&algoid->algorithm);
+ free_data(&algoid->parameters);
+}
+
+static void
+free_decoded_spki(KMF_X509_SPKI *spki)
+{
+ if (spki != NULL) {
+ free_algoid(&spki->algorithm);
+ free_data(&spki->subjectPublicKey);
+ }
+}
+
+static void
+free_rdn_data(KMF_X509_NAME *name)
+{
+ KMF_X509_RDN *newrdn = NULL;
+ KMF_X509_TYPE_VALUE_PAIR *av = NULL;
+ int i, j;
+
+ if (name && name->numberOfRDNs) {
+ for (i = 0; i < name->numberOfRDNs; i++) {
+ newrdn = &name->RelativeDistinguishedName[i];
+ for (j = 0; j < newrdn->numberOfPairs; j++) {
+ av = &newrdn->AttributeTypeAndValue[j];
+ free_data(&av->type);
+ free_data(&av->value);
+ }
+ free(newrdn->AttributeTypeAndValue);
+ }
+ free(name->RelativeDistinguishedName);
+ name->numberOfRDNs = 0;
+ name->RelativeDistinguishedName = NULL;
+ }
+}
+
+static void
+free_validity(KMF_X509_VALIDITY *validity)
+{
+ free_data(&validity->notBefore.time);
+ free_data(&validity->notAfter.time);
+}
+
+static void
+free_one_extension(KMF_X509_EXTENSION *exptr)
+{
+ free_data(&exptr->extnId);
+ free_data(&exptr->BERvalue);
+
+ if (exptr->value.tagAndValue) {
+ free_data(&exptr->value.tagAndValue->value);
+ free(exptr->value.tagAndValue);
+ }
+}
+
+static void
+free_extensions(KMF_X509_EXTENSIONS *extns)
+{
+ int i;
+ KMF_X509_EXTENSION *exptr;
+
+ if (extns && extns->numberOfExtensions > 0) {
+ for (i = 0; i < extns->numberOfExtensions; i++) {
+ exptr = &extns->extensions[i];
+ free_one_extension(exptr);
+ }
+ free(extns->extensions);
+ extns->numberOfExtensions = 0;
+ extns->extensions = NULL;
+ }
+}
+
+static void
+free_tbscsr(KMF_TBS_CSR *tbscsr)
+{
+ if (tbscsr) {
+ free_data(&tbscsr->version);
+
+ free_rdn_data(&tbscsr->subject);
+
+ free_decoded_spki(&tbscsr->subjectPublicKeyInfo);
+
+ free_extensions(&tbscsr->extensions);
+ }
+}
+
+
+static void
+free_bigint(KMF_BIGINT *bn)
+{
+ if (bn != NULL && bn->val != NULL) {
+ free(bn->val);
+ bn->val = NULL;
+ bn->len = 0;
+ }
+}
+
+static void
+free_tbscert(KMF_X509_TBS_CERT *tbscert)
+{
+ if (tbscert) {
+ free_data(&tbscert->version);
+ free_bigint(&tbscert->serialNumber);
+ free_algoid(&tbscert->signature);
+
+ free_rdn_data(&tbscert->issuer);
+ free_rdn_data(&tbscert->subject);
+
+ free_validity(&tbscert->validity);
+
+ free_data(&tbscert->issuerUniqueIdentifier);
+ free_data(&tbscert->subjectUniqueIdentifier);
+ free_decoded_spki(&tbscert->subjectPublicKeyInfo);
+ free_extensions(&tbscert->extensions);
+
+ free_data(&tbscert->issuerUniqueIdentifier);
+ free_data(&tbscert->subjectUniqueIdentifier);
+ }
+}
+
+static void
+free_decoded_cert(KMF_X509_CERTIFICATE *certptr)
+{
+ if (!certptr)
+ return;
+
+ free_tbscert(&certptr->certificate);
+
+ free_algoid(&certptr->signature.algorithmIdentifier);
+ free_data(&certptr->signature.encrypted);
+}
+
+static KMF_RETURN
+get_algoid(BerElement *asn1, KMF_X509_ALGORITHM_IDENTIFIER *algoid)
+{
+ KMF_RETURN ret = KMF_OK;
+ ber_tag_t tag, newtag;
+ ber_len_t size;
+ BerValue AlgOID = {NULL, 0};
+
+ tag = kmfber_next_element(asn1, &size, NULL);
+ if (tag != BER_CONSTRUCTED_SEQUENCE)
+ return (KMF_ERR_BAD_CERT_FORMAT);
+
+ if ((tag = kmfber_scanf(asn1, "{Dt", &AlgOID, &newtag)) == -1) {
+ return (KMF_ERR_BAD_CERT_FORMAT);
+ }
+ algoid->algorithm.Data = (uchar_t *)AlgOID.bv_val;
+ algoid->algorithm.Length = AlgOID.bv_len;
+
+ if (newtag == BER_NULL) {
+ (void) kmfber_scanf(asn1, "n}");
+ algoid->parameters.Data = NULL;
+ algoid->parameters.Length = 0;
+ } else {
+ /* Peek at the tag and length bytes */
+ if ((kmfber_scanf(asn1, "tl", &tag, &size)) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ /*
+ * We need to read the tag and the length bytes too,
+ * so adjust the size.
+ */
+ size += kmfber_calc_taglen(tag) + kmfber_calc_lenlen(size);
+ algoid->parameters.Data = malloc(size);
+ if (algoid->parameters.Data == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ /* read the raw data into the Algoritm params area. */
+ if (kmfber_read(asn1, (char *)algoid->parameters.Data,
+ size) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ algoid->parameters.Length = size;
+ if ((tag = kmfber_scanf(asn1, "}")) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ }
+ }
+cleanup:
+ if (ret != KMF_OK) {
+ free_algoid(algoid);
+ }
+
+ return (ret);
+}
+
+static KMF_RETURN
+CopyData(KMF_DATA *src, KMF_DATA *dst)
+{
+ if (src && dst && src->Data != NULL && src->Length > 0) {
+ dst->Length = src->Length;
+ dst->Data = malloc(sizeof (dst->Length));
+ if (dst->Data == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memcpy(dst->Data, src->Data, src->Length);
+ }
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+encode_spki(BerElement *asn1, KMF_X509_SPKI *spki)
+{
+ KMF_RETURN ret = KMF_OK;
+
+ if (kmfber_printf(asn1, "{") == -1)
+ return (KMF_ERR_BAD_CERT_FORMAT);
+
+ if ((ret = encode_algoid(asn1, &spki->algorithm)) != KMF_OK)
+ return (ret);
+
+ if (kmfber_printf(asn1, "B}", spki->subjectPublicKey.Data,
+ spki->subjectPublicKey.Length * 8) == -1)
+ return (KMF_ERR_BAD_CERT_FORMAT);
+
+ return (ret);
+}
+
+KMF_RETURN
+DerEncodeSPKI(KMF_X509_SPKI *spki, KMF_DATA *EncodedSPKI)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1;
+ BerValue *result;
+
+ if (spki == NULL || EncodedSPKI == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if ((asn1 = kmfder_alloc()) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if ((ret = encode_spki(asn1, spki)) != KMF_OK) {
+ return (ret);
+ }
+
+ if (kmfber_flatten(asn1, &result) == -1) {
+ kmfber_free(asn1, 1);
+ return (KMF_ERR_ENCODING);
+ }
+
+ EncodedSPKI->Data = (uchar_t *)result->bv_val;
+ EncodedSPKI->Length = result->bv_len;
+
+ free(result);
+ kmfber_free(asn1, 1);
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+get_spki(BerElement *asn1, KMF_X509_SPKI *spki)
+{
+ KMF_RETURN ret = KMF_OK;
+ char *bitstr = NULL;
+ ber_len_t size;
+
+ if (kmfber_scanf(asn1, "{") == -1)
+ return (KMF_ERR_BAD_CERT_FORMAT);
+
+ if ((ret = get_algoid(asn1, &spki->algorithm)) != KMF_OK)
+ return (ret);
+
+ if (kmfber_scanf(asn1, "B}", &bitstr, &size) == BER_BIT_STRING) {
+ spki->subjectPublicKey.Data = (uchar_t *)bitstr;
+ spki->subjectPublicKey.Length = size / 8;
+ } else {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+cleanup:
+ if (ret != KMF_OK) {
+ if (bitstr != NULL)
+ free(bitstr);
+ spki->subjectPublicKey.Data = NULL;
+ spki->subjectPublicKey.Length = 0;
+
+ free_algoid(&spki->algorithm);
+ }
+ return (ret);
+}
+
+KMF_RETURN
+DerEncodeDSASignature(KMF_DATA *rawdata, KMF_DATA *signature)
+{
+ BerElement *asn1;
+ BerValue *buf;
+ int n;
+
+ if (rawdata == NULL || signature == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (rawdata->Data == NULL || rawdata->Length != DSA_RAW_SIG_LEN)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ asn1 = kmfder_alloc();
+ if (asn1 == NULL)
+ return (KMF_ERR_MEMORY);
+
+ /*
+ * The DSA signature is the concatenation of 2 SHA-1 hashed
+ * bignum values.
+ */
+ n = DSA_RAW_SIG_LEN/2;
+ if (kmfber_printf(asn1, "{II}",
+ rawdata->Data, n,
+ &rawdata->Data[n], n) == -1) {
+ kmfber_free(asn1, 1);
+ return (KMF_ERR_MEMORY);
+ }
+
+ if (kmfber_flatten(asn1, &buf) == -1) {
+ kmfber_free(asn1, 1);
+ return (KMF_ERR_ENCODING);
+ }
+
+ signature->Data = (uchar_t *)buf->bv_val;
+ signature->Length = buf->bv_len;
+
+ kmfber_free(asn1, 1);
+ free(buf);
+
+ return (KMF_OK);
+}
+
+KMF_RETURN
+DerDecodeDSASignature(KMF_DATA *encoded, KMF_DATA *signature)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1 = NULL;
+ BerValue buf, *R = NULL, *S = NULL;
+
+ buf.bv_val = (char *)encoded->Data;
+ buf.bv_len = encoded->Length;
+
+ if (encoded == NULL || encoded->Data == NULL ||
+ signature == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ signature->Data = NULL;
+ signature->Length = 0;
+
+ if ((asn1 = kmfder_init(&buf)) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (kmfber_scanf(asn1, "{II}", &R, &S) == -1) {
+ ret = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+ signature->Length = R->bv_len + S->bv_len;
+ signature->Data = malloc(signature->Length);
+ if (signature->Data == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ (void) memcpy(signature->Data, R->bv_val, R->bv_len);
+ (void) memcpy(&signature->Data[R->bv_len], S->bv_val, S->bv_len);
+
+cleanup:
+ if (R && R->bv_val)
+ free(R->bv_val);
+ if (S && S->bv_val)
+ free(S->bv_val);
+
+ if (S) free(S);
+ if (R) free(R);
+
+ if (asn1) kmfber_free(asn1, 1);
+
+ return (ret);
+}
+
+KMF_RETURN
+DerDecodeSPKI(KMF_DATA *EncodedSPKI, KMF_X509_SPKI *spki)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1;
+ BerValue bv;
+
+ if (EncodedSPKI == NULL || EncodedSPKI->Data == NULL ||
+ spki == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(spki, 0, sizeof (KMF_X509_SPKI));
+
+ bv.bv_val = (char *)EncodedSPKI->Data;
+ bv.bv_len = EncodedSPKI->Length;
+
+ if ((asn1 = kmfder_init(&bv)) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ ret = get_spki(asn1, spki);
+
+cleanup:
+ if (ret != KMF_OK) {
+ free_decoded_spki(spki);
+ }
+ kmfber_free(asn1, 1);
+
+ return (ret);
+}
+
+KMF_RETURN
+CopySPKI(KMF_X509_SPKI *src,
+ KMF_X509_SPKI **dest)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_SPKI *newspki;
+
+ *dest = NULL;
+
+ newspki = malloc(sizeof (KMF_X509_SPKI));
+ if (newspki == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(newspki, 0, sizeof (KMF_X509_SPKI));
+
+ ret = CopyData(&src->algorithm.algorithm,
+ &newspki->algorithm.algorithm);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ ret = CopyData(&src->algorithm.parameters,
+ &newspki->algorithm.parameters);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ ret = CopyData(&src->subjectPublicKey,
+ &newspki->subjectPublicKey);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ *dest = newspki;
+cleanup:
+ if (ret != KMF_OK) {
+ if (newspki)
+ free_decoded_spki(newspki);
+ }
+ return (ret);
+}
+
+static KMF_RETURN
+encode_validity(BerElement *asn1, KMF_X509_VALIDITY *validity)
+{
+ int ret;
+
+ ret = kmfber_printf(asn1, "{tsts}",
+ validity->notBefore.timeType,
+ validity->notBefore.time.Data,
+ validity->notAfter.timeType,
+ validity->notAfter.time.Data);
+
+ if (ret == -1)
+ return (KMF_ERR_BAD_CERT_FORMAT);
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+get_validity(BerElement *asn1, KMF_X509_VALIDITY *validity)
+{
+ KMF_RETURN ret = KMF_OK;
+ int tag;
+ int t1, t2;
+ ber_len_t size;
+ char *t1str, *t2str;
+
+ (void) memset(validity, 0, sizeof (KMF_X509_VALIDITY));
+
+ tag = kmfber_next_element(asn1, &size, NULL);
+ if (tag != BER_CONSTRUCTED_SEQUENCE) {
+ return (KMF_ERR_BAD_CERT_FORMAT);
+ }
+
+ if (kmfber_scanf(asn1, "{tata}", &t1, &t1str, &t2, &t2str) == -1) {
+ return (KMF_ERR_BAD_CERT_FORMAT);
+ }
+
+ validity->notBefore.timeType = t1;
+ validity->notBefore.time.Data = (uchar_t *)t1str;
+ validity->notBefore.time.Length = strlen(t1str);
+
+ validity->notAfter.timeType = t2;
+ validity->notAfter.time.Data = (uchar_t *)t2str;
+ validity->notAfter.time.Length = strlen(t2str);
+
+ return (ret);
+}
+
+KMF_RETURN
+AddRDN(KMF_X509_NAME *name, KMF_X509_RDN *newrdn)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_RDN *rdnslot = NULL;
+
+ /* Add new RDN record to existing list */
+ name->numberOfRDNs++;
+ name->RelativeDistinguishedName =
+ realloc(name->RelativeDistinguishedName,
+ name->numberOfRDNs * sizeof (KMF_X509_RDN));
+
+ if (name->RelativeDistinguishedName == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ rdnslot = &name->RelativeDistinguishedName[name->numberOfRDNs-1];
+
+ if (newrdn) {
+ (void) memcpy(rdnslot, newrdn, sizeof (KMF_X509_RDN));
+ } else {
+ rdnslot->numberOfPairs = 0;
+ rdnslot->AttributeTypeAndValue = NULL;
+ }
+
+cleanup:
+ /* No cleanup needed here */
+ return (ret);
+}
+
+static KMF_RETURN
+encode_rdn(BerElement *asn1, KMF_X509_NAME *name)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_TYPE_VALUE_PAIR *attrtvpair = NULL;
+ int i;
+ KMF_X509_RDN *rdn;
+
+ if (kmfber_printf(asn1, "{") == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ for (i = 0; i < name->numberOfRDNs; i++) {
+ if (kmfber_printf(asn1, "[") == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ rdn = &name->RelativeDistinguishedName[i];
+ attrtvpair = rdn->AttributeTypeAndValue;
+
+ if (rdn->numberOfPairs > 0) {
+ if (kmfber_printf(asn1, "{Dto}",
+ &attrtvpair->type,
+ attrtvpair->valueType,
+ attrtvpair->value.Data,
+ attrtvpair->value.Length) == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ }
+ if (kmfber_printf(asn1, "]") == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ }
+
+ if (kmfber_printf(asn1, "}") == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+cleanup:
+ /* No cleanup needed here */
+
+ return (ret);
+}
+
+
+KMF_RETURN
+CopyRDN(KMF_X509_NAME *srcname, KMF_X509_NAME **destname)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_NAME *newname = NULL;
+ KMF_X509_RDN *rdn, *dstrdn;
+ KMF_X509_TYPE_VALUE_PAIR *av = NULL;
+ KMF_X509_TYPE_VALUE_PAIR *srcav = NULL;
+ KMF_X509_TYPE_VALUE_PAIR *dstav = NULL;
+ int i, j;
+
+ newname = malloc(sizeof (KMF_X509_NAME));
+ if (newname == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(newname, 0, sizeof (KMF_X509_NAME));
+
+ newname->numberOfRDNs = srcname->numberOfRDNs;
+ newname->RelativeDistinguishedName = malloc(newname->numberOfRDNs *
+ sizeof (KMF_X509_RDN));
+ if (newname->RelativeDistinguishedName == NULL) {
+ free(newname);
+ return (KMF_ERR_MEMORY);
+ }
+ /* Copy each RDN in the list */
+ for (i = 0; i < newname->numberOfRDNs; i++) {
+ rdn = &srcname->RelativeDistinguishedName[i];
+
+ dstrdn = &newname->RelativeDistinguishedName[i];
+ (void) memset(dstrdn, 0, sizeof (KMF_X509_RDN));
+
+ dstrdn->numberOfPairs = rdn->numberOfPairs;
+ if (dstrdn->numberOfPairs > 0) {
+ av = malloc(dstrdn->numberOfPairs *
+ sizeof (KMF_X509_TYPE_VALUE_PAIR));
+ if (av == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ (void) memset(av, 0, dstrdn->numberOfPairs *
+ sizeof (KMF_X509_TYPE_VALUE_PAIR));
+
+ dstrdn->AttributeTypeAndValue = av;
+ if (av == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ /* Copy each A/V pair in the list */
+ for (j = 0; j < dstrdn->numberOfPairs; j++) {
+ srcav = &rdn->AttributeTypeAndValue[j];
+ dstav = &dstrdn->AttributeTypeAndValue[j];
+ if ((ret = CopyData(&srcav->type,
+ &dstav->type)) != KMF_OK)
+ goto cleanup;
+ dstav->valueType = srcav->valueType;
+ if ((ret = CopyData(&srcav->value,
+ &dstav->value)) != KMF_OK)
+ goto cleanup;
+ }
+ } else {
+ dstrdn->AttributeTypeAndValue = NULL;
+ }
+ }
+ *destname = newname;
+
+cleanup:
+ if (ret != KMF_OK) {
+ if (newname)
+ free_rdn_data(newname);
+
+ free(newname);
+ *destname = NULL;
+ }
+ return (ret);
+}
+
+#define VALID_DIRECTORYSTRING_TAG(t) ( \
+ (t == BER_UTF8_STRING) || \
+ (t == BER_PRINTABLE_STRING) || \
+ (t == BER_IA5STRING) || \
+ (t == BER_T61STRING) || \
+ (t == BER_BMP_STRING) || \
+ (t == BER_UNIVERSAL_STRING))
+
+static KMF_RETURN
+get_rdn(BerElement *asn1, KMF_X509_NAME *name)
+{
+ KMF_RETURN ret = KMF_OK;
+ ber_len_t size;
+ char *end;
+ int tag;
+ BerValue AttrOID;
+ char *AttrValue = NULL;
+ KMF_X509_TYPE_VALUE_PAIR *newpair = NULL;
+ KMF_X509_RDN newrdn;
+
+ /*
+ * AttributeType ::= OBJECT IDENTIFIER
+ * AttributeValue ::= ANY
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ *
+ * Name ::= CHOICE { -- only one possibility for now --
+ * rdnSequence RDNSequence }
+ *
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ * DistinguishedName ::= RDNSequence
+ *
+ * RelativeDistinguishedName ::=
+ * SET SIZE (1 .. MAX) OF AttributeTypeAndValue
+ *
+ */
+
+ name->numberOfRDNs = 0;
+ name->RelativeDistinguishedName = NULL;
+
+ /* Get the beginning of the RDN Set and a ptr to the end */
+ tag = kmfber_first_element(asn1, &size, &end);
+ if (tag != BER_CONSTRUCTED_SET) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ /* Walk through the individual SET items until the "end" is reached */
+ while ((tag = kmfber_next_element(asn1, &size, end)) ==
+ BER_CONSTRUCTED_SET) {
+ /* Skip over the SET tag */
+ if (kmfber_scanf(asn1, "T", &tag) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ break;
+ }
+
+ /* An "empty" set member means we tack on an empty node */
+ if (size == 0) {
+ if ((ret = AddRDN(name, NULL)) != KMF_OK)
+ goto cleanup;
+ continue;
+ }
+
+ /* Attr OID and peek at the next tag and field length */
+ if (kmfber_scanf(asn1, "{Dtl", &AttrOID, &tag, &size) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ break;
+ }
+
+ if (!(VALID_DIRECTORYSTRING_TAG(tag))) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ break;
+ }
+
+ if (kmfber_scanf(asn1, "a}]", &AttrValue) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ break;
+ }
+
+ /* Allocate a new name/value pair record */
+ newpair = malloc(sizeof (KMF_X509_TYPE_VALUE_PAIR));
+ if (newpair == NULL) {
+ ret = KMF_ERR_MEMORY;
+ break;
+ }
+ (void) memset(newpair, 0, sizeof (KMF_X509_TYPE_VALUE_PAIR));
+ newpair->type.Data = (uchar_t *)AttrOID.bv_val;
+ newpair->type.Length = AttrOID.bv_len;
+ newpair->valueType = tag; /* what kind of string is it? */
+ newpair->value.Data = (uchar_t *)AttrValue;
+ newpair->value.Length = strlen(AttrValue);
+
+ (void) memset(&newrdn, 0, sizeof (KMF_X509_RDN));
+ newrdn.numberOfPairs = 1;
+ newrdn.AttributeTypeAndValue = newpair;
+
+ if ((ret = AddRDN(name, &newrdn)) != KMF_OK)
+ break;
+ }
+
+cleanup:
+ if (ret != KMF_OK) {
+ free_rdn_data(name);
+ }
+ return (ret);
+}
+
+static KMF_RETURN
+set_der_integer(KMF_DATA *data, int value)
+{
+ if (data == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ data->Data = malloc(sizeof (int));
+ if (data->Data == NULL)
+ return (KMF_ERR_MEMORY);
+
+ data->Length = sizeof (int);
+ (void) memcpy((void *)data->Data, (const void *)&value, sizeof (int));
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+set_bigint(KMF_BIGINT *data, KMF_BIGINT *bigint)
+{
+ if (data == NULL || bigint == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ data->val = malloc(bigint->len);
+ if (data->val == NULL)
+ return (KMF_ERR_MEMORY);
+
+ data->len = bigint->len;
+ (void) memcpy((void *)data->val, (const void *)bigint->val,
+ bigint->len);
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+encode_uniqueid(BerElement *asn1, int tag, KMF_DATA *id)
+{
+ KMF_RETURN ret = KMF_OK;
+ uint32_t len;
+
+ len = kmfber_calc_taglen(BER_BIT_STRING) +
+ kmfber_calc_lenlen(id->Length * 8) + id->Length;
+ if (kmfber_printf(asn1, "TlB", tag, len,
+ id->Data, id->Length * 8) == -1)
+ return (KMF_ERR_BAD_CERT_FORMAT);
+
+ return (ret);
+}
+
+static KMF_RETURN
+encode_extension_list(BerElement *asn1, KMF_X509_EXTENSIONS *extns)
+{
+ KMF_RETURN ret = KMF_OK;
+ int i;
+
+ for (i = 0; i < extns->numberOfExtensions; i++) {
+ BerValue v;
+ v.bv_val = (char *)extns->extensions[i].extnId.Data;
+ v.bv_len = extns->extensions[i].extnId.Length;
+
+ if (kmfber_printf(asn1, "{D", &v) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ if (extns->extensions[i].critical) {
+ if (kmfber_printf(asn1, "b",
+ extns->extensions[i].critical) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+ }
+
+ if (kmfber_printf(asn1, "o}",
+ extns->extensions[i].BERvalue.Data,
+ extns->extensions[i].BERvalue.Length) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+ }
+cleanup:
+ return (ret);
+}
+
+static KMF_RETURN
+encode_extensions(BerElement *asn1, KMF_X509_EXTENSIONS *extns)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *extn = NULL;
+ BerValue *extnvalue = NULL;
+
+ extn = kmfder_alloc();
+ if (extn == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (kmfber_printf(extn, "{") == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ ret = encode_extension_list(extn, extns);
+
+ if (kmfber_printf(extn, "}") == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ if (kmfber_flatten(extn, &extnvalue) == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ if (kmfber_printf(asn1, "Tl", 0xA3, extnvalue->bv_len) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ if (kmfber_write(asn1, extnvalue->bv_val, extnvalue->bv_len, 0) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+cleanup:
+ kmfber_free(extn, 1);
+ if (extnvalue != NULL)
+ kmfber_bvfree(extnvalue);
+
+ return (ret);
+}
+
+static KMF_RETURN
+get_one_extension(BerElement *asn1, KMF_X509_EXTENSION **retex, char *end)
+{
+ KMF_RETURN ret = KMF_OK;
+ ber_len_t size;
+ int critical, tag;
+ KMF_X509_EXTENSION *ex = NULL;
+ BerValue extOID;
+ BerValue extValue;
+ BerElement *extnber = NULL;
+
+ if (kmfber_scanf(asn1, "T", &tag) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ tag = kmfber_next_element(asn1, &size, end);
+ if (tag != BER_OBJECT_IDENTIFIER) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ if (kmfber_scanf(asn1, "D", &extOID) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ tag = kmfber_next_element(asn1, &size, end);
+ if (tag != BER_BOOLEAN) {
+ critical = 0;
+ if (tag != BER_OCTET_STRING)
+ goto cleanup;
+ } else {
+ if (kmfber_scanf(asn1, "b", &critical) == -1)
+ goto cleanup;
+ }
+
+ tag = kmfber_next_element(asn1, &size, end);
+ if (tag != BER_OCTET_STRING) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ if (kmfber_scanf(asn1, "o", &extValue) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ /* allocate a new Extension record */
+ ex = malloc(sizeof (KMF_X509_EXTENSION));
+ if (ex == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ (void) memset(ex, 0, sizeof (ex));
+
+ ex->extnId.Data = (uchar_t *)extOID.bv_val;
+ ex->extnId.Length = extOID.bv_len;
+ ex->critical = critical;
+ ex->format = KMF_X509_DATAFORMAT_ENCODED;
+ ex->BERvalue.Data = (uchar_t *)extValue.bv_val;
+ ex->BERvalue.Length = extValue.bv_len;
+
+ /* Tag and value is a little tricky */
+ ex->value.tagAndValue = malloc(sizeof (KMF_X509EXT_TAGandVALUE));
+ if (ex->value.tagAndValue == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ (void) memset(ex->value.tagAndValue, 0,
+ sizeof (KMF_X509EXT_TAGandVALUE));
+
+ /* Parse the Extension value field */
+ extnber = kmfder_init(&extValue);
+ if (extnber == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ /* Get the tag and length of the extension field */
+ if (kmfber_scanf(extnber, "tl", &tag, &size) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ if (kmfber_scanf(extnber, "T", &tag) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ ex->value.tagAndValue->value.Data = malloc(size);
+ ex->value.tagAndValue->value.Length = size;
+ size = kmfber_read(extnber,
+ (char *)ex->value.tagAndValue->value.Data, size);
+ if (size != ex->value.tagAndValue->value.Length) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ kmfber_free(extnber, 1);
+ ex->value.tagAndValue->type = tag;
+
+ *retex = ex;
+cleanup:
+ if (ret != KMF_OK) {
+ if (ex != NULL)
+ free_one_extension(ex);
+ }
+
+ return (ret);
+}
+
+static KMF_RETURN
+get_extensions(BerElement *asn1, KMF_X509_EXTENSIONS *extns)
+{
+ KMF_RETURN ret = KMF_OK;
+ ber_len_t size;
+ char *end = NULL;
+ KMF_X509_EXTENSION *ex = NULL;
+
+ /*
+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ *
+ * Extension ::= SEQUENCE {
+ * extnID OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING }
+ *
+ * { {{D}Bo}, ... }
+ */
+ if (kmfber_first_element(asn1, &size, &end) !=
+ BER_CONSTRUCTED_SEQUENCE)
+ return (KMF_ERR_BAD_CERT_FORMAT);
+
+ while (kmfber_next_element(asn1, &size, end) ==
+ BER_CONSTRUCTED_SEQUENCE) {
+ ret = get_one_extension(asn1, &ex, end);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ extns->numberOfExtensions++;
+ extns->extensions = realloc(extns->extensions,
+ extns->numberOfExtensions *
+ sizeof (KMF_X509_EXTENSION));
+ if (extns->extensions == NULL) {
+ ret = KMF_ERR_MEMORY;
+ break;
+ }
+
+ extns->extensions[extns->numberOfExtensions-1] = *ex;
+ free(ex);
+ }
+
+cleanup:
+ if (ret != KMF_OK)
+ free_extensions(extns);
+
+ return (ret);
+}
+
+KMF_RETURN
+decode_tbscert_data(BerElement *asn1,
+ KMF_X509_TBS_CERT **signed_cert_ptr_ptr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_TBS_CERT *tbscert = NULL;
+ int tag, version;
+ struct berval *bvserno = NULL;
+ KMF_BIGINT serno;
+
+ if (kmfber_scanf(asn1, "{t", &tag) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ /* Version number is optional */
+ if (tag == 0xA0) {
+ if (kmfber_scanf(asn1, "Ti", &tag, &version) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ } else {
+ version = 0; /* DEFAULT v1 (0) */
+ }
+
+ /* Now get the serial number, it is not optional */
+ if (kmfber_scanf(asn1, "I", &bvserno) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ } else {
+ serno.val = (uchar_t *)bvserno->bv_val;
+ serno.len = bvserno->bv_len;
+ }
+
+ tbscert = malloc(sizeof (KMF_X509_TBS_CERT));
+ if (!tbscert) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ (void) memset(tbscert, 0, sizeof (KMF_X509_TBS_CERT));
+
+ if ((ret = set_der_integer(&tbscert->version, version)) != KMF_OK)
+ goto cleanup;
+
+ if ((ret = set_bigint(&tbscert->serialNumber, &serno)) != KMF_OK)
+ goto cleanup;
+
+ if ((ret = get_algoid(asn1, &tbscert->signature)) != KMF_OK)
+ goto cleanup;
+
+ if ((ret = get_rdn(asn1, &tbscert->issuer)) != KMF_OK)
+ goto cleanup;
+
+ if ((ret = get_validity(asn1, &tbscert->validity)) != KMF_OK)
+ goto cleanup;
+
+ if ((ret = get_rdn(asn1, &tbscert->subject)) != KMF_OK)
+ goto cleanup;
+
+ if ((ret = get_spki(asn1, &tbscert->subjectPublicKeyInfo)) != KMF_OK)
+ goto cleanup;
+
+ /* Check for the optional fields */
+ tbscert->extensions.numberOfExtensions = 0;
+ tbscert->extensions.extensions = NULL;
+
+ while ((kmfber_scanf(asn1, "t", &tag)) != -1 &&
+ (tag == 0xA1 || tag == 0xA2 || tag == 0xA3)) {
+ char *optfield;
+ ber_len_t len;
+
+ /* consume the tag and length */
+ (void) kmfber_scanf(asn1, "T", &tag);
+ switch (tag) {
+ case 0xA1:
+ if (kmfber_scanf(asn1, "B", &optfield, &len) !=
+ BER_BIT_STRING) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ tbscert->issuerUniqueIdentifier.Data =
+ (uchar_t *)optfield;
+ tbscert->issuerUniqueIdentifier.Length =
+ len / 8;
+ break;
+ case 0xA2:
+ if (kmfber_scanf(asn1, "B", &optfield, &len) !=
+ BER_BIT_STRING) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ tbscert->subjectUniqueIdentifier.Data =
+ (uchar_t *)optfield;
+ tbscert->subjectUniqueIdentifier.Length =
+ len / 8;
+ break;
+ case 0xA3:
+ ret = get_extensions(asn1, &tbscert->extensions);
+ break;
+ }
+ }
+
+ *signed_cert_ptr_ptr = tbscert;
+
+cleanup:
+ if (bvserno != NULL) {
+ free(bvserno->bv_val);
+ free(bvserno);
+ }
+ if (ret != KMF_OK) {
+ if (tbscert) {
+ free_tbscert(tbscert);
+ free(tbscert);
+ }
+ *signed_cert_ptr_ptr = NULL;
+ }
+ return (ret);
+}
+
+KMF_RETURN
+DerDecodeTbsCertificate(const KMF_DATA *Value,
+ KMF_X509_TBS_CERT **tbscert)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1 = NULL;
+ BerValue rawcert;
+ KMF_X509_TBS_CERT *newcert = NULL;
+
+ if (!tbscert || !Value || !Value->Data || !Value->Length)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rawcert.bv_val = (char *)Value->Data;
+ rawcert.bv_len = Value->Length;
+
+ if ((asn1 = kmfder_init(&rawcert)) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ ret = decode_tbscert_data(asn1, &newcert);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ *tbscert = newcert;
+
+cleanup:
+ if (ret != KMF_OK) {
+ if (newcert)
+ free_tbscert(newcert);
+ *tbscert = NULL;
+ }
+ kmfber_free(asn1, 1);
+
+ return (ret);
+}
+
+/*
+ * Name: DerDecodeSignedCertificate
+ *
+ * Description:
+ * DER decodes the encoded X509 certificate
+ *
+ * Parameters:
+ * Value (input): DER encoded object that shd be decoded
+ *
+ * signed_cert_ptr_ptr (output) : Decoded KMF_X509_CERTIFICATE object
+ */
+KMF_RETURN
+DerDecodeSignedCertificate(const KMF_DATA *Value,
+ KMF_X509_CERTIFICATE **signed_cert_ptr_ptr)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1 = NULL;
+ BerValue rawcert;
+ ber_tag_t tag;
+ ber_len_t size;
+ char *end = NULL;
+ char *signature;
+ KMF_X509_TBS_CERT *tbscert = NULL;
+ KMF_X509_CERTIFICATE *certptr = NULL;
+
+ if (!signed_cert_ptr_ptr || !Value || !Value->Data || !Value->Length)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rawcert.bv_val = (char *)Value->Data;
+ rawcert.bv_len = Value->Length;
+
+ if ((asn1 = kmfder_init(&rawcert)) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (kmfber_first_element(asn1, &size, &end) !=
+ BER_CONSTRUCTED_SEQUENCE) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ certptr = malloc(sizeof (KMF_X509_CERTIFICATE));
+ if (certptr == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ (void) memset(certptr, 0, sizeof (KMF_X509_CERTIFICATE));
+
+ ret = decode_tbscert_data(asn1, &tbscert);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ certptr->certificate = *tbscert;
+ free(tbscert);
+ tbscert = NULL;
+
+ /*
+ * The signature data my not be present yet.
+ */
+ if ((ret = get_algoid(asn1,
+ &certptr->signature.algorithmIdentifier)) == KMF_OK) {
+
+ /* Check to see if the cert has a signature yet */
+ if (kmfber_next_element(asn1, &size, end) == BER_BIT_STRING) {
+ /* Finally, get the encrypted signature BITSTRING */
+ if (kmfber_scanf(asn1, "tl", &tag, &size) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ if (tag != BER_BIT_STRING) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ if (kmfber_scanf(asn1, "B}", &signature, &size) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ certptr->signature.encrypted.Data =
+ (uchar_t *)signature;
+ certptr->signature.encrypted.Length = size / 8;
+ } else {
+ certptr->signature.encrypted.Data = NULL;
+ certptr->signature.encrypted.Length = 0;
+ }
+ } else {
+ (void) memset(&certptr->signature, 0,
+ sizeof (certptr->signature));
+ ret = KMF_OK;
+ }
+
+ *signed_cert_ptr_ptr = certptr;
+cleanup:
+ if (ret != KMF_OK) {
+ if (certptr) {
+ free_decoded_cert(certptr);
+ free(certptr);
+ }
+
+ *signed_cert_ptr_ptr = NULL;
+ }
+ if (asn1)
+ kmfber_free(asn1, 1);
+
+ return (ret);
+
+}
+
+KMF_RETURN
+DerDecodeExtension(KMF_DATA *Data, KMF_X509_EXTENSION **extn)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1 = NULL;
+ BerValue bv;
+
+ bv.bv_val = (char *)Data->Data;
+ bv.bv_len = Data->Length;
+
+ asn1 = kmfder_init(&bv);
+ if (asn1 == NULL)
+ return (KMF_ERR_MEMORY);
+
+ ret = get_one_extension(asn1, extn, NULL);
+
+cleanup:
+ if (ret != KMF_OK) {
+ if (*extn != NULL) {
+ free(*extn);
+ }
+ *extn = NULL;
+ }
+
+ kmfber_free(asn1, 1);
+ return (ret);
+}
+
+KMF_RETURN
+DerDecodeName(KMF_DATA *encodedname, KMF_X509_NAME *name)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1 = NULL;
+ BerValue bv;
+
+ bv.bv_val = (char *)encodedname->Data;
+ bv.bv_len = encodedname->Length;
+
+ asn1 = kmfder_init(&bv);
+ if (asn1 == NULL)
+ return (KMF_ERR_MEMORY);
+
+ (void) memset((void *)name, 0, sizeof (KMF_X509_NAME));
+
+ if ((ret = get_rdn(asn1, name)) != KMF_OK)
+ goto cleanup;
+
+cleanup:
+ if (asn1)
+ kmfber_free(asn1, 1);
+ return (ret);
+}
+
+KMF_RETURN
+DerEncodeName(KMF_X509_NAME *name, KMF_DATA *encodedname)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1 = NULL;
+ BerValue *bv = NULL;
+
+ asn1 = kmfder_alloc();
+ if (asn1 == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if ((ret = encode_rdn(asn1, name)) != KMF_OK)
+ goto cleanup;
+
+ if (kmfber_flatten(asn1, &bv) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ encodedname->Data = (uchar_t *)bv->bv_val;
+ encodedname->Length = bv->bv_len;
+
+cleanup:
+ if (bv)
+ free(bv);
+
+ if (asn1)
+ kmfber_free(asn1, 1);
+
+ return (ret);
+}
+
+static KMF_RETURN
+encode_tbs_cert(BerElement *asn1, KMF_X509_TBS_CERT *tbscert)
+{
+ KMF_RETURN ret = KMF_OK;
+ uint32_t version;
+
+ /* version should be 4 bytes or less */
+ if (tbscert->version.Length > sizeof (int))
+ return (KMF_ERR_BAD_CERT_FORMAT);
+
+ (void) memcpy(&version, tbscert->version.Data,
+ tbscert->version.Length);
+
+ /* Start the sequence and add the version */
+ if (kmfber_printf(asn1, "{Tli", 0xA0, 3, version) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ /* Write the serial number */
+ if (kmfber_printf(asn1, "I",
+ (char *)tbscert->serialNumber.val,
+ (size_t)tbscert->serialNumber.len) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ if ((ret = encode_algoid(asn1, &tbscert->signature)) != KMF_OK)
+ goto cleanup;
+
+ /* Encode the Issuer RDN */
+ if ((ret = encode_rdn(asn1, &tbscert->issuer)) != KMF_OK)
+ goto cleanup;
+
+ /* Encode the Validity fields */
+ if ((ret = encode_validity(asn1, &tbscert->validity)) != KMF_OK)
+ goto cleanup;
+
+ /* Encode the Subject RDN */
+ if ((ret = encode_rdn(asn1, &tbscert->subject)) != KMF_OK)
+ goto cleanup;
+
+ /* Encode the Subject Public Key Info */
+ if ((ret = encode_spki(asn1, &tbscert->subjectPublicKeyInfo)) != KMF_OK)
+ goto cleanup;
+
+ /* Optional field: issuer Unique ID */
+ if (tbscert->issuerUniqueIdentifier.Length > 0) {
+ if ((ret = encode_uniqueid(asn1, 0xA1,
+ &tbscert->issuerUniqueIdentifier)) != KMF_OK)
+ goto cleanup;
+ }
+
+ /* Optional field: Subject Unique ID */
+ if (tbscert->subjectUniqueIdentifier.Length > 0) {
+ if ((ret = encode_uniqueid(asn1, 0xA2,
+ &tbscert->subjectUniqueIdentifier)) != KMF_OK)
+ goto cleanup;
+ }
+
+ /* Optional field: Certificate Extensions */
+ if (tbscert->extensions.numberOfExtensions > 0) {
+ if ((ret = encode_extensions(asn1,
+ &tbscert->extensions)) != KMF_OK)
+ goto cleanup;
+ }
+
+ /* Close out the TBSCert sequence */
+ if (kmfber_printf(asn1, "}") == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+cleanup:
+ /*
+ * Memory cleanup is done in the caller or in the individual
+ * encoding routines.
+ */
+
+ return (ret);
+}
+
+KMF_RETURN
+DerEncodeTbsCertificate(KMF_X509_TBS_CERT *tbs_cert_ptr,
+ KMF_DATA *enc_tbs_cert_ptr)
+{
+ KMF_RETURN ret;
+ BerElement *asn1 = NULL;
+ BerValue *tbsdata = NULL;
+
+ asn1 = kmfder_alloc();
+ if (asn1 == NULL)
+ return (KMF_ERR_MEMORY);
+
+ enc_tbs_cert_ptr->Data = NULL;
+ enc_tbs_cert_ptr->Length = 0;
+
+ ret = encode_tbs_cert(asn1, tbs_cert_ptr);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ if (kmfber_flatten(asn1, &tbsdata) == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ enc_tbs_cert_ptr->Data = (uchar_t *)tbsdata->bv_val;
+ enc_tbs_cert_ptr->Length = tbsdata->bv_len;
+
+cleanup:
+ if (ret != KMF_OK)
+ free_data(enc_tbs_cert_ptr);
+
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+
+ if (tbsdata)
+ free(tbsdata);
+
+ return (ret);
+}
+
+KMF_RETURN
+DerEncodeSignedCertificate(KMF_X509_CERTIFICATE *signed_cert_ptr,
+ KMF_DATA *encodedcert)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_TBS_CERT *tbscert = NULL;
+ KMF_X509_SIGNATURE *signature = NULL;
+ BerElement *asn1 = NULL;
+ BerValue *tbsdata = NULL;
+
+ if (signed_cert_ptr == NULL || encodedcert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ encodedcert->Data = NULL;
+ encodedcert->Length = 0;
+
+ tbscert = &signed_cert_ptr->certificate;
+ signature = &signed_cert_ptr->signature;
+
+ asn1 = kmfder_alloc();
+ if (asn1 == NULL)
+ return (KMF_ERR_MEMORY);
+
+ /* Start outer X509 Certificate SEQUENCE */
+ if (kmfber_printf(asn1, "{") == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ if ((ret = encode_tbs_cert(asn1, tbscert)) != KMF_OK) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ /* Add the Algorithm & Signature Sequence */
+ if ((ret = encode_algoid(asn1,
+ &signature->algorithmIdentifier)) != KMF_OK)
+ goto cleanup;
+
+ if (signature->encrypted.Length > 0) {
+ if (kmfber_printf(asn1, "B", signature->encrypted.Data,
+ signature->encrypted.Length * 8) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ }
+
+ if (kmfber_printf(asn1, "}") == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ if (kmfber_flatten(asn1, &tbsdata) == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ encodedcert->Data = (uchar_t *)tbsdata->bv_val;
+ encodedcert->Length = tbsdata->bv_len;
+
+cleanup:
+ if (ret != KMF_OK)
+ free_data(encodedcert);
+
+ if (tbsdata)
+ free(tbsdata);
+
+ if (asn1)
+ kmfber_free(asn1, 1);
+
+ return (ret);
+}
+
+KMF_RETURN
+ExtractX509CertParts(KMF_DATA *x509cert, KMF_DATA *tbscert,
+ KMF_DATA *signature)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *der = NULL;
+ BerValue x509;
+ ber_tag_t tag;
+ ber_len_t size;
+
+ if (tbscert == NULL || x509cert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ x509.bv_val = (char *)x509cert->Data;
+ x509.bv_len = x509cert->Length;
+
+ der = kmfder_init(&x509);
+ if (der == NULL)
+ return (KMF_ERR_MEMORY);
+
+ /* Skip over the overall Sequence tag to get at the TBS Cert data */
+ if (kmfber_scanf(der, "Tl", &tag, &size) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ if (tag != BER_CONSTRUCTED_SEQUENCE) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ /*
+ * Since we are extracting a copy of the ENCODED bytes, we
+ * must make sure to also include the bytes for the tag and
+ * the length fields for the CONSTRUCTED SEQUENCE (TBSCert).
+ */
+ size += kmfber_calc_taglen(tag) + kmfber_calc_lenlen(size);
+
+ tbscert->Data = malloc(size);
+ if (tbscert->Data == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ tbscert->Length = size;
+
+ /* The der data ptr is now set to the start of the TBS cert sequence */
+ size = kmfber_read(der, (char *)tbscert->Data, tbscert->Length);
+ if (size != tbscert->Length) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ if (signature != NULL) {
+ KMF_X509_ALGORITHM_IDENTIFIER algoid;
+ if ((ret = get_algoid(der, &algoid)) != KMF_OK)
+ goto cleanup;
+ free_algoid(&algoid);
+
+ if (kmfber_scanf(der, "tl", &tag, &size) != BER_BIT_STRING) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ /* Now get the signature data */
+ if (kmfber_scanf(der, "B", (char **)&signature->Data,
+ (ber_len_t *)&signature->Length) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ /* convert bitstring length to bytes */
+ signature->Length = signature->Length / 8;
+ }
+
+cleanup:
+ if (der)
+ kmfber_free(der, 1);
+
+ if (ret != KMF_OK)
+ free_data(tbscert);
+
+ return (ret);
+}
+
+/*
+ * Name: GetKeyFromSpki
+ *
+ * Description:
+ * This function parses the KMF_X509_SPKI into its
+ * key and parameter components based on the key generation algorithm.
+ * NOTE: Currently, it only checks for the RSA and DSA algorithms.
+ * The RSA algorithm is equivalent to the default behavior.
+ * All other algorithms will default to the parameters = NULL and the
+ * key data equal to whatever is in the CSSM_KEY structure for the key
+ *
+ * Parameters:
+ * AlgId (input) : Algorithm identifier
+ * SpkiPtr (input): SPKI structure that contains the key
+ * key_ptr(output): The output key
+ *
+ */
+KMF_RETURN
+GetKeyFromSpki(KMF_ALGORITHM_INDEX AlgId,
+ KMF_X509_SPKI *SpkiPtr,
+ KMF_DATA **key_ptr)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1;
+ BerValue *encodedkey = NULL;
+
+ if (!key_ptr || !SpkiPtr) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ *key_ptr = NULL;
+
+ switch (AlgId) {
+ case KMF_ALGID_DSA:
+ asn1 = kmfder_alloc();
+ if (asn1 == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ if ((ret = encode_spki(asn1, SpkiPtr)) != KMF_OK) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ if (kmfber_flatten(asn1, &encodedkey) == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ *key_ptr = malloc(sizeof (KMF_DATA));
+
+ if (!*key_ptr) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ (*key_ptr)->Length = encodedkey->bv_len;
+ (*key_ptr)->Data = (uchar_t *)encodedkey->bv_val;
+cleanup:
+ kmfber_free(asn1, 1);
+ if (encodedkey)
+ free(encodedkey);
+ break;
+ default: /* RSA */
+ *key_ptr = malloc(sizeof (KMF_DATA));
+
+ if (!*key_ptr) {
+ return (KMF_ERR_MEMORY);
+ }
+ (*key_ptr)->Length = SpkiPtr->subjectPublicKey.Length;
+ (*key_ptr)->Data = malloc((*key_ptr)->Length);
+
+ if (!(*key_ptr)->Data) {
+ free(*key_ptr);
+ *key_ptr = NULL;
+ return (KMF_ERR_MEMORY);
+ }
+ (void) memcpy((*key_ptr)->Data,
+ SpkiPtr->subjectPublicKey.Data,
+ (*key_ptr)->Length);
+ return (ret);
+ }
+ return (ret);
+}
+
+static KMF_RETURN
+decode_csr_extensions(BerElement *asn1, KMF_X509_EXTENSIONS *extns)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerValue oid;
+
+ if (kmfber_scanf(asn1, "{D", &oid) == -1) {
+ return (KMF_ERR_UNKNOWN_CSR_ATTRIBUTE);
+ }
+
+ /* We only understand extension requests in a CSR */
+ if (memcmp(oid.bv_val, extension_request_oid.Data,
+ oid.bv_len) != 0) {
+ return (KMF_ERR_UNKNOWN_CSR_ATTRIBUTE);
+ }
+
+ if (kmfber_scanf(asn1, "[") == -1) {
+ return (KMF_ERR_ENCODING);
+ }
+ ret = get_extensions(asn1, extns);
+
+
+ return (ret);
+}
+
+static KMF_RETURN
+decode_tbscsr_data(BerElement *asn1,
+ KMF_TBS_CSR **signed_csr_ptr_ptr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_TBS_CSR *tbscsr = NULL;
+ char *end = NULL;
+ uint32_t version;
+ ber_tag_t tag;
+ ber_len_t size;
+
+ /* Now get the version number, it is not optional */
+ if (kmfber_scanf(asn1, "{i", &version) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ tbscsr = malloc(sizeof (KMF_TBS_CSR));
+ if (!tbscsr) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ (void) memset(tbscsr, 0, sizeof (KMF_TBS_CSR));
+
+ if ((ret = set_der_integer(&tbscsr->version, version)) != KMF_OK)
+ goto cleanup;
+
+ if ((ret = get_rdn(asn1, &tbscsr->subject)) != KMF_OK)
+ goto cleanup;
+
+ if ((ret = get_spki(asn1, &tbscsr->subjectPublicKeyInfo)) != KMF_OK)
+ goto cleanup;
+
+ /* Check for the optional fields (attributes) */
+ if (kmfber_next_element(asn1, &size, end) == 0xA0) {
+ if (kmfber_scanf(asn1, "Tl", &tag, &size) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ ret = decode_csr_extensions(asn1, &tbscsr->extensions);
+ }
+ if (ret == KMF_OK)
+ *signed_csr_ptr_ptr = tbscsr;
+
+cleanup:
+ if (ret != KMF_OK) {
+ if (tbscsr) {
+ free_tbscsr(tbscsr);
+ free(tbscsr);
+ }
+ *signed_csr_ptr_ptr = NULL;
+ }
+ return (ret);
+}
+
+KMF_RETURN
+DerDecodeTbsCsr(const KMF_DATA *Value,
+ KMF_TBS_CSR **tbscsr)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1 = NULL;
+ BerValue rawcsr;
+ KMF_TBS_CSR *newcsr = NULL;
+
+ if (!tbscsr || !Value || !Value->Data || !Value->Length)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rawcsr.bv_val = (char *)Value->Data;
+ rawcsr.bv_len = Value->Length;
+
+ if ((asn1 = kmfder_init(&rawcsr)) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ ret = decode_tbscsr_data(asn1, &newcsr);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ *tbscsr = newcsr;
+
+cleanup:
+ if (ret != KMF_OK) {
+ if (newcsr)
+ free_tbscsr(newcsr);
+ *tbscsr = NULL;
+ }
+ kmfber_free(asn1, 1);
+
+ return (ret);
+}
+
+KMF_RETURN
+DerDecodeSignedCsr(const KMF_DATA *Value,
+ KMF_CSR_DATA **signed_csr_ptr_ptr)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1 = NULL;
+ BerValue rawcsr;
+ int tag;
+ ber_len_t size;
+ char *end = NULL;
+ char *signature;
+ KMF_TBS_CSR *tbscsr = NULL;
+ KMF_CSR_DATA *csrptr = NULL;
+
+ if (!signed_csr_ptr_ptr || !Value || !Value->Data || !Value->Length)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rawcsr.bv_val = (char *)Value->Data;
+ rawcsr.bv_len = Value->Length;
+
+ if ((asn1 = kmfder_init(&rawcsr)) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (kmfber_first_element(asn1, &size, &end) !=
+ BER_CONSTRUCTED_SEQUENCE) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ csrptr = malloc(sizeof (KMF_CSR_DATA));
+ if (csrptr == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ (void) memset(csrptr, 0, sizeof (KMF_CSR_DATA));
+
+ ret = decode_tbscsr_data(asn1, &tbscsr);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ csrptr->csr = *tbscsr;
+ free(tbscsr);
+ tbscsr = NULL;
+
+ if ((ret = get_algoid(asn1,
+ &csrptr->signature.algorithmIdentifier)) != KMF_OK)
+ goto cleanup;
+
+ /* Check to see if the cert has a signature yet */
+ if (kmfber_next_element(asn1, &size, end) == BER_BIT_STRING) {
+ /* Finally, get the encrypted signature BITSTRING */
+ if (kmfber_scanf(asn1, "tl", &tag, &size) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ if (tag != BER_BIT_STRING) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ if (kmfber_scanf(asn1, "B}", &signature, &size) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ csrptr->signature.encrypted.Data = (uchar_t *)signature;
+ csrptr->signature.encrypted.Length = size / 8;
+ } else {
+ csrptr->signature.encrypted.Data = NULL;
+ csrptr->signature.encrypted.Length = 0;
+ }
+
+ *signed_csr_ptr_ptr = csrptr;
+cleanup:
+ if (ret != KMF_OK) {
+ free_tbscsr(&csrptr->csr);
+ free_algoid(&csrptr->signature.algorithmIdentifier);
+ if (csrptr->signature.encrypted.Data)
+ free(csrptr->signature.encrypted.Data);
+
+ if (csrptr)
+ free(csrptr);
+
+ *signed_csr_ptr_ptr = NULL;
+ }
+ if (asn1)
+ kmfber_free(asn1, 1);
+
+ return (ret);
+
+}
+
+static KMF_RETURN
+encode_csr_extensions(BerElement *asn1, KMF_TBS_CSR *tbscsr)
+{
+ KMF_RETURN ret = KMF_OK;
+ int attlen = 0;
+ BerElement *extnasn1 = NULL;
+ BerValue *extnvalue = NULL;
+
+ /* Optional field: CSR attributes and extensions */
+ if (tbscsr->extensions.numberOfExtensions > 0) {
+ if (kmfber_printf(asn1, "T", 0xA0) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+ } else {
+ /* No extensions or attributes to encode */
+ return (KMF_OK);
+ }
+
+ /*
+ * attributes [0] Attributes
+ * Attributes := SET OF Attribute
+ * Attribute := SEQUENCE {
+ * { ATTRIBUTE ID
+ * values SET SIZE(1..MAX) of ATTRIBUTE
+ * }
+ *
+ * Ex: { ExtensionRequest OID [ { {extn1 } , {extn2 } } ] }
+ */
+
+ /*
+ * Encode any extensions and add to the attributes section.
+ */
+ if (tbscsr->extensions.numberOfExtensions > 0) {
+ extnasn1 = kmfder_alloc();
+ if (extnasn1 == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ if (kmfber_printf(extnasn1, "{D[{",
+ &extension_request_oid) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup_1;
+ }
+
+ if ((ret = encode_extension_list(extnasn1,
+ &tbscsr->extensions)) != KMF_OK) {
+ goto cleanup_1;
+ }
+
+ if (kmfber_printf(extnasn1, "}]}") == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup_1;
+ }
+
+ if (kmfber_flatten(extnasn1, &extnvalue) == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup_1;
+ }
+cleanup_1:
+ kmfber_free(extnasn1, 1);
+
+ if (ret == KMF_OK)
+ /* Add 2 bytes to cover the tag and the length */
+ attlen = extnvalue->bv_len;
+ }
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ if (kmfber_printf(asn1, "l", attlen) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ /* Write the actual encoded extensions */
+ if (extnvalue != NULL && extnvalue->bv_val != NULL) {
+ if (kmfber_write(asn1, extnvalue->bv_val,
+ extnvalue->bv_len, 0) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ /*
+ * Memory cleanup is done in the caller or in the individual
+ * encoding routines.
+ */
+ if (extnvalue) {
+ if (extnvalue->bv_val)
+ free(extnvalue->bv_val);
+ free(extnvalue);
+ }
+
+ return (ret);
+}
+
+static KMF_RETURN
+encode_tbs_csr(BerElement *asn1, KMF_TBS_CSR *tbscsr)
+{
+ KMF_RETURN ret = KMF_OK;
+ uint32_t version;
+
+ /* Start the version */
+ (void) memcpy(&version, tbscsr->version.Data,
+ tbscsr->version.Length);
+
+ if (kmfber_printf(asn1, "{i", &version) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ /* Encode the Subject RDN */
+ if ((ret = encode_rdn(asn1, &tbscsr->subject)) != KMF_OK)
+ goto cleanup;
+
+ /* Encode the Subject Public Key Info */
+ if ((ret = encode_spki(asn1, &tbscsr->subjectPublicKeyInfo)) != KMF_OK)
+ goto cleanup;
+
+
+ if ((ret = encode_csr_extensions(asn1, tbscsr)) != KMF_OK)
+ goto cleanup;
+
+ /* Close out the TBSCert sequence */
+ if (kmfber_printf(asn1, "}") == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+cleanup:
+ return (ret);
+}
+
+KMF_RETURN
+DerEncodeDSAPrivateKey(KMF_DATA *encodedkey, KMF_RAW_DSA_KEY *dsa)
+{
+ KMF_RETURN rv = KMF_OK;
+ BerElement *asn1 = NULL;
+ BerValue *dsadata = NULL;
+
+ asn1 = kmfder_alloc();
+ if (asn1 == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (kmfber_printf(asn1, "I",
+ dsa->value.val, dsa->value.len) == -1) {
+ rv = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ if (kmfber_flatten(asn1, &dsadata) == -1) {
+ rv = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ encodedkey->Data = (uchar_t *)dsadata->bv_val;
+ encodedkey->Length = dsadata->bv_len;
+
+ free(dsadata);
+cleanup:
+ kmfber_free(asn1, 1);
+ return (rv);
+}
+
+KMF_RETURN
+DerEncodeRSAPrivateKey(KMF_DATA *encodedkey, KMF_RAW_RSA_KEY *rsa)
+{
+ KMF_RETURN rv = KMF_OK;
+ BerElement *asn1 = NULL;
+ uchar_t ver = 0;
+ BerValue *rsadata = NULL;
+
+ asn1 = kmfder_alloc();
+ if (asn1 == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (kmfber_printf(asn1, "{IIIIIIIII}",
+ &ver, 1,
+ rsa->mod.val, rsa->mod.len,
+ rsa->pubexp.val, rsa->pubexp.len,
+ rsa->priexp.val, rsa->priexp.len,
+ rsa->prime1.val, rsa->prime1.len,
+ rsa->prime2.val, rsa->prime2.len,
+ rsa->exp1.val, rsa->exp1.len,
+ rsa->exp2.val, rsa->exp2.len,
+ rsa->coef.val, rsa->coef.len) == -1)
+ goto cleanup;
+
+ if (kmfber_flatten(asn1, &rsadata) == -1) {
+ rv = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ encodedkey->Data = (uchar_t *)rsadata->bv_val;
+ encodedkey->Length = rsadata->bv_len;
+
+ free(rsadata);
+cleanup:
+ kmfber_free(asn1, 1);
+ return (rv);
+}
+
+
+KMF_RETURN
+DerEncodeTbsCsr(KMF_TBS_CSR *tbs_csr_ptr,
+ KMF_DATA *enc_tbs_csr_ptr)
+{
+ KMF_RETURN ret;
+ BerValue *tbsdata = NULL;
+ BerElement *asn1 = NULL;
+
+ asn1 = kmfder_alloc();
+
+ enc_tbs_csr_ptr->Data = NULL;
+ enc_tbs_csr_ptr->Length = 0;
+
+ if (asn1 == NULL)
+ return (KMF_ERR_MEMORY);
+
+ ret = encode_tbs_csr(asn1, tbs_csr_ptr);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ if (kmfber_flatten(asn1, &tbsdata) == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ enc_tbs_csr_ptr->Data = (uchar_t *)tbsdata->bv_val;
+ enc_tbs_csr_ptr->Length = tbsdata->bv_len;
+
+cleanup:
+ if (ret != KMF_OK)
+ free_data(enc_tbs_csr_ptr);
+
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+
+ if (tbsdata)
+ free(tbsdata);
+
+ return (ret);
+}
+
+KMF_RETURN
+DerEncodeSignedCsr(KMF_CSR_DATA *signed_csr_ptr,
+ KMF_DATA *encodedcsr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_TBS_CSR *tbscsr = NULL;
+ KMF_X509_SIGNATURE *signature = NULL;
+ BerElement *asn1 = NULL;
+ BerValue *tbsdata = NULL;
+
+ if (signed_csr_ptr == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ tbscsr = &signed_csr_ptr->csr;
+ signature = &signed_csr_ptr->signature;
+
+ asn1 = kmfder_alloc();
+ if (asn1 == NULL)
+ return (KMF_ERR_MEMORY);
+
+ /* Start outer CSR SEQUENCE */
+ if (kmfber_printf(asn1, "{") == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ ret = encode_tbs_csr(asn1, tbscsr);
+
+ /* Add the Algorithm & Signature Sequence */
+ if ((ret = encode_algoid(asn1,
+ &signature->algorithmIdentifier)) != KMF_OK)
+ goto cleanup;
+
+ if (signature->encrypted.Length > 0) {
+ if (kmfber_printf(asn1, "B", signature->encrypted.Data,
+ signature->encrypted.Length * 8) == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ }
+
+ if (kmfber_printf(asn1, "}") == -1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ if (kmfber_flatten(asn1, &tbsdata) == -1) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ encodedcsr->Data = (uchar_t *)tbsdata->bv_val;
+ encodedcsr->Length = tbsdata->bv_len;
+
+cleanup:
+ if (ret != KMF_OK) {
+ free_data(encodedcsr);
+ }
+
+ if (tbsdata)
+ free(tbsdata);
+
+ if (asn1)
+ kmfber_free(asn1, 1);
+ return (ret);
+}
+
+KMF_RETURN
+ExtractSPKIData(
+ const KMF_X509_SPKI *pKey,
+ KMF_ALGORITHM_INDEX AlgorithmId,
+ KMF_DATA *pKeyParts,
+ uint32_t *uNumKeyParts)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1 = NULL;
+ BerValue *P, *Q, *G, *Mod, *Exp, *PubKey;
+ BerValue PubKeyParams, PubKeyData;
+
+ if (pKeyParts == NULL || uNumKeyParts == NULL || pKey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ switch (AlgorithmId) {
+ case KMF_ALGID_DSA:
+ case KMF_ALGID_SHA1WithDSA:
+ /* First, get the parameters from the algorithm definition */
+ PubKeyParams.bv_val = (char *)pKey->algorithm.parameters.Data;
+ PubKeyParams.bv_len = pKey->algorithm.parameters.Length;
+ if ((asn1 = kmfder_init(&PubKeyParams)) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (kmfber_scanf(asn1, "{III}", &P, &Q, &G) == -1) {
+ kmfber_free(asn1, 1);
+ return (KMF_ERR_BAD_KEY_FORMAT);
+ }
+ pKeyParts[KMF_DSA_PRIME].Data = (uchar_t *)P->bv_val;
+ pKeyParts[KMF_DSA_PRIME].Length = P->bv_len;
+ pKeyParts[KMF_DSA_SUB_PRIME].Data = (uchar_t *)Q->bv_val;
+ pKeyParts[KMF_DSA_SUB_PRIME].Length = Q->bv_len;
+ pKeyParts[KMF_DSA_BASE].Data = (uchar_t *)G->bv_val;
+ pKeyParts[KMF_DSA_BASE].Length = G->bv_len;
+
+ free(P);
+ free(Q);
+ free(G);
+ kmfber_free(asn1, 1);
+
+ /* Get the PubKey data */
+ PubKeyData.bv_val = (char *)pKey->subjectPublicKey.Data;
+ PubKeyData.bv_len = pKey->subjectPublicKey.Length;
+ if ((asn1 = kmfder_init(&PubKeyData)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ PubKey = NULL;
+ if (kmfber_scanf(asn1, "I", &PubKey) == -1) {
+ ret = KMF_ERR_BAD_KEY_FORMAT;
+ goto cleanup;
+ }
+ pKeyParts[KMF_DSA_PUBLIC_VALUE].Data =
+ (uchar_t *)PubKey->bv_val;
+ pKeyParts[KMF_DSA_PUBLIC_VALUE].Length = PubKey->bv_len;
+
+ free(PubKey);
+
+ *uNumKeyParts = KMF_NUMBER_DSA_PUBLIC_KEY_PARTS;
+ break;
+
+ case KMF_ALGID_RSA:
+ case KMF_ALGID_MD2WithRSA:
+ case KMF_ALGID_MD5WithRSA:
+ case KMF_ALGID_SHA1WithRSA:
+ PubKeyData.bv_val = (char *)pKey->subjectPublicKey.Data;
+ PubKeyData.bv_len = pKey->subjectPublicKey.Length;
+ if ((asn1 = kmfder_init(&PubKeyData)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ if (kmfber_scanf(asn1, "{II}", &Mod, &Exp) == -1) {
+ ret = KMF_ERR_BAD_KEY_FORMAT;
+ goto cleanup;
+ }
+ pKeyParts[KMF_RSA_MODULUS].Data = (uchar_t *)Mod->bv_val;
+ pKeyParts[KMF_RSA_MODULUS].Length = Mod->bv_len;
+ pKeyParts[KMF_RSA_PUBLIC_EXPONENT].Data =
+ (uchar_t *)Exp->bv_val;
+ pKeyParts[KMF_RSA_PUBLIC_EXPONENT].Length = Exp->bv_len;
+ *uNumKeyParts = KMF_NUMBER_RSA_PUBLIC_KEY_PARTS;
+
+ free(Mod);
+ free(Exp);
+ break;
+ default:
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+cleanup:
+ if (ret != KMF_OK) {
+ int i;
+ for (i = 0; i < *uNumKeyParts; i++)
+ free_data(&pKeyParts[i]);
+ }
+ if (asn1 != NULL) {
+ kmfber_free(asn1, 1);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/libkmf/ber_der/common/decode.c b/usr/src/lib/libkmf/ber_der/common/decode.c
new file mode 100644
index 0000000000..7d6167fc51
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/common/decode.c
@@ -0,0 +1,817 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+/* decode.c - ber input decoding routines */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <strings.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#include <ber_der.h>
+#include "kmfber_int.h"
+
+static void
+ber_svecfree(char **vals)
+{
+ int i;
+
+ if (vals == NULL)
+ return;
+ for (i = 0; vals[i] != NULL; i++)
+ free(vals[i]);
+ free((char *)vals);
+}
+
+/*
+ * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber.
+ * If that changes, the kmfber_peek_tag() and/or
+ * kmfkmfber_skip_tag() implementations will need to be changed.
+ */
+/* return the tag - KMFBER_DEFAULT returned means trouble */
+static ber_tag_t
+kmfber_get_tag(BerElement *ber)
+{
+ unsigned char xbyte;
+ ber_tag_t tag;
+ char *tagp;
+ int i;
+
+ if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
+ return (KMFBER_DEFAULT);
+
+ if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK)
+ return ((ber_uint_t)xbyte);
+
+ tagp = (char *)&tag;
+ tagp[0] = xbyte;
+ for (i = 1; i < sizeof (ber_int_t); i++) {
+ if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
+ return (KMFBER_DEFAULT);
+
+ tagp[i] = xbyte;
+
+ if (! (xbyte & KMFBER_MORE_TAG_MASK))
+ break;
+ }
+
+ /* tag too big! */
+ if (i == sizeof (ber_int_t))
+ return (KMFBER_DEFAULT);
+
+ /* want leading, not trailing 0's */
+ return (tag >> (sizeof (ber_int_t)- i - 1));
+}
+
+/*
+ * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
+ * If that changes, the implementation of kmfber_peek_tag() will need to
+ * be changed.
+ */
+ber_tag_t
+kmfber_skip_tag(BerElement *ber, ber_len_t *len)
+{
+ ber_tag_t tag;
+ unsigned char lc;
+ int noctets, diff;
+ uint32_t netlen;
+
+ /*
+ * Any ber element looks like this: tag length contents.
+ * Assuming everything's ok, we return the tag byte (we
+ * can assume a single byte), and return the length in len.
+ *
+ * Assumptions:
+ * 1) definite lengths
+ * 2) primitive encodings used whenever possible
+ */
+
+ /*
+ * First, we read the tag.
+ */
+
+ if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT)
+ return (KMFBER_DEFAULT);
+
+ /*
+ * Next, read the length. The first byte contains the length of
+ * the length. If bit 8 is set, the length is the long form,
+ * otherwise it's the short form. We don't allow a length that's
+ * greater than what we can hold in an unsigned long.
+ */
+
+ *len = 0;
+ netlen = 0;
+ if (kmfber_read(ber, (char *)&lc, 1) != 1)
+ return (KMFBER_DEFAULT);
+ if (lc & 0x80) {
+ noctets = (lc & 0x7f);
+ if (noctets > sizeof (ber_uint_t))
+ return (KMFBER_DEFAULT);
+ diff = sizeof (ber_int_t) - noctets;
+ if (kmfber_read(ber, (char *)&netlen + diff, noctets)
+ != noctets)
+ return (KMFBER_DEFAULT);
+ *len = ntohl(netlen);
+ } else {
+ *len = lc;
+ }
+
+ return (tag);
+}
+
+
+/*
+ * Note: Previously, we passed the "ber" parameter directly to
+ * kmfber_skip_tag(), saving and restoring the ber_ptr element only.
+ * We now take advantage of the fact that the only ber structure
+ * elements touched by kmfber_skip_tag() are ber_end and ber_ptr.
+ * If that changes, this code must change too.
+ */
+static ber_tag_t
+kmfber_peek_tag(BerElement *ber, ber_len_t *len)
+{
+ BerElement bercopy;
+
+ bercopy.ber_end = ber->ber_end;
+ bercopy.ber_ptr = ber->ber_ptr;
+ return (kmfber_skip_tag(&bercopy, len));
+}
+
+static int
+ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len)
+{
+ int i;
+ ber_int_t value;
+ unsigned char buffer[sizeof (ber_int_t)];
+ /*
+ * The tag and length have already been stripped off. We should
+ * be sitting right before len bytes of 2's complement integer,
+ * ready to be read straight into an int. We may have to sign
+ * extend after we read it in.
+ */
+
+ if (len > sizeof (ber_slen_t))
+ return (-1);
+
+ /* read into the low-order bytes of netnum */
+ if (kmfber_read(ber, (char *)buffer, len) != len)
+ return (-1);
+
+ /* This sets the required sign extension */
+ if (len != 0) {
+ value = 0x80 & buffer[0] ? (-1) : 0;
+ } else {
+ value = 0;
+ }
+
+ for (i = 0; i < len; i++)
+ value = (value << 8) | buffer[i];
+
+ *num = value;
+
+ return (len);
+}
+
+static ber_tag_t
+kmfber_get_int(BerElement *ber, ber_int_t *num)
+{
+ ber_tag_t tag;
+ ber_len_t len;
+
+ if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
+ return (KMFBER_DEFAULT);
+
+ /*
+ * len is being demoted to a long here -- possible conversion error
+ */
+
+ if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len)
+ return (KMFBER_DEFAULT);
+ else
+ return (tag);
+}
+
+static ber_tag_t
+kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len)
+{
+ ber_len_t datalen;
+ ber_tag_t tag;
+#ifdef STR_TRANSLATION
+ char *transbuf;
+#endif /* STR_TRANSLATION */
+
+ if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
+ return (KMFBER_DEFAULT);
+ if (datalen > (*len - 1))
+ return (KMFBER_DEFAULT);
+
+ /*
+ * datalen is being demoted to a long here -- possible conversion error
+ */
+
+ if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen)
+ return (KMFBER_DEFAULT);
+
+ buf[datalen] = '\0';
+
+#ifdef STR_TRANSLATION
+ if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS)
+ != 0 && ber->ber_decode_translate_proc != NULL) {
+
+ transbuf = buf;
+ ++datalen;
+ if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen,
+ 0) != 0) {
+ return (KMFBER_DEFAULT);
+ }
+ if (datalen > *len) {
+ free(transbuf);
+ return (KMFBER_DEFAULT);
+ }
+ (void) memmove(buf, transbuf, datalen);
+ free(transbuf);
+ --datalen;
+ }
+#endif /* STR_TRANSLATION */
+
+ *len = datalen;
+ return (tag);
+}
+
+static ber_tag_t
+kmfber_get_stringa(BerElement *ber, char **buf)
+{
+ ber_len_t datalen;
+ ber_tag_t tag;
+
+ if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
+ return (KMFBER_DEFAULT);
+
+ if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL)
+ return (KMFBER_DEFAULT);
+
+ /*
+ * datalen is being demoted to a long here -- possible conversion error
+ */
+ if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
+ return (KMFBER_DEFAULT);
+ (*buf)[datalen] = '\0';
+
+ return (tag);
+}
+
+ber_tag_t
+ber_get_oid(BerElement *ber, struct berval *oid)
+{
+ ber_len_t len;
+ ber_tag_t tag;
+
+ if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) {
+ return (KMFBER_DEFAULT);
+ }
+
+ if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) {
+ return (KMFBER_DEFAULT);
+ }
+ oid->bv_len = len;
+
+ if (kmfber_read(ber, oid->bv_val, oid->bv_len) !=
+ (ber_slen_t)oid->bv_len)
+ return (KMFBER_DEFAULT);
+
+ return (tag);
+}
+
+ber_tag_t
+ber_get_bigint(BerElement *ber, struct berval **bv)
+{
+ ber_len_t len;
+ ber_tag_t tag;
+
+ if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
+ == NULL) {
+ return (KMFBER_DEFAULT);
+ }
+
+ if ((tag = kmfber_skip_tag(ber, &len)) != BER_INTEGER) {
+ return (KMFBER_DEFAULT);
+ }
+
+ if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
+ == NULL) {
+ return (KMFBER_DEFAULT);
+ }
+
+ /*
+ * len is being demoted to a long here -- possible conversion error
+ */
+ if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
+ return (KMFBER_DEFAULT);
+
+ (*bv)->bv_len = len;
+
+ /* If DER encoding, strip leading 0's */
+ if (ber->ber_options & KMFBER_OPT_USE_DER) {
+ char *p = (*bv)->bv_val;
+ while ((*p == 0x00) && ((*bv)->bv_len > 0)) {
+ p++;
+ (*bv)->bv_len--;
+ }
+ /*
+ * Shift the buffer to the beginning of the allocated space
+ * so it can be properly freed later.
+ */
+ if ((p > (*bv)->bv_val) && ((*bv)->bv_len > 0))
+ (void) bcopy(p, (*bv)->bv_val, (*bv)->bv_len);
+ }
+
+ return (tag);
+}
+
+static ber_tag_t
+kmfber_get_stringal(BerElement *ber, struct berval **bv)
+{
+ ber_len_t len;
+ ber_tag_t tag;
+
+ if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
+ == NULL) {
+ return (KMFBER_DEFAULT);
+ }
+
+ if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) {
+ return (KMFBER_DEFAULT);
+ }
+
+ if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
+ == NULL) {
+ return (KMFBER_DEFAULT);
+ }
+
+ /*
+ * len is being demoted to a long here -- possible conversion error
+ */
+ if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
+ return (KMFBER_DEFAULT);
+ ((*bv)->bv_val)[len] = '\0';
+ (*bv)->bv_len = len;
+
+ return (tag);
+}
+
+static ber_tag_t
+kmfber_get_bitstringa(BerElement *ber, char **buf, ber_len_t *blen)
+{
+ ber_len_t datalen;
+ ber_tag_t tag;
+ unsigned char unusedbits;
+
+ if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
+ return (KMFBER_DEFAULT);
+
+ if ((*buf = (char *)malloc((size_t)datalen - 1)) == NULL)
+ return (KMFBER_DEFAULT);
+
+ if (kmfber_read(ber, (char *)&unusedbits, 1) != 1)
+ return (KMFBER_DEFAULT);
+
+ /* Subtract 1 for the unused bits */
+ datalen--;
+
+ /*
+ * datalen is being demoted to a long here -- possible conversion error
+ */
+ if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
+ return (KMFBER_DEFAULT);
+
+ *blen = datalen * 8 - unusedbits;
+ return (tag);
+}
+
+static ber_tag_t
+kmfber_get_null(BerElement *ber)
+{
+ ber_len_t len;
+ ber_tag_t tag;
+
+ if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
+ return (KMFBER_DEFAULT);
+
+ if (len != 0)
+ return (KMFBER_DEFAULT);
+
+ return (tag);
+}
+
+static ber_tag_t
+kmfber_get_boolean(BerElement *ber, int *boolval)
+{
+ ber_int_t longbool;
+ int rc;
+
+ rc = kmfber_get_int(ber, &longbool);
+ *boolval = longbool;
+
+ return (rc);
+}
+
+ber_tag_t
+kmfber_first_element(BerElement *ber, ber_len_t *len, char **last)
+{
+ /* skip the sequence header, use the len to mark where to stop */
+ if (kmfber_skip_tag(ber, len) == KMFBER_DEFAULT) {
+ return (KMFBER_ERROR);
+ }
+
+ *last = ber->ber_ptr + *len;
+
+ if (*last == ber->ber_ptr) {
+ return (KMFBER_END_OF_SEQORSET);
+ }
+
+ return (kmfber_peek_tag(ber, len));
+}
+
+ber_tag_t
+kmfber_next_element(BerElement *ber, ber_len_t *len, char *last)
+{
+ if (ber->ber_ptr == last) {
+ return (KMFBER_END_OF_SEQORSET);
+ }
+
+ return (kmfber_peek_tag(ber, len));
+}
+
+void
+kmfber_bvfree(struct berval *bv)
+{
+ if (bv != NULL) {
+ if (bv->bv_val != NULL) {
+ free(bv->bv_val);
+ }
+ free((char *)bv);
+ }
+}
+
+void
+kmfber_bvecfree(struct berval **bv)
+{
+ int i;
+
+ if (bv != NULL) {
+ for (i = 0; bv[i] != NULL; i++) {
+ kmfber_bvfree(bv[i]);
+ }
+ free((char *)bv);
+ }
+}
+
+/* VARARGS */
+ber_tag_t
+kmfber_scanf(BerElement *ber, const char *fmt, ...)
+{
+ va_list ap;
+ char *last, *p;
+ char *s, **ss, ***sss;
+ struct berval ***bv, **bvp, *bval;
+ int *i, j;
+ ber_slen_t *l;
+ ber_int_t rc, tag, *b_int;
+ ber_tag_t *t;
+ ber_len_t len;
+ size_t array_size;
+
+ va_start(ap, fmt);
+
+ for (rc = 0, p = (char *)fmt; *p && rc != KMFBER_DEFAULT; p++) {
+ switch (*p) {
+ case 'a': /* octet string - allocate storage as needed */
+ ss = va_arg(ap, char **);
+ rc = kmfber_get_stringa(ber, ss);
+ break;
+
+ case 'b': /* boolean */
+ i = va_arg(ap, int *);
+ rc = kmfber_get_boolean(ber, i);
+ break;
+
+ case 'D': /* Object ID */
+ bval = va_arg(ap, struct berval *);
+ rc = ber_get_oid(ber, bval);
+ break;
+ case 'e': /* enumerated */
+ case 'i': /* int */
+ b_int = va_arg(ap, ber_int_t *);
+ rc = kmfber_get_int(ber, b_int);
+ break;
+
+ case 'l': /* length of next item */
+ l = va_arg(ap, ber_slen_t *);
+ rc = kmfber_peek_tag(ber, (ber_len_t *)l);
+ break;
+
+ case 'n': /* null */
+ rc = kmfber_get_null(ber);
+ break;
+
+ case 's': /* octet string - in a buffer */
+ s = va_arg(ap, char *);
+ l = va_arg(ap, ber_slen_t *);
+ rc = kmfber_get_stringb(ber, s, (ber_len_t *)l);
+ break;
+
+ case 'o': /* octet string in a supplied berval */
+ bval = va_arg(ap, struct berval *);
+ (void) kmfber_peek_tag(ber, &bval->bv_len);
+ rc = kmfber_get_stringa(ber, &bval->bv_val);
+ break;
+
+ case 'I': /* variable length Integer */
+ /* Treat INTEGER same as an OCTET string, but ignore the tag */
+ bvp = va_arg(ap, struct berval **);
+ rc = ber_get_bigint(ber, bvp);
+ break;
+ case 'O': /* octet string - allocate & include length */
+ bvp = va_arg(ap, struct berval **);
+ rc = kmfber_get_stringal(ber, bvp);
+ break;
+
+ case 'B': /* bit string - allocate storage as needed */
+ ss = va_arg(ap, char **);
+ l = va_arg(ap, ber_slen_t *); /* for length, in bits */
+ rc = kmfber_get_bitstringa(ber, ss, (ber_len_t *)l);
+ break;
+
+ case 't': /* tag of next item */
+ t = va_arg(ap, ber_tag_t *);
+ *t = kmfber_peek_tag(ber, &len);
+ rc = (ber_int_t)(*t);
+ break;
+
+ case 'T': /* skip tag of next item */
+ t = va_arg(ap, ber_tag_t *);
+ *t = kmfber_skip_tag(ber, &len);
+ rc = (ber_int_t)(*t);
+ break;
+
+ case 'v': /* sequence of strings */
+ sss = va_arg(ap, char ***);
+ *sss = NULL;
+ j = 0;
+ array_size = 0;
+ for (tag = kmfber_first_element(ber, &len, &last);
+ (tag != KMFBER_DEFAULT &&
+ tag != KMFBER_END_OF_SEQORSET &&
+ rc != KMFBER_DEFAULT);
+ tag = kmfber_next_element(ber, &len, last)) {
+ if (*sss == NULL) {
+ /* Make room for at least 15 strings */
+ *sss = (char **)malloc(16 * sizeof (char *));
+ array_size = 16;
+ } else {
+ if ((size_t)(j+2) > array_size) {
+ /* We'v overflowed our buffer */
+ *sss = (char **)realloc(*sss,
+ (array_size * 2) * sizeof (char *));
+ array_size = array_size * 2;
+ }
+ }
+ rc = kmfber_get_stringa(ber, &((*sss)[j]));
+ j++;
+ }
+ if (rc != KMFBER_DEFAULT &&
+ tag != KMFBER_END_OF_SEQORSET) {
+ rc = KMFBER_DEFAULT;
+ }
+ if (j > 0)
+ (*sss)[j] = NULL;
+ break;
+
+ case 'V': /* sequence of strings + lengths */
+ bv = va_arg(ap, struct berval ***);
+ *bv = NULL;
+ j = 0;
+ for (tag = kmfber_first_element(ber, &len, &last);
+ (tag != KMFBER_DEFAULT &&
+ tag != KMFBER_END_OF_SEQORSET &&
+ rc != KMFBER_DEFAULT);
+ tag = kmfber_next_element(ber, &len, last)) {
+ if (*bv == NULL) {
+ *bv = (struct berval **)malloc(
+ 2 * sizeof (struct berval *));
+ } else {
+ *bv = (struct berval **)realloc(*bv,
+ (j + 2) * sizeof (struct berval *));
+ }
+ rc = kmfber_get_stringal(ber, &((*bv)[j]));
+ j++;
+ }
+ if (rc != KMFBER_DEFAULT &&
+ tag != KMFBER_END_OF_SEQORSET) {
+ rc = KMFBER_DEFAULT;
+ }
+ if (j > 0)
+ (*bv)[j] = NULL;
+ break;
+
+ case 'x': /* skip the next element - whatever it is */
+ if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
+ break;
+ ber->ber_ptr += len;
+ break;
+
+ case '{': /* begin sequence */
+ case '[': /* begin set */
+ if (*(p + 1) != 'v' && *(p + 1) != 'V')
+ rc = kmfber_skip_tag(ber, &len);
+ break;
+
+ case '}': /* end sequence */
+ case ']': /* end set */
+ break;
+
+ default:
+#ifdef KMFBER_DEBUG
+ {
+ char msg[80];
+ sprintf(msg, "unknown fmt %c\n", *p);
+ ber_err_print(msg);
+ }
+#endif
+ rc = KMFBER_DEFAULT;
+ break;
+ }
+ }
+
+
+ va_end(ap);
+ if (rc == KMFBER_DEFAULT) {
+ va_start(ap, fmt);
+ for (p--; fmt < p && *fmt; fmt++) {
+ switch (*fmt) {
+ case 'a': /* octet string - allocate storage as needed */
+ ss = va_arg(ap, char **);
+ free(*ss);
+ *ss = NULL;
+ break;
+
+ case 'b': /* boolean */
+ i = va_arg(ap, int *);
+ break;
+
+ case 'e': /* enumerated */
+ case 'i': /* int */
+ l = va_arg(ap, ber_slen_t *);
+ break;
+
+ case 'l': /* length of next item */
+ l = va_arg(ap, ber_slen_t *);
+ break;
+
+ case 'n': /* null */
+ break;
+
+ case 's': /* octet string - in a buffer */
+ s = va_arg(ap, char *);
+ l = va_arg(ap, ber_slen_t *);
+ break;
+
+ case 'o': /* octet string in a supplied berval */
+ bval = va_arg(ap, struct berval *);
+ if (bval->bv_val) free(bval->bv_val);
+ (void) memset(bval, 0, sizeof (struct berval));
+ break;
+
+ case 'O': /* octet string - allocate & include length */
+ bvp = va_arg(ap, struct berval **);
+ kmfber_bvfree(*bvp);
+ bvp = NULL;
+ break;
+
+ case 'B': /* bit string - allocate storage as needed */
+ ss = va_arg(ap, char **);
+ l = va_arg(ap, ber_slen_t *); /* for length, in bits */
+ if (*ss) free(*ss);
+ *ss = NULL;
+ break;
+
+ case 't': /* tag of next item */
+ t = va_arg(ap, ber_tag_t *);
+ break;
+ case 'T': /* skip tag of next item */
+ t = va_arg(ap, ber_tag_t *);
+ break;
+
+ case 'v': /* sequence of strings */
+ sss = va_arg(ap, char ***);
+ ber_svecfree(*sss);
+ *sss = NULL;
+ break;
+
+ case 'V': /* sequence of strings + lengths */
+ bv = va_arg(ap, struct berval ***);
+ kmfber_bvecfree(*bv);
+ *bv = NULL;
+ break;
+
+ case 'x': /* skip the next element - whatever it is */
+ break;
+
+ case '{': /* begin sequence */
+ case '[': /* begin set */
+ break;
+
+ case '}': /* end sequence */
+ case ']': /* end set */
+ break;
+
+ default:
+ break;
+ }
+ } /* for */
+ va_end(ap);
+ } /* if */
+
+
+ return (rc);
+}
+
+struct berval *
+kmfber_bvdup(const struct berval *bv)
+{
+ struct berval *new;
+
+ if ((new = (struct berval *)malloc(sizeof (struct berval)))
+ == NULL) {
+ return (NULL);
+ }
+ if (bv->bv_val == NULL) {
+ new->bv_val = NULL;
+ new->bv_len = 0;
+ } else {
+ if ((new->bv_val = (char *)malloc(bv->bv_len + 1))
+ == NULL) {
+ return (NULL);
+ }
+ (void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len);
+ new->bv_val[bv->bv_len] = '\0';
+ new->bv_len = bv->bv_len;
+ }
+
+ return (new);
+}
diff --git a/usr/src/lib/libkmf/ber_der/common/encode.c b/usr/src/lib/libkmf/ber_der/common/encode.c
new file mode 100644
index 0000000000..bf78d8e719
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/common/encode.c
@@ -0,0 +1,744 @@
+/*
+ * 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
+ */
+
+/*
+ * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#include <ber_der.h>
+#include "kmfber_int.h"
+
+/* the following constants are used in kmfber_calc_lenlen */
+
+#define LENMASK1 0xFF
+#define LENMASK2 0xFFFF
+#define LENMASK3 0xFFFFFF
+#define LENMASK4 0xFFFFFFFF
+#define _MASK 0x80
+
+int
+kmfber_calc_taglen(ber_tag_t tag)
+{
+ int i;
+ ber_int_t mask;
+
+ /* find the first non-all-zero byte in the tag */
+ for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
+ mask = (LENMASK3 << (i * 8));
+ /* not all zero */
+ if (tag & mask)
+ break;
+ }
+
+ return (i + 1);
+}
+
+static int
+ber_put_tag(BerElement *ber, ber_tag_t tag, int nosos)
+{
+ ber_int_t taglen;
+ ber_tag_t ntag;
+
+ taglen = kmfber_calc_taglen(tag);
+
+ ntag = htonl(tag);
+
+ return (kmfber_write(ber,
+ ((char *) &ntag) + sizeof (ber_int_t) - taglen,
+ taglen, nosos));
+}
+
+int
+kmfber_calc_lenlen(ber_int_t len)
+{
+ /*
+ * short len if it's less than 128 - one byte giving the len,
+ * with bit 8 0.
+ */
+
+ if (len <= 0x7F)
+ return (1);
+
+ /*
+ * long len otherwise - one byte with bit 8 set, giving the
+ * length of the length, followed by the length itself.
+ */
+
+ if (len <= LENMASK1)
+ return (2);
+ if (len <= LENMASK2)
+ return (3);
+ if (len <= LENMASK3)
+ return (4);
+
+ return (5);
+}
+
+int
+kmfber_put_len(BerElement *ber, ber_int_t len, int nosos)
+{
+ int i;
+ char lenlen;
+ ber_int_t mask, netlen;
+
+ /*
+ * short len if it's less than 128 - one byte giving the len,
+ * with bit 8 0.
+ */
+ if (len <= 127) {
+ netlen = htonl(len);
+ return (kmfber_write(ber,
+ (char *)&netlen + sizeof (ber_int_t) - 1,
+ 1, nosos));
+ }
+
+ /*
+ * long len otherwise - one byte with bit 8 set, giving the
+ * length of the length, followed by the length itself.
+ */
+
+ /* find the first non-all-zero byte */
+ for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
+ mask = (LENMASK1 << (i * 8));
+ /* not all zero */
+ if (len & mask)
+ break;
+ }
+ lenlen = ++i;
+ if (lenlen > 4)
+ return (-1);
+ lenlen |= 0x80;
+
+ /* write the length of the length */
+ if (kmfber_write(ber, &lenlen, 1, nosos) != 1)
+ return (-1);
+
+ /* write the length itself */
+ netlen = htonl(len);
+ if (kmfber_write(ber,
+ (char *) &netlen + (sizeof (ber_int_t) - i), i, nosos) != i)
+ return (-1);
+
+ return (i + 1);
+}
+
+static int
+ber_put_int_or_enum(BerElement *ber, ber_int_t num, ber_tag_t tag)
+{
+ int i, sign;
+ ber_int_t len, lenlen, taglen, netnum, mask;
+
+ sign = (num < 0);
+
+ /*
+ * high bit is set - look for first non-all-one byte
+ * high bit is clear - look for first non-all-zero byte
+ */
+ for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
+ mask = (LENMASK1 << (i * 8));
+
+ if (sign) {
+ /* not all ones */
+ if ((num & mask) != mask)
+ break;
+ } else {
+ /* not all zero */
+ if (num & mask)
+ break;
+ }
+ }
+
+ /*
+ * we now have the "leading byte". if the high bit on this
+ * byte matches the sign bit, we need to "back up" a byte.
+ */
+ mask = (num & (_MASK << (i * 8)));
+ if ((mask && !sign) || (sign && !mask))
+ i++;
+
+ len = i + 1;
+
+ if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
+ return (-1);
+
+ if ((lenlen = kmfber_put_len(ber, len, 0)) == -1)
+ return (-1);
+ i++;
+ netnum = htonl(num);
+ if (kmfber_write(ber,
+ (char *) &netnum + (sizeof (ber_int_t) - i), i, 0) == i)
+ /* length of tag + length + contents */
+ return (taglen + lenlen + i);
+
+ return (-1);
+}
+
+static int
+kmfber_put_enum(BerElement *ber, ber_int_t num, ber_tag_t tag)
+{
+ if (tag == KMFBER_DEFAULT)
+ tag = BER_ENUMERATED;
+
+ return (ber_put_int_or_enum(ber, num, tag));
+}
+
+int
+ber_put_int(BerElement *ber, ber_int_t num, ber_tag_t tag)
+{
+ if (tag == KMFBER_DEFAULT)
+ tag = BER_INTEGER;
+
+ return (ber_put_int_or_enum(ber, num, tag));
+}
+
+int
+ber_put_oid(BerElement *ber, struct berval *oid, ber_tag_t tag)
+{
+ ber_int_t taglen, lenlen, rc, len;
+
+ if (tag == KMFBER_DEFAULT)
+ tag = 0x06; /* TODO: Add new OID constant to header */
+
+ if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
+ return (-1);
+
+ len = (ber_int_t)oid->bv_len;
+ if ((lenlen = kmfber_put_len(ber, len, 0)) == -1 ||
+ kmfber_write(ber, oid->bv_val, oid->bv_len, 0) !=
+ (ber_int_t)oid->bv_len) {
+ rc = -1;
+ } else {
+ /* return length of tag + length + contents */
+ rc = taglen + lenlen + oid->bv_len;
+ }
+ return (rc);
+}
+
+int
+ber_put_big_int(BerElement *ber, ber_tag_t tag, char *data,
+ ber_len_t len)
+{
+ ber_int_t taglen, lenlen, ilen, rc;
+
+ if (tag == KMFBER_DEFAULT)
+ tag = BER_INTEGER;
+
+ if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
+ return (-1);
+
+ ilen = (ber_int_t)len;
+ if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 ||
+ kmfber_write(ber, data, len, 0) != (ber_int_t)len) {
+ rc = -1;
+ } else {
+ /* return length of tag + length + contents */
+ rc = taglen + lenlen + len;
+ }
+ return (rc);
+}
+
+static int
+kmfber_put_ostring(BerElement *ber, char *str, ber_len_t len,
+ ber_tag_t tag)
+{
+ ber_int_t taglen, lenlen, ilen, rc;
+#ifdef STR_TRANSLATION
+ int free_str;
+#endif /* STR_TRANSLATION */
+
+ if (tag == KMFBER_DEFAULT)
+ tag = BER_OCTET_STRING;
+
+ if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
+ return (-1);
+
+#ifdef STR_TRANSLATION
+ if (len > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) != 0 &&
+ ber->ber_encode_translate_proc != NULL) {
+ if ((*(ber->ber_encode_translate_proc))(&str, &len, 0)
+ != 0) {
+ return (-1);
+ }
+ free_str = 1;
+ } else {
+ free_str = 0;
+ }
+#endif /* STR_TRANSLATION */
+
+ /*
+ * Note: below is a spot where we limit ber_write
+ * to signed long (instead of unsigned long)
+ */
+ ilen = (ber_int_t)len;
+ if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 ||
+ kmfber_write(ber, str, len, 0) != (ber_int_t)len) {
+ rc = -1;
+ } else {
+ /* return length of tag + length + contents */
+ rc = taglen + lenlen + len;
+ }
+
+#ifdef STR_TRANSLATION
+ if (free_str) {
+ free(str);
+ }
+#endif /* STR_TRANSLATION */
+
+ return (rc);
+}
+
+static int
+kmfber_put_string(BerElement *ber, char *str, ber_tag_t tag)
+{
+ return (kmfber_put_ostring(ber, str, (ber_len_t)strlen(str), tag));
+}
+
+static int
+kmfber_put_bitstring(BerElement *ber, char *str,
+ ber_len_t blen /* in bits */, ber_tag_t tag)
+{
+ ber_int_t taglen, lenlen, len;
+ unsigned char unusedbits;
+
+ if (tag == KMFBER_DEFAULT)
+ tag = BER_BIT_STRING;
+
+ if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
+ return (-1);
+
+ len = (blen + 7) / 8;
+ unusedbits = (unsigned char) (len * 8 - blen);
+ if ((lenlen = kmfber_put_len(ber, len + 1, 0)) == -1)
+ return (-1);
+
+ if (kmfber_write(ber, (char *)&unusedbits, 1, 0) != 1)
+ return (-1);
+
+ if (kmfber_write(ber, str, len, 0) != len)
+ return (-1);
+
+ /* return length of tag + length + unused bit count + contents */
+ return (taglen + 1 + lenlen + len);
+}
+
+static int
+kmfber_put_null(BerElement *ber, ber_tag_t tag)
+{
+ int taglen;
+
+ if (tag == KMFBER_DEFAULT)
+ tag = BER_NULL;
+
+ if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
+ return (-1);
+
+ if (kmfber_put_len(ber, 0, 0) != 1)
+ return (-1);
+
+ return (taglen + 1);
+}
+
+static int
+kmfber_put_boolean(BerElement *ber, int boolval, ber_tag_t tag)
+{
+ int taglen;
+ unsigned char trueval = 0xff;
+ unsigned char falseval = 0x00;
+
+ if (tag == KMFBER_DEFAULT)
+ tag = BER_BOOLEAN;
+
+ if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
+ return (-1);
+
+ if (kmfber_put_len(ber, 1, 0) != 1)
+ return (-1);
+
+ if (kmfber_write(ber, (char *)(boolval ? &trueval : &falseval), 1, 0)
+ != 1)
+ return (-1);
+
+ return (taglen + 2);
+}
+
+#define FOUR_BYTE_LEN 5
+
+
+/*
+ * The idea here is roughly this: we maintain a stack of these Seqorset
+ * structures. This is pushed when we see the beginning of a new set or
+ * sequence. It is popped when we see the end of a set or sequence.
+ * Since we don't want to malloc and free these structures all the time,
+ * we pre-allocate a small set of them within the ber element structure.
+ * thus we need to spot when we've overflowed this stack and fall back to
+ * malloc'ing instead.
+ */
+static int
+ber_start_seqorset(BerElement *ber, ber_tag_t tag)
+{
+ Seqorset *new_sos;
+
+ /* can we fit into the local stack ? */
+ if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) {
+ /* yes */
+ new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn];
+ } else {
+ /* no */
+ if ((new_sos = (Seqorset *)malloc(sizeof (Seqorset)))
+ == NULLSEQORSET) {
+ return (-1);
+ }
+ }
+ ber->ber_sos_stack_posn++;
+
+ if (ber->ber_sos == NULLSEQORSET)
+ new_sos->sos_first = ber->ber_ptr;
+ else
+ new_sos->sos_first = ber->ber_sos->sos_ptr;
+
+ /* Set aside room for a 4 byte length field */
+ new_sos->sos_ptr = new_sos->sos_first + kmfber_calc_taglen(tag) +
+ FOUR_BYTE_LEN;
+ new_sos->sos_tag = tag;
+
+ new_sos->sos_next = ber->ber_sos;
+ new_sos->sos_clen = 0;
+
+ ber->ber_sos = new_sos;
+ if (ber->ber_sos->sos_ptr > ber->ber_end) {
+ (void) realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end);
+ }
+ return (0);
+}
+
+static int
+kmfber_start_seq(BerElement *ber, ber_tag_t tag)
+{
+ if (tag == KMFBER_DEFAULT)
+ tag = BER_CONSTRUCTED_SEQUENCE;
+
+ return (ber_start_seqorset(ber, tag));
+}
+
+static int
+kmfber_start_set(BerElement *ber, ber_tag_t tag)
+{
+ if (tag == KMFBER_DEFAULT)
+ tag = BER_CONSTRUCTED_SET;
+
+ return (ber_start_seqorset(ber, tag));
+}
+
+static int
+ber_put_seqorset(BerElement *ber)
+{
+ ber_int_t netlen, len, taglen, lenlen;
+ unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1;
+ Seqorset *next;
+ Seqorset **sos = &ber->ber_sos;
+
+ /*
+ * If this is the toplevel sequence or set, we need to actually
+ * write the stuff out. Otherwise, it's already been put in
+ * the appropriate buffer and will be written when the toplevel
+ * one is written. In this case all we need to do is update the
+ * length and tag.
+ */
+
+ len = (*sos)->sos_clen;
+ netlen = (ber_len_t)htonl(len);
+
+ if (ber->ber_options & KMFBER_OPT_USE_DER) {
+ lenlen = kmfber_calc_lenlen(len);
+ } else {
+ lenlen = FOUR_BYTE_LEN;
+ }
+
+ if ((next = (*sos)->sos_next) == NULLSEQORSET) {
+ /* write the tag */
+ if ((taglen = ber_put_tag(ber, (*sos)->sos_tag, 1)) == -1)
+ return (-1);
+
+ if (ber->ber_options & KMFBER_OPT_USE_DER) {
+ /* Write the length in the minimum # of octets */
+ if (kmfber_put_len(ber, len, 1) == -1)
+ return (-1);
+
+ if (lenlen != FOUR_BYTE_LEN) {
+ /*
+ * We set aside FOUR_BYTE_LEN bytes for
+ * the length field. Move the data if
+ * we don't actually need that much
+ */
+ (void) memmove((*sos)->sos_first + taglen +
+ lenlen, (*sos)->sos_first + taglen +
+ FOUR_BYTE_LEN, len);
+ }
+ } else {
+ /* Fill FOUR_BYTE_LEN bytes for length field */
+ /* one byte of length length */
+ if (kmfber_write(ber, (char *)&ltag, 1, 1) != 1)
+ return (-1);
+
+ /* the length itself */
+ if (kmfber_write(ber,
+ (char *)&netlen + sizeof (ber_int_t)
+ - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1) !=
+ FOUR_BYTE_LEN - 1)
+ return (-1);
+ }
+ /* The ber_ptr is at the set/seq start - move it to the end */
+ ber->ber_ptr += len;
+ } else {
+ ber_tag_t ntag;
+
+ /* the tag */
+ taglen = kmfber_calc_taglen((*sos)->sos_tag);
+ ntag = htonl((*sos)->sos_tag);
+ (void) memmove((*sos)->sos_first, (char *)&ntag +
+ sizeof (ber_int_t) - taglen, taglen);
+
+ if (ber->ber_options & KMFBER_OPT_USE_DER) {
+ ltag = (lenlen == 1) ? (unsigned char)len :
+ (unsigned char) (0x80 + (lenlen - 1));
+ }
+
+ /* one byte of length length */
+ (void) memmove((*sos)->sos_first + 1, &ltag, 1);
+
+ if (ber->ber_options & KMFBER_OPT_USE_DER) {
+ if (lenlen > 1) {
+ /* Write the length itself */
+ (void) memmove((*sos)->sos_first + 2,
+ (char *)&netlen + sizeof (ber_uint_t) -
+ (lenlen - 1),
+ lenlen - 1);
+ }
+ if (lenlen != FOUR_BYTE_LEN) {
+ /*
+ * We set aside FOUR_BYTE_LEN bytes for
+ * the length field. Move the data if
+ * we don't actually need that much
+ */
+ (void) memmove((*sos)->sos_first + taglen +
+ lenlen, (*sos)->sos_first + taglen +
+ FOUR_BYTE_LEN, len);
+ }
+ } else {
+ /* the length itself */
+ (void) memmove((*sos)->sos_first + taglen + 1,
+ (char *) &netlen + sizeof (ber_int_t) -
+ (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1);
+ }
+
+ next->sos_clen += (taglen + lenlen + len);
+ next->sos_ptr += (taglen + lenlen + len);
+ }
+
+ /* we're done with this seqorset, so free it up */
+ /* was this one from the local stack ? */
+ if (ber->ber_sos_stack_posn > SOS_STACK_SIZE) {
+ free((char *)(*sos));
+ }
+ ber->ber_sos_stack_posn--;
+ *sos = next;
+
+ return (taglen + lenlen + len);
+}
+
+/* VARARGS */
+int
+kmfber_printf(BerElement *ber, const char *fmt, ...)
+{
+ va_list ap;
+ char *s, **ss;
+ struct berval **bv, *oid;
+ int rc, i, t;
+ ber_int_t len;
+
+ va_start(ap, fmt);
+
+#ifdef KMFBER_DEBUG
+ if (lber_debug & 64) {
+ char msg[80];
+ sprintf(msg, "kmfber_printf fmt (%s)\n", fmt);
+ ber_err_print(msg);
+ }
+#endif
+
+ for (rc = 0; *fmt && rc != -1; fmt++) {
+ switch (*fmt) {
+ case 'b': /* boolean */
+ i = va_arg(ap, int);
+ rc = kmfber_put_boolean(ber, i, ber->ber_tag);
+ break;
+
+ case 'i': /* int */
+ i = va_arg(ap, int);
+ rc = ber_put_int(ber, (ber_int_t)i, ber->ber_tag);
+ break;
+
+ case 'D': /* Object ID */
+ if ((oid = va_arg(ap, struct berval *)) == NULL)
+ break;
+ rc = ber_put_oid(ber, oid, ber->ber_tag);
+ break;
+ case 'I': /* int */
+ s = va_arg(ap, char *);
+ len = va_arg(ap, ber_int_t);
+ rc = ber_put_big_int(ber, ber->ber_tag, s, len);
+ break;
+
+ case 'e': /* enumeration */
+ i = va_arg(ap, int);
+ rc = kmfber_put_enum(ber, (ber_int_t)i, ber->ber_tag);
+ break;
+
+ case 'l':
+ t = va_arg(ap, int);
+ rc = kmfber_put_len(ber, t, 0);
+ break;
+ case 'n': /* null */
+ rc = kmfber_put_null(ber, ber->ber_tag);
+ break;
+
+ case 'o': /* octet string (non-null terminated) */
+ s = va_arg(ap, char *);
+ len = va_arg(ap, int);
+ rc = kmfber_put_ostring(ber, s, len, ber->ber_tag);
+ break;
+
+ case 's': /* string */
+ s = va_arg(ap, char *);
+ rc = kmfber_put_string(ber, s, ber->ber_tag);
+ break;
+
+ case 'B': /* bit string */
+ s = va_arg(ap, char *);
+ len = va_arg(ap, int); /* in bits */
+ rc = kmfber_put_bitstring(ber, s, len, ber->ber_tag);
+ break;
+
+ case 't': /* tag for the next element */
+ ber->ber_tag = va_arg(ap, ber_tag_t);
+ ber->ber_usertag = 1;
+ break;
+
+ case 'T': /* Write an explicit tag, but don't change current */
+ t = va_arg(ap, int);
+ rc = ber_put_tag(ber, t, 0);
+ break;
+
+ case 'v': /* vector of strings */
+ if ((ss = va_arg(ap, char **)) == NULL)
+ break;
+ for (i = 0; ss[i] != NULL; i++) {
+ if ((rc = kmfber_put_string(ber, ss[i],
+ ber->ber_tag)) == -1)
+ break;
+ }
+ break;
+
+ case 'V': /* sequences of strings + lengths */
+ if ((bv = va_arg(ap, struct berval **)) == NULL)
+ break;
+ for (i = 0; bv[i] != NULL; i++) {
+ if ((rc = kmfber_put_ostring(ber, bv[i]->bv_val,
+ bv[i]->bv_len, ber->ber_tag)) == -1)
+ break;
+ }
+ break;
+
+ case '{': /* begin sequence */
+ rc = kmfber_start_seq(ber, ber->ber_tag);
+ break;
+
+ case '}': /* end sequence */
+ rc = ber_put_seqorset(ber);
+ break;
+
+ case '[': /* begin set */
+ rc = kmfber_start_set(ber, ber->ber_tag);
+ break;
+
+ case ']': /* end set */
+ rc = ber_put_seqorset(ber);
+ break;
+
+ default: {
+#ifdef KMFBER_DEBUG
+ char msg[80];
+ sprintf(msg, "unknown fmt %c\n", *fmt);
+ ber_err_print(msg);
+#endif
+ rc = -1;
+ break;
+ }
+ }
+
+ if (ber->ber_usertag == 0)
+ ber->ber_tag = KMFBER_DEFAULT;
+ else
+ ber->ber_usertag = 0;
+ }
+
+ va_end(ap);
+
+ return (rc);
+}
diff --git a/usr/src/lib/libkmf/ber_der/common/io.c b/usr/src/lib/libkmf/ber_der/common/io.c
new file mode 100644
index 0000000000..415bbba9c4
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/common/io.c
@@ -0,0 +1,419 @@
+/*
+ * 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
+ */
+
+/*
+ * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#include <stdlib.h>
+#include <ber_der.h>
+#include "kmfber_int.h"
+
+#define EXBUFSIZ 1024
+
+/*
+ * Note: kmfber_read() only uses the ber_end and ber_ptr elements of ber.
+ * Functions like kmfber_get_tag(), kmfber_skip_tag, and kmfber_peek_tag()
+ * rely on that fact, so if this code is changed to use any additional
+ * elements of the ber structure, those functions will need to be changed
+ * as well.
+ */
+ber_int_t
+kmfber_read(BerElement *ber, char *buf, ber_len_t len)
+{
+ size_t actuallen;
+ size_t nleft;
+
+ nleft = ber->ber_end - ber->ber_ptr;
+ actuallen = nleft < len ? nleft : len;
+
+ (void) memmove(buf, ber->ber_ptr, (size_t)actuallen);
+
+ ber->ber_ptr += actuallen;
+
+ return ((ber_int_t)actuallen);
+}
+
+/*
+ * enlarge the ber buffer.
+ * return 0 on success, -1 on error.
+ */
+static int
+kmfber_realloc(BerElement *ber, ber_len_t len)
+{
+ ber_uint_t need, have, total;
+ size_t have_bytes;
+ Seqorset *s;
+ size_t off;
+ char *oldbuf;
+
+ have_bytes = ber->ber_end - ber->ber_buf;
+ have = have_bytes / EXBUFSIZ;
+ need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
+ total = have * EXBUFSIZ + need * EXBUFSIZ;
+
+ oldbuf = ber->ber_buf;
+
+ if (ber->ber_buf == NULL) {
+ if ((ber->ber_buf = (char *)malloc((size_t)total))
+ == NULL) {
+ return (-1);
+ }
+ ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER;
+ } else {
+ if (ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER) {
+ /* transition to malloc'd buffer */
+ if ((ber->ber_buf = (char *)malloc(
+ (size_t)total)) == NULL) {
+ return (-1);
+ }
+ ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER;
+ /* copy existing data into new malloc'd buffer */
+ (void) memmove(ber->ber_buf, oldbuf, have_bytes);
+ } else {
+ if ((ber->ber_buf = (char *)realloc(
+ ber->ber_buf, (size_t)total)) == NULL) {
+ return (-1);
+ }
+ }
+ }
+
+ ber->ber_end = ber->ber_buf + total;
+
+ /*
+ * If the stinking thing was moved, we need to go through and
+ * reset all the sos and ber pointers. Offsets would've been
+ * a better idea... oh well.
+ */
+
+ if (ber->ber_buf != oldbuf) {
+ ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
+
+ for (s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next) {
+ off = s->sos_first - oldbuf;
+ s->sos_first = ber->ber_buf + off;
+
+ off = s->sos_ptr - oldbuf;
+ s->sos_ptr = ber->ber_buf + off;
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * returns "len" on success and -1 on failure.
+ */
+ber_int_t
+kmfber_write(BerElement *ber, char *buf, ber_len_t len, int nosos)
+{
+ if (nosos || ber->ber_sos == NULL) {
+ if (ber->ber_ptr + len > ber->ber_end) {
+ if (kmfber_realloc(ber, len) != 0)
+ return (-1);
+ }
+ (void) memmove(ber->ber_ptr, buf, (size_t)len);
+ ber->ber_ptr += len;
+ return (len);
+ } else {
+ if (ber->ber_sos->sos_ptr + len > ber->ber_end) {
+ if (kmfber_realloc(ber, len) != 0)
+ return (-1);
+ }
+ (void) memmove(ber->ber_sos->sos_ptr, buf, (size_t)len);
+ ber->ber_sos->sos_ptr += len;
+ ber->ber_sos->sos_clen += len;
+ return (len);
+ }
+}
+
+void
+kmfber_free(BerElement *ber, int freebuf)
+{
+ if (ber != NULL) {
+ if (freebuf &&
+ !(ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER)) {
+ free(ber->ber_buf);
+ }
+ free((char *)ber);
+ }
+}
+
+/* we pre-allocate a buffer to save the extra malloc later */
+BerElement *
+kmfber_alloc_t(int options)
+{
+ BerElement *ber;
+
+ if ((ber = (BerElement*)calloc(1,
+ sizeof (struct berelement) + EXBUFSIZ)) == NULL) {
+ return (NULL);
+ }
+
+ ber->ber_tag = KMFBER_DEFAULT;
+ ber->ber_options = options;
+ ber->ber_buf = (char *)ber + sizeof (struct berelement);
+ ber->ber_ptr = ber->ber_buf;
+ ber->ber_end = ber->ber_buf + EXBUFSIZ;
+ ber->ber_flags = KMFBER_FLAG_NO_FREE_BUFFER;
+
+ return (ber);
+}
+
+
+BerElement *
+kmfber_alloc()
+{
+ return (kmfber_alloc_t(0));
+}
+
+BerElement *
+kmfder_alloc()
+{
+ return (kmfber_alloc_t(KMFBER_OPT_USE_DER));
+}
+
+BerElement *
+kmfber_dup(BerElement *ber)
+{
+ BerElement *new;
+
+ if ((new = kmfber_alloc()) == NULL)
+ return (NULL);
+
+ *new = *ber;
+
+ return (new);
+}
+
+
+void
+ber_init_w_nullchar(BerElement *ber, int options)
+{
+ (void) memset((char *)ber, '\0', sizeof (struct berelement));
+ ber->ber_tag = KMFBER_DEFAULT;
+
+ ber->ber_options = options;
+}
+
+
+void
+kmfber_reset(BerElement *ber, int was_writing)
+{
+ if (was_writing) {
+ ber->ber_end = ber->ber_ptr;
+ ber->ber_ptr = ber->ber_buf;
+ } else {
+ ber->ber_ptr = ber->ber_end;
+ }
+
+ ber->ber_rwptr = NULL;
+}
+
+
+#ifdef KMFBER_DEBUG
+
+void
+ber_dump(BerElement *ber, int inout)
+{
+ char msg[128];
+ sprintf(msg, "ber_dump: buf 0x%lx, ptr 0x%lx, rwptr 0x%lx, end 0x%lx\n",
+ ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end);
+ ber_err_print(msg);
+ if (inout == 1) {
+ sprintf(msg, " current len %ld, contents:\n",
+ ber->ber_end - ber->ber_ptr);
+ ber_err_print(msg);
+ lber_bprint(ber->ber_ptr, ber->ber_end - ber->ber_ptr);
+ } else {
+ sprintf(msg, " current len %ld, contents:\n",
+ ber->ber_ptr - ber->ber_buf);
+ ber_err_print(msg);
+ lber_bprint(ber->ber_buf, ber->ber_ptr - ber->ber_buf);
+ }
+}
+
+void
+ber_sos_dump(Seqorset *sos)
+{
+ char msg[80];
+ ber_err_print("*** sos dump ***\n");
+ while (sos != NULLSEQORSET) {
+ sprintf(msg, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n",
+ sos->sos_clen, sos->sos_first, sos->sos_ptr);
+ ber_err_print(msg);
+ sprintf(msg, " current len %ld contents:\n",
+ sos->sos_ptr - sos->sos_first);
+ ber_err_print(msg);
+ lber_bprint(sos->sos_first, sos->sos_ptr - sos->sos_first);
+
+ sos = sos->sos_next;
+ }
+ ber_err_print("*** end dump ***\n");
+}
+
+#endif
+
+/* new dboreham code below: */
+struct byte_buffer {
+ unsigned char *p;
+ int offset;
+ int length;
+};
+typedef struct byte_buffer byte_buffer;
+
+/*
+ * The kmfber_flatten routine allocates a struct berval whose contents
+ * are a BER encoding taken from the ber argument. The bvPtr pointer
+ * points to the returned berval, which must be freed using
+ * kmfber_bvfree(). This routine returns 0 on success and -1 on error.
+ * The use of kmfber_flatten on a BerElement in which all '{' and '}'
+ * format modifiers have not been properly matched can result in a
+ * berval whose contents are not a valid BER encoding.
+ * Note that the ber_ptr is not modified.
+ */
+int
+kmfber_flatten(BerElement *ber, struct berval **bvPtr)
+{
+ struct berval *new;
+ ber_len_t len;
+
+ /* allocate a struct berval */
+ new = (struct berval *)malloc((size_t)(sizeof (struct berval)));
+ if (new == NULL) {
+ return (-1);
+ }
+ (void) memset(new, 0, sizeof (struct berval));
+
+ /*
+ * Copy everything from the BerElement's ber_buf to ber_ptr
+ * into the berval structure.
+ */
+ if (ber == NULL) {
+ new->bv_val = NULL;
+ new->bv_len = 0;
+ } else {
+ len = ber->ber_ptr - ber->ber_buf;
+ new->bv_val = (char *)malloc((size_t)(len + 1));
+ if (new->bv_val == NULL) {
+ kmfber_bvfree(new);
+ return (-1);
+ }
+ (void) memmove(new->bv_val, ber->ber_buf, (size_t)len);
+ new->bv_val[len] = '\0';
+ new->bv_len = len;
+ }
+
+ /* set bvPtr pointer to point to the returned berval */
+ *bvPtr = new;
+
+ return (0);
+}
+
+BerElement *
+kmfder_init(const struct berval *bv)
+{
+ BerElement *ber;
+
+ /* construct BerElement */
+ if ((ber = kmfber_alloc_t(KMFBER_OPT_USE_DER)) != NULL) {
+ /* copy data from the bv argument into BerElement */
+ /* XXXmcs: had to cast unsigned long bv_len to long */
+ if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) !=
+ (ber_slen_t)bv->bv_len) {
+ kmfber_free(ber, 1);
+ return (NULL);
+ }
+ }
+ /*
+ * reset ber_ptr back to the beginning of buffer so that this new
+ * and initialized ber element can be READ
+ */
+ kmfber_reset(ber, 1);
+
+ /*
+ * return a ptr to a new BerElement containing a copy of the data
+ * in the bv argument or a null pointer on error
+ */
+ return (ber);
+}
+
+BerElement *
+kmfber_init(const struct berval *bv)
+{
+ BerElement *ber;
+
+ /* construct BerElement */
+ if ((ber = kmfber_alloc_t(0)) != NULL) {
+ /* copy data from the bv argument into BerElement */
+ /* XXXmcs: had to cast unsigned long bv_len to long */
+ if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) !=
+ (ber_slen_t)bv->bv_len) {
+ kmfber_free(ber, 1);
+ return (NULL);
+ }
+ }
+ /*
+ * reset ber_ptr back to the beginning of buffer so that this new
+ * and initialized ber element can be READ
+ */
+ kmfber_reset(ber, 1);
+
+ /*
+ * return a ptr to a new BerElement containing a copy of the data
+ * in the bv argument or a null pointer on error
+ */
+ return (ber);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/p12common.h b/usr/src/lib/libkmf/ber_der/common/llib-lkmfberder
index 03a2a6ae5e..44d4dec3b5 100644
--- a/usr/src/cmd/cmd-crypto/pktool/p12common.h
+++ b/usr/src/lib/libkmf/ber_der/common/llib-lkmfberder
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,27 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#ifndef _PKTOOL_P12COMMON_H
-#define _PKTOOL_P12COMMON_H
-
#pragma ident "%Z%%M% %I% %E% SMI"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <openssl/bio.h>
-
-extern int create_pkcs12(char *filename, BIO **fbio);
-extern int open_pkcs12(char *filename, BIO **fbio);
-extern void close_pkcs12(BIO *fbio);
-
-#ifdef __cplusplus
-}
-#endif
+/* LINTLIBRARY */
+/* PROTOLIB1 */
-#endif /* _PKTOOL_P12COMMON_H */
+#include <ber_der.h>
diff --git a/usr/src/lib/libkmf/ber_der/common/mapfile-vers b/usr/src/lib/libkmf/ber_der/common/mapfile-vers
new file mode 100644
index 0000000000..bb8ee5b20e
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/common/mapfile-vers
@@ -0,0 +1,67 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate_1.1 {
+ global:
+ AddRDN;
+ CopyRDN;
+ CopySPKI;
+ DerDecodeDSASignature;
+ DerDecodeExtension;
+ DerDecodeName;
+ DerDecodeSPKI;
+ DerDecodeSignedCertificate;
+ DerDecodeSignedCsr;
+ DerDecodeTbsCertificate;
+ DerDecodeTbsCsr;
+ DerEncodeDSAPrivateKey;
+ DerEncodeDSASignature;
+ DerEncodeName;
+ DerEncodeRSAPrivateKey;
+ DerEncodeSPKI;
+ DerEncodeSignedCertificate;
+ DerEncodeSignedCsr;
+ DerEncodeTbsCertificate;
+ DerEncodeTbsCsr;
+ ExtractSPKIData;
+ ExtractX509CertParts;
+ GetKeyFromSpki;
+ kmfber_alloc;
+ kmfber_first_element;
+ kmfber_flatten;
+ kmfber_free;
+ kmfber_init;
+ kmfber_next_element;
+ kmfber_printf;
+ kmfber_read;
+ kmfber_scanf;
+ kmfber_write;
+ kmfder_alloc;
+ kmfder_init;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libkmf/ber_der/i386/Makefile b/usr/src/lib/libkmf/ber_der/i386/Makefile
new file mode 100644
index 0000000000..bda92e4278
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/i386/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libkmf/ber_der/inc/ber_der.h b/usr/src/lib/libkmf/ber_der/inc/ber_der.h
new file mode 100644
index 0000000000..12bd743179
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/inc/ber_der.h
@@ -0,0 +1,180 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * File: BER_DER.H
+ *
+ * Copyright (c) 1995-2000 Intel Corporation. All rights reserved.
+ *
+ * Portions:
+ * (C) COPYRIGHT International Business Machines Corp. 1996, 1997
+ * All Rights Reserved
+ *
+ * US Government Users Restricted Rights - Use, duplication or
+ * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
+ */
+
+/*
+ * This is the header file for some Basic Encoding Rules and Distinguished
+ * Encoding Rules (BER/DER) routines.
+ */
+
+#ifndef BER_DER_H
+#define BER_DER_H
+
+#include <kmfapi.h>
+
+#define BER_BOOLEAN 1
+#define BER_INTEGER 2
+#define BER_BIT_STRING 3
+#define BER_OCTET_STRING 4
+#define BER_NULL 5
+#define BER_OBJECT_IDENTIFIER 6
+#define BER_ENUMERATED 10
+#define BER_UTF8_STRING 12
+#define BER_SEQUENCE 16
+#define BER_SET 17
+#define BER_PRINTABLE_STRING 19
+#define BER_T61STRING 20
+#define BER_IA5STRING 22
+#define BER_UTCTIME 23
+#define BER_GENTIME 24
+#define BER_UNIVERSAL_STRING 28
+#define BER_BMP_STRING 30
+
+#define BER_CLASS_MASK 0xc0
+#define BER_CLASS_UNIVERSAL 0x00
+#define BER_CLASS_APPLICATION 0x40
+#define BER_CLASS_CONTEXTSPECIFIC 0x80
+#define BER_CLASS_PRIVATE 0xc0
+#define BER_CONSTRUCTED 0x20
+#define BER_CONSTRUCTED_SEQUENCE (BER_CONSTRUCTED | BER_SEQUENCE)
+#define BER_CONSTRUCTED_SET (BER_CONSTRUCTED | BER_SET)
+
+#define KMFBER_BIG_TAG_MASK 0x1f
+#define KMFBER_MORE_TAG_MASK 0x80
+
+#define KMFBER_DEFAULT 0xFFFFFFFF
+#define KMFBER_ERROR 0xFFFFFFFF
+#define KMFBER_END_OF_SEQORSET 0xfffffffe
+
+/* BerElement set/get options */
+#define KMFBER_OPT_REMAINING_BYTES 0x01
+#define KMFBER_OPT_TOTAL_BYTES 0x02
+#define KMFBER_OPT_USE_DER 0x04
+#define KMFBER_OPT_TRANSLATE_STRINGS 0x08
+#define KMFBER_OPT_BYTES_TO_WRITE 0x10
+#define KMFBER_OPT_DEBUG_LEVEL 0x40
+
+typedef size_t ber_len_t; /* for BER len */
+typedef long ber_slen_t; /* signed equivalent of ber_len_t */
+typedef int32_t ber_tag_t; /* for BER tags */
+typedef int32_t ber_int_t; /* for BER ints, enums, and Booleans */
+typedef uint32_t ber_uint_t; /* unsigned equivalent of ber_int_t */
+
+typedef struct berelement BerElement;
+typedef int (*BERTranslateProc)(char **, ber_uint_t *, int);
+
+typedef struct berval {
+ ber_len_t bv_len;
+ char *bv_val;
+} BerValue;
+
+#define SAFEMEMCPY(d, s, n) memmove(d, s, n)
+
+BerElement *kmfder_init(const struct berval *bv);
+BerElement *kmfber_init(const struct berval *bv);
+int kmfber_calc_taglen(ber_tag_t);
+int kmfber_calc_lenlen(ber_int_t);
+int kmfber_put_len(BerElement *, ber_int_t, int);
+
+/*
+ * public decode routines
+ */
+ber_tag_t kmfber_first_element(BerElement *, ber_len_t *, char **);
+ber_tag_t kmfber_next_element(BerElement *, ber_len_t *, char *);
+ber_tag_t kmfber_scanf(BerElement *, const char *, ...);
+
+void kmfber_bvfree(struct berval *);
+void kmfber_bvecfree(struct berval **);
+struct berval *kmfber_bvdup(const struct berval *);
+
+/*
+ * public encoding routines
+ */
+extern int kmfber_printf(BerElement *, const char *, ...);
+extern int kmfber_flatten(BerElement *, struct berval **);
+
+/*
+ * miscellaneous public routines
+ */
+extern void kmfber_free(BerElement *ber, int freebuf);
+extern BerElement* kmfber_alloc(void);
+extern BerElement* kmfder_alloc(void);
+extern BerElement* kmfber_alloc_t(int);
+extern BerElement* kmfber_dup(BerElement *);
+extern ber_int_t kmfber_read(BerElement *, char *, ber_len_t);
+extern ber_int_t kmfber_write(BerElement *, char *, ber_len_t, int);
+extern void kmfber_reset(BerElement *, int);
+
+/* Routines KMF uses to encode/decode Cert objects */
+extern KMF_RETURN DerDecodeSignedCertificate(const KMF_DATA *,
+ KMF_X509_CERTIFICATE **);
+extern KMF_RETURN DerEncodeSignedCertificate(KMF_X509_CERTIFICATE *,
+ KMF_DATA *);
+
+KMF_RETURN DerDecodeTbsCertificate(const KMF_DATA *,
+ KMF_X509_TBS_CERT **);
+KMF_RETURN DerEncodeTbsCertificate(KMF_X509_TBS_CERT *, KMF_DATA *);
+
+KMF_RETURN DerDecodeSignedCsr(const KMF_DATA *, KMF_CSR_DATA **);
+extern KMF_RETURN DerEncodeSignedCsr(KMF_CSR_DATA *, KMF_DATA *);
+extern KMF_RETURN DerDecodeTbsCsr(const KMF_DATA *, KMF_TBS_CSR **);
+extern KMF_RETURN DerEncodeTbsCsr(KMF_TBS_CSR *, KMF_DATA *);
+
+KMF_RETURN ExtractX509CertParts(KMF_DATA *, KMF_DATA *, KMF_DATA *);
+KMF_RETURN GetKeyFromSpki(KMF_ALGORITHM_INDEX, KMF_X509_SPKI *,
+ KMF_DATA **);
+extern KMF_RETURN DerEncodeName(KMF_X509_NAME *, KMF_DATA *);
+KMF_RETURN DerDecodeName(KMF_DATA *, KMF_X509_NAME *);
+KMF_RETURN DerDecodeExtension(KMF_DATA *, KMF_X509_EXTENSION **);
+KMF_RETURN CopyRDN(KMF_X509_NAME *, KMF_X509_NAME **);
+KMF_RETURN CopySPKI(KMF_X509_SPKI *,
+ KMF_X509_SPKI **);
+extern KMF_RETURN DerDecodeSPKI(KMF_DATA *, KMF_X509_SPKI *);
+extern KMF_RETURN DerDecodeDSASignature(KMF_DATA *, KMF_DATA *);
+extern KMF_RETURN DerEncodeDSASignature(KMF_DATA *, KMF_DATA *);
+KMF_RETURN DerEncodeAlgoid(KMF_DATA *, KMF_DATA *);
+KMF_RETURN DerDecodeSPKI(KMF_DATA *, KMF_X509_SPKI *);
+KMF_RETURN DerEncodeSPKI(KMF_X509_SPKI *, KMF_DATA *);
+extern KMF_RETURN ExtractSPKIData(const KMF_X509_SPKI *,
+ KMF_ALGORITHM_INDEX, KMF_DATA *, uint32_t *);
+extern KMF_RETURN AddRDN(KMF_X509_NAME *, KMF_X509_RDN *);
+KMF_RETURN DerEncodeRSAPrivateKey(KMF_DATA *, KMF_RAW_RSA_KEY *);
+KMF_RETURN DerEncodeDSAPrivateKey(KMF_DATA *, KMF_RAW_DSA_KEY *);
+
+#endif /* BER_DER_H */
diff --git a/usr/src/lib/libkmf/ber_der/inc/kmfber_int.h b/usr/src/lib/libkmf/ber_der/inc/kmfber_int.h
new file mode 100644
index 0000000000..735452e433
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/inc/kmfber_int.h
@@ -0,0 +1,128 @@
+/*
+ * 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
+ */
+/*
+ * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+
+#ifndef _KMFBER_INT_H
+#define _KMFBER_INT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <malloc.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory.h>
+#include <string.h>
+
+typedef struct seqorset {
+ ber_len_t sos_clen;
+ ber_tag_t sos_tag;
+ char *sos_first;
+ char *sos_ptr;
+ struct seqorset *sos_next;
+} Seqorset;
+#define NULLSEQORSET ((Seqorset *) 0)
+
+#define SOS_STACK_SIZE 8 /* depth of the pre-allocated sos structure stack */
+
+struct berelement {
+ char *ber_buf;
+ char *ber_ptr;
+ char *ber_end;
+ struct seqorset *ber_sos;
+ ber_tag_t ber_tag;
+ ber_len_t ber_len;
+ int ber_usertag;
+ char ber_options;
+ char *ber_rwptr;
+ BERTranslateProc ber_encode_translate_proc;
+ BERTranslateProc ber_decode_translate_proc;
+ int ber_flags;
+#define KMFBER_FLAG_NO_FREE_BUFFER 1 /* don't free ber_buf */
+ int ber_sos_stack_posn;
+ Seqorset ber_sos_stack[SOS_STACK_SIZE];
+};
+
+/* function prototypes */
+void ber_err_print(char *data);
+
+#define THEMEMCPY(d, s, n) memmove(d, s, n)
+
+#ifdef SAFEMEMCPY
+#undef SAFEMEMCPY
+#define SAFEMEMCPY(d, s, n) memmove(d, s, n);
+#endif
+
+/* allow the library to access the debug variable */
+
+#ifdef KMFBER_DEBUG
+extern int kmfber_debug;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _KMFBER_INT_H */
diff --git a/usr/src/lib/libkmf/ber_der/sparc/Makefile b/usr/src/lib/libkmf/ber_der/sparc/Makefile
new file mode 100644
index 0000000000..6dd6b42169
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/sparc/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libkmf/ber_der/sparcv9/Makefile b/usr/src/lib/libkmf/ber_der/sparcv9/Makefile
new file mode 100644
index 0000000000..3dfc6b7784
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/sparcv9/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libkmf/include/algorithm.h b/usr/src/lib/libkmf/include/algorithm.h
new file mode 100644
index 0000000000..5353e4e8bc
--- /dev/null
+++ b/usr/src/lib/libkmf/include/algorithm.h
@@ -0,0 +1,69 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ *
+ * File: ALGORITHM.H
+ *
+ * Copyright (c) 1995-2000 Intel Corporation. All rights reserved.
+ */
+
+#ifndef _ALGORITHM_H
+#define _ALGORITHM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <kmftypes.h>
+#include <security/cryptoki.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pkcs_algorithm_map
+{
+ CK_MECHANISM_TYPE pkcs_mechanism;
+ uint32_t algorithm;
+ uint32_t context_type;
+ uint32_t enc_mode;
+ CK_BBOOL bMultiPart;
+ CK_BBOOL fix_keylength;
+ uint32_t keylength;
+ CK_BBOOL fix_blocksize;
+ uint32_t block_size;
+ CK_BBOOL requires_iv;
+ uint32_t iv_length;
+ CK_FLAGS required_flags;
+ CK_KEY_TYPE key_type;
+ char *szDescription;
+} PKCS_ALGORITHM_MAP;
+
+extern KMF_SIGNATURE_MODE PKCS_GetDefaultSignatureMode(KMF_ALGORITHM_INDEX);
+extern PKCS_ALGORITHM_MAP* PKCS_GetAlgorithmMap(KMF_ALGCLASS, uint32_t,
+ uint32_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ALGORITHM_H */
diff --git a/usr/src/lib/libkmf/include/kmfapi.h b/usr/src/lib/libkmf/include/kmfapi.h
new file mode 100644
index 0000000000..64ded2ce6a
--- /dev/null
+++ b/usr/src/lib/libkmf/include/kmfapi.h
@@ -0,0 +1,346 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ *
+ * Constant definitions and function prototypes for the KMF library.
+ * Commonly used data types are defined in "kmftypes.h".
+ */
+
+#ifndef _KMFAPI_H
+#define _KMFAPI_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <kmftypes.h>
+#include <security/cryptoki.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Setup operations.
+ */
+extern KMF_RETURN KMF_Initialize(KMF_HANDLE_T *, char *, char *);
+extern KMF_RETURN KMF_ConfigureKeystore(KMF_HANDLE_T, KMF_CONFIG_PARAMS *);
+extern KMF_RETURN KMF_Finalize(KMF_HANDLE_T);
+
+/*
+ * Key operations.
+ */
+extern KMF_RETURN KMF_SignDataWithKey(KMF_HANDLE_T,
+ KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+extern KMF_RETURN KMF_VerifyDataWithKey(KMF_HANDLE_T,
+ KMF_KEY_HANDLE *, KMF_ALGORITHM_INDEX, KMF_DATA *, KMF_DATA *);
+
+extern KMF_RETURN KMF_CreateKeypair(KMF_HANDLE_T,
+ KMF_CREATEKEYPAIR_PARAMS *, KMF_KEY_HANDLE *, KMF_KEY_HANDLE *);
+
+extern KMF_RETURN KMF_DeleteKeyFromKeystore(KMF_HANDLE_T,
+ KMF_DELETEKEY_PARAMS *, KMF_KEY_HANDLE *);
+
+extern KMF_RETURN KMF_SignCertRecord(KMF_HANDLE_T, KMF_KEY_HANDLE *,
+ KMF_X509_CERTIFICATE *, KMF_DATA *);
+
+extern KMF_RETURN KMF_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *,
+ KMF_KEY_HANDLE *, uint32_t *);
+
+extern KMF_RETURN KMF_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *,
+ KMF_RAW_KEY_DATA *);
+
+extern KMF_RETURN KMF_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *,
+ KMF_KEY_HANDLE *);
+
+extern KMF_RETURN KMF_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *,
+ KMF_RAW_SYM_KEY *);
+
+/*
+ * Certificate operations.
+ */
+extern KMF_RETURN KMF_FindCert(KMF_HANDLE_T, KMF_FINDCERT_PARAMS *,
+ KMF_X509_DER_CERT *, uint32_t *);
+
+extern KMF_RETURN KMF_EncodeCertRecord(KMF_X509_CERTIFICATE *,
+ KMF_DATA *);
+extern KMF_RETURN KMF_SignCertWithKey(KMF_HANDLE_T, const KMF_DATA *,
+ KMF_KEY_HANDLE *, KMF_DATA *);
+extern KMF_RETURN KMF_SignCertWithCert(KMF_HANDLE_T,
+ KMF_CRYPTOWITHCERT_PARAMS *,
+ const KMF_DATA *, KMF_DATA *, KMF_DATA *);
+
+extern KMF_RETURN KMF_SignDataWithCert(KMF_HANDLE_T,
+ KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *, KMF_DATA *, KMF_DATA *);
+
+extern KMF_RETURN KMF_VerifyCertWithKey(KMF_HANDLE_T, KMF_KEY_HANDLE *,
+ const KMF_DATA *);
+extern KMF_RETURN KMF_VerifyCertWithCert(KMF_HANDLE_T, const KMF_DATA *,
+ const KMF_DATA *);
+extern KMF_RETURN KMF_VerifyDataWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_DATA *,
+ const KMF_DATA *);
+
+extern KMF_RETURN KMF_EncryptWithCert(KMF_HANDLE_T, KMF_DATA *,
+ KMF_DATA *, KMF_DATA *);
+
+extern KMF_RETURN KMF_DecryptWithCert(KMF_HANDLE_T,
+ KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *, KMF_DATA *, KMF_DATA *);
+
+extern KMF_RETURN KMF_StoreCert(KMF_HANDLE_T,
+ KMF_STORECERT_PARAMS *, KMF_DATA *);
+extern KMF_RETURN KMF_ImportCert(KMF_HANDLE_T, KMF_IMPORTCERT_PARAMS *);
+extern KMF_RETURN KMF_DeleteCertFromKeystore(KMF_HANDLE_T,
+ KMF_DELETECERT_PARAMS *);
+
+extern KMF_RETURN KMF_ValidateCert(KMF_HANDLE_T,
+ KMF_VALIDATECERT_PARAMS *, int *);
+
+extern KMF_RETURN KMF_CreateCertFile(KMF_DATA *, KMF_ENCODE_FORMAT, char *);
+
+extern KMF_RETURN KMF_DownloadCert(KMF_HANDLE_T, char *, char *, int,
+ unsigned int, char *, KMF_ENCODE_FORMAT *);
+extern KMF_RETURN KMF_IsCertFile(KMF_HANDLE_T, char *, KMF_ENCODE_FORMAT *);
+
+extern KMF_RETURN KMF_CheckCertDate(KMF_HANDLE_T, KMF_DATA *);
+
+/*
+ * CRL operations.
+ */
+extern KMF_RETURN KMF_ImportCRL(KMF_HANDLE_T, KMF_IMPORTCRL_PARAMS *);
+extern KMF_RETURN KMF_DeleteCRL(KMF_HANDLE_T, KMF_DELETECRL_PARAMS *);
+extern KMF_RETURN KMF_ListCRL(KMF_HANDLE_T, KMF_LISTCRL_PARAMS *, char **);
+extern KMF_RETURN KMF_FindCRL(KMF_HANDLE_T, KMF_FINDCRL_PARAMS *,
+ char **, int *);
+
+extern KMF_RETURN KMF_FindCertInCRL(KMF_HANDLE_T,
+ KMF_FINDCERTINCRL_PARAMS *);
+extern KMF_RETURN KMF_VerifyCRLFile(KMF_HANDLE_T,
+ KMF_VERIFYCRL_PARAMS *);
+
+extern KMF_RETURN KMF_CheckCRLDate(KMF_HANDLE_T,
+ KMF_CHECKCRLDATE_PARAMS *);
+extern KMF_RETURN KMF_DownloadCRL(KMF_HANDLE_T, char *, char *,
+ int, unsigned int, char *, KMF_ENCODE_FORMAT *);
+extern KMF_RETURN KMF_IsCRLFile(KMF_HANDLE_T, char *, KMF_ENCODE_FORMAT *);
+
+/*
+ * CSR operations.
+ */
+extern KMF_RETURN KMF_SetCSRPubKey(KMF_HANDLE_T,
+ KMF_KEY_HANDLE *, KMF_CSR_DATA *);
+extern KMF_RETURN KMF_SetCSRVersion(KMF_CSR_DATA *, uint32_t);
+extern KMF_RETURN KMF_SetCSRSubjectName(KMF_CSR_DATA *, KMF_X509_NAME *);
+extern KMF_RETURN KMF_CreateCSRFile(KMF_DATA *, KMF_ENCODE_FORMAT, char *);
+extern KMF_RETURN KMF_SetCSRExtension(KMF_CSR_DATA *, KMF_X509_EXTENSION *);
+extern KMF_RETURN KMF_SetCSRSignatureAlgorithm(KMF_CSR_DATA *,
+ KMF_ALGORITHM_INDEX);
+extern KMF_RETURN KMF_SetCSRSubjectAltName(KMF_CSR_DATA *, char *,
+ int, KMF_GENERALNAMECHOICES);
+extern KMF_RETURN KMF_SetCSRKeyUsage(KMF_CSR_DATA *, int, uint16_t);
+extern KMF_RETURN KMF_SignCSR(KMF_HANDLE_T, const KMF_CSR_DATA *,
+ KMF_KEY_HANDLE *, KMF_DATA *);
+
+/*
+ * GetCert operations.
+ */
+extern KMF_RETURN KMF_GetCertExtensionData(const KMF_DATA *, KMF_OID *,
+ KMF_X509_EXTENSION *);
+
+extern KMF_RETURN KMF_GetCertCriticalExtensions(const KMF_DATA *,
+ KMF_X509_EXTENSION **, int *);
+
+extern KMF_RETURN KMF_GetCertNonCriticalExtensions(const KMF_DATA *,
+ KMF_X509_EXTENSION **, int *);
+
+extern KMF_RETURN KMF_GetCertKeyUsageExt(const KMF_DATA *,
+ KMF_X509EXT_KEY_USAGE *);
+
+extern KMF_RETURN KMF_GetCertEKU(const KMF_DATA *, KMF_X509EXT_EKU *);
+
+extern KMF_RETURN KMF_GetCertBasicConstraintExt(const KMF_DATA *,
+ KMF_BOOL *, KMF_X509EXT_BASICCONSTRAINTS *);
+
+extern KMF_RETURN KMF_GetCertPoliciesExt(const KMF_DATA *,
+ KMF_BOOL *, KMF_X509EXT_CERT_POLICIES *);
+
+extern KMF_RETURN KMF_GetCertAuthInfoAccessExt(const KMF_DATA *,
+ KMF_X509EXT_AUTHINFOACCESS *);
+
+extern KMF_RETURN KMF_GetCertCRLDistributionPointsExt(const KMF_DATA *,
+ KMF_X509EXT_CRLDISTPOINTS *);
+
+extern KMF_RETURN KMF_GetCertVersionString(KMF_HANDLE_T,
+ const KMF_DATA *, char **);
+
+extern KMF_RETURN KMF_GetCertSubjectNameString(KMF_HANDLE_T, const KMF_DATA *,
+ char **);
+
+extern KMF_RETURN KMF_GetCertIssuerNameString(KMF_HANDLE_T,
+ const KMF_DATA *, char **);
+
+extern KMF_RETURN KMF_GetCertSerialNumberString(KMF_HANDLE_T, const KMF_DATA *,
+ char **);
+
+extern KMF_RETURN KMF_GetCertStartDateString(KMF_HANDLE_T,
+ const KMF_DATA *, char **);
+
+extern KMF_RETURN KMF_GetCertEndDateString(KMF_HANDLE_T,
+ const KMF_DATA *, char **);
+
+extern KMF_RETURN KMF_GetCertPubKeyAlgString(KMF_HANDLE_T,
+ const KMF_DATA *, char **);
+
+extern KMF_RETURN KMF_GetCertSignatureAlgString(KMF_HANDLE_T,
+ const KMF_DATA *, char **);
+
+extern KMF_RETURN KMF_GetCertPubKeyDataString(KMF_HANDLE_T,
+ const KMF_DATA *, char **);
+
+extern KMF_RETURN KMF_GetCertEmailString(KMF_HANDLE_T,
+ const KMF_DATA *, char **);
+
+extern KMF_RETURN KMF_GetCertExtensionString(KMF_HANDLE_T, const KMF_DATA *,
+ KMF_PRINTABLE_ITEM, char **);
+
+extern KMF_RETURN KMF_GetCertIDData(const KMF_DATA *, KMF_DATA *);
+extern KMF_RETURN KMF_GetCertIDString(const KMF_DATA *, char **);
+extern KMF_RETURN KMF_GetCertValidity(const KMF_DATA *, time_t *, time_t *);
+
+/*
+ * SetCert operations
+ */
+extern KMF_RETURN KMF_SetCertPubKey(KMF_HANDLE_T, KMF_KEY_HANDLE *,
+ KMF_X509_CERTIFICATE *);
+
+extern KMF_RETURN KMF_SetCertSubjectName(KMF_X509_CERTIFICATE *,
+ KMF_X509_NAME *);
+
+extern KMF_RETURN KMF_SetCertKeyUsage(KMF_X509_CERTIFICATE *, int, uint16_t);
+
+extern KMF_RETURN KMF_SetCertIssuerName(KMF_X509_CERTIFICATE *,
+ KMF_X509_NAME *);
+
+extern KMF_RETURN KMF_SetCertSignatureAlgorithm(KMF_X509_CERTIFICATE *,
+ KMF_ALGORITHM_INDEX);
+
+extern KMF_RETURN KMF_SetCertValidityTimes(KMF_X509_CERTIFICATE *,
+ time_t, uint32_t);
+
+extern KMF_RETURN KMF_SetCertSerialNumber(KMF_X509_CERTIFICATE *,
+ KMF_BIGINT *);
+
+extern KMF_RETURN KMF_SetCertVersion(KMF_X509_CERTIFICATE *, uint32_t);
+
+extern KMF_RETURN KMF_SetCertIssuerAltName(KMF_X509_CERTIFICATE *,
+ int, KMF_GENERALNAMECHOICES, char *);
+
+extern KMF_RETURN KMF_SetCertSubjectAltName(KMF_X509_CERTIFICATE *,
+ int, KMF_GENERALNAMECHOICES, char *);
+
+extern KMF_RETURN KMF_AddCertEKU(KMF_X509_CERTIFICATE *, KMF_OID *, int);
+
+extern KMF_RETURN KMF_SetCertExtension(KMF_X509_CERTIFICATE *,
+ KMF_X509_EXTENSION *);
+
+extern KMF_RETURN KMF_SetCertBasicConstraintExt(KMF_X509_CERTIFICATE *,
+ KMF_BOOL, KMF_X509EXT_BASICCONSTRAINTS *);
+
+extern KMF_RETURN KMF_ExportPK12(KMF_HANDLE_T, KMF_EXPORTP12_PARAMS *, char *);
+extern KMF_RETURN KMF_ImportPK12(KMF_HANDLE_T, char *, KMF_CREDENTIAL *,
+ KMF_DATA **, int *, KMF_RAW_KEY_DATA **, int *);
+
+/*
+ * Get OCSP response operation.
+ */
+extern KMF_RETURN KMF_GetOCSPForCert(KMF_HANDLE_T, KMF_DATA *, KMF_DATA *,
+ KMF_DATA *);
+
+extern KMF_RETURN KMF_CreateOCSPRequest(KMF_HANDLE_T, KMF_OCSPREQUEST_PARAMS *,
+ char *);
+
+extern KMF_RETURN KMF_GetEncodedOCSPResponse(KMF_HANDLE_T, char *, char *, int,
+ char *, int, char *, unsigned int);
+
+extern KMF_RETURN KMF_GetOCSPStatusForCert(KMF_HANDLE_T,
+ KMF_OCSPRESPONSE_PARAMS_INPUT *,
+ KMF_OCSPRESPONSE_PARAMS_OUTPUT *);
+
+/*
+ * Policy Operations
+ */
+extern KMF_RETURN KMF_SetPolicy(KMF_HANDLE_T, char *, char *);
+
+/*
+ * Error handling.
+ */
+extern KMF_RETURN KMF_GetPluginErrorString(KMF_HANDLE_T, char **);
+extern KMF_RETURN KMF_GetKMFErrorString(KMF_RETURN, char **);
+
+/*
+ * Miscellaneous
+ */
+extern KMF_RETURN KMF_DNParser(char *, KMF_X509_NAME *);
+extern KMF_RETURN KMF_DN2Der(KMF_X509_NAME *, KMF_DATA *);
+extern KMF_RETURN KMF_ReadInputFile(KMF_HANDLE_T, char *, KMF_DATA *);
+extern KMF_RETURN KMF_Der2Pem(KMF_OBJECT_TYPE, unsigned char *,
+ int, unsigned char **, int *);
+extern KMF_RETURN KMF_Pem2Der(unsigned char *, int, unsigned char **, int *);
+extern char *KMF_OID2String(KMF_OID *);
+extern KMF_RETURN KMF_String2OID(char *, KMF_OID *);
+extern int KMF_CompareRDNs(KMF_X509_NAME *, KMF_X509_NAME *);
+extern KMF_RETURN KMF_GetFileFormat(char *, KMF_ENCODE_FORMAT *);
+extern uint16_t KMF_StringToKeyUsage(char *);
+extern KMF_RETURN KMF_SetTokenPin(KMF_HANDLE_T, KMF_SETPIN_PARAMS *,
+ KMF_CREDENTIAL *);
+extern KMF_RETURN KMF_HexString2Bytes(unsigned char *, unsigned char **,
+ size_t *);
+
+/*
+ * Memory cleanup operations
+ */
+extern void KMF_FreeDN(KMF_X509_NAME *);
+extern void KMF_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *);
+extern void KMF_FreeData(KMF_DATA *);
+extern void KMF_FreeAlgOID(KMF_X509_ALGORITHM_IDENTIFIER *);
+extern void KMF_FreeExtension(KMF_X509_EXTENSION *);
+extern void KMF_FreeTBSCSR(KMF_TBS_CSR *);
+extern void KMF_FreeSignedCSR(KMF_CSR_DATA *);
+extern void KMF_FreeTBSCert(KMF_X509_TBS_CERT *);
+extern void KMF_FreeSignedCert(KMF_X509_CERTIFICATE *);
+extern void KMF_FreeString(char *);
+extern void KMF_FreeEKU(KMF_X509EXT_EKU *);
+extern void KMF_FreeSPKI(KMF_X509_SPKI *);
+extern void KMF_FreeKMFKey(KMF_HANDLE_T, KMF_KEY_HANDLE *);
+extern void KMF_FreeBigint(KMF_BIGINT *);
+extern void KMF_FreeRawKey(KMF_RAW_KEY_DATA *);
+extern void KMF_FreeRawSymKey(KMF_RAW_SYM_KEY *);
+extern void KMF_FreeCRLDistributionPoints(KMF_X509EXT_CRLDISTPOINTS *);
+
+/* APIs for PKCS#11 token */
+extern KMF_RETURN KMF_PK11TokenLookup(KMF_HANDLE_T, char *, CK_SLOT_ID *);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _KMFAPI_H */
diff --git a/usr/src/lib/libkmf/include/kmfapiP.h b/usr/src/lib/libkmf/include/kmfapiP.h
new file mode 100644
index 0000000000..64b524b6a7
--- /dev/null
+++ b/usr/src/lib/libkmf/include/kmfapiP.h
@@ -0,0 +1,348 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#ifndef _KMFAPIP_H
+#define _KMFAPIP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <kmfapi.h>
+#include <kmfpolicy.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Plugin function table */
+typedef struct {
+ ushort_t version;
+ KMF_RETURN (*ConfigureKeystore) (
+ KMF_HANDLE_T,
+ KMF_CONFIG_PARAMS *);
+
+ KMF_RETURN (*FindCert) (
+ KMF_HANDLE_T,
+ KMF_FINDCERT_PARAMS *,
+ KMF_X509_DER_CERT *,
+ uint32_t *);
+
+ void (*FreeKMFCert) (
+ KMF_HANDLE_T,
+ KMF_X509_DER_CERT *);
+
+ KMF_RETURN (*StoreCert) (
+ KMF_HANDLE_T,
+ KMF_STORECERT_PARAMS *,
+ KMF_DATA *);
+
+ KMF_RETURN (*ImportCert) (
+ KMF_HANDLE_T,
+ KMF_IMPORTCERT_PARAMS *);
+
+ KMF_RETURN (*ImportCRL) (
+ KMF_HANDLE_T,
+ KMF_IMPORTCRL_PARAMS *);
+
+ KMF_RETURN (*DeleteCert) (
+ KMF_HANDLE_T,
+ KMF_DELETECERT_PARAMS *);
+
+ KMF_RETURN (*DeleteCRL) (
+ KMF_HANDLE_T,
+ KMF_DELETECRL_PARAMS *);
+
+ KMF_RETURN (*CreateKeypair) (
+ KMF_HANDLE_T,
+ KMF_CREATEKEYPAIR_PARAMS *,
+ KMF_KEY_HANDLE *,
+ KMF_KEY_HANDLE *);
+
+ KMF_RETURN (*FindKey) (
+ KMF_HANDLE_T,
+ KMF_FINDKEY_PARAMS *,
+ KMF_KEY_HANDLE *,
+ uint32_t *);
+
+ KMF_RETURN (*EncodePubkeyData) (
+ KMF_HANDLE_T,
+ KMF_KEY_HANDLE *,
+ KMF_DATA *);
+
+ KMF_RETURN (*SignData) (
+ KMF_HANDLE_T,
+ KMF_KEY_HANDLE *,
+ KMF_OID *,
+ KMF_DATA *,
+ KMF_DATA *);
+
+ KMF_RETURN (*DeleteKey) (
+ KMF_HANDLE_T,
+ KMF_DELETEKEY_PARAMS *,
+ KMF_KEY_HANDLE *,
+ boolean_t);
+
+ KMF_RETURN (*ListCRL) (
+ KMF_HANDLE_T,
+ KMF_LISTCRL_PARAMS *,
+ char **);
+
+ KMF_RETURN (*FindCRL) (
+ KMF_HANDLE_T,
+ KMF_FINDCRL_PARAMS *,
+ char **,
+ int *);
+
+ KMF_RETURN (*FindCertInCRL) (
+ KMF_HANDLE_T,
+ KMF_FINDCERTINCRL_PARAMS *);
+
+ KMF_RETURN (*GetErrorString) (
+ KMF_HANDLE_T,
+ char **);
+
+ KMF_RETURN (*GetPrikeyByCert) (
+ KMF_HANDLE_T,
+ KMF_CRYPTOWITHCERT_PARAMS *,
+ KMF_DATA *,
+ KMF_KEY_HANDLE *,
+ KMF_KEY_ALG);
+
+ KMF_RETURN (*DecryptData) (
+ KMF_HANDLE_T,
+ KMF_KEY_HANDLE *,
+ KMF_OID *,
+ KMF_DATA *,
+ KMF_DATA *);
+
+ KMF_RETURN (*ExportP12)(
+ KMF_HANDLE_T,
+ KMF_EXPORTP12_PARAMS *,
+ int, KMF_X509_DER_CERT *,
+ int, KMF_KEY_HANDLE *,
+ char *);
+
+ KMF_RETURN (*StorePrivateKey)(
+ KMF_HANDLE_T,
+ KMF_STOREKEY_PARAMS *,
+ KMF_RAW_KEY_DATA *);
+
+ KMF_RETURN (*CreateSymKey) (
+ KMF_HANDLE_T,
+ KMF_CREATESYMKEY_PARAMS *,
+ KMF_KEY_HANDLE *);
+
+ KMF_RETURN (*GetSymKeyValue) (
+ KMF_HANDLE_T,
+ KMF_KEY_HANDLE *,
+ KMF_RAW_SYM_KEY *);
+
+ KMF_RETURN (*SetTokenPin) (
+ KMF_HANDLE_T,
+ KMF_SETPIN_PARAMS *,
+ KMF_CREDENTIAL *);
+
+ void (*Finalize) ();
+
+} KMF_PLUGIN_FUNCLIST;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE type;
+ char *applications;
+ char *path;
+ void *dldesc;
+ KMF_PLUGIN_FUNCLIST *funclist;
+} KMF_PLUGIN;
+
+typedef struct _KMF_PLUGIN_LIST {
+ KMF_PLUGIN *plugin;
+ struct _KMF_PLUGIN_LIST *next;
+} KMF_PLUGIN_LIST;
+
+typedef struct _kmf_handle {
+ /*
+ * session handle opened by KMF_SelectToken() to talk
+ * to a specific slot in Crypto framework. It is used
+ * by pkcs11 plugin module.
+ */
+ CK_SESSION_HANDLE pk11handle;
+ KMF_ERROR lasterr;
+ KMF_POLICY_RECORD *policy;
+ KMF_PLUGIN_LIST *plugins;
+} KMF_HANDLE;
+
+#define CLEAR_ERROR(h, rv) { \
+ if (h == NULL) { \
+ rv = KMF_ERR_BAD_PARAMETER; \
+ } else { \
+ h->lasterr.errcode = 0; \
+ h->lasterr.kstype = 0; \
+ rv = KMF_OK; \
+ } \
+}
+
+#define KMF_PLUGIN_INIT_SYMBOL "KMF_Plugin_Initialize"
+
+#ifndef KMF_PLUGIN_PATH
+#if defined(__sparcv9)
+#define KMF_PLUGIN_PATH "/usr/lib/security/sparcv9/"
+#elif defined(__sparc)
+#define KMF_PLUGIN_PATH "/usr/lib/security/"
+#elif defined(__i386)
+#define KMF_PLUGIN_PATH "/usr/lib/security/"
+#elif defined(__amd64)
+#define KMF_PLUGIN_PATH "/usr/lib/security/amd64/"
+#endif
+#endif /* !KMF_PLUGIN_PATH */
+
+KMF_PLUGIN_FUNCLIST *KMF_Plugin_Initialize();
+
+KMF_RETURN
+SignCert(KMF_HANDLE_T, const KMF_DATA *, KMF_KEY_HANDLE *, KMF_DATA *);
+
+KMF_RETURN
+VerifyCertWithKey(KMF_HANDLE_T, KMF_DATA *, const KMF_DATA *);
+
+KMF_RETURN
+VerifyCertWithCert(KMF_HANDLE_T, const KMF_DATA *, const KMF_DATA *);
+
+KMF_RETURN
+VerifyDataWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_DATA *, const KMF_DATA *);
+
+KMF_RETURN
+VerifyDataWithKey(KMF_HANDLE_T, KMF_DATA *, KMF_ALGORITHM_INDEX, KMF_DATA *,
+ KMF_DATA *);
+
+KMF_RETURN
+EncryptWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+DecryptWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_KEY_HANDLE *, KMF_DATA *,
+ KMF_DATA *);
+
+KMF_RETURN
+SignCsr(KMF_HANDLE_T, const KMF_DATA *, KMF_KEY_HANDLE *,
+ KMF_X509_ALGORITHM_IDENTIFIER *, KMF_DATA *);
+
+KMF_BOOL PKCS_ConvertAlgorithmId2PKCSKeyType(
+ KMF_ALGORITHM_INDEX, CK_KEY_TYPE *);
+
+KMF_RETURN PKCS_VerifyData(
+ KMF_HANDLE *,
+ KMF_ALGORITHM_INDEX,
+ KMF_X509_SPKI *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN PKCS_EncryptData(
+ KMF_HANDLE *,
+ KMF_ALGORITHM_INDEX,
+ KMF_X509_SPKI *,
+ KMF_DATA *,
+ KMF_DATA *);
+
+KMF_PLUGIN *FindPlugin(KMF_HANDLE_T, KMF_KEYSTORE_TYPE);
+
+KMF_BOOL IsEqualOid(KMF_OID *, KMF_OID *);
+
+KMF_OID *X509_AlgIdToAlgorithmOid(KMF_ALGORITHM_INDEX);
+
+KMF_ALGORITHM_INDEX X509_AlgorithmOidToAlgId(KMF_OID *);
+KMF_RETURN GetIDFromSPKI(KMF_X509_SPKI *, KMF_DATA *);
+CK_RV DigestData(CK_SESSION_HANDLE, KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN KMF_SetAltName(KMF_X509_EXTENSIONS *,
+ KMF_OID *, int, KMF_GENERALNAMECHOICES, char *);
+KMF_RETURN GetSequenceContents(char *, size_t, char **, size_t *);
+KMF_X509_EXTENSION *FindExtn(KMF_X509_EXTENSIONS *, KMF_OID *);
+KMF_RETURN add_an_extension(KMF_X509_EXTENSIONS *exts,
+ KMF_X509_EXTENSION *newextn);
+KMF_RETURN set_integer(KMF_DATA *, void *, int);
+void free_keyidlist(KMF_OID *, int);
+KMF_RETURN copy_data(KMF_DATA *, KMF_DATA *);
+void Cleanup_PK11_Session(KMF_HANDLE_T handle);
+void free_dp_name(KMF_CRL_DIST_POINT *);
+void free_dp(KMF_CRL_DIST_POINT *);
+KMF_RETURN set_key_usage_extension(KMF_X509_EXTENSIONS *,
+ int, uint32_t);
+int is_pk11_ready();
+KMF_RETURN KMF_SelectToken(KMF_HANDLE_T, char *, int);
+
+
+/* Indexes into the key parts array for RSA keys */
+#define KMF_RSA_MODULUS (0)
+#define KMF_RSA_PUBLIC_EXPONENT (1)
+#define KMF_RSA_PRIVATE_EXPONENT (2)
+#define KMF_RSA_PRIME1 (3)
+#define KMF_RSA_PRIME2 (4)
+#define KMF_RSA_EXPONENT1 (5)
+#define KMF_RSA_EXPONENT2 (6)
+#define KMF_RSA_COEFFICIENT (7)
+
+/* Key part counts for RSA keys */
+#define KMF_NUMBER_RSA_PUBLIC_KEY_PARTS (2)
+#define KMF_NUMBER_RSA_PRIVATE_KEY_PARTS (8)
+
+/* Key part counts for DSA keys */
+#define KMF_NUMBER_DSA_PUBLIC_KEY_PARTS (4)
+#define KMF_NUMBER_DSA_PRIVATE_KEY_PARTS (4)
+
+/* Indexes into the key parts array for DSA keys */
+#define KMF_DSA_PRIME (0)
+#define KMF_DSA_SUB_PRIME (1)
+#define KMF_DSA_BASE (2)
+#define KMF_DSA_PUBLIC_VALUE (3)
+
+#ifndef max
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+/* Maximum key parts for all algorithms */
+#define KMF_MAX_PUBLIC_KEY_PARTS \
+ (max(KMF_NUMBER_RSA_PUBLIC_KEY_PARTS, \
+ KMF_NUMBER_DSA_PUBLIC_KEY_PARTS))
+
+#define KMF_MAX_PRIVATE_KEY_PARTS \
+ (max(KMF_NUMBER_RSA_PRIVATE_KEY_PARTS, \
+ KMF_NUMBER_DSA_PRIVATE_KEY_PARTS))
+
+#define KMF_MAX_KEY_PARTS \
+ (max(KMF_MAX_PUBLIC_KEY_PARTS, KMF_MAX_PRIVATE_KEY_PARTS))
+
+typedef enum {
+ KMF_ALGMODE_NONE = 0,
+ KMF_ALGMODE_CUSTOM,
+ KMF_ALGMODE_PUBLIC_KEY,
+ KMF_ALGMODE_PRIVATE_KEY,
+ KMF_ALGMODE_PKCS1_EMSA_V15
+} KMF_SIGNATURE_MODE;
+
+#define KMF_CERT_PRINTABLE_LEN 1024
+#define SHA1_HASH_LENGTH 20
+
+#define OCSPREQ_TEMPNAME "/tmp/ocsp.reqXXXXXX"
+#define OCSPRESP_TEMPNAME "/tmp/ocsp.respXXXXXX"
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _KMFAPIP_H */
diff --git a/usr/src/lib/libkmf/include/kmfpolicy.h b/usr/src/lib/libkmf/include/kmfpolicy.h
new file mode 100644
index 0000000000..e00c55e620
--- /dev/null
+++ b/usr/src/lib/libkmf/include/kmfpolicy.h
@@ -0,0 +1,197 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#ifndef _KMFPOLICY_H
+#define _KMFPOLICY_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <kmfapi.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ char *name;
+ char *serial;
+}KMF_RESP_CERT_POLICY;
+
+typedef struct {
+ char *responderURI;
+ char *proxy;
+ boolean_t uri_from_cert;
+ char *response_lifetime;
+ boolean_t ignore_response_sign;
+}KMF_OCSP_BASIC_POLICY;
+
+typedef struct {
+ KMF_OCSP_BASIC_POLICY basic;
+ KMF_RESP_CERT_POLICY resp_cert;
+ boolean_t has_resp_cert;
+}KMF_OCSP_POLICY;
+
+typedef struct {
+ char *basefilename;
+ char *directory;
+ char *proxy;
+ boolean_t get_crl_uri;
+ boolean_t ignore_crl_sign;
+ boolean_t ignore_crl_date;
+}KMF_CRL_POLICY;
+
+typedef struct {
+ KMF_OCSP_POLICY ocsp_info;
+ KMF_CRL_POLICY crl_info;
+}KMF_VALIDATION_POLICY;
+
+typedef struct {
+ int eku_count;
+ KMF_OID *ekulist;
+}KMF_EKU_POLICY;
+
+
+#define KMF_REVOCATION_METHOD_CRL 0x1
+#define KMF_REVOCATION_METHOD_OCSP 0x2
+
+
+typedef struct {
+ char *name;
+ KMF_VALIDATION_POLICY validation_info;
+ KMF_EKU_POLICY eku_set;
+ uint32_t ku_bits;
+ boolean_t ignore_date;
+ boolean_t ignore_unknown_ekus;
+ boolean_t ignore_trust_anchor;
+ char *validity_adjusttime;
+ char *ta_name;
+ char *ta_serial;
+ uint32_t revocation;
+} KMF_POLICY_RECORD;
+
+
+/*
+ * Short cut for ocsp_info and etc.
+ */
+#define VAL_OCSP validation_info.ocsp_info
+
+#define VAL_OCSP_BASIC VAL_OCSP.basic
+#define VAL_OCSP_RESPONDER_URI VAL_OCSP_BASIC.responderURI
+#define VAL_OCSP_PROXY VAL_OCSP_BASIC.proxy
+#define VAL_OCSP_URI_FROM_CERT VAL_OCSP_BASIC.uri_from_cert
+#define VAL_OCSP_RESP_LIFETIME VAL_OCSP_BASIC.response_lifetime
+#define VAL_OCSP_IGNORE_RESP_SIGN VAL_OCSP_BASIC.ignore_response_sign
+
+#define VAL_OCSP_RESP_CERT VAL_OCSP.resp_cert
+#define VAL_OCSP_RESP_CERT_NAME VAL_OCSP_RESP_CERT.name
+#define VAL_OCSP_RESP_CERT_SERIAL VAL_OCSP_RESP_CERT.serial
+
+/*
+ * Short cut for crl_info and etc.
+ */
+#define VAL_CRL validation_info.crl_info
+#define VAL_CRL_BASEFILENAME validation_info.crl_info.basefilename
+#define VAL_CRL_DIRECTORY validation_info.crl_info.directory
+#define VAL_CRL_GET_URI validation_info.crl_info.get_crl_uri
+#define VAL_CRL_PROXY validation_info.crl_info.proxy
+#define VAL_CRL_IGNORE_SIGN validation_info.crl_info.ignore_crl_sign
+#define VAL_CRL_IGNORE_DATE validation_info.crl_info.ignore_crl_date
+
+/*
+ * Policy related constant definitions.
+ */
+#define KMF_POLICY_DTD "/usr/share/lib/xml/dtd/kmfpolicy.dtd"
+#define KMF_DEFAULT_POLICY_FILE "/etc/security/kmfpolicy.xml"
+
+#define KMF_DEFAULT_POLICY_NAME "default"
+
+#define KMF_POLICY_ROOT "kmf-policy-db"
+
+#define KULOWBIT 7
+#define KUHIGHBIT 15
+
+#define KMF_POLICY_ELEMENT "kmf-policy"
+#define KMF_POLICY_NAME_ATTR "name"
+#define KMF_OPTIONS_IGNORE_DATE_ATTR "ignore-date"
+#define KMF_OPTIONS_IGNORE_UNKNOWN_EKUS "ignore-unknown-eku"
+#define KMF_OPTIONS_IGNORE_TRUST_ANCHOR "ignore-trust-anchor"
+#define KMF_OPTIONS_VALIDITY_ADJUSTTIME "validity-adjusttime"
+#define KMF_POLICY_TA_NAME_ATTR "ta-name"
+#define KMF_POLICY_TA_SERIAL_ATTR "ta-serial"
+
+#define KMF_VALIDATION_METHODS_ELEMENT "validation-methods"
+
+#define KMF_OCSP_ELEMENT "ocsp"
+#define KMF_OCSP_BASIC_ELEMENT "ocsp-basic"
+#define KMF_OCSP_RESPONDER_ATTR "responder"
+#define KMF_OCSP_PROXY_ATTR "proxy"
+#define KMF_OCSP_URI_ATTR "uri-from-cert"
+#define KMF_OCSP_RESPONSE_LIFETIME_ATTR "response-lifetime"
+#define KMF_OCSP_IGNORE_SIGN_ATTR "ignore-response-sign"
+#define KMF_OCSP_RESPONDER_CERT_ELEMENT "responder-cert"
+
+#define KMF_CERT_NAME_ATTR "name"
+#define KMF_CERT_SERIAL_ATTR "serial"
+
+#define KMF_CRL_ELEMENT "crl"
+#define KMF_CRL_BASENAME_ATTR "basefilename"
+#define KMF_CRL_DIRECTORY_ATTR "directory"
+#define KMF_CRL_GET_URI_ATTR "get-crl-uri"
+#define KMF_CRL_PROXY_ATTR "proxy"
+#define KMF_CRL_IGNORE_SIGN_ATTR "ignore-crl-sign"
+#define KMF_CRL_IGNORE_DATE_ATTR "ignore-crl-date"
+
+#define KMF_KEY_USAGE_SET_ELEMENT "key-usage-set"
+#define KMF_KEY_USAGE_ELEMENT "key-usage"
+#define KMF_KEY_USAGE_USE_ATTR "use"
+
+#define KMF_EKU_ELEMENT "ext-key-usage"
+#define KMF_EKU_NAME_ELEMENT "eku-name"
+#define KMF_EKU_NAME_ATTR "name"
+#define KMF_EKU_OID_ELEMENT "eku-oid"
+#define KMF_EKU_OID_ATTR "oid"
+
+#define TMPFILE_TEMPLATE "policyXXXXXX"
+
+extern char *ku2str(uint32_t);
+extern uint32_t str2ku(char *);
+extern int parsePolicyElement(xmlNodePtr, KMF_POLICY_RECORD *);
+
+extern char *KMF_OID2EKUString(KMF_OID *);
+extern KMF_OID *kmf_ekuname2oid(char *);
+extern KMF_OID *kmf_string2oid(char *);
+
+extern KMF_RETURN KMF_GetPolicy(char *, char *, KMF_POLICY_RECORD *);
+extern KMF_RETURN KMF_AddPolicyToDB(KMF_POLICY_RECORD *, char *, boolean_t);
+extern KMF_RETURN KMF_DeletePolicyFromDB(char *, char *);
+extern KMF_RETURN KMF_VerifyPolicy(KMF_POLICY_RECORD *);
+
+extern void KMF_FreePolicyRecord(KMF_POLICY_RECORD *);
+extern void KMF_FreeEKUPolicy(KMF_EKU_POLICY *);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _KMFPOLICY_H */
diff --git a/usr/src/lib/libkmf/include/kmftypes.h b/usr/src/lib/libkmf/include/kmftypes.h
new file mode 100644
index 0000000000..a5f71d30d9
--- /dev/null
+++ b/usr/src/lib/libkmf/include/kmftypes.h
@@ -0,0 +1,1363 @@
+/*
+ * 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
+ */
+/*
+ * File: kmftypes.h
+ *
+ * Copyright (c) 1995-2000 Intel Corporation. All rights reserved.
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _KMFTYPES_H
+#define _KMFTYPES_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <pthread.h>
+
+#include <security/cryptoki.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint32_t KMF_BOOL;
+
+#define KMF_FALSE (0)
+#define KMF_TRUE (1)
+
+/* KMF_HANDLE_T is a pointer to an incomplete C struct for type safety. */
+typedef struct _kmf_handle *KMF_HANDLE_T;
+
+/*
+ * KMF_DATA
+ * The KMF_DATA structure is used to associate a length, in bytes, with
+ * an arbitrary block of contiguous memory.
+ */
+typedef struct kmf_data
+{
+ size_t Length; /* in bytes */
+ uchar_t *Data;
+} KMF_DATA;
+
+typedef struct {
+ uchar_t *val;
+ size_t len;
+} KMF_BIGINT;
+
+/*
+ * KMF_OID
+ * The object identifier (OID) structure is used to hold a unique identifier for
+ * the atomic data fields and the compound substructure that comprise the fields
+ * of a certificate or CRL.
+ */
+typedef KMF_DATA KMF_OID;
+
+typedef struct kmf_x509_private {
+ int keystore_type;
+ int flags; /* see below */
+ char *label;
+#define KMF_FLAG_CERT_VALID 1 /* contains valid certificate */
+#define KMF_FLAG_CERT_SIGNED 2 /* this is a signed certificate */
+} KMF_X509_PRIVATE, KMF_X509_PRIVATE_PTR;
+
+/*
+ * KMF_X509_DER_CERT
+ * This structure associates packed DER certificate data.
+ * Also, it contains the private information internal used
+ * by KMF layer.
+ */
+typedef struct
+{
+ KMF_DATA certificate;
+ KMF_X509_PRIVATE kmf_private;
+} KMF_X509_DER_CERT;
+
+typedef enum {
+ KMF_KEYSTORE_NSS = 1,
+ KMF_KEYSTORE_OPENSSL = 2,
+ KMF_KEYSTORE_PK11TOKEN = 3,
+ KMF_KEYSTORE_DEFAULT /* based on configuration */
+} KMF_KEYSTORE_TYPE;
+
+#define VALID_KEYSTORE_TYPE(t) ((t >= KMF_KEYSTORE_NSS) &&\
+ (t <= KMF_KEYSTORE_PK11TOKEN))
+
+typedef enum {
+ KMF_FORMAT_UNDEF = 0,
+ KMF_FORMAT_ASN1 = 1, /* DER */
+ KMF_FORMAT_PEM = 2,
+ KMF_FORMAT_PKCS12 = 3,
+ KMF_FORMAT_RAWKEY = 4 /* For FindKey operation */
+} KMF_ENCODE_FORMAT;
+
+typedef enum {
+ KMF_ALL_CERTS = 0,
+ KMF_NONEXPIRED_CERTS = 1,
+ KMF_EXPIRED_CERTS = 2
+} KMF_CERT_VALIDITY;
+
+typedef enum {
+ KMF_KU_SIGN_CERT = 0,
+ KMF_KU_SIGN_DATA = 1,
+ KMF_KU_ENCRYPT_DATA = 2
+} KMF_KU_PURPOSE;
+
+
+/* Keystore Configuration */
+typedef struct {
+ char *configdir;
+ char *certPrefix;
+ char *keyPrefix;
+ char *secModName;
+} KMF_NSS_CONFIG;
+
+typedef struct {
+ char *label;
+ boolean_t readonly;
+} KMF_PKCS11_CONFIG;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ union {
+ KMF_NSS_CONFIG nss_conf;
+ KMF_PKCS11_CONFIG pkcs11_conf;
+ } ks_config_u;
+} KMF_CONFIG_PARAMS;
+
+#define nssconfig ks_config_u.nss_conf
+#define pkcs11config ks_config_u.pkcs11_conf
+
+/*
+ * Generic credential structure used by other structures below
+ * to convey authentication information to the underlying
+ * mechanisms.
+ */
+typedef struct {
+ char *cred;
+ uint32_t credlen;
+} KMF_CREDENTIAL;
+
+typedef struct
+{
+ char *trustflag;
+ char *slotlabel; /* "internal" by default */
+ int issuerId;
+ int subjectId;
+ char *crlfile; /* for ImportCRL */
+ boolean_t crl_check; /* for ImportCRL */
+
+ /*
+ * crl_subjName and crl_issuerName are used as the CRL deletion
+ * criteria. One should be non-NULL and the other one should be NULL.
+ * If crl_subjName is not NULL, then delete CRL by the subject name.
+ * Othewise, delete by the issuer name.
+ */
+ char *crl_subjName;
+ char *crl_issuerName;
+} KMF_NSS_PARAMS;
+
+typedef struct {
+ char *dirpath;
+ char *certfile;
+ char *crlfile;
+ char *keyfile;
+ char *outcrlfile;
+ boolean_t crl_check; /* CRL import check; default is true */
+ KMF_ENCODE_FORMAT format; /* output file format */
+} KMF_OPENSSL_PARAMS;
+
+typedef struct {
+ boolean_t private; /* for finding CKA_PRIVATE objects */
+ boolean_t sensitive;
+ boolean_t not_extractable;
+} KMF_PKCS11_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ char *certLabel;
+ char *issuer;
+ char *subject;
+ char *idstr;
+ KMF_BIGINT *serial;
+ KMF_CERT_VALIDITY find_cert_validity;
+
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ KMF_PKCS11_PARAMS pkcs11_opts;
+ } ks_opt_u;
+} KMF_FINDCERT_PARAMS, KMF_DELETECERT_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ char *certLabel;
+ char *issuer;
+ char *subject;
+ char *idstr;
+ KMF_BIGINT *serial;
+ KMF_DATA *ocsp_response;
+
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ KMF_PKCS11_PARAMS pkcs11_opts;
+ } ks_opt_u;
+} KMF_VALIDATECERT_PARAMS;
+
+typedef enum {
+ KMF_KEYALG_NONE = 0,
+ KMF_RSA = 1,
+ KMF_DSA = 2,
+ KMF_AES = 3,
+ KMF_RC4 = 4,
+ KMF_DES = 5,
+ KMF_DES3 = 6
+}KMF_KEY_ALG;
+
+typedef enum {
+ KMF_KEYCLASS_NONE = 0,
+ KMF_ASYM_PUB = 1, /* public key of an asymmetric keypair */
+ KMF_ASYM_PRI = 2, /* private key of an asymmetric keypair */
+ KMF_SYMMETRIC = 3 /* symmetric key */
+}KMF_KEY_CLASS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ KMF_CREDENTIAL cred;
+ KMF_KEY_CLASS keyclass;
+ KMF_KEY_ALG keytype;
+ KMF_ENCODE_FORMAT format; /* for key */
+ char *findLabel;
+ char *idstr;
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ KMF_PKCS11_PARAMS pkcs11_opts;
+ } ks_opt_u;
+} KMF_FINDKEY_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype; /* all */
+ char *certLabel;
+
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ } ks_opt_u;
+} KMF_STORECERT_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ KMF_CREDENTIAL cred;
+ KMF_DATA *certificate;
+ char *label;
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ } ks_opt_u;
+} KMF_STOREKEY_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ KMF_CREDENTIAL cred;
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ } ks_opt_u;
+} KMF_DELETEKEY_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ char *certfile;
+ char *certLabel;
+
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ } ks_opt_u;
+} KMF_IMPORTCERT_PARAMS;
+
+typedef enum {
+ KMF_CERT = 0,
+ KMF_CSR = 1,
+ KMF_CRL = 2
+}KMF_OBJECT_TYPE;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ KMF_KEY_ALG keytype;
+ uint32_t keylength;
+ char *keylabel;
+ KMF_CREDENTIAL cred;
+ KMF_BIGINT rsa_exponent;
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ }ks_opt_u;
+} KMF_CREATEKEYPAIR_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ } ks_opt_u;
+} KMF_IMPORTCRL_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ } ks_opt_u;
+} KMF_DELETECRL_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ } ks_opt_u;
+} KMF_LISTCRL_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ } ks_opt_u;
+} KMF_FINDCRL_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ char *certLabel;
+
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ } ks_opt_u;
+} KMF_FINDCERTINCRL_PARAMS;
+
+typedef struct {
+ char *crl_name;
+ KMF_DATA *tacert;
+} KMF_VERIFYCRL_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ KMF_CREDENTIAL cred;
+ KMF_ENCODE_FORMAT format; /* for key */
+ char *certLabel;
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ }ks_opt_u;
+} KMF_CRYPTOWITHCERT_PARAMS;
+
+typedef struct {
+ char *crl_name;
+} KMF_CHECKCRLDATE_PARAMS;
+
+typedef struct {
+ CK_SLOT_ID slot;
+} pk11_setpin_opts;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ char *tokenname;
+ KMF_CREDENTIAL cred; /* current token PIN */
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ pk11_setpin_opts pkcs11_opts;
+ }ks_opt_u;
+} KMF_SETPIN_PARAMS;
+
+typedef struct {
+ KMF_BIGINT mod;
+ KMF_BIGINT pubexp;
+ KMF_BIGINT priexp;
+ KMF_BIGINT prime1;
+ KMF_BIGINT prime2;
+ KMF_BIGINT exp1;
+ KMF_BIGINT exp2;
+ KMF_BIGINT coef;
+} KMF_RAW_RSA_KEY;
+
+typedef struct {
+ KMF_BIGINT prime;
+ KMF_BIGINT subprime;
+ KMF_BIGINT base;
+ KMF_BIGINT value;
+} KMF_RAW_DSA_KEY;
+
+typedef struct {
+ KMF_BIGINT keydata;
+} KMF_RAW_SYM_KEY;
+
+typedef struct {
+ KMF_KEY_ALG keytype;
+ union {
+ KMF_RAW_RSA_KEY rsa;
+ KMF_RAW_DSA_KEY dsa;
+ KMF_RAW_SYM_KEY sym;
+ }rawdata;
+} KMF_RAW_KEY_DATA;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ char *certLabel;
+ char *issuer;
+ char *subject;
+ char *idstr;
+ KMF_BIGINT *serial;
+ KMF_CREDENTIAL cred; /* cred for accessing the token */
+ KMF_CREDENTIAL p12cred; /* cred used for securing the file */
+
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ }ks_opt_u;
+} KMF_EXPORTP12_PARAMS;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ KMF_KEY_ALG keytype;
+ uint32_t keylength;
+ char *keylabel;
+ KMF_CREDENTIAL cred;
+ union {
+ KMF_NSS_PARAMS nss_opts;
+ KMF_OPENSSL_PARAMS openssl_opts;
+ KMF_PKCS11_PARAMS pkcs11_opts;
+ }ks_opt_u;
+} KMF_CREATESYMKEY_PARAMS;
+
+/* Data structures for OCSP support */
+typedef struct {
+ KMF_DATA *issuer_cert;
+ KMF_DATA *user_cert;
+} KMF_OCSPREQUEST_PARAMS;
+
+typedef struct {
+ KMF_DATA *response;
+ KMF_DATA *issuer_cert;
+ KMF_DATA *user_cert;
+ KMF_DATA *signer_cert; /* can be NULL */
+ boolean_t ignore_response_sign; /* default is FALSE */
+ uint32_t response_lifetime; /* in seconds */
+} KMF_OCSPRESPONSE_PARAMS_INPUT;
+
+typedef enum {
+ OCSP_GOOD = 0,
+ OCSP_REVOKED = 1,
+ OCSP_UNKNOWN = 2
+} KMF_OCSP_CERT_STATUS;
+
+typedef struct {
+ int response_status;
+ int reason; /* if revoked */
+ KMF_OCSP_CERT_STATUS cert_status;
+} KMF_OCSPRESPONSE_PARAMS_OUTPUT;
+
+#define nssparms ks_opt_u.nss_opts
+#define sslparms ks_opt_u.openssl_opts
+#define pkcs11parms ks_opt_u.pkcs11_opts
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ KMF_KEY_ALG keyalg;
+ KMF_KEY_CLASS keyclass;
+ boolean_t israw;
+ char *keylabel;
+ void *keyp;
+} KMF_KEY_HANDLE;
+
+typedef struct {
+ KMF_KEYSTORE_TYPE kstype;
+ uint32_t errcode;
+} KMF_ERROR;
+
+/*
+ * Typenames to use with subjectAltName
+ */
+typedef enum {
+ GENNAME_OTHERNAME = 0x00,
+ GENNAME_RFC822NAME,
+ GENNAME_DNSNAME,
+ GENNAME_X400ADDRESS,
+ GENNAME_DIRECTORYNAME,
+ GENNAME_EDIPARTYNAME,
+ GENNAME_URI,
+ GENNAME_IPADDRESS,
+ GENNAME_REGISTEREDID
+} KMF_GENERALNAMECHOICES;
+
+/*
+ * KMF_FIELD
+ * This structure contains the OID/value pair for any item that can be
+ * identified by an OID.
+ */
+typedef struct
+{
+ KMF_OID FieldOid;
+ KMF_DATA FieldValue;
+} KMF_FIELD;
+
+typedef enum {
+ KMF_OK = 0x00,
+ KMF_ERR_BAD_PARAMETER = 0x01,
+ KMF_ERR_BAD_KEY_FORMAT = 0x02,
+ KMF_ERR_BAD_ALGORITHM = 0x03,
+ KMF_ERR_MEMORY = 0x04,
+ KMF_ERR_ENCODING = 0x05,
+ KMF_ERR_PLUGIN_INIT = 0x06,
+ KMF_ERR_PLUGIN_NOTFOUND = 0x07,
+ KMF_ERR_INTERNAL = 0x0b,
+ KMF_ERR_BAD_CERT_FORMAT = 0x0c,
+ KMF_ERR_KEYGEN_FAILED = 0x0d,
+ KMF_ERR_UNINITIALIZED = 0x10,
+ KMF_ERR_ISSUER = 0x11,
+ KMF_ERR_NOT_REVOKED = 0x12,
+ KMF_ERR_CERT_NOT_FOUND = 0x13,
+ KMF_ERR_CRL_NOT_FOUND = 0x14,
+ KMF_ERR_RDN_PARSER = 0x15,
+ KMF_ERR_RDN_ATTR = 0x16,
+ KMF_ERR_SLOTNAME = 0x17,
+ KMF_ERR_EMPTY_CRL = 0x18,
+ KMF_ERR_BUFFER_SIZE = 0x19,
+ KMF_ERR_AUTH_FAILED = 0x1a,
+ KMF_ERR_TOKEN_SELECTED = 0x1b,
+ KMF_ERR_NO_TOKEN_SELECTED = 0x1c,
+ KMF_ERR_TOKEN_NOT_PRESENT = 0x1d,
+ KMF_ERR_EXTENSION_NOT_FOUND = 0x1e,
+ KMF_ERR_POLICY_ENGINE = 0x1f,
+ KMF_ERR_POLICY_DB_FORMAT = 0x20,
+ KMF_ERR_POLICY_NOT_FOUND = 0x21,
+ KMF_ERR_POLICY_DB_FILE = 0x22,
+ KMF_ERR_POLICY_NAME = 0x23,
+ KMF_ERR_OCSP_POLICY = 0x24,
+ KMF_ERR_TA_POLICY = 0x25,
+ KMF_ERR_KEY_NOT_FOUND = 0x26,
+ KMF_ERR_OPEN_FILE = 0x27,
+ KMF_ERR_OCSP_BAD_ISSUER = 0x28,
+ KMF_ERR_OCSP_BAD_CERT = 0x29,
+ KMF_ERR_OCSP_CREATE_REQUEST = 0x2a,
+ KMF_ERR_CONNECT_SERVER = 0x2b,
+ KMF_ERR_SEND_REQUEST = 0x2c,
+ KMF_ERR_OCSP_CERTID = 0x2d,
+ KMF_ERR_OCSP_MALFORMED_RESPONSE = 0x2e,
+ KMF_ERR_OCSP_RESPONSE_STATUS = 0x2f,
+ KMF_ERR_OCSP_NO_BASIC_RESPONSE = 0x30,
+ KMF_ERR_OCSP_BAD_SIGNER = 0x31,
+ KMF_ERR_OCSP_RESPONSE_SIGNATURE = 0x32,
+ KMF_ERR_OCSP_UNKNOWN_CERT = 0x33,
+ KMF_ERR_OCSP_STATUS_TIME_INVALID = 0x34,
+ KMF_ERR_BAD_HTTP_RESPONSE = 0x35,
+ KMF_ERR_RECV_RESPONSE = 0x36,
+ KMF_ERR_RECV_TIMEOUT = 0x37,
+ KMF_ERR_DUPLICATE_KEYFILE = 0x38,
+ KMF_ERR_AMBIGUOUS_PATHNAME = 0x39,
+ KMF_ERR_FUNCTION_NOT_FOUND = 0x3a,
+ KMF_ERR_PKCS12_FORMAT = 0x3b,
+ KMF_ERR_BAD_KEY_TYPE = 0x3c,
+ KMF_ERR_BAD_KEY_CLASS = 0x3d,
+ KMF_ERR_BAD_KEY_SIZE = 0x3e,
+ KMF_ERR_BAD_HEX_STRING = 0x3f,
+ KMF_ERR_KEYUSAGE = 0x40,
+ KMF_ERR_VALIDITY_PERIOD = 0x41,
+ KMF_ERR_OCSP_REVOKED = 0x42,
+ KMF_ERR_CERT_MULTIPLE_FOUND = 0x43,
+ KMF_ERR_WRITE_FILE = 0x44,
+ KMF_ERR_BAD_URI = 0x45,
+ KMF_ERR_BAD_CRLFILE = 0x46,
+ KMF_ERR_BAD_CERTFILE = 0x47,
+ KMF_ERR_GETKEYVALUE_FAILED = 0x48,
+ KMF_ERR_BAD_KEYHANDLE = 0x49,
+ KMF_ERR_BAD_OBJECT_TYPE = 0x4a,
+ KMF_ERR_OCSP_RESPONSE_LIFETIME = 0x4b,
+ KMF_ERR_UNKNOWN_CSR_ATTRIBUTE = 0x4c,
+ KMF_ERR_UNINITIALIZED_TOKEN = 0x4d,
+ KMF_ERR_INCOMPLETE_TBS_CERT = 0x4e,
+ KMF_ERR_MISSING_ERRCODE = 0x4f,
+ KMF_KEYSTORE_ALREADY_INITIALIZED = 0x50
+} KMF_RETURN;
+
+typedef enum {
+ OCSP_SUCCESS = 0,
+ OCSP_MALFORMED_REQUEST = 1,
+ OCSP_INTERNAL_ERROR = 2,
+ OCSP_TRYLATER = 3,
+ OCSP_SIGREQUIRED = 4,
+ OCSP_UNAUTHORIZED = 5
+} KMF_OCSP_RESPONSE_STATUS;
+
+typedef enum {
+ OCSP_NOSTATUS = -1,
+ OCSP_UNSPECIFIED = 0,
+ OCSP_KEYCOMPROMISE = 1,
+ OCSP_CACOMPROMISE = 2,
+ OCSP_AFFILIATIONCHANGE = 3,
+ OCSP_SUPERCEDED = 4,
+ OCSP_CESSATIONOFOPERATION = 5,
+ OCSP_CERTIFICATEHOLD = 6,
+ OCSP_REMOVEFROMCRL = 7
+} KMF_OCSP_REVOKED_STATUS;
+
+typedef enum {
+ KMF_ALGCLASS_NONE = 0,
+ KMF_ALGCLASS_CUSTOM,
+ KMF_ALGCLASS_SIGNATURE,
+ KMF_ALGCLASS_SYMMETRIC,
+ KMF_ALGCLASS_DIGEST,
+ KMF_ALGCLASS_RANDOMGEN,
+ KMF_ALGCLASS_UNIQUEGEN,
+ KMF_ALGCLASS_MAC,
+ KMF_ALGCLASS_ASYMMETRIC,
+ KMF_ALGCLASS_KEYGEN,
+ KMF_ALGCLASS_DERIVEKEY
+} KMF_ALGCLASS;
+
+/*
+ * Algorithms
+ * This type defines a set of constants used to identify cryptographic
+ * algorithms.
+ */
+typedef enum {
+ KMF_ALGID_NONE = 0,
+ KMF_ALGID_CUSTOM,
+ KMF_ALGID_SHA1,
+ KMF_ALGID_RSA,
+ KMF_ALGID_DSA,
+ KMF_ALGID_MD5WithRSA,
+ KMF_ALGID_MD2WithRSA,
+ KMF_ALGID_SHA1WithRSA,
+ KMF_ALGID_SHA1WithDSA
+} KMF_ALGORITHM_INDEX;
+
+typedef enum {
+ KMF_CERT_ISSUER = 1,
+ KMF_CERT_SUBJECT,
+ KMF_CERT_VERSION,
+ KMF_CERT_SERIALNUM,
+ KMF_CERT_NOTBEFORE,
+ KMF_CERT_NOTAFTER,
+ KMF_CERT_PUBKEY_ALG,
+ KMF_CERT_SIGNATURE_ALG,
+ KMF_CERT_EMAIL,
+ KMF_CERT_PUBKEY_DATA,
+ KMF_X509_EXT_PRIV_KEY_USAGE_PERIOD,
+ KMF_X509_EXT_CERT_POLICIES,
+ KMF_X509_EXT_SUBJ_ALTNAME,
+ KMF_X509_EXT_ISSUER_ALTNAME,
+ KMF_X509_EXT_BASIC_CONSTRAINTS,
+ KMF_X509_EXT_NAME_CONSTRAINTS,
+ KMF_X509_EXT_POLICY_CONSTRAINTS,
+ KMF_X509_EXT_EXT_KEY_USAGE,
+ KMF_X509_EXT_INHIBIT_ANY_POLICY,
+ KMF_X509_EXT_AUTH_KEY_ID,
+ KMF_X509_EXT_SUBJ_KEY_ID,
+ KMF_X509_EXT_POLICY_MAPPINGS,
+ KMF_X509_EXT_CRL_DIST_POINTS,
+ KMF_X509_EXT_FRESHEST_CRL,
+ KMF_X509_EXT_KEY_USAGE
+} KMF_PRINTABLE_ITEM;
+
+/*
+ * KMF_X509_ALGORITHM_IDENTIFIER
+ * This structure holds an object identifier naming a
+ * cryptographic algorithm and an optional set of
+ * parameters to be used as input to that algorithm.
+ */
+typedef struct
+{
+ KMF_OID algorithm;
+ KMF_DATA parameters;
+} KMF_X509_ALGORITHM_IDENTIFIER;
+
+/*
+ * KMF_X509_TYPE_VALUE_PAIR
+ * This structure contain an type-value pair.
+ */
+typedef struct
+{
+ KMF_OID type;
+ uint8_t valueType; /* The Tag to use when BER encoded */
+ KMF_DATA value;
+} KMF_X509_TYPE_VALUE_PAIR;
+
+
+/*
+ * KMF_X509_RDN
+ * This structure contains a Relative Distinguished Name
+ * composed of an ordered set of type-value pairs.
+ */
+typedef struct
+{
+ uint32_t numberOfPairs;
+ KMF_X509_TYPE_VALUE_PAIR *AttributeTypeAndValue;
+} KMF_X509_RDN;
+
+/*
+ * KMF_X509_NAME
+ * This structure contains a set of Relative Distinguished Names.
+ */
+typedef struct
+{
+ uint32_t numberOfRDNs;
+ KMF_X509_RDN *RelativeDistinguishedName;
+} KMF_X509_NAME;
+
+/*
+ * KMF_X509_SPKI
+ * This structure contains the public key and the
+ * description of the verification algorithm
+ * appropriate for use with this key.
+ */
+typedef struct
+{
+ KMF_X509_ALGORITHM_IDENTIFIER algorithm;
+ KMF_DATA subjectPublicKey;
+} KMF_X509_SPKI;
+
+/*
+ * KMF_X509_TIME
+ * Time is represented as a string according to the
+ * definitions of GeneralizedTime and UTCTime
+ * defined in RFC 2459.
+ */
+typedef struct
+{
+ uint8_t timeType;
+ KMF_DATA time;
+} KMF_X509_TIME;
+
+/*
+ * KMF_X509_VALIDITY
+ */
+typedef struct
+{
+ KMF_X509_TIME notBefore;
+ KMF_X509_TIME notAfter;
+} KMF_X509_VALIDITY;
+
+/*
+ * KMF_X509EXT_BASICCONSTRAINTS
+ */
+typedef struct
+{
+ KMF_BOOL cA;
+ KMF_BOOL pathLenConstraintPresent;
+ uint32_t pathLenConstraint;
+} KMF_X509EXT_BASICCONSTRAINTS;
+
+/*
+ * KMF_X509EXT_DATA_FORMAT
+ * This list defines the valid formats for a certificate extension.
+ */
+typedef enum
+{
+ KMF_X509_DATAFORMAT_ENCODED = 0,
+ KMF_X509_DATAFORMAT_PARSED,
+ KMF_X509_DATAFORMAT_PAIR
+} KMF_X509EXT_DATA_FORMAT;
+
+
+/*
+ * KMF_X509EXT_TAGandVALUE
+ * This structure contains a BER/DER encoded
+ * extension value and the type of that value.
+ */
+typedef struct
+{
+ uint8_t type;
+ KMF_DATA value;
+} KMF_X509EXT_TAGandVALUE;
+
+
+/*
+ * KMF_X509EXT_PAIR
+ * This structure aggregates two extension representations:
+ * a tag and value, and a parsed X509 extension representation.
+ */
+typedef struct
+{
+ KMF_X509EXT_TAGandVALUE tagAndValue;
+ void *parsedValue;
+} KMF_X509EXT_PAIR;
+
+/*
+ * KMF_X509_EXTENSION
+ * This structure contains a complete certificate extension.
+ */
+typedef struct
+{
+ KMF_OID extnId;
+ KMF_BOOL critical;
+ KMF_X509EXT_DATA_FORMAT format;
+ union
+ {
+ KMF_X509EXT_TAGandVALUE *tagAndValue;
+ void *parsedValue;
+ KMF_X509EXT_PAIR *valuePair;
+ } value;
+ KMF_DATA BERvalue;
+} KMF_X509_EXTENSION;
+
+
+/*
+ * KMF_X509_EXTENSIONS
+ * This structure contains the set of all certificate
+ * extensions contained in a certificate.
+ */
+typedef struct
+{
+ uint32_t numberOfExtensions;
+ KMF_X509_EXTENSION *extensions;
+} KMF_X509_EXTENSIONS;
+
+/*
+ * KMF_X509_TBS_CERT
+ * This structure contains a complete X.509 certificate.
+ */
+typedef struct
+{
+ KMF_DATA version;
+ KMF_BIGINT serialNumber;
+ KMF_X509_ALGORITHM_IDENTIFIER signature;
+ KMF_X509_NAME issuer;
+ KMF_X509_VALIDITY validity;
+ KMF_X509_NAME subject;
+ KMF_X509_SPKI subjectPublicKeyInfo;
+ KMF_DATA issuerUniqueIdentifier;
+ KMF_DATA subjectUniqueIdentifier;
+ KMF_X509_EXTENSIONS extensions;
+} KMF_X509_TBS_CERT;
+
+/*
+ * KMF_X509_SIGNATURE
+ * This structure contains a cryptographic digital signature.
+ */
+typedef struct
+{
+ KMF_X509_ALGORITHM_IDENTIFIER algorithmIdentifier;
+ KMF_DATA encrypted;
+} KMF_X509_SIGNATURE;
+
+/*
+ * KMF_X509_CERTIFICATE
+ * This structure associates a set of decoded certificate
+ * values with the signature covering those values.
+ */
+typedef struct
+{
+ KMF_X509_TBS_CERT certificate;
+ KMF_X509_SIGNATURE signature;
+} KMF_X509_CERTIFICATE;
+
+#define CERT_ALG_OID(c) &c->certificate.signature.algorithm
+#define CERT_SIG_OID(c) &c->signature.algorithmIdentifier.algorithm
+
+/*
+ * KMF_TBS_CSR
+ * This structure contains a complete PKCS#10 certificate request
+ */
+typedef struct
+{
+ KMF_DATA version;
+ KMF_X509_NAME subject;
+ KMF_X509_SPKI subjectPublicKeyInfo;
+ KMF_X509_EXTENSIONS extensions;
+} KMF_TBS_CSR;
+
+/*
+ * KMF_CSR_DATA
+ * This structure contains a complete PKCS#10 certificate signed request
+ */
+typedef struct
+{
+ KMF_TBS_CSR csr;
+ KMF_X509_SIGNATURE signature;
+} KMF_CSR_DATA;
+
+/*
+ * KMF_X509EXT_POLICYQUALIFIERINFO
+ */
+typedef struct
+{
+ KMF_OID policyQualifierId;
+ KMF_DATA value;
+} KMF_X509EXT_POLICYQUALIFIERINFO;
+
+/*
+ * KMF_X509EXT_POLICYQUALIFIERS
+ */
+typedef struct
+{
+ uint32_t numberOfPolicyQualifiers;
+ KMF_X509EXT_POLICYQUALIFIERINFO *policyQualifier;
+} KMF_X509EXT_POLICYQUALIFIERS;
+
+/*
+ * KMF_X509EXT_POLICYINFO
+ */
+typedef struct
+{
+ KMF_OID policyIdentifier;
+ KMF_X509EXT_POLICYQUALIFIERS policyQualifiers;
+} KMF_X509EXT_POLICYINFO;
+
+typedef struct
+{
+ uint32_t numberOfPolicyInfo;
+ KMF_X509EXT_POLICYINFO *policyInfo;
+} KMF_X509EXT_CERT_POLICIES;
+
+typedef struct
+{
+ uchar_t critical;
+ uint16_t KeyUsageBits;
+} KMF_X509EXT_KEY_USAGE;
+
+typedef struct
+{
+ uchar_t critical;
+ uint16_t nEKUs;
+ KMF_OID *keyPurposeIdList;
+} KMF_X509EXT_EKU;
+
+
+/*
+ * X509 AuthorityInfoAccess extension
+ */
+typedef struct
+{
+ KMF_OID AccessMethod;
+ KMF_DATA AccessLocation;
+} KMF_X509EXT_ACCESSDESC;
+
+typedef struct
+{
+ uint32_t numberOfAccessDescription;
+ KMF_X509EXT_ACCESSDESC *AccessDesc;
+} KMF_X509EXT_AUTHINFOACCESS;
+
+
+/*
+ * X509 Crl Distribution Point extension
+ */
+typedef struct {
+ KMF_GENERALNAMECHOICES choice;
+ KMF_DATA name;
+} KMF_GENERALNAME;
+
+typedef struct {
+ uint32_t number;
+ KMF_GENERALNAME *namelist;
+} KMF_GENERALNAMES;
+
+typedef enum {
+ DP_GENERAL_NAME = 1,
+ DP_RELATIVE_NAME = 2
+} KMF_CRL_DIST_POINT_TYPE;
+
+typedef struct {
+ KMF_CRL_DIST_POINT_TYPE type;
+ union {
+ KMF_GENERALNAMES full_name;
+ KMF_DATA relative_name;
+ } name;
+ KMF_DATA reasons;
+ KMF_GENERALNAMES crl_issuer;
+} KMF_CRL_DIST_POINT;
+
+typedef struct {
+ uint32_t number;
+ KMF_CRL_DIST_POINT *dplist;
+} KMF_X509EXT_CRLDISTPOINTS;
+
+
+/*
+ * Definitions for common X.509v3 certificate attribute OIDs
+ */
+#define OID_ISO_MEMBER 42 /* Also in PKCS */
+#define OID_US OID_ISO_MEMBER, 134, 72 /* Also in PKCS */
+#define OID_CA OID_ISO_MEMBER, 124
+
+#define OID_ISO_IDENTIFIED_ORG 43
+#define OID_OSINET OID_ISO_IDENTIFIED_ORG, 4
+#define OID_GOSIP OID_ISO_IDENTIFIED_ORG, 5
+#define OID_DOD OID_ISO_IDENTIFIED_ORG, 6
+#define OID_OIW OID_ISO_IDENTIFIED_ORG, 14 /* Also in x9.57 */
+
+#define OID_ISO_CCITT_DIR_SERVICE 85
+#define OID_ISO_CCITT_COUNTRY 96
+#define OID_COUNTRY_US OID_ISO_CCITT_COUNTRY, 134, 72
+#define OID_COUNTRY_CA OID_ISO_CCITT_COUNTRY, 124
+#define OID_COUNTRY_US_ORG OID_COUNTRY_US, 1
+#define OID_COUNTRY_US_MHS_MD OID_COUNTRY_US, 2
+#define OID_COUNTRY_US_STATE OID_COUNTRY_US, 3
+
+/* From the PKCS Standards */
+#define OID_ISO_MEMBER_LENGTH 1
+#define OID_US_LENGTH (OID_ISO_MEMBER_LENGTH + 2)
+
+#define OID_RSA OID_US, 134, 247, 13
+#define OID_RSA_LENGTH (OID_US_LENGTH + 3)
+
+#define OID_RSA_HASH OID_RSA, 2
+#define OID_RSA_HASH_LENGTH (OID_RSA_LENGTH + 1)
+
+#define OID_RSA_ENCRYPT OID_RSA, 3
+#define OID_RSA_ENCRYPT_LENGTH (OID_RSA_LENGTH + 1)
+
+#define OID_PKCS OID_RSA, 1
+#define OID_PKCS_LENGTH (OID_RSA_LENGTH + 1)
+
+#define OID_PKCS_1 OID_PKCS, 1
+#define OID_PKCS_1_LENGTH (OID_PKCS_LENGTH + 1)
+
+#define OID_PKCS_2 OID_PKCS, 2
+#define OID_PKCS_3 OID_PKCS, 3
+#define OID_PKCS_3_LENGTH (OID_PKCS_LENGTH + 1)
+
+#define OID_PKCS_4 OID_PKCS, 4
+#define OID_PKCS_5 OID_PKCS, 5
+#define OID_PKCS_5_LENGTH (OID_PKCS_LENGTH + 1)
+#define OID_PKCS_6 OID_PKCS, 6
+#define OID_PKCS_7 OID_PKCS, 7
+#define OID_PKCS_7_LENGTH (OID_PKCS_LENGTH + 1)
+
+#define OID_PKCS_7_Data OID_PKCS_7, 1
+#define OID_PKCS_7_SignedData OID_PKCS_7, 2
+#define OID_PKCS_7_EnvelopedData OID_PKCS_7, 3
+#define OID_PKCS_7_SignedAndEnvelopedData OID_PKCS_7, 4
+#define OID_PKCS_7_DigestedData OID_PKCS_7, 5
+#define OID_PKCS_7_EncryptedData OID_PKCS_7, 6
+
+#define OID_PKCS_8 OID_PKCS, 8
+#define OID_PKCS_9 OID_PKCS, 9
+#define OID_PKCS_9_LENGTH (OID_PKCS_LENGTH + 1)
+
+#define OID_PKCS_9_CONTENT_TYPE OID_PKCS_9, 3
+#define OID_PKCS_9_MESSAGE_DIGEST OID_PKCS_9, 4
+#define OID_PKCS_9_SIGNING_TIME OID_PKCS_9, 5
+#define OID_PKCS_9_COUNTER_SIGNATURE OID_PKCS_9, 6
+#define OID_PKCS_9_EXTENSION_REQUEST OID_PKCS_9, 14
+
+#define OID_PKCS_10 OID_PKCS, 10
+
+#define OID_PKCS_12 OID_PKCS, 12
+#define OID_PKCS_12_LENGTH (OID_PKCS_LENGTH + 1)
+
+#define PBEWithSHAAnd128BitRC4 OID_PKCS_12, 1, 1
+#define PBEWithSHAAnd40BitRC4 OID_PKCS_12, 1, 2
+#define PBEWithSHAAnd3KeyTripleDES_CBC OID_PKCS_12, 1, 3
+#define PBEWithSHAAnd2KeyTripleDES_CBC OID_PKCS_12, 1, 4
+#define PBEWithSHAAnd128BitRC2_CBC OID_PKCS_12, 1, 5
+#define PBEWithSHAAnd40BitRC2_CBC OID_PKCS_12, 1, 6
+
+#define OID_BAG_TYPES OID_PKCS_12, 10, 1
+#define OID_KeyBag OID_BAG_TYPES, 1
+#define OID_PKCS8ShroudedKeyBag OID_BAG_TYPES, 2
+#define OID_CertBag OID_BAG_TYPES, 3
+#define OID_CrlBag OID_BAG_TYPES, 4
+#define OID_SecretBag OID_BAG_TYPES, 5
+#define OID_SafeContentsBag OID_BAG_TYPES, 6
+
+#define OID_ContentInfo OID_PKCS_7, 0, 1
+
+#define OID_CERT_TYPES OID_PKCS_9, 22
+#define OID_x509Certificate OID_CERT_TYPES, 1
+#define OID_sdsiCertificate OID_CERT_TYPES, 2
+
+#define OID_CRL_TYPES OID_PKCS_9, 23
+#define OID_x509Crl OID_CRL_TYPES, 1
+
+#define OID_DS OID_ISO_CCITT_DIR_SERVICE /* Also in X.501 */
+#define OID_DS_LENGTH 1
+
+#define OID_ATTR_TYPE OID_DS, 4 /* Also in X.501 */
+#define OID_ATTR_TYPE_LENGTH (OID_DS_LENGTH + 1)
+
+#define OID_DSALG OID_DS, 8 /* Also in X.501 */
+#define OID_DSALG_LENGTH (OID_DS_LENGTH + 1)
+
+#define OID_EXTENSION OID_DS, 29 /* Also in X.501 */
+#define OID_EXTENSION_LENGTH (OID_DS_LENGTH + 1)
+
+/*
+ * From RFC 1274:
+ * {itu-t(0) data(9) pss(2342) ucl(19200300) pilot(100) pilotAttributeType(1) }
+ */
+#define OID_PILOT 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x1
+#define OID_PILOT_LENGTH 9
+
+#define OID_USERID OID_PILOT 1
+#define OID_USERID_LENGTH (OID_PILOT_LENGTH + 1)
+
+/*
+ * From PKIX part1
+ * { iso(1) identified-organization(3) dod(6) internet(1)
+ * security(5) mechanisms(5) pkix(7) }
+ */
+#define OID_PKIX 43, 6, 1, 5, 5, 7
+#define OID_PKIX_LENGTH 6
+
+/* private certificate extensions, { id-pkix 1 } */
+#define OID_PKIX_PE OID_PKIX, 1
+#define OID_PKIX_PE_LENGTH (OID_PKIX_LENGTH + 1)
+
+/* policy qualifier types {id-pkix 2 } */
+#define OID_PKIX_QT OID_PKIX, 2
+#define OID_PKIX_QT_LENGTH (OID_PKIX_LENGTH + 1)
+
+/* CPS qualifier, { id-qt 1 } */
+#define OID_PKIX_QT_CPS OID_PKIX_QT, 1
+#define OID_PKIX_QT_CPS_LENGTH (OID_PKIX_QT_LENGTH + 1)
+/* user notice qualifier, { id-qt 2 } */
+#define OID_PKIX_QT_UNOTICE OID_PKIX_QT, 2
+#define OID_PKIX_QT_UNOTICE_LENGTH (OID_PKIX_QT_LENGTH + 1)
+
+/* extended key purpose OIDs {id-pkix 3 } */
+#define OID_PKIX_KP OID_PKIX, 3
+#define OID_PKIX_KP_LENGTH (OID_PKIX_LENGTH + 1)
+
+/* access descriptors {id-pkix 4 } */
+#define OID_PKIX_AD OID_PKIX, 48
+#define OID_PKIX_AD_LENGTH (OID_PKIX_LENGTH + 1)
+
+/* access descriptors */
+/* OCSP */
+#define OID_PKIX_AD_OCSP OID_PKIX_AD, 1
+#define OID_PKIX_AD_OCSP_LENGTH (OID_PKIX_AD_LENGTH + 1)
+
+/* cAIssuers */
+#define OID_PKIX_AD_CAISSUERS OID_PKIX_AD, 2
+#define OID_PKIX_AD_CAISSUERS_LENGTH (OID_PKIX_AD_LENGTH + 1)
+
+/* end PKIX part1 */
+#define OID_APPL_TCP_PROTO 43, 6, 1, 2, 1, 27, 4
+#define OID_APPL_TCP_PROTO_LENGTH 8
+
+#define OID_DAP OID_DS, 3, 1
+#define OID_DAP_LENGTH (OID_DS_LENGTH + 2)
+
+/* From x9.57 */
+#define OID_OIW_LENGTH 2
+
+#define OID_OIW_SECSIG OID_OIW, 3
+#define OID_OIW_SECSIG_LENGTH (OID_OIW_LENGTH + 1)
+
+#define OID_OIW_ALGORITHM OID_OIW_SECSIG, 2
+#define OID_OIW_ALGORITHM_LENGTH (OID_OIW_SECSIG_LENGTH + 1)
+
+#define OID_OIWDIR OID_OIW, 7, 2
+#define OID_OIWDIR_LENGTH (OID_OIW_LENGTH + 2)
+
+#define OID_OIWDIR_CRPT OID_OIWDIR, 1
+
+#define OID_OIWDIR_HASH OID_OIWDIR, 2
+#define OID_OIWDIR_HASH_LENGTH (OID_OIWDIR_LENGTH + 1)
+
+#define OID_OIWDIR_SIGN OID_OIWDIR, 3
+#define OID_OIWDIR_SIGN_LENGTH (OID_OIWDIR_LENGTH + 1)
+
+#define OID_X9CM OID_US, 206, 56
+#define OID_X9CM_MODULE OID_X9CM, 1
+#define OID_X9CM_INSTRUCTION OID_X9CM, 2
+#define OID_X9CM_ATTR OID_X9CM, 3
+#define OID_X9CM_X9ALGORITHM OID_X9CM, 4
+#define OID_X9CM_X9ALGORITHM_LENGTH ((OID_US_LENGTH) + 2 + 1)
+
+#define INTEL 96, 134, 72, 1, 134, 248, 77
+#define INTEL_LENGTH 7
+
+#define INTEL_SEC_FORMATS INTEL_CDSASECURITY, 1
+#define INTEL_SEC_FORMATS_LENGTH (INTEL_CDSASECURITY_LENGTH + 1)
+
+#define INTEL_SEC_ALGS INTEL_CDSASECURITY, 2, 5
+#define INTEL_SEC_ALGS_LENGTH (INTEL_CDSASECURITY_LENGTH + 2)
+
+extern const KMF_OID
+KMFOID_AliasedEntryName,
+KMFOID_AuthorityRevocationList,
+KMFOID_BusinessCategory,
+KMFOID_CACertificate,
+KMFOID_CertificateRevocationList,
+KMFOID_ChallengePassword,
+KMFOID_CollectiveFacsimileTelephoneNumber,
+KMFOID_CollectiveInternationalISDNNumber,
+KMFOID_CollectiveOrganizationName,
+KMFOID_CollectiveOrganizationalUnitName,
+KMFOID_CollectivePhysicalDeliveryOfficeName,
+KMFOID_CollectivePostOfficeBox,
+KMFOID_CollectivePostalAddress,
+KMFOID_CollectivePostalCode,
+KMFOID_CollectiveStateProvinceName,
+KMFOID_CollectiveStreetAddress,
+KMFOID_CollectiveTelephoneNumber,
+KMFOID_CollectiveTelexNumber,
+KMFOID_CollectiveTelexTerminalIdentifier,
+KMFOID_CommonName,
+KMFOID_ContentType,
+KMFOID_CounterSignature,
+KMFOID_CountryName,
+KMFOID_CrossCertificatePair,
+KMFOID_DNQualifier,
+KMFOID_Description,
+KMFOID_DestinationIndicator,
+KMFOID_DistinguishedName,
+KMFOID_EmailAddress,
+KMFOID_EnhancedSearchGuide,
+KMFOID_ExtendedCertificateAttributes,
+KMFOID_ExtensionRequest,
+KMFOID_FacsimileTelephoneNumber,
+KMFOID_GenerationQualifier,
+KMFOID_GivenName,
+KMFOID_HouseIdentifier,
+KMFOID_Initials,
+KMFOID_InternationalISDNNumber,
+KMFOID_KnowledgeInformation,
+KMFOID_LocalityName,
+KMFOID_Member,
+KMFOID_MessageDigest,
+KMFOID_Name,
+KMFOID_ObjectClass,
+KMFOID_OrganizationName,
+KMFOID_OrganizationalUnitName,
+KMFOID_Owner,
+KMFOID_PhysicalDeliveryOfficeName,
+KMFOID_PostOfficeBox,
+KMFOID_PostalAddress,
+KMFOID_PostalCode,
+KMFOID_PreferredDeliveryMethod,
+KMFOID_PresentationAddress,
+KMFOID_ProtocolInformation,
+KMFOID_RFC822mailbox,
+KMFOID_RegisteredAddress,
+KMFOID_RoleOccupant,
+KMFOID_SearchGuide,
+KMFOID_SeeAlso,
+KMFOID_SerialNumber,
+KMFOID_SigningTime,
+KMFOID_StateProvinceName,
+KMFOID_StreetAddress,
+KMFOID_SupportedApplicationContext,
+KMFOID_Surname,
+KMFOID_TelephoneNumber,
+KMFOID_TelexNumber,
+KMFOID_TelexTerminalIdentifier,
+KMFOID_Title,
+KMFOID_UniqueIdentifier,
+KMFOID_UniqueMember,
+KMFOID_UnstructuredAddress,
+KMFOID_UnstructuredName,
+KMFOID_UserCertificate,
+KMFOID_UserPassword,
+KMFOID_X_121Address,
+KMFOID_domainComponent,
+KMFOID_userid;
+
+extern const KMF_OID
+KMFOID_AuthorityKeyID,
+KMFOID_AuthorityInfoAccess,
+KMFOID_VerisignCertificatePolicy,
+KMFOID_KeyUsageRestriction,
+KMFOID_SubjectDirectoryAttributes,
+KMFOID_SubjectKeyIdentifier,
+KMFOID_KeyUsage,
+KMFOID_PrivateKeyUsagePeriod,
+KMFOID_SubjectAltName,
+KMFOID_IssuerAltName,
+KMFOID_BasicConstraints,
+KMFOID_CrlNumber,
+KMFOID_CrlReason,
+KMFOID_HoldInstructionCode,
+KMFOID_InvalidityDate,
+KMFOID_DeltaCrlIndicator,
+KMFOID_IssuingDistributionPoints,
+KMFOID_NameConstraints,
+KMFOID_CrlDistributionPoints,
+KMFOID_CertificatePolicies,
+KMFOID_PolicyMappings,
+KMFOID_PolicyConstraints,
+KMFOID_AuthorityKeyIdentifier,
+KMFOID_ExtendedKeyUsage,
+KMFOID_PkixAdOcsp,
+KMFOID_PkixAdCaIssuers,
+KMFOID_PKIX_PQ_CPSuri,
+KMFOID_PKIX_PQ_Unotice,
+KMFOID_PKIX_KP_ServerAuth,
+KMFOID_PKIX_KP_ClientAuth,
+KMFOID_PKIX_KP_CodeSigning,
+KMFOID_PKIX_KP_EmailProtection,
+KMFOID_PKIX_KP_IPSecEndSystem,
+KMFOID_PKIX_KP_IPSecTunnel,
+KMFOID_PKIX_KP_IPSecUser,
+KMFOID_PKIX_KP_TimeStamping,
+KMFOID_PKIX_KP_OCSPSigning;
+
+/*
+ * KMF Certificate validation codes. These may be masked together.
+ */
+#define KMF_CERT_VALIDATE_OK 0x00
+#define KMF_CERT_VALIDATE_ERR_TA 0x01
+#define KMF_CERT_VALIDATE_ERR_USER 0x02
+#define KMF_CERT_VALIDATE_ERR_SIGNATURE 0x04
+#define KMF_CERT_VALIDATE_ERR_KEYUSAGE 0x08
+#define KMF_CERT_VALIDATE_ERR_EXT_KEYUSAGE 0x10
+#define KMF_CERT_VALIDATE_ERR_TIME 0x20
+#define KMF_CERT_VALIDATE_ERR_CRL 0x40
+#define KMF_CERT_VALIDATE_ERR_OCSP 0x80
+#define KMF_CERT_VALIDATE_ERR_ISSUER 0x100
+
+/*
+ * KMF Key Usage bitmasks
+ */
+#define KMF_digitalSignature 0x8000
+#define KMF_nonRepudiation 0x4000
+#define KMF_keyEncipherment 0x2000
+#define KMF_dataEncipherment 0x1000
+#define KMF_keyAgreement 0x0800
+#define KMF_keyCertSign 0x0400
+#define KMF_cRLSign 0x0200
+#define KMF_encipherOnly 0x0100
+#define KMF_decipherOnly 0x0080
+
+#define KMF_KUBITMASK 0xFF80
+
+/*
+ * KMF Extended KeyUsage OID definitions
+ */
+#define KMF_EKU_SERVERAUTH 0x01
+#define KMF_EKU_CLIENTAUTH 0x02
+#define KMF_EKU_CODESIGNING 0x04
+#define KMF_EKU_EMAIL 0x08
+#define KMF_EKU_TIMESTAMP 0x10
+#define KMF_EKU_OCSPSIGNING 0x20
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _KMFTYPES_H */
diff --git a/usr/src/lib/libkmf/include/oidsalg.h b/usr/src/lib/libkmf/include/oidsalg.h
new file mode 100644
index 0000000000..af9f5e2ead
--- /dev/null
+++ b/usr/src/lib/libkmf/include/oidsalg.h
@@ -0,0 +1,73 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * File: oidsalg.h
+ *
+ * Copyright (c) 1995-2000 Intel Corporation. All rights reserved.
+ *
+ */
+
+#ifndef _OIDSALG_H
+#define _OIDSALG_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <kmftypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint8_t
+ OID_OIW_SHA1[] = { OID_OIW_ALGORITHM, 26},
+ OID_OIW_DSA[] = { OID_OIW_ALGORITHM, 12 },
+ OID_OIW_DSAWithSHA1[] = { OID_OIW_ALGORITHM, 27 },
+ OID_RSAEncryption[] = { OID_PKCS_1, 1 },
+ OID_MD2WithRSA[] = { OID_PKCS_1, 2 },
+ OID_MD5WithRSA[] = { OID_PKCS_1, 4 },
+ OID_SHA1WithRSA[] = { OID_PKCS_1, 5 },
+ OID_X9CM_DSA[] = { OID_X9CM_X9ALGORITHM, 1 },
+ OID_X9CM_DSAWithSHA1[] = { OID_X9CM_X9ALGORITHM, 3}
+;
+
+KMF_OID
+ KMFOID_SHA1 = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_SHA1},
+ KMFOID_RSA = {OID_PKCS_1_LENGTH+1, OID_RSAEncryption},
+ KMFOID_DSA = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_DSA},
+ KMFOID_MD5WithRSA = {OID_PKCS_1_LENGTH+1, OID_MD5WithRSA},
+ KMFOID_MD2WithRSA = {OID_PKCS_1_LENGTH+1, OID_MD2WithRSA},
+ KMFOID_SHA1WithRSA = {OID_PKCS_1_LENGTH+1, OID_SHA1WithRSA},
+ KMFOID_SHA1WithDSA = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_DSAWithSHA1},
+ KMFOID_OIW_DSAWithSHA1 = {OID_OIW_ALGORITHM_LENGTH+1,
+ OID_OIW_DSAWithSHA1},
+ KMFOID_X9CM_DSA = {OID_X9CM_X9ALGORITHM_LENGTH+1, OID_X9CM_DSA},
+ KMFOID_X9CM_DSAWithSHA1 = {OID_X9CM_X9ALGORITHM_LENGTH+1,
+ OID_X9CM_DSAWithSHA1}
+
+;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _OIDSALG_H */
diff --git a/usr/src/lib/libkmf/include/pem_encode.h b/usr/src/lib/libkmf/include/pem_encode.h
new file mode 100644
index 0000000000..7ba568d2cf
--- /dev/null
+++ b/usr/src/lib/libkmf/include/pem_encode.h
@@ -0,0 +1,137 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PEM_ENCODE_H
+#define _PEM_ENCODE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+#define PEM_STRING_X509 "CERTIFICATE"
+#define PEM_STRING_X509_REQ "CERTIFICATE REQUEST"
+#define PEM_STRING_X509_CRL "X509 CRL"
+#define PEM_BUFSIZE 1024
+
+/*
+ * 0xF0 is a EOLN
+ * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
+ * 0xF2 is EOF
+ * 0xE0 is ignore at start of line.
+ * 0xFF is error
+ */
+
+#define B64_EOLN 0xF0
+#define B64_CR 0xF1
+#define B64_EOF 0xF2
+#define B64_WS 0xE0
+#define B64_ERROR 0xFF
+#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3)
+
+typedef struct pem_encode_ctx_st
+{
+ int num; /* number saved in a partial encode/decode */
+ /*
+ * The length is either the output line length
+ * (in input bytes) or the shortest input line
+ * length that is ok. Once decoding begins,
+ * the length is adjusted up each time a longer
+ * line is decoded.
+ */
+ int length;
+ unsigned char enc_data[80]; /* data to encode */
+ int line_num; /* number read on current line */
+ int expect_nl;
+} PEM_ENCODE_CTX;
+
+KMF_RETURN
+Der2Pem(KMF_OBJECT_TYPE, unsigned char *, int, unsigned char **, int *);
+
+KMF_RETURN
+Pem2Der(unsigned char *, int, unsigned char **, int *);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _PEM_ENCODE_H */
diff --git a/usr/src/lib/libkmf/include/rdn_parser.h b/usr/src/lib/libkmf/include/rdn_parser.h
new file mode 100644
index 0000000000..d94208e1b2
--- /dev/null
+++ b/usr/src/lib/libkmf/include/rdn_parser.h
@@ -0,0 +1,126 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _RDN_PARSER_H
+#define _RDN_PARSER_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+typedef enum {
+ OID_AVA_COMMON_NAME = 0,
+ OID_AVA_SURNAME,
+ OID_AVA_GIVEN_NAME,
+ OID_AVA_LOCALITY,
+ OID_AVA_STATE_OR_PROVINCE,
+ OID_AVA_ORGANIZATION_NAME,
+ OID_AVA_ORGANIZATIONAL_UNIT_NAME,
+ OID_AVA_COUNTRY_NAME,
+ OID_AVA_STREET_ADDRESS,
+ OID_AVA_DC,
+ OID_RFC1274_UID,
+ OID_PKCS9_EMAIL_ADDRESS,
+ OID_RFC1274_MAIL,
+ OID_UNKNOWN
+} OidAvaTag;
+
+struct NameToKind {
+ const char *name;
+ OidAvaTag kind;
+ KMF_OID *OID;
+};
+
+#define C_DOUBLE_QUOTE '\042'
+
+#define C_BACKSLASH '\134'
+
+#define C_EQUAL '='
+
+#define OPTIONAL_SPACE(c) \
+ (((c) == ' ') || ((c) == '\r') || ((c) == '\n'))
+
+#define SPECIAL_CHAR(c) \
+ (((c) == ',') || ((c) == '=') || ((c) == C_DOUBLE_QUOTE) || \
+ ((c) == '\r') || ((c) == '\n') || ((c) == '+') || \
+ ((c) == '<') || ((c) == '>') || ((c) == '#') || \
+ ((c) == ';') || ((c) == C_BACKSLASH))
+
+
+#define IS_PRINTABLE(c) \
+ ((((c) >= 'a') && ((c) <= 'z')) || \
+ (((c) >= 'A') && ((c) <= 'Z')) || \
+ (((c) >= '0') && ((c) <= '9')) || \
+ ((c) == ' ') || \
+ ((c) == '\'') || \
+ ((c) == '\050') || /* ( */ \
+ ((c) == '\051') || /* ) */ \
+ (((c) >= '+') && ((c) <= '/')) || /* + , - . / */ \
+ ((c) == ':') || \
+ ((c) == '=') || \
+ ((c) == '?'))
+
+
+KMF_RETURN ParseDistinguishedName(char *, int, KMF_X509_NAME *);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _RDN_PARSER_H */
diff --git a/usr/src/lib/libkmf/libkmf/Makefile b/usr/src/lib/libkmf/libkmf/Makefile
new file mode 100644
index 0000000000..ebc53eefb3
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/Makefile
@@ -0,0 +1,51 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libkmf/libkmf/Makefile
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS= $(MACH)
+
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+check := TARGET= check
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/libkmf/Makefile.com b/usr/src/lib/libkmf/libkmf/Makefile.com
new file mode 100644
index 0000000000..fc951c006b
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/Makefile.com
@@ -0,0 +1,76 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY= libkmf.a
+VERS= .1
+
+OBJECTS= \
+ algoid.o \
+ algorithm.o \
+ certgetsetop.o \
+ certop.o \
+ client.o \
+ csrcrlop.o \
+ generalop.o \
+ keyop.o \
+ kmfoids.o \
+ pem_encode.o \
+ pk11tokens.o \
+ policy.o \
+ pk11keys.o \
+ rdn_parser.o
+
+BERDERLIB= -lkmfberder
+BERDERLIB64= -lkmfberder
+
+CRYPTOUTILLIB= -lcryptoutil
+CRYPTOUTILLIB64= -lcryptoutil
+
+include $(SRC)/lib/Makefile.lib
+
+SRCDIR= ../common
+INCDIR= ../../include
+
+LIBS= $(DYNLIB) $(LINTLIB)
+
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+LDLIBS += $(BERDERLIB) $(CRYPTOUTILLIB) -lpkcs11 -lnsl -lsocket -lc
+LDLIBS64 += $(BERDERLIB64) $(CRYPTOUTILLIB64) -lpkcs11 -lnsl -lsocket -lc
+
+# DYNLIB libraries do not have lint libs and are not linted
+$(DYNLIB) := LDLIBS += -lxml2
+$(DYNLIB64) := LDLIBS64 += -lxml2
+
+CPPFLAGS += -I$(INCDIR) -I/usr/include/libxml2 -I../../ber_der/inc -I$(SRCDIR)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/libkmf/amd64/Makefile b/usr/src/lib/libkmf/libkmf/amd64/Makefile
new file mode 100644
index 0000000000..3dfc6b7784
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/amd64/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libkmf/libkmf/common/algoid.c b/usr/src/lib/libkmf/libkmf/common/algoid.c
new file mode 100644
index 0000000000..cbe2bd8f4c
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/algoid.c
@@ -0,0 +1,126 @@
+/*
+ * 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
+ *
+ * ----------------------------------------------------------------------
+ * File: algoid.c
+ *
+ * Copyright (c) 1995-2000 Intel Corporation. All rights reserved.
+ * ----------------------------------------------------------------------
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <kmfapiP.h>
+#include <oidsalg.h>
+
+typedef struct {
+ KMF_OID * AlgOID;
+ KMF_ALGORITHM_INDEX AlgID;
+} KMF_OID_ID;
+
+/*
+ * The following table defines the mapping of AlgOID's to AlgID's.
+ */
+static KMF_OID_ID ALGOID_ID_Table[] = {
+ {&KMFOID_X9CM_DSA, KMF_ALGID_DSA},
+ {&KMFOID_X9CM_DSAWithSHA1, KMF_ALGID_SHA1WithDSA},
+ {&KMFOID_SHA1, KMF_ALGID_SHA1},
+ {&KMFOID_RSA, KMF_ALGID_RSA},
+ {&KMFOID_DSA, KMF_ALGID_DSA},
+ {&KMFOID_MD5WithRSA, KMF_ALGID_MD5WithRSA},
+ {&KMFOID_MD2WithRSA, KMF_ALGID_MD2WithRSA},
+ {&KMFOID_SHA1WithRSA, KMF_ALGID_SHA1WithRSA},
+ {&KMFOID_SHA1WithDSA, KMF_ALGID_SHA1WithDSA}
+};
+
+#define NUM_ALGOIDS ((sizeof (ALGOID_ID_Table))/(sizeof (ALGOID_ID_Table[0])))
+
+/*
+ * Name: X509_AlgIdToAlgorithmOid
+ *
+ * Description:
+ * This function maps the specified AlgID to the corresponding
+ * Algorithm OID.
+ *
+ * Parameters:
+ * alg_int - AlgID to be mapped.
+ *
+ * Return value:
+ * Pointer to OID structure and NULL in case of failure.
+ *
+ */
+KMF_OID *
+X509_AlgIdToAlgorithmOid(KMF_ALGORITHM_INDEX alg_int)
+{
+ int i;
+
+ switch (alg_int) {
+ case KMF_ALGID_NONE:
+ return (NULL);
+
+ default:
+ for (i = 0; i < NUM_ALGOIDS; i++) {
+ if (ALGOID_ID_Table[i].AlgID == alg_int)
+ return (ALGOID_ID_Table[i].AlgOID);
+ }
+ break;
+ }
+
+ return (NULL);
+}
+
+/*
+ * Name: X509_AlgorithmOidToAlgId
+ *
+ * Description:
+ * This function maps the specified Algorithm OID to the corresponding
+ * AlgID.
+ *
+ * Parameters:
+ * Oid - OID to be mapped.
+ *
+ * Return value:
+ * Algorithm ID and KMF_ALGID_NONE in case of failures.
+ */
+KMF_ALGORITHM_INDEX
+X509_AlgorithmOidToAlgId(KMF_OID * Oid)
+{
+ int i;
+
+ if ((Oid == NULL) ||
+ (Oid->Data == NULL) ||
+ (Oid->Length == 0)) {
+ return (KMF_ALGID_NONE);
+ }
+
+ for (i = 0; i < NUM_ALGOIDS; i++) {
+ if (IsEqualOid(ALGOID_ID_Table[i].AlgOID, Oid))
+ return (ALGOID_ID_Table[i].AlgID);
+ }
+
+ return (KMF_ALGID_NONE);
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/algorithm.c b/usr/src/lib/libkmf/libkmf/common/algorithm.c
new file mode 100644
index 0000000000..fd8bfc0a2d
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/algorithm.c
@@ -0,0 +1,172 @@
+/*
+ * 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
+ *
+ * File: algorithm.c
+ *
+ * Copyright (c) 1995-2000 Intel Corporation. All rights reserved.
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <kmfapiP.h>
+#include <algorithm.h>
+#include <security/cryptoki.h>
+
+typedef struct _pkcs_key_type_map
+{
+ KMF_ALGORITHM_INDEX CssmAlgorithmId;
+ CK_KEY_TYPE ckKeyType;
+}
+PKCS_KEY_TYPE_MAP;
+
+static const PKCS_KEY_TYPE_MAP _PKCS2KMFKeyTypeMap[] = {
+ { KMF_ALGID_RSA, CKK_RSA },
+ { KMF_ALGID_DSA, CKK_DSA }
+};
+
+#define SUP(_ckmech_, _kmfalg_, _kmfcls_, _kmfmode_, _multi_, \
+ _fixkelen_, _keylen_, _fixblksz_, _blksz_, _reqiv_, _ivlen_,\
+ _regalgflg_, _keytype_, _desc_) \
+ { _ckmech_, _kmfalg_, _kmfcls_, _kmfmode_, _multi_, _fixkelen_,\
+ _keylen_, _fixblksz_, _blksz_, _reqiv_, _ivlen_, _regalgflg_,\
+ _keytype_, _desc_ },
+
+static const PKCS_ALGORITHM_MAP _PKCS2KMFMap[] = {
+/*
+ * PKCS #11 Mechanism,
+ * Alg. ID
+ * Alg. Class
+ * Alg. Mode
+ * Milti-Part
+ * Fix Key Length
+ * Key Length
+ * Fix Block Size
+ * Block Size
+ * Needs IV
+ * IV Length
+ * Alg. Flags
+ * Type
+ * Description
+ */
+SUP(CKM_RSA_PKCS_KEY_PAIR_GEN, KMF_ALGID_RSA, KMF_ALGCLASS_KEYGEN,\
+ KMF_ALGMODE_NONE, 0, 0, 0,\
+ 0, 0, 0, 0, CKF_GENERATE_KEY_PAIR,\
+ CKK_RSA, "RSA PKCS #1 Key Pair Generation")
+SUP(CKM_RSA_X_509, KMF_ALGID_RSA, KMF_ALGCLASS_ASYMMETRIC, KMF_ALGMODE_NONE,
+ 0, 0, 0, 0, 0, 0, 0, CKF_ENCRYPT,
+ CKK_RSA, "RSA RAW Encryption")
+SUP(CKM_RSA_X_509, KMF_ALGID_RSA, KMF_ALGCLASS_ASYMMETRIC, KMF_ALGMODE_NONE,
+ 0, 0, 0, 0, 0, 0, 0, CKF_SIGN_RECOVER,
+ CKK_RSA, "RSA RAW Private Key Encryption")
+SUP(CKM_RSA_X_509, KMF_ALGID_RSA, KMF_ALGCLASS_SIGNATURE, KMF_ALGMODE_NONE,
+ 0, 0, 0, 0, 0, 0, 0, CKF_SIGN,
+ CKK_RSA, "RSA RAW Signature")
+SUP(CKM_RSA_PKCS, KMF_ALGID_RSA, KMF_ALGCLASS_SIGNATURE,
+ KMF_ALGMODE_PKCS1_EMSA_V15,
+ 0, 0, 0, 0, 0, 0, 0, CKF_SIGN, CKK_RSA,
+ "RSA PKCS #1 Signature")
+SUP(CKM_MD2_RSA_PKCS, KMF_ALGID_MD2WithRSA, KMF_ALGCLASS_SIGNATURE,
+ KMF_ALGMODE_PKCS1_EMSA_V15, 1, 0, 0, 0, 0,
+ 0, 0, CKF_SIGN, CKK_RSA, "MD2 w/RSA Signature")
+SUP(CKM_MD5_RSA_PKCS, KMF_ALGID_MD5WithRSA, KMF_ALGCLASS_SIGNATURE,
+ KMF_ALGMODE_PKCS1_EMSA_V15, 1, 0, 0, 0, 0,
+ 0, 0, CKF_SIGN, CKK_RSA, "MD5 w/RSA Signature")
+SUP(CKM_SHA1_RSA_PKCS, KMF_ALGID_SHA1WithRSA, KMF_ALGCLASS_SIGNATURE,
+ KMF_ALGMODE_PKCS1_EMSA_V15, 1, 0, 0, 0, 0,
+ 0, 0, CKF_SIGN, CKK_RSA, "SHA-1 w/RSA Signature")
+
+SUP(CKM_DSA_KEY_PAIR_GEN, KMF_ALGID_DSA, KMF_ALGCLASS_KEYGEN, KMF_ALGMODE_NONE,
+ 0, 0, 0, 0, 0, 0, 0,
+ CKF_GENERATE_KEY_PAIR, CKK_DSA, "DSA Key Pair Generation")
+
+SUP(CKM_DSA, KMF_ALGID_DSA, KMF_ALGCLASS_SIGNATURE, KMF_ALGMODE_NONE,
+ 0, 0, 0, 0, 0, 0, 0, CKF_SIGN,
+ CKK_DSA, "DSA Signature")
+
+SUP(CKM_DSA_SHA1, KMF_ALGID_SHA1WithDSA, KMF_ALGCLASS_SIGNATURE,
+ KMF_ALGMODE_NONE, 1, 0, 0, 0, 0, 0,
+ 0, CKF_SIGN, CKK_DSA, "SHA-1 w/DSA Signature")
+
+SUP(CKM_SHA_1, KMF_ALGID_SHA1, KMF_ALGCLASS_DIGEST, KMF_ALGMODE_NONE,
+ 1, 1, 20, 0, 0, 0, 0, CKF_DIGEST, (CK_KEY_TYPE)-1, "SHA-1")
+};
+
+/* Undefine the macro definitions */
+#undef SUP
+
+/* Number of items in the algorithm map table */
+#define _PKCS2KMFMapCount (\
+ sizeof (_PKCS2KMFMap) / sizeof (_PKCS2KMFMap[0]))
+
+/* Indicator that the algorithm was not found */
+#define PKCS_ALGORITHM_NOT_FOUND ((uint32_t)(~0))
+
+/*
+ * Name: PKCSConv_GetMechanism
+ *
+ * Description:
+ * Searches the _PKCS2KMFMap table for a matching set of CSSM alg.
+ * description parameters.
+ *
+ * Parameters:
+ * algType (input) - KMF_ALGCLASS_* identifier to match.
+ * algID (input) - KMF_ALGID_* identifier to match.
+ * mode (input) - KMF_ALGMODE_* identifier to match. Use
+ * KMF_ALGMODE_NONE if a mode does not apply.
+ *
+ * Returns:
+ * Pointer to the lookup table entry that matches requested parameters.
+ * Ptr->keylength will equal PKCS11CONVERT_NOT_FOUND if no match is found.
+ */
+PKCS_ALGORITHM_MAP *
+PKCS_GetAlgorithmMap(KMF_ALGCLASS algType, uint32_t algID, uint32_t mode)
+{
+ uint32_t i = 0;
+
+ for (i = 0; i < _PKCS2KMFMapCount; i++) {
+ if ((_PKCS2KMFMap[i].context_type == algType) &&
+ (_PKCS2KMFMap[i].algorithm == algID) &&
+ (_PKCS2KMFMap[i].enc_mode == mode)) {
+ return ((PKCS_ALGORITHM_MAP *)&(_PKCS2KMFMap[i]));
+ }
+ }
+
+ return (NULL);
+}
+
+KMF_BOOL
+PKCS_ConvertAlgorithmId2PKCSKeyType(KMF_ALGORITHM_INDEX AlgId,
+ CK_KEY_TYPE *pckKeyType)
+{
+ uint32_t uIndex;
+ uint32_t uMapSize = sizeof (_PKCS2KMFKeyTypeMap) /
+ sizeof (PKCS_KEY_TYPE_MAP);
+
+ for (uIndex = 0; uIndex < uMapSize; uIndex++) {
+ if (_PKCS2KMFKeyTypeMap[uIndex].CssmAlgorithmId == AlgId) {
+ *pckKeyType = _PKCS2KMFKeyTypeMap[uIndex].ckKeyType;
+ return (1);
+ }
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/certgetsetop.c b/usr/src/lib/libkmf/libkmf/common/certgetsetop.c
new file mode 100644
index 0000000000..15b490b6f7
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/certgetsetop.c
@@ -0,0 +1,2300 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright(c) 1995-2000 Intel Corporation. All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <link.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ber_der.h>
+#include <kmfapiP.h>
+#include <libgen.h>
+#include <cryptoutil.h>
+
+KMF_RETURN
+copy_data(KMF_DATA *dst, KMF_DATA *src)
+{
+ KMF_RETURN ret = KMF_OK;
+
+ if (dst == NULL || src == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ dst->Data = malloc(src->Length);
+ if (dst->Data == NULL)
+ return (KMF_ERR_MEMORY);
+
+ dst->Length = src->Length;
+ (void) memcpy(dst->Data, src->Data, src->Length);
+
+ return (ret);
+}
+
+static KMF_RETURN
+copy_extension_data(KMF_X509_EXTENSION *dstext,
+ KMF_X509_EXTENSION *srcext)
+{
+ KMF_RETURN ret = KMF_OK;
+
+ if (dstext == NULL || srcext == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(dstext, 0, sizeof (KMF_X509_EXTENSION));
+
+ ret = copy_data(&dstext->extnId, &srcext->extnId);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ dstext->extnId.Length = srcext->extnId.Length;
+ dstext->critical = srcext->critical;
+ dstext->format = srcext->format;
+
+ ret = copy_data(&dstext->BERvalue, &srcext->BERvalue);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ dstext->value.tagAndValue = malloc(sizeof (KMF_X509EXT_TAGandVALUE));
+ if (dstext->value.tagAndValue == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ (void) memset(dstext->value.tagAndValue, 0,
+ sizeof (KMF_X509EXT_TAGandVALUE));
+
+ ret = copy_data(&dstext->value.tagAndValue->value,
+ &srcext->value.tagAndValue->value);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ dstext->value.tagAndValue->type = srcext->value.tagAndValue->type;
+
+cleanup:
+ if (ret != KMF_OK) {
+ if (dstext->extnId.Data != NULL)
+ KMF_FreeData(&dstext->extnId);
+
+ if (dstext->BERvalue.Data != NULL)
+ KMF_FreeData(&dstext->BERvalue);
+
+ if (dstext->value.tagAndValue->value.Data == NULL)
+ KMF_FreeData(&dstext->value.tagAndValue->value);
+ }
+
+ return (ret);
+}
+
+/*
+ * Given a block of DER encoded X.509 certificate data and
+ * an OID for the desired extension, this routine will
+ * parse the cert data and return the data associated with
+ * the extension if it is found.
+ *
+ * RETURNS:
+ * KMF_OK - if extension found and copied OK.
+ * KMF_ERR_EXTENSION_NOT_FOUND - extension not found.
+ * parsing and memory allocation errors are also possible.
+ */
+KMF_RETURN
+KMF_GetCertExtensionData(const KMF_DATA *certdata,
+ KMF_OID *extoid, KMF_X509_EXTENSION *extdata)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_CERTIFICATE *cert = NULL;
+ KMF_X509_EXTENSION *eptr = NULL;
+ int i, found = 0;
+
+ if (certdata == NULL || extoid == NULL || extdata == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ ret = DerDecodeSignedCertificate(certdata, &cert);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (cert->certificate.extensions.numberOfExtensions == 0)
+ return (KMF_ERR_EXTENSION_NOT_FOUND);
+
+ (void) memset((void *)extdata, 0, sizeof (KMF_X509_EXTENSION));
+ for (i = 0; !found &&
+ i < cert->certificate.extensions.numberOfExtensions;
+ i++) {
+ eptr = &cert->certificate.extensions.extensions[i];
+ if (IsEqualOid(extoid, &eptr->extnId)) {
+ ret = copy_extension_data(extdata, eptr);
+ found++;
+ }
+ }
+ if (!found)
+ ret = KMF_ERR_EXTENSION_NOT_FOUND;
+
+ if (cert != NULL) {
+ KMF_FreeSignedCert(cert);
+ free(cert);
+ }
+
+ return (ret);
+}
+
+/*
+ * Given a block of DER encoded X.509 certificate data,
+ * search the extensions and return the OIDs for all
+ * extensions marked "critical".
+ *
+ *
+ * RETURNS:
+ * KMF_OK - if extension found and copied OK.
+ * parsing and memory allocation errors are also possible.
+ *
+ * OIDlist - array of KMF_OID records, allocated
+ * by this function.
+ * NumOIDs - number of critical extensions found.
+ */
+KMF_RETURN
+KMF_GetCertCriticalExtensions(const KMF_DATA *certdata,
+ KMF_X509_EXTENSION **extlist, int *nextns)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_CERTIFICATE *cert;
+ KMF_X509_EXTENSION *eptr, *elist;
+ int i;
+
+ if (certdata == NULL || extlist == NULL || nextns == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ *nextns = 0;
+ *extlist = elist = NULL;
+ ret = DerDecodeSignedCertificate(certdata, &cert);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (cert->certificate.extensions.numberOfExtensions == 0)
+ return (KMF_ERR_EXTENSION_NOT_FOUND);
+
+ for (i = 0; i < cert->certificate.extensions.numberOfExtensions;
+ i++) {
+ eptr = &cert->certificate.extensions.extensions[i];
+ if (eptr->critical != 0) {
+ (*nextns)++;
+ elist = realloc(elist, sizeof (KMF_X509_EXTENSION) *
+ (*nextns));
+ if (elist == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+ ret = copy_extension_data(&elist[(*nextns) - 1],
+ eptr);
+ if (ret != KMF_OK)
+ goto end;
+ }
+ }
+end:
+ KMF_FreeSignedCert(cert);
+ free(cert);
+ if (ret != KMF_OK) {
+ if (elist != NULL) {
+ free(elist);
+ elist = NULL;
+ }
+ *nextns = 0;
+ }
+ *extlist = elist;
+
+ return (ret);
+}
+
+/*
+ * Given a block of DER encoded X.509 certificate data,
+ * search the extensions and return the OIDs for all
+ * extensions NOT marked "critical".
+ *
+ *
+ * RETURNS:
+ * KMF_OK - if extension found and copied OK.
+ * parsing and memory allocation errors are also possible.
+ *
+ * OIDlist - array of KMF_OID records, allocated
+ * by this function.
+ * NumOIDs - number of critical extensions found.
+ */
+KMF_RETURN
+KMF_GetCertNonCriticalExtensions(const KMF_DATA *certdata,
+ KMF_X509_EXTENSION **extlist, int *nextns)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_CERTIFICATE *cert;
+ KMF_X509_EXTENSION *eptr, *elist;
+ int i;
+
+ if (certdata == NULL || extlist == NULL || nextns == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ *nextns = 0;
+ *extlist = elist = NULL;
+ ret = DerDecodeSignedCertificate(certdata, &cert);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (cert->certificate.extensions.numberOfExtensions == 0)
+ return (KMF_ERR_EXTENSION_NOT_FOUND);
+
+ for (i = 0; i < cert->certificate.extensions.numberOfExtensions;
+ i++) {
+ eptr = &cert->certificate.extensions.extensions[i];
+ if (eptr->critical == 0) {
+ (*nextns)++;
+ elist = realloc(elist, sizeof (KMF_X509_EXTENSION) *
+ (*nextns));
+ if (elist == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+ ret = copy_extension_data(&elist[(*nextns) - 1],
+ eptr);
+ if (ret != KMF_OK)
+ goto end;
+ }
+ }
+end:
+ KMF_FreeSignedCert(cert);
+ free(cert);
+ if (ret != KMF_OK) {
+ if (elist != NULL) {
+ free(elist);
+ elist = NULL;
+ }
+ *nextns = 0;
+ }
+ *extlist = elist;
+
+ return (ret);
+}
+
+/*
+ * If the given certificate data (X.509 DER encoded data)
+ * contains the Key Usage extension, parse that
+ * data and return it in the KMF_X509EXT_BASICCONSTRAINTS
+ * record.
+ *
+ * RETURNS:
+ * KMF_OK - success
+ * KMF_ERR_BAD_PARAMETER - input data was bad.
+ * KMF_ERR_EXTENSION_NOT_FOUND - extension not found.
+ */
+KMF_RETURN
+KMF_GetCertKeyUsageExt(const KMF_DATA *certdata,
+ KMF_X509EXT_KEY_USAGE *keyusage)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSION extn;
+
+ if (certdata == NULL || keyusage == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&extn, 0, sizeof (extn));
+ /*
+ * Check standard KeyUsage bits
+ */
+ ret = KMF_GetCertExtensionData(certdata,
+ (KMF_OID *)&KMFOID_KeyUsage, &extn);
+
+ if (ret != KMF_OK) {
+ goto end;
+ }
+ keyusage->critical = (extn.critical != 0);
+ if (extn.value.tagAndValue->value.Length > 1) {
+ keyusage->KeyUsageBits =
+ extn.value.tagAndValue->value.Data[1] << 8;
+ } else {
+ keyusage->KeyUsageBits =
+ extn.value.tagAndValue->value.Data[0];
+ }
+end:
+ KMF_FreeExtension(&extn);
+ return (ret);
+}
+
+static KMF_BOOL
+isEKUPresent(KMF_X509EXT_EKU *ekuptr, KMF_OID *ekuoid)
+{
+ int i;
+
+ if (ekuptr == NULL || ekuoid == NULL)
+ return (0);
+
+ for (i = 0; i < ekuptr->nEKUs; i++)
+ if (IsEqualOid(&ekuptr->keyPurposeIdList[i], ekuoid))
+ return (1);
+
+ return (0);
+}
+
+static KMF_RETURN
+parse_eku_data(const KMF_DATA *asn1data, KMF_X509EXT_EKU *ekuptr)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *asn1 = NULL;
+ BerValue exdata;
+ KMF_OID oid;
+ char *end = NULL;
+ ber_len_t size;
+
+ /*
+ * Decode the ASN.1 data for the extension.
+ */
+ exdata.bv_val = (char *)asn1data->Data;
+ exdata.bv_len = asn1data->Length;
+
+ if ((asn1 = kmfder_init(&exdata)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ /*
+ * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+ */
+ if (kmfber_first_element(asn1, &size, &end) !=
+ BER_OBJECT_IDENTIFIER) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+
+ /*
+ * Count the number of EKU OIDs and store in
+ * the array.
+ */
+ while (kmfber_next_element(asn1, &size, end) ==
+ BER_OBJECT_IDENTIFIER) {
+
+ /* Skip over the CONSTRUCTED SET tag */
+ if (kmfber_scanf(asn1, "D", &oid) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ ekuptr->nEKUs++;
+ ekuptr->keyPurposeIdList = realloc(ekuptr->keyPurposeIdList,
+ ekuptr->nEKUs * sizeof (KMF_OID));
+ if (ekuptr->keyPurposeIdList == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+ ekuptr->keyPurposeIdList[ekuptr->nEKUs - 1] = oid;
+ }
+
+end:
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+
+ if (ret != KMF_OK) {
+ if (ekuptr->keyPurposeIdList != NULL) {
+ free_keyidlist(ekuptr->keyPurposeIdList, ekuptr->nEKUs);
+ ekuptr->keyPurposeIdList = NULL;
+ ekuptr->critical = 0;
+ }
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetCertEKU(const KMF_DATA *certdata,
+ KMF_X509EXT_EKU *ekuptr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSION extn;
+
+ if (certdata == NULL || ekuptr == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&extn, 0, sizeof (KMF_X509_EXTENSION));
+
+ ekuptr->nEKUs = 0;
+ ekuptr->keyPurposeIdList = NULL;
+ ekuptr->critical = 0;
+
+ ret = KMF_GetCertExtensionData(certdata,
+ (KMF_OID *)&KMFOID_ExtendedKeyUsage, &extn);
+
+ if (ret != KMF_OK) {
+ goto end;
+ }
+
+ ret = parse_eku_data(&extn.BERvalue, ekuptr);
+
+end:
+ KMF_FreeExtension(&extn);
+
+ return (ret);
+}
+
+/*
+ * If the given certificate data (X.509 DER encoded data)
+ * contains the Basic Constraints extension, parse that
+ * data and return it in the KMF_X509EXT_BASICCONSTRAINTS
+ * record.
+ *
+ * RETURNS:
+ * KMF_OK - success
+ * KMF_ERR_BAD_PARAMETER - input data was bad.
+ * KMF_ERR_EXTENSION_NOT_FOUND - extension not found.
+ */
+KMF_RETURN
+KMF_GetCertBasicConstraintExt(const KMF_DATA *certdata,
+ KMF_BOOL *critical, KMF_X509EXT_BASICCONSTRAINTS *constraint)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSION extn;
+ BerElement *asn1 = NULL;
+ BerValue exdata;
+ ber_len_t size;
+ char *end = NULL;
+ int tag;
+
+ if (certdata == NULL || constraint == NULL || critical == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&extn, 0, sizeof (KMF_X509_EXTENSION));
+ ret = KMF_GetCertExtensionData(certdata,
+ (KMF_OID *)&KMFOID_BasicConstraints, &extn);
+
+ if (ret != KMF_OK) {
+ goto end;
+ }
+
+ *critical = (extn.critical != 0);
+
+ exdata.bv_val = (char *)extn.value.tagAndValue->value.Data;
+ exdata.bv_len = extn.value.tagAndValue->value.Length;
+
+ if ((asn1 = kmfder_init(&exdata)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ if (kmfber_scanf(asn1, "b", &constraint->cA) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ constraint->pathLenConstraintPresent = KMF_FALSE;
+
+ tag = kmfber_next_element(asn1, &size, end);
+ if (tag == BER_INTEGER) {
+ if (kmfber_scanf(asn1, "i",
+ &constraint->pathLenConstraint) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ constraint->pathLenConstraintPresent = KMF_TRUE;
+ }
+end:
+ KMF_FreeExtension(&extn);
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+
+ return (ret);
+}
+
+static KMF_X509EXT_POLICYQUALIFIERINFO *
+get_pqinfo(BerElement *asn1)
+{
+ KMF_X509EXT_POLICYQUALIFIERINFO *pqinfo = NULL;
+ KMF_RETURN ret = KMF_OK;
+ int tag;
+ ber_len_t size;
+ char *end = NULL;
+
+ /*
+ * Policy Qualifiers may be a list of sequences.
+ *
+ * PolicyInformation ::= SEQUENCE {
+ * policyIdentifier CertPolicyId,
+ * policyQualifiers SEQUENCE SIZE (1..MAX) OF
+ * PolicyQualifierInfo OPTIONAL
+ * }
+ *
+ * PolicyQualifierInfo ::= SEQUENCE {
+ * policyQualifierId PolicyQualifierId,
+ * qualifier ANY DEFINED BY policyQualifierId
+ * }
+ */
+
+
+ /*
+ * We already got the CertPolicyId, we just need to
+ * find all of the policyQualifiers in the set.
+ *
+ * Mark the first element of the SEQUENCE and reset the end ptr
+ * so the ber/der code knows when to stop looking.
+ */
+ if ((tag = kmfber_first_element(asn1, &size, &end)) !=
+ BER_CONSTRUCTED_SEQUENCE) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ /* We found a sequence, loop until done */
+ while ((tag = kmfber_next_element(asn1, &size, end)) ==
+ BER_CONSTRUCTED_SEQUENCE) {
+
+ /* Skip over the CONSTRUCTED SET tag */
+ if (kmfber_scanf(asn1, "T", &tag) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ /*
+ * Allocate memory for the Policy Qualifier Info
+ */
+ pqinfo = malloc(sizeof (KMF_X509EXT_POLICYQUALIFIERINFO));
+ if (pqinfo == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+ (void) memset((void *)pqinfo, 0,
+ sizeof (KMF_X509EXT_POLICYQUALIFIERINFO));
+ /*
+ * Read the PolicyQualifier OID
+ */
+ if (kmfber_scanf(asn1, "D",
+ &pqinfo->policyQualifierId) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ /*
+ * The OID of the policyQualifierId determines what
+ * sort of data comes next.
+ */
+ if (IsEqualOid(&pqinfo->policyQualifierId,
+ (KMF_OID *)&KMFOID_PKIX_PQ_CPSuri)) {
+ /*
+ * CPS uri must be an IA5STRING
+ */
+ if (kmfber_scanf(asn1, "tl", &tag, &size) ==
+ KMFBER_DEFAULT || tag != BER_IA5STRING ||
+ size == 0) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ if ((pqinfo->value.Data = malloc(size)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+ if (kmfber_scanf(asn1, "s", pqinfo->value.Data,
+ &pqinfo->value.Length) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ } else if (IsEqualOid(&pqinfo->policyQualifierId,
+ (KMF_OID *)&KMFOID_PKIX_PQ_Unotice)) {
+ if (kmfber_scanf(asn1, "tl", &tag, &size) ==
+ KMFBER_DEFAULT ||
+ tag != BER_CONSTRUCTED_SEQUENCE) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ /*
+ * For now, just copy the while UserNotice ASN.1
+ * blob into the pqinfo data record.
+ * TBD - parse it into individual fields.
+ */
+ if ((pqinfo->value.Data = malloc(size)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+ if (kmfber_scanf(asn1, "s", pqinfo->value.Data,
+ &pqinfo->value.Length) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ } else {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ }
+end:
+ if (ret != KMF_OK) {
+ if (pqinfo != NULL) {
+ KMF_FreeData(&pqinfo->value);
+ KMF_FreeData(&pqinfo->policyQualifierId);
+ free(pqinfo);
+ pqinfo = NULL;
+ }
+ }
+ return (pqinfo);
+}
+
+/*
+ * If the given certificate data (X.509 DER encoded data)
+ * contains the Certificate Policies extension, parse that
+ * data and return it in the KMF_X509EXT_CERT_POLICIES
+ * record.
+ *
+ * RETURNS:
+ * KMF_OK - success
+ * KMF_ERR_BAD_PARAMETER - input data was bad.
+ * KMF_ERR_EXTENSION_NOT_FOUND - extension not found.
+ * parsing and memory allocation errors are also possible.
+ */
+KMF_RETURN
+KMF_GetCertPoliciesExt(const KMF_DATA *certdata,
+ KMF_BOOL *critical, KMF_X509EXT_CERT_POLICIES *extptr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSION extn;
+ KMF_X509EXT_POLICYINFO *pinfo;
+ KMF_X509EXT_POLICYQUALIFIERINFO *pqinfo;
+ BerElement *asn1 = NULL;
+ BerValue exdata;
+ ber_len_t size;
+ char *end = NULL;
+ int tag;
+
+ if (certdata == NULL || critical == NULL || extptr == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&extn, 0, sizeof (extn));
+ ret = KMF_GetCertExtensionData(certdata,
+ (KMF_OID *)&KMFOID_CertificatePolicies, &extn);
+
+ if (ret != KMF_OK) {
+ goto end;
+ }
+
+ *critical = (extn.critical != 0);
+
+ /*
+ * Decode the ASN.1 data for the extension.
+ */
+ exdata.bv_val = (char *)extn.BERvalue.Data;
+ exdata.bv_len = extn.BERvalue.Length;
+
+ (void) memset((void *)extptr, 0, sizeof (KMF_X509EXT_CERT_POLICIES));
+
+ if ((asn1 = kmfder_init(&exdata)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ /*
+ * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+ */
+ if ((tag = kmfber_first_element(asn1, &size, &end)) !=
+ BER_CONSTRUCTED_SEQUENCE) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+
+ /*
+ * Collect all of the PolicyInformation SEQUENCES
+ *
+ * PolicyInformation ::= SEQUENCE {
+ * policyIdentifier CertPolicyId,
+ * policyQualifiers SEQUENCE SIZE (1..MAX) OF
+ * PolicyQualifierInfo OPTIONAL
+ * }
+ *
+ * Loop over the SEQUENCES of PolicyInfo
+ */
+ while ((tag = kmfber_next_element(asn1, &size, end)) ==
+ BER_CONSTRUCTED_SEQUENCE) {
+
+ /* Skip over the CONSTRUCTED SET tag */
+ if (kmfber_scanf(asn1, "T", &tag) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+
+ pinfo = malloc(sizeof (KMF_X509EXT_POLICYINFO));
+ if (pinfo == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+ (void) memset((void *)pinfo, 0,
+ sizeof (KMF_X509EXT_POLICYINFO));
+ /*
+ * Decode the PolicyInformation SEQUENCE
+ */
+ if ((tag = kmfber_scanf(asn1, "D",
+ &pinfo->policyIdentifier)) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ /*
+ * Gather all of the associated PolicyQualifierInfo recs
+ */
+ pqinfo = get_pqinfo(asn1);
+ if (pqinfo != NULL) {
+ int cnt =
+ pinfo->policyQualifiers.numberOfPolicyQualifiers;
+ cnt++;
+ pinfo->policyQualifiers.policyQualifier = realloc(
+ pinfo->policyQualifiers.policyQualifier,
+ cnt * sizeof (KMF_X509EXT_POLICYQUALIFIERINFO));
+ if (pinfo->policyQualifiers.policyQualifier == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+ pinfo->policyQualifiers.numberOfPolicyQualifiers =
+ cnt;
+ pinfo->policyQualifiers.policyQualifier[cnt-1] =
+ *pqinfo;
+
+ free(pqinfo);
+ }
+ extptr->numberOfPolicyInfo++;
+ extptr->policyInfo = realloc(extptr->policyInfo,
+ extptr->numberOfPolicyInfo *
+ sizeof (KMF_X509EXT_POLICYINFO));
+ if (extptr->policyInfo == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+ extptr->policyInfo[extptr->numberOfPolicyInfo-1] = *pinfo;
+ free(pinfo);
+ }
+
+
+end:
+ KMF_FreeExtension(&extn);
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+ return (ret);
+}
+
+/*
+ * If the given certificate data (X.509 DER encoded data)
+ * contains the Authority Information Access extension, parse that
+ * data and return it in the KMF_X509EXT_AUTHINFOACCESS
+ * record.
+ *
+ * RETURNS:
+ * KMF_OK - success
+ * KMF_ERR_BAD_PARAMETER - input data was bad.
+ * KMF_ERR_EXTENSION_NOT_FOUND - extension not found.
+ */
+KMF_RETURN
+KMF_GetCertAuthInfoAccessExt(const KMF_DATA *certdata,
+ KMF_X509EXT_AUTHINFOACCESS *aia)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSION extn;
+ BerElement *asn1 = NULL;
+ BerValue exdata;
+ ber_len_t size;
+ char *end = NULL;
+ int tag;
+ KMF_X509EXT_ACCESSDESC *access_info = NULL;
+
+ if (certdata == NULL || aia == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ (void) memset(&extn, 0, sizeof (KMF_X509_EXTENSION));
+ ret = KMF_GetCertExtensionData(certdata,
+ (KMF_OID *)&KMFOID_AuthorityInfoAccess, &extn);
+
+ if (ret != KMF_OK) {
+ goto end;
+ }
+
+ /*
+ * Decode the ASN.1 data for the extension.
+ */
+ exdata.bv_val = (char *)extn.BERvalue.Data;
+ exdata.bv_len = extn.BERvalue.Length;
+
+ (void) memset((void *)aia, 0, sizeof (KMF_X509EXT_AUTHINFOACCESS));
+
+ if ((asn1 = kmfder_init(&exdata)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ /*
+ * AuthorityInfoAccessSyntax ::=
+ * SEQUENCE SIZE (1..MAX) OF AccessDescription
+ */
+ if ((tag = kmfber_first_element(asn1, &size, &end)) !=
+ BER_CONSTRUCTED_SEQUENCE) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+
+ /*
+ * AccessDescription ::= SEQUENCE {
+ * accessMethod OBJECT IDENTIFIER,
+ * accessLocation GeneralName }
+ */
+ while ((tag = kmfber_next_element(asn1, &size, end)) ==
+ BER_CONSTRUCTED_SEQUENCE) {
+
+ /* Skip over the CONSTRUCTED SET tag */
+ if (kmfber_scanf(asn1, "T", &tag) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+
+ access_info = malloc(sizeof (KMF_X509EXT_ACCESSDESC));
+ if (access_info == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ (void) memset((void *)access_info, 0,
+ sizeof (KMF_X509EXT_ACCESSDESC));
+
+ /*
+ * Read the AccessMethod OID
+ */
+ if (kmfber_scanf(asn1, "D",
+ &access_info->AccessMethod) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+
+ /*
+ * The OID of the AccessMethod determines what
+ * sort of data comes next.
+ */
+ if (IsEqualOid(&access_info->AccessMethod,
+ (KMF_OID *)&KMFOID_PkixAdOcsp)) {
+ if (kmfber_scanf(asn1, "tl", &tag, &size) ==
+ KMFBER_DEFAULT || size == 0) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+
+ /*
+ * OCSP uri must be an IA5STRING or a GENNAME_URI
+ * with an implicit tag.
+ */
+ if (tag != BER_IA5STRING &&
+ tag != (0x80 | GENNAME_URI)) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+
+ if ((access_info->AccessLocation.Data =
+ malloc(size)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ if (kmfber_scanf(asn1, "s",
+ access_info->AccessLocation.Data,
+ &access_info->AccessLocation.Length) ==
+ KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ } else if (IsEqualOid(&access_info->AccessMethod,
+ (KMF_OID *)&KMFOID_PkixAdCaIssuers)) {
+ /* will be supported later with PKIX */
+ free(access_info);
+ access_info = NULL;
+ continue;
+ } else {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+
+ aia->numberOfAccessDescription++;
+ aia->AccessDesc = realloc(aia->AccessDesc,
+ aia->numberOfAccessDescription *
+ sizeof (KMF_X509EXT_ACCESSDESC));
+
+ if (aia->AccessDesc == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ aia->AccessDesc[aia->numberOfAccessDescription-1] =
+ *access_info;
+ free(access_info);
+ access_info = NULL;
+ }
+
+end:
+ KMF_FreeExtension(&extn);
+ if (access_info != NULL)
+ free(access_info);
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+ return (ret);
+
+}
+
+/*
+ * This function parses the name portion of a der-encoded distribution point
+ * returns it in the KMF_CRL_DIST_POINT record.
+ *
+ * The "DistributionPointName" syntax is
+ *
+ * DistributionPointName ::= CHOICE {
+ * fullName [0] GeneralNames,
+ * nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
+ *
+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GerneralName
+ *
+ * Note: for phase 1, we support fullName only.
+ */
+static KMF_RETURN
+parse_dp_name(char *dp_der_code, int dp_der_size, KMF_CRL_DIST_POINT *dp)
+{
+ KMF_RETURN ret = KMF_OK;
+ char *url = NULL;
+ BerElement *asn1 = NULL;
+ BerValue ber_data;
+ ber_len_t size;
+ char *end = NULL;
+ int tag;
+ KMF_GENERALNAMES *fullname;
+
+ if (dp_der_code == NULL || dp_der_size == 0 || dp == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ ber_data.bv_val = dp_der_code;
+ ber_data.bv_len = dp_der_size;
+ if ((asn1 = kmfder_init(&ber_data)) == NULL)
+ return (KMF_ERR_BAD_CERT_FORMAT);
+
+ tag = kmfber_first_element(asn1, &size, &end);
+ if (tag != 0xA0 && tag != 0xA1) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto out;
+ }
+
+ if (tag == 0xA0) { /* fullName */
+ dp->type = DP_GENERAL_NAME;
+
+ fullname = &(dp->name.full_name);
+ fullname->number = 0;
+
+ /* Skip over the explicit tag and size */
+ (void) kmfber_scanf(asn1, "T", &tag);
+
+ tag = kmfber_next_element(asn1, &size, end);
+ while (tag != KMFBER_DEFAULT &&
+ tag != KMFBER_END_OF_SEQORSET) {
+
+ if (kmfber_scanf(asn1, "tl", &tag, &size) ==
+ KMFBER_DEFAULT || size == 0) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto out;
+ }
+
+ /* For phase 1, we are interested in a URI name only */
+ if (tag != (0x80 | GENNAME_URI)) {
+ tag = kmfber_next_element(asn1, &size, end);
+ continue;
+ }
+
+ if ((url = malloc(size)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ /* Skip type and len, then read url and save it. */
+ if (kmfber_read(asn1, url, 2) != 2) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto out;
+ }
+
+ if (kmfber_read(asn1, url, size) !=
+ (ber_slen_t)size) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto out;
+ }
+
+ fullname->number++;
+ fullname->namelist = realloc(fullname->namelist,
+ fullname->number * sizeof (KMF_GENERALNAME));
+ if (fullname->namelist == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ fullname->namelist[fullname->number - 1].choice =
+ GENNAME_URI;
+ fullname->namelist[fullname->number - 1].name.Length =
+ size;
+ fullname->namelist[fullname->number - 1].name.Data =
+ (unsigned char *)url;
+
+ /* next */
+ tag = kmfber_next_element(asn1, &size, end);
+ }
+
+ } else if (tag == 0xA1) {
+ /* "nameRelativeToCRLIssuer" is not supported at phase 1. */
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto out;
+ }
+
+out:
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+
+ if (ret != KMF_OK) {
+ free_dp_name(dp);
+ }
+
+ if (ret == KMF_OK && fullname->number == 0) {
+ ret = KMF_ERR_EXTENSION_NOT_FOUND;
+ if (url != NULL)
+ free(url);
+ }
+
+ return (ret);
+}
+
+/*
+ * This function retrieves the CRL Distribution Points extension data from
+ * a DER encoded certificate if it contains this extension, parses the
+ * extension data, and returns it in the KMF_X509EXT_CRLDISTPOINTS record.
+ */
+KMF_RETURN
+KMF_GetCertCRLDistributionPointsExt(const KMF_DATA *certdata,
+ KMF_X509EXT_CRLDISTPOINTS *crl_dps)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSION extn;
+ BerElement *asn1 = NULL;
+ BerValue exdata;
+ ber_len_t size;
+ char *end = NULL;
+ int tag;
+ KMF_CRL_DIST_POINT *dp = NULL;
+ int i;
+
+ if (certdata == NULL || crl_dps == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* Get the ASN.1 data for this extension. */
+ (void) memset(&extn, 0, sizeof (KMF_X509_EXTENSION));
+ ret = KMF_GetCertExtensionData(certdata,
+ (KMF_OID *)&KMFOID_CrlDistributionPoints, &extn);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ /*
+ * Decode the CRLDistributionPoints ASN.1 data. The Syntax for
+ * CRLDistributionPoints is
+ *
+ * CRLDistributionPoints ::=
+ * SEQUENCE SIZE (1..MAX) OF DistributionPoint
+ *
+ * DistributionPoint ::= SEQUENCE {
+ * distributionPoint [0] DistributionPointName OPTIONAL,
+ * reasons [1] ReasonFlags OPTIONAL,
+ * cRLIssuer [2] GeneralNames OPTIONAL }
+ */
+
+ exdata.bv_val = (char *)extn.BERvalue.Data;
+ exdata.bv_len = extn.BERvalue.Length;
+ if ((asn1 = kmfder_init(&exdata)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ if ((tag = kmfber_first_element(asn1, &size, &end)) !=
+ BER_CONSTRUCTED_SEQUENCE) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto out;
+ }
+
+ (void) memset((void *)crl_dps, 0, sizeof (KMF_X509EXT_CRLDISTPOINTS));
+
+ while ((tag = kmfber_next_element(asn1, &size, end)) ==
+ BER_CONSTRUCTED_SEQUENCE) {
+ boolean_t has_name = B_FALSE;
+ boolean_t has_issuer = B_FALSE;
+
+ /* Skip over the CONSTRUCTED SET tag */
+ if (kmfber_scanf(asn1, "T", &tag) == KMFBER_DEFAULT) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto out;
+ }
+
+ tag = kmfber_next_element(asn1, &size, end);
+ if (tag != 0xA0 && tag != 0xA1 && tag != 0xA2)
+ goto out;
+
+ if ((dp = malloc(sizeof (KMF_CRL_DIST_POINT))) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) memset((void *)dp, 0, sizeof (KMF_CRL_DIST_POINT));
+
+ if (tag == 0xA0) { /* distributionPoint Name */
+ char *name_der;
+ int name_size = size + 2;
+
+ if ((name_der = malloc(name_size)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ free(dp);
+ dp = NULL;
+ goto out;
+ }
+
+ if (kmfber_read(asn1, name_der, name_size) !=
+ (ber_slen_t)(name_size)) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ free(name_der);
+ free(dp);
+ dp = NULL;
+ goto out;
+ }
+ has_name = B_TRUE;
+
+ ret = parse_dp_name(name_der, name_size, dp);
+ free(name_der);
+ if (ret != KMF_OK) {
+ free(dp);
+ dp = NULL;
+ goto out;
+ }
+
+ /* next field */
+ tag = kmfber_next_element(asn1, &size, end);
+ }
+
+ if (tag == 0XA1) { /* reasons */
+ char *bit_string;
+ int len;
+
+ if (kmfber_scanf(asn1, "B", &bit_string, &len) !=
+ BER_BIT_STRING) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ free(dp);
+ dp = NULL;
+ goto out;
+ }
+
+ dp->reasons.Length = len / 8;
+ if ((dp->reasons.Data = malloc(dp->reasons.Length)) ==
+ NULL) {
+ ret = KMF_ERR_MEMORY;
+ free(dp);
+ dp = NULL;
+ goto out;
+ }
+ (void) memcpy(dp->reasons.Data, (uchar_t *)bit_string,
+ dp->reasons.Length);
+
+ /* next field */
+ tag = kmfber_next_element(asn1, &size, end);
+ }
+
+ if (tag == 0XA2) { /* cRLIssuer */
+ char *issuer_der = NULL;
+ int issuer_size;
+
+ /* For cRLIssuer, read the data only at phase 1 */
+ issuer_size = size + 2;
+ issuer_der = malloc(issuer_size);
+ if (issuer_der == NULL) {
+ ret = KMF_ERR_MEMORY;
+ free(dp);
+ dp = NULL;
+ goto out;
+ }
+
+ if (kmfber_read(asn1, issuer_der, issuer_size) !=
+ (ber_slen_t)(issuer_size)) {
+ free(issuer_der);
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ free(dp);
+ dp = NULL;
+ goto out;
+ }
+
+ has_issuer = B_TRUE;
+ free(issuer_der);
+ }
+
+ /* A distribution point cannot have a "reasons" field only. */
+ if (has_name == B_FALSE && has_issuer == B_FALSE) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ free_dp(dp);
+ free(dp);
+ dp = NULL;
+ goto out;
+ }
+
+ /*
+ * Although it is legal that a distributioon point contains
+ * a cRLIssuer field only, with or without "reasons", we will
+ * skip it if the name field is not presented for phase 1.
+ */
+ if (has_name == B_FALSE) {
+ free_dp(dp);
+ } else {
+ crl_dps->number++;
+ crl_dps->dplist = realloc(crl_dps->dplist,
+ crl_dps->number * sizeof (KMF_CRL_DIST_POINT));
+ if (crl_dps->dplist == NULL) {
+ ret = KMF_ERR_MEMORY;
+ free_dp(dp);
+ free(dp);
+ dp = NULL;
+ goto out;
+ }
+ crl_dps->dplist[crl_dps->number - 1] = *dp;
+ /* free the dp itself since we just used its contents */
+ }
+ if (dp != NULL) {
+ free(dp);
+ dp = NULL;
+ }
+ }
+
+out:
+ KMF_FreeExtension(&extn);
+
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+
+ if (ret != KMF_OK) {
+ for (i = 0; i < crl_dps->number; i++)
+ free_dp(&(crl_dps->dplist[i]));
+ free(crl_dps->dplist);
+ }
+
+ if (ret == KMF_OK && crl_dps->number == 0) {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ }
+
+ return (ret);
+}
+
+static KMF_RETURN
+KMF_CertGetPrintable(KMF_HANDLE_T handle, const KMF_DATA *SignedCert,
+ KMF_PRINTABLE_ITEM flag, char *resultStr)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN (*getPrintableFn)(void *, const KMF_DATA *,
+ KMF_PRINTABLE_ITEM, char *);
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignedCert == NULL ||
+ resultStr == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * This framework function is actually implemented in the openssl
+ * plugin library, so we find the function address and call it.
+ */
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ if (plugin == NULL || plugin->dldesc == NULL) {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ getPrintableFn = (KMF_RETURN(*)())dlsym(plugin->dldesc,
+ "OpenSSL_CertGetPrintable");
+ if (getPrintableFn == NULL) {
+ return (KMF_ERR_FUNCTION_NOT_FOUND);
+ }
+
+ return (getPrintableFn(handle, SignedCert, flag, resultStr));
+}
+
+KMF_RETURN
+KMF_GetCertVersionString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert,
+ char **result)
+{
+ KMF_RETURN ret;
+ char *tmpstr;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignedCert == NULL || result == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ tmpstr = malloc(KMF_CERT_PRINTABLE_LEN);
+ if (tmpstr == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN);
+
+ ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_VERSION,
+ tmpstr);
+
+ if (ret == KMF_OK) {
+ *result = tmpstr;
+ } else {
+ free(tmpstr);
+ *result = NULL;
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetCertSubjectNameString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert,
+ char **result)
+{
+ KMF_RETURN ret;
+ char *tmpstr;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignedCert == NULL || result == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ tmpstr = malloc(KMF_CERT_PRINTABLE_LEN);
+ if (tmpstr == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN);
+
+ ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_SUBJECT,
+ tmpstr);
+
+ if (ret == KMF_OK) {
+ *result = tmpstr;
+ } else {
+ free(tmpstr);
+ *result = NULL;
+ }
+
+ return (ret);
+
+}
+
+KMF_RETURN
+KMF_GetCertIssuerNameString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert,
+ char **result)
+{
+ KMF_RETURN ret;
+ char *tmpstr;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignedCert == NULL || result == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ tmpstr = malloc(KMF_CERT_PRINTABLE_LEN);
+ if (tmpstr == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN);
+
+ ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_ISSUER,
+ tmpstr);
+
+ if (ret == KMF_OK) {
+ *result = tmpstr;
+ } else {
+ free(tmpstr);
+ *result = NULL;
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetCertSerialNumberString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert,
+ char **result)
+{
+ KMF_RETURN ret;
+ char *tmpstr;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignedCert == NULL || result == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ tmpstr = malloc(KMF_CERT_PRINTABLE_LEN);
+ if (tmpstr == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN);
+
+ ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_SERIALNUM,
+ tmpstr);
+
+ if (ret == KMF_OK) {
+ *result = tmpstr;
+ } else {
+ free(tmpstr);
+ *result = NULL;
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetCertStartDateString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert,
+ char **result)
+{
+ KMF_RETURN ret;
+ char *tmpstr;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignedCert == NULL || result == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ tmpstr = malloc(KMF_CERT_PRINTABLE_LEN);
+ if (tmpstr == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN);
+
+ ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_NOTBEFORE,
+ tmpstr);
+
+ if (ret == KMF_OK) {
+ *result = tmpstr;
+ } else {
+ free(tmpstr);
+ *result = NULL;
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetCertEndDateString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert,
+ char **result)
+{
+ KMF_RETURN ret;
+ char *tmpstr;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignedCert == NULL || result == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ tmpstr = malloc(KMF_CERT_PRINTABLE_LEN);
+ if (tmpstr == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN);
+
+ ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_NOTAFTER,
+ tmpstr);
+
+ if (ret == KMF_OK) {
+ *result = tmpstr;
+ } else {
+ free(tmpstr);
+ *result = NULL;
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetCertPubKeyAlgString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert,
+ char **result)
+{
+ KMF_RETURN ret;
+ char *tmpstr;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignedCert == NULL || result == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ tmpstr = malloc(KMF_CERT_PRINTABLE_LEN);
+ if (tmpstr == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN);
+
+ ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_PUBKEY_ALG,
+ tmpstr);
+
+ if (ret == KMF_OK) {
+ *result = tmpstr;
+ } else {
+ free(tmpstr);
+ *result = NULL;
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetCertSignatureAlgString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert,
+ char **result)
+{
+ KMF_RETURN ret;
+ char *tmpstr;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignedCert == NULL || result == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ tmpstr = malloc(KMF_CERT_PRINTABLE_LEN);
+ if (tmpstr == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN);
+
+ ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_SIGNATURE_ALG,
+ tmpstr);
+
+ if (ret == KMF_OK) {
+ *result = tmpstr;
+ } else {
+ free(tmpstr);
+ *result = NULL;
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetCertPubKeyDataString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert,
+ char **result)
+{
+ KMF_RETURN ret;
+ char *tmpstr;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignedCert == NULL || result == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ tmpstr = malloc(KMF_CERT_PRINTABLE_LEN);
+ if (tmpstr == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN);
+
+ ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_PUBKEY_DATA,
+ tmpstr);
+
+ if (ret == KMF_OK) {
+ *result = tmpstr;
+ } else {
+ free(tmpstr);
+ *result = NULL;
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetCertEmailString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert,
+ char **result)
+{
+ KMF_RETURN ret;
+ char *tmpstr;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignedCert == NULL || result == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ tmpstr = malloc(KMF_CERT_PRINTABLE_LEN);
+ if (tmpstr == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN);
+
+ ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_EMAIL,
+ tmpstr);
+
+ if (ret == KMF_OK) {
+ *result = tmpstr;
+ } else {
+ free(tmpstr);
+ *result = NULL;
+ }
+
+ return (ret);
+}
+
+/*
+ * Given a certificate (DER Encoded data) and a KMF
+ * extension identifier constant (e.g. KMF_X509_EXT_*),
+ * return a human readable interpretation of the
+ * extension data.
+ *
+ * The string will be a maximum of KMF_CERT_PRINTABLE_LEN
+ * bytes long. The string is allocated locally and
+ * must be freed by the caller.
+ */
+KMF_RETURN
+KMF_GetCertExtensionString(KMF_HANDLE_T handle, const KMF_DATA *cert,
+ KMF_PRINTABLE_ITEM extension, char **result)
+{
+ KMF_RETURN ret;
+ char *tmpstr;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (cert == NULL || result == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ tmpstr = malloc(KMF_CERT_PRINTABLE_LEN);
+ if (tmpstr == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN);
+
+ ret = KMF_CertGetPrintable(handle, cert, extension, tmpstr);
+
+ if (ret == KMF_OK) {
+ *result = tmpstr;
+ } else {
+ free(tmpstr);
+ *result = NULL;
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetCertIDData(const KMF_DATA *SignedCert, KMF_DATA *ID)
+{
+ KMF_RETURN ret;
+ KMF_X509_CERTIFICATE *cert = NULL;
+
+ if (SignedCert == NULL || ID == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ ret = DerDecodeSignedCertificate(SignedCert, &cert);
+ if (ret != KMF_OK)
+ return (ret);
+
+ ret = GetIDFromSPKI(&cert->certificate.subjectPublicKeyInfo, ID);
+
+ KMF_FreeSignedCert(cert);
+ free(cert);
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetCertIDString(const KMF_DATA *SignedCert,
+ char **idstr)
+{
+ KMF_RETURN ret;
+ KMF_DATA ID = {NULL, 0};
+ char tmpstr[256];
+ int i;
+
+ if (SignedCert == NULL || idstr == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ ret = KMF_GetCertIDData(SignedCert, &ID);
+ if (ret != KMF_OK) {
+ KMF_FreeData(&ID);
+ return (ret);
+ }
+
+ (void) memset(tmpstr, 0, sizeof (tmpstr));
+ for (i = 0; i < ID.Length; i++) {
+ int len = strlen(tmpstr);
+ (void) snprintf(&tmpstr[len], sizeof (tmpstr) - len,
+ "%02x", (uchar_t)ID.Data[i]);
+ if ((i+1) < ID.Length)
+ (void) strcat(tmpstr, ":");
+ }
+ *idstr = strdup(tmpstr);
+ if ((*idstr) == NULL)
+ ret = KMF_ERR_MEMORY;
+
+ KMF_FreeData(&ID);
+
+ return (ret);
+}
+
+/*
+ * This function gets the time_t values of the notbefore and notafter dates
+ * from a der-encoded certificate.
+ */
+KMF_RETURN
+KMF_GetCertValidity(const KMF_DATA *cert, time_t *not_before,
+ time_t *not_after)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_X509_CERTIFICATE *certData = NULL;
+ struct tm tm_tmp;
+ time_t t_notbefore;
+ time_t t_notafter;
+ unsigned char *not_before_str;
+ unsigned char *not_after_str;
+
+ if (cert == NULL || not_before == NULL || not_after == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = DerDecodeSignedCertificate(cert, &certData);
+ if (rv != KMF_OK)
+ return (rv);
+
+ /* Get notBefore */
+ not_before_str = certData->certificate.validity.notBefore.time.Data;
+ if (strptime((const char *)not_before_str, "%y %m %d %H %M %S",
+ &tm_tmp) == NULL) {
+ rv = KMF_ERR_VALIDITY_PERIOD;
+ goto out;
+ }
+
+ errno = 0;
+ if (((t_notbefore = mktime(&tm_tmp)) == (time_t)(-1)) &&
+ errno == EOVERFLOW) {
+ rv = KMF_ERR_VALIDITY_PERIOD;
+ goto out;
+ }
+ *not_before = t_notbefore;
+
+ /* Get notAfter */
+ not_after_str = certData->certificate.validity.notAfter.time.Data;
+ if (strptime((const char *)not_after_str, "%y %m %d %H %M %S",
+ &tm_tmp) == NULL) {
+ rv = KMF_ERR_VALIDITY_PERIOD;
+ goto out;
+ }
+
+ errno = 0;
+ if (((t_notafter = mktime(&tm_tmp)) == (time_t)(-1)) &&
+ errno == EOVERFLOW) {
+ rv = KMF_ERR_VALIDITY_PERIOD;
+ goto out;
+ }
+ *not_after = t_notafter;
+
+out:
+ if (certData != NULL) {
+ KMF_FreeSignedCert(certData);
+ free(certData);
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+KMF_SetCertPubKey(KMF_HANDLE_T handle,
+ KMF_KEY_HANDLE *KMFKey,
+ KMF_X509_CERTIFICATE *Cert)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_SPKI *spki_ptr;
+ KMF_PLUGIN *plugin;
+ KMF_DATA KeyData = {NULL, 0};
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (KMFKey == NULL || Cert == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* The keystore must extract the pubkey data */
+ plugin = FindPlugin(handle, KMFKey->kstype);
+ if (plugin != NULL && plugin->funclist->EncodePubkeyData != NULL) {
+ ret = plugin->funclist->EncodePubkeyData(handle,
+ KMFKey, &KeyData);
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ spki_ptr = &Cert->certificate.subjectPublicKeyInfo;
+
+ if (KeyData.Data != NULL) {
+ ret = DerDecodeSPKI(&KeyData, spki_ptr);
+ free(KeyData.Data);
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_SetCertSubjectName(KMF_X509_CERTIFICATE *CertData,
+ KMF_X509_NAME *subject_name_ptr)
+{
+ if (CertData != NULL && subject_name_ptr != NULL)
+ CertData->certificate.subject = *subject_name_ptr;
+ else
+ return (KMF_ERR_BAD_PARAMETER);
+
+ return (KMF_OK);
+}
+
+KMF_RETURN
+set_key_usage_extension(KMF_X509_EXTENSIONS *extns,
+ int critical, uint32_t bits)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSION extn;
+ BerElement *asn1 = NULL;
+ BerValue *extdata;
+ int bitlen, i;
+ uint16_t kubits = (uint16_t)(bits & 0x0000ffff);
+
+ if (extns == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&extn, 0, sizeof (extn));
+ ret = copy_data(&extn.extnId, (KMF_OID *)&KMFOID_KeyUsage);
+ if (ret != KMF_OK)
+ return (ret);
+ extn.critical = critical;
+ extn.format = KMF_X509_DATAFORMAT_ENCODED;
+
+ for (i = 7; i <= 15 && !(kubits & (1 << i)); i++);
+
+ bitlen = 16 - i;
+
+ if ((asn1 = kmfder_alloc()) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ kubits = htons(kubits);
+ if (kmfber_printf(asn1, "B", (char *)&kubits, bitlen) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+ if (kmfber_flatten(asn1, &extdata) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ extn.BERvalue.Data = (uchar_t *)extdata->bv_val;
+ extn.BERvalue.Length = extdata->bv_len;
+
+ free(extdata);
+
+ ret = add_an_extension(extns, &extn);
+ if (ret != KMF_OK) {
+ free(extn.BERvalue.Data);
+ }
+out:
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_SetCertKeyUsage(KMF_X509_CERTIFICATE *CertData,
+ int critical, uint16_t kubits)
+{
+ KMF_RETURN ret = KMF_OK;
+
+ if (CertData == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ ret = set_key_usage_extension(
+ &CertData->certificate.extensions,
+ critical, kubits);
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_SetCertIssuerName(KMF_X509_CERTIFICATE *CertData,
+ KMF_X509_NAME *issuer_name_ptr)
+{
+ if (CertData != NULL && issuer_name_ptr != NULL)
+ CertData->certificate.issuer = *issuer_name_ptr;
+ else
+ return (KMF_ERR_BAD_PARAMETER);
+
+ return (KMF_OK);
+}
+
+KMF_RETURN
+KMF_SetCertSignatureAlgorithm(KMF_X509_CERTIFICATE *CertData,
+ KMF_ALGORITHM_INDEX sigAlg)
+{
+ KMF_OID *alg;
+
+ if (CertData == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ alg = X509_AlgIdToAlgorithmOid(sigAlg);
+
+ if (alg != NULL) {
+ (void) copy_data((KMF_DATA *)
+ &CertData->certificate.signature.algorithm,
+ (KMF_DATA *)alg);
+ (void) copy_data(&CertData->certificate.signature.parameters,
+ &CertData->certificate.subjectPublicKeyInfo.algorithm.
+ parameters);
+
+ (void) copy_data(
+ &CertData->signature.algorithmIdentifier.algorithm,
+ &CertData->certificate.signature.algorithm);
+ (void) copy_data(
+ &CertData->signature.algorithmIdentifier.parameters,
+ &CertData->certificate.signature.parameters);
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ return (KMF_OK);
+}
+
+KMF_RETURN
+KMF_SetCertValidityTimes(KMF_X509_CERTIFICATE *CertData,
+ time_t notBefore, uint32_t delta)
+{
+ time_t clock;
+ struct tm *gmt;
+ char szNotBefore[256];
+ char szNotAfter[256];
+
+ if (CertData == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Set up validity fields */
+ if (notBefore == NULL)
+ clock = time(NULL);
+ else
+ clock = notBefore;
+
+ gmt = gmtime(&clock); /* valid starting today */
+
+ /* Build the format in 2 parts so SCCS doesn't get confused */
+ (void) strftime(szNotBefore, sizeof (szNotBefore),
+ "%y%m%d%H" "%M00Z", gmt);
+
+ CertData->certificate.validity.notBefore.timeType = BER_UTCTIME;
+ CertData->certificate.validity.notBefore.time.Length =
+ strlen((char *)szNotBefore);
+ CertData->certificate.validity.notBefore.time.Data =
+ (uchar_t *)strdup(szNotBefore);
+
+ clock += delta;
+ gmt = gmtime(&clock);
+
+ /* Build the format in 2 parts so SCCS doesn't get confused */
+ (void) strftime(szNotAfter, sizeof (szNotAfter),
+ "%y%m%d%H" "%M00Z", gmt);
+
+ CertData->certificate.validity.notAfter.timeType = BER_UTCTIME;
+ CertData->certificate.validity.notAfter.time.Length =
+ strlen((char *)szNotAfter);
+ CertData->certificate.validity.notAfter.time.Data =
+ (uchar_t *)strdup(szNotAfter);
+
+ return (KMF_OK);
+}
+
+/*
+ * Utility routine to set Integer values in the Certificate template
+ * for things like serialNumber and Version. The data structure
+ * expects pointers, not literal values, so we must allocate
+ * and copy here. Don't use memory from the stack since this data
+ * is freed later and that would be bad.
+ */
+KMF_RETURN
+set_integer(KMF_DATA *data, void *value, int length)
+{
+ if (data == NULL || value == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ data->Data = malloc(length);
+ if (data->Data == NULL)
+ return (KMF_ERR_MEMORY);
+
+ data->Length = length;
+ (void) memcpy((void *)data->Data, (const void *)value, length);
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+set_bigint(KMF_BIGINT *data, KMF_BIGINT *bigint)
+{
+ if (data == NULL || bigint == NULL || bigint->len == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ data->val = malloc(bigint->len);
+ if (data->val == NULL)
+ return (KMF_ERR_MEMORY);
+
+ data->len = bigint->len;
+
+ (void) memcpy((void *)data->val, bigint->val, bigint->len);
+
+ return (KMF_OK);
+
+}
+
+KMF_RETURN
+KMF_SetCertSerialNumber(KMF_X509_CERTIFICATE *CertData,
+ KMF_BIGINT *serno)
+{
+ if (CertData == NULL || serno == NULL || serno->len == 0)
+ return (KMF_ERR_BAD_PARAMETER);
+ return (set_bigint(&CertData->certificate.serialNumber, serno));
+}
+
+KMF_RETURN
+KMF_SetCertVersion(KMF_X509_CERTIFICATE *CertData,
+ uint32_t version)
+{
+ if (CertData == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ /*
+ * From RFC 3280:
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ */
+ if (version != 0 && version != 1 && version != 2)
+ return (KMF_ERR_BAD_PARAMETER);
+ return (set_integer(&CertData->certificate.version, (void *)&version,
+ sizeof (uint32_t)));
+}
+
+KMF_RETURN
+KMF_SetCertIssuerAltName(KMF_X509_CERTIFICATE *CertData,
+ int critical,
+ KMF_GENERALNAMECHOICES nametype,
+ char *namedata)
+{
+ if (CertData == NULL || namedata == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ return (KMF_SetAltName(
+ &CertData->certificate.extensions,
+ (KMF_OID *)&KMFOID_IssuerAltName,
+ critical, nametype, namedata));
+}
+
+KMF_RETURN
+KMF_SetCertSubjectAltName(KMF_X509_CERTIFICATE *CertData,
+ int critical,
+ KMF_GENERALNAMECHOICES nametype,
+ char *namedata)
+{
+ if (CertData == NULL || namedata == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ return (KMF_SetAltName(&CertData->certificate.extensions,
+ (KMF_OID *)&KMFOID_SubjectAltName,
+ critical, nametype, namedata));
+}
+
+KMF_RETURN
+KMF_AddCertEKU(KMF_X509_CERTIFICATE *CertData, KMF_OID *ekuOID,
+ int critical)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSION *foundextn;
+ KMF_X509_EXTENSION newextn;
+ BerElement *asn1 = NULL;
+ BerValue *extdata = NULL;
+ char *olddata = NULL;
+ size_t oldsize = 0;
+ KMF_X509EXT_EKU ekudata;
+
+ if (CertData == NULL || ekuOID == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&ekudata, 0, sizeof (KMF_X509EXT_EKU));
+ (void) memset(&newextn, 0, sizeof (newextn));
+
+ foundextn = FindExtn(&CertData->certificate.extensions,
+ (KMF_OID *)&KMFOID_ExtendedKeyUsage);
+ if (foundextn != NULL) {
+ ret = GetSequenceContents(
+ (char *)foundextn->BERvalue.Data,
+ foundextn->BERvalue.Length,
+ &olddata, &oldsize);
+ if (ret != KMF_OK)
+ goto out;
+
+ /*
+ * If the EKU is already in the cert, then just return OK.
+ */
+ ret = parse_eku_data(&foundextn->BERvalue, &ekudata);
+ if (ret == KMF_OK) {
+ if (isEKUPresent(&ekudata, ekuOID)) {
+ goto out;
+ }
+ }
+ }
+ if ((asn1 = kmfder_alloc()) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (kmfber_printf(asn1, "{") == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ /* Write the old extension data first */
+ if (olddata != NULL && oldsize > 0) {
+ if (kmfber_write(asn1, olddata, oldsize, 0) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+ }
+
+ /* Append this EKU OID and close the sequence */
+ if (kmfber_printf(asn1, "D}", ekuOID) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ if (kmfber_flatten(asn1, &extdata) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ /*
+ * If we are just adding to an existing list of EKU OIDs,
+ * just replace the BER data associated with the found extension.
+ */
+ if (foundextn != NULL) {
+ free(foundextn->BERvalue.Data);
+ foundextn->critical = critical;
+ foundextn->BERvalue.Data = (uchar_t *)extdata->bv_val;
+ foundextn->BERvalue.Length = extdata->bv_len;
+ } else {
+ ret = copy_data(&newextn.extnId,
+ (KMF_DATA *)&KMFOID_ExtendedKeyUsage);
+ if (ret != KMF_OK)
+ goto out;
+ newextn.critical = critical;
+ newextn.format = KMF_X509_DATAFORMAT_ENCODED;
+ newextn.BERvalue.Data = (uchar_t *)extdata->bv_val;
+ newextn.BERvalue.Length = extdata->bv_len;
+ ret = KMF_SetCertExtension(CertData, &newextn);
+ if (ret != KMF_OK)
+ free(newextn.BERvalue.Data);
+ }
+
+out:
+ KMF_FreeEKU(&ekudata);
+ if (extdata != NULL)
+ free(extdata);
+
+ if (olddata != NULL)
+ free(olddata);
+
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+
+ if (ret != KMF_OK)
+ KMF_FreeData(&newextn.extnId);
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_SetCertExtension(KMF_X509_CERTIFICATE *CertData,
+ KMF_X509_EXTENSION *extn)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSIONS *exts;
+
+ if (CertData == NULL || extn == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ exts = &CertData->certificate.extensions;
+
+ ret = add_an_extension(exts, extn);
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_SetCertBasicConstraintExt(KMF_X509_CERTIFICATE *CertData,
+ KMF_BOOL critical, KMF_X509EXT_BASICCONSTRAINTS *constraint)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSION extn;
+ BerElement *asn1 = NULL;
+ BerValue *extdata;
+
+ if ((CertData == NULL) || (constraint == NULL))
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&extn, 0, sizeof (extn));
+ ret = copy_data(&extn.extnId, (KMF_OID *)&KMFOID_BasicConstraints);
+ if (ret != KMF_OK)
+ return (ret);
+ extn.critical = critical;
+ extn.format = KMF_X509_DATAFORMAT_ENCODED;
+
+ if ((asn1 = kmfder_alloc()) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (kmfber_printf(asn1, "{") == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ if (kmfber_printf(asn1, "b", constraint->cA) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ if (constraint->pathLenConstraintPresent) {
+ /* Write the pathLenConstraint value */
+ if (kmfber_printf(asn1, "i",
+ constraint->pathLenConstraint) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+ }
+
+ if (kmfber_printf(asn1, "}") == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ if (kmfber_flatten(asn1, &extdata) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ extn.BERvalue.Data = (uchar_t *)extdata->bv_val;
+ extn.BERvalue.Length = extdata->bv_len;
+
+ free(extdata);
+ ret = KMF_SetCertExtension(CertData, &extn);
+ if (ret != KMF_OK) {
+ free(extn.BERvalue.Data);
+ }
+
+out:
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+
+ return (ret);
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/certop.c b/usr/src/lib/libkmf/libkmf/common/certop.c
new file mode 100644
index 0000000000..879701e427
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/certop.c
@@ -0,0 +1,2773 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright(c) 1995-2000 Intel Corporation. All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <link.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <ber_der.h>
+#include <kmfapiP.h>
+#include <pem_encode.h>
+#include <libgen.h>
+#include <cryptoutil.h>
+
+#define CERTFILE_TEMPNAME "/tmp/user.certXXXXXX"
+#define CRLFILE_TEMPNAME "/tmp/crlXXXXXX"
+#define X509_FORMAT_VERSION 2
+
+static KMF_RETURN
+get_keyalg_from_cert(KMF_DATA *cert, KMF_KEY_ALG *keyalg)
+{
+ KMF_RETURN rv;
+ KMF_X509_CERTIFICATE *SignerCert = NULL;
+ KMF_ALGORITHM_INDEX AlgorithmId;
+
+ rv = DerDecodeSignedCertificate(cert, &SignerCert);
+
+ if (rv != KMF_OK)
+ return (rv);
+
+ /* Get the algorithm info from the signer certificate */
+ AlgorithmId = X509_AlgorithmOidToAlgId(
+ &SignerCert->signature.algorithmIdentifier.algorithm);
+
+ switch (AlgorithmId) {
+ case KMF_ALGID_MD5WithRSA:
+ case KMF_ALGID_MD2WithRSA:
+ case KMF_ALGID_SHA1WithRSA:
+ *keyalg = KMF_RSA;
+ break;
+ case KMF_ALGID_SHA1WithDSA:
+ *keyalg = KMF_DSA;
+ break;
+ default:
+ rv = KMF_ERR_BAD_ALGORITHM;
+ }
+
+ KMF_FreeSignedCert(SignerCert);
+ free(SignerCert);
+ return (rv);
+}
+
+/*
+ *
+ * Name: find_private_key_by_cert
+ *
+ * Description:
+ * This function finds the corresponding private key in keystore
+ * for a certificate
+ *
+ * Parameters:
+ * handle(input) - opaque handle for KMF session
+ * params(input) - contains parameters used to find the private key
+ * SignerCertData(input) - pointer to a KMF_DATA structure containing a
+ * signer certificate
+ * key(output) - contains the found private key handle
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+static KMF_RETURN
+find_private_key_by_cert(KMF_HANDLE_T handle,
+ KMF_CRYPTOWITHCERT_PARAMS *params,
+ KMF_DATA *SignerCertData,
+ KMF_KEY_HANDLE *key)
+{
+
+ KMF_RETURN ret;
+ KMF_KEY_ALG keytype;
+ KMF_PLUGIN *plugin;
+
+ if (handle == NULL || params == NULL ||
+ SignerCertData == NULL || key == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(key, 0, sizeof (KMF_KEY_HANDLE));
+ ret = get_keyalg_from_cert(SignerCertData, &keytype);
+ if (ret != KMF_OK)
+ return (ret);
+
+ /* Find the private key from the keystore */
+ plugin = FindPlugin(handle, params->kstype);
+
+ if (plugin != NULL && plugin->funclist->GetPrikeyByCert != NULL) {
+ CLEAR_ERROR(handle, ret);
+ return (plugin->funclist->GetPrikeyByCert(handle,
+ params, SignerCertData, key, keytype));
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+}
+
+static KMF_RETURN
+check_key_usage(void *handle,
+ const KMF_DATA *cert,
+ const KMF_KU_PURPOSE purpose)
+{
+ KMF_X509EXT_BASICCONSTRAINTS constraint;
+ KMF_BOOL critical = B_FALSE;
+ KMF_X509EXT_KEY_USAGE keyusage;
+ KMF_RETURN ret = KMF_OK;
+
+ if (handle == NULL || cert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&constraint, 0, sizeof (KMF_X509EXT_BASICCONSTRAINTS));
+ (void) memset(&keyusage, 0, sizeof (KMF_X509EXT_KEY_USAGE));
+
+ ret = KMF_GetCertKeyUsageExt(cert, &keyusage);
+ if (ret != KMF_OK)
+ /*
+ * If absent or error, the cert is assumed to be invalid
+ * for all key usage checking.
+ */
+ return (ret);
+
+
+ switch (purpose) {
+ case KMF_KU_SIGN_CERT:
+ /*
+ * RFC 3280:
+ * The keyCertSign bit is asserted when the subject
+ * public key is used for verifying a signature on
+ * public key certificates. If the keyCertSign bit
+ * is asserted, then the cA bit in the basic constraints
+ * extension (section 4.2.1.10) MUST also be asserted.
+ * The basic constraints extension MUST appear as a
+ * critical extension in all CA certificates that
+ * contain public keys used to validate digital
+ * signatures on certificates.
+ */
+ ret = KMF_GetCertBasicConstraintExt(cert, &critical,
+ &constraint);
+
+ if ((ret != KMF_ERR_EXTENSION_NOT_FOUND) && (ret != KMF_OK)) {
+ /* real error */
+ return (ret);
+ }
+
+ if ((!critical) || (!constraint.cA) ||
+ (!(keyusage.KeyUsageBits & KMF_keyCertSign)))
+ return (KMF_ERR_KEYUSAGE);
+ break;
+ case KMF_KU_SIGN_DATA:
+ /*
+ * RFC 3280:
+ * The digitalSignature bit is asserted when the subject
+ * public key is used with a digital signature mechanism
+ * to support security services other than certificate
+ * signing(bit 5), or CRL signing(bit 6).
+ */
+ if (!(keyusage.KeyUsageBits & KMF_digitalSignature))
+ return (KMF_ERR_KEYUSAGE);
+ break;
+ case KMF_KU_ENCRYPT_DATA:
+ /*
+ * RFC 3280:
+ * The dataEncipherment bit is asserted when the subject
+ * public key is used for enciphering user data, other than
+ * cryptographic keys.
+ */
+ if (!(keyusage.KeyUsageBits & KMF_dataEncipherment))
+ return (KMF_ERR_KEYUSAGE);
+ break;
+ default:
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ return (KMF_OK);
+}
+
+KMF_RETURN
+KMF_FindCert(KMF_HANDLE_T handle, KMF_FINDCERT_PARAMS *target,
+ KMF_X509_DER_CERT *kmf_cert,
+ uint32_t *num_certs)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN rv = KMF_OK;
+
+
+ CLEAR_ERROR(handle, rv);
+ if (rv != KMF_OK)
+ return (rv);
+
+ if (target == NULL || num_certs == NULL)
+ return (KMF_ERR_BAD_PARAMETER); /* ILLEGAL ARGS ERROR */
+
+ if ((target->find_cert_validity < KMF_ALL_CERTS) ||
+ (target->find_cert_validity > KMF_EXPIRED_CERTS))
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, target->kstype);
+
+ if (plugin != NULL && plugin->funclist->FindCert != NULL) {
+ return (plugin->funclist->FindCert(handle, target,
+ kmf_cert, num_certs));
+ }
+
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+}
+
+#define NODATA(d) (d.Data == NULL || d.Length == NULL)
+
+KMF_RETURN
+KMF_EncodeCertRecord(KMF_X509_CERTIFICATE *CertData, KMF_DATA *encodedCert)
+{
+ KMF_RETURN ret;
+
+ if (CertData == NULL || encodedCert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * Validate that all required fields are present.
+ */
+ if (NODATA(CertData->certificate.version) ||
+ NODATA(CertData->certificate.signature.algorithm) ||
+ NODATA(CertData->certificate.subjectPublicKeyInfo.subjectPublicKey) ||
+ CertData->certificate.serialNumber.val == NULL ||
+ CertData->certificate.serialNumber.len == 0 ||
+ CertData->certificate.subject.numberOfRDNs == 0 ||
+ CertData->certificate.issuer.numberOfRDNs == 0) {
+ return (KMF_ERR_INCOMPLETE_TBS_CERT);
+ }
+
+ encodedCert->Length = 0;
+ encodedCert->Data = NULL;
+
+ /* Pack the new certificate */
+ ret = DerEncodeSignedCertificate(CertData, encodedCert);
+
+ return (ret);
+}
+
+/*
+ *
+ * Name: KMF_SignCertWithKey
+ *
+ * Description:
+ * This function signs a certificate using the private key and
+ * returns the result as a signed, encoded certificate in SignedCert
+ *
+ * Parameters:
+ * handle(input) - opaque handle for KMF session
+ * CertToBeSigned(input) - pointer to a KMF_DATA structure containing a
+ * DER encoded certificate to be signed
+ * Signkey(input) - pointer to private key handle needed for signing
+ * SignedCert(output) - pointer to the KMF_DATA structure containing the
+ * signed certificate
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_SignCertWithKey(KMF_HANDLE_T handle,
+ const KMF_DATA *CertToBeSigned,
+ KMF_KEY_HANDLE *Signkey,
+ KMF_DATA *SignedCert)
+{
+ KMF_RETURN err;
+
+ CLEAR_ERROR(handle, err);
+ if (err != KMF_OK)
+ return (err);
+
+ if (CertToBeSigned == NULL ||
+ Signkey == NULL || SignedCert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ err = SignCert(handle, CertToBeSigned, Signkey, SignedCert);
+
+ return (err);
+}
+
+/*
+ *
+ * Name: KMF_SignCertWithCert
+ *
+ * Description:
+ * This function signs a certificate using the signer cert and
+ * returns the result as a signed, encoded certificate in SignedCert
+ *
+ * Parameters:
+ * handle(input) - opaque handle for KMF session
+ * params(input) - contains parameters to be used for signing
+ * CertToBeSigned(input) - pointer to a KMF_DATA structure containing a
+ * DER encoded certificate to be signed
+ * SignerCert(input) - pointer to a KMF_DATA structure containing a
+ * signer certificate
+ * SignedCert(output) - pointer to the KMF_DATA structure containing the
+ * DER encoded signed certificate
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_SignCertWithCert(KMF_HANDLE_T handle,
+ KMF_CRYPTOWITHCERT_PARAMS *params,
+ const KMF_DATA *CertToBeSigned,
+ KMF_DATA *SignerCert,
+ KMF_DATA *SignedCert)
+{
+ KMF_RETURN ret;
+ KMF_KEY_HANDLE Signkey;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (CertToBeSigned == NULL ||
+ SignerCert == NULL || SignedCert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* check the keyUsage of signer's certificate */
+ ret = check_key_usage(handle, SignerCert, KMF_KU_SIGN_CERT);
+ if (ret != KMF_OK)
+ return (ret);
+
+ /*
+ * Retrieve the private key from the keystore for the
+ * signer certificate.
+ */
+ ret = find_private_key_by_cert(handle, params, SignerCert, &Signkey);
+ if (ret != KMF_OK)
+ return (ret);
+
+ ret = SignCert(handle, CertToBeSigned, &Signkey, SignedCert);
+
+ KMF_FreeKMFKey(handle, &Signkey);
+
+ return (ret);
+}
+
+/*
+ *
+ * Name: KMF_SignDataWithCert
+ *
+ * Description:
+ * This function signs a block of data using the signer cert and
+ * returns the the signature in output
+ *
+ * Parameters:
+ * handle(input) - opaque handle for KMF session
+ * params(input) - contains parameters to be used for signing
+ * tobesigned(input) - pointer to a KMF_DATA structure containing a
+ * the data to be signed
+ * output(output) - pointer to the KMF_DATA structure containing the
+ * signed data
+ * SignerCertData(input) - pointer to a KMF_DATA structure containing a
+ * signer certificate
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_SignDataWithCert(KMF_HANDLE_T handle,
+ KMF_CRYPTOWITHCERT_PARAMS *params,
+ KMF_DATA *tobesigned,
+ KMF_DATA *output,
+ KMF_DATA *SignerCertData)
+{
+
+ KMF_RETURN ret;
+ KMF_KEY_HANDLE Signkey;
+ KMF_X509_CERTIFICATE *SignerCert = NULL;
+ KMF_PLUGIN *plugin;
+ KMF_ALGORITHM_INDEX AlgId;
+ KMF_DATA signature = {0, NULL};
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (tobesigned == NULL ||
+ SignerCertData == NULL || output == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* check the keyUsage of signer's certificate */
+ ret = check_key_usage(handle, SignerCertData, KMF_KU_SIGN_DATA);
+ if (ret != KMF_OK)
+ return (ret);
+
+ /*
+ * Retrieve the private key from the keystore based on
+ * the signer certificate.
+ */
+ ret = find_private_key_by_cert(handle, params, SignerCertData,
+ &Signkey);
+ if (ret != KMF_OK) {
+ goto cleanup;
+ }
+
+ ret = DerDecodeSignedCertificate(SignerCertData, &SignerCert);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ plugin = FindPlugin(handle, Signkey.kstype);
+ if (plugin != NULL && plugin->funclist->SignData != NULL) {
+ ret = plugin->funclist->SignData(handle, &Signkey,
+ CERT_ALG_OID(SignerCert), tobesigned, output);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ AlgId = X509_AlgorithmOidToAlgId(CERT_ALG_OID(SignerCert));
+
+ /*
+ * For DSA, NSS returns an encoded signature. Decode the
+ * signature as DSA signature should be 40-byte long.
+ */
+ if ((AlgId == KMF_ALGID_SHA1WithDSA) &&
+ (plugin->type == KMF_KEYSTORE_NSS)) {
+ ret = DerDecodeDSASignature(output, &signature);
+ if (ret != KMF_OK) {
+ goto cleanup;
+ } else {
+ output->Length = signature.Length;
+ (void) memcpy(output->Data, signature.Data,
+ signature.Length);
+ }
+ } else if (AlgId == KMF_ALGID_NONE) {
+ ret = KMF_ERR_BAD_ALGORITHM;
+ }
+ } else {
+ ret = KMF_ERR_PLUGIN_NOTFOUND;
+ }
+
+cleanup:
+ if (signature.Data)
+ free(signature.Data);
+
+ KMF_FreeKMFKey(handle, &Signkey);
+ if (SignerCert != NULL) {
+ KMF_FreeSignedCert(SignerCert);
+ free(SignerCert);
+ }
+
+ return (ret);
+}
+
+/*
+ *
+ * Name: KMF_VerifyCertWithKey
+ *
+ * Description:
+ * This function verifies that the CertToBeVerified was signed
+ * using a specific private key and that the certificate has not
+ * been altered since it was signed using that private key
+ *
+ * Parameters:
+ * handle(input) - opaque handle for KMF session
+ * KMFKey(input) - holds public key information for verification
+ * CertToBeVerified(input) - A signed certificate whose signature
+ * is to be verified
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition. The value KMF_OK indicates success. All other
+ * values represent an error condition.
+ */
+KMF_RETURN
+KMF_VerifyCertWithKey(KMF_HANDLE_T handle,
+ KMF_KEY_HANDLE *KMFKey,
+ const KMF_DATA *CertToBeVerified)
+{
+ KMF_RETURN err;
+ KMF_DATA derkey = {0, NULL};
+ KMF_PLUGIN *plugin;
+
+ CLEAR_ERROR(handle, err);
+ if (err != KMF_OK)
+ return (err);
+
+ if (KMFKey == NULL ||
+ CertToBeVerified == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* The keystore must extract the pubkey data */
+ plugin = FindPlugin(handle, KMFKey->kstype);
+ if (plugin != NULL && plugin->funclist->EncodePubkeyData != NULL) {
+ err = plugin->funclist->EncodePubkeyData(handle,
+ KMFKey, &derkey);
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ if (err == KMF_OK && derkey.Length > 0) {
+ /* check the caller and do other setup for this SPI call */
+ err = VerifyCertWithKey(handle, &derkey, CertToBeVerified);
+
+ if (derkey.Data != NULL)
+ free(derkey.Data);
+ }
+
+ return (err);
+}
+
+/*
+ *
+ * Name: KMF_VerifyCertWithCert
+ *
+ * Description:
+ * Function to verify the signature of a signed certificate
+ *
+ * Parameters:
+ * handle - pointer to KMF handle
+ * CertToBeVerified(input) - pointer to the signed certificate
+ * SignerCert(input) - pointer to certificate used in signing
+ *
+ * Returns:
+ * A KMF_RETURN value.
+ * The value KMF_OK indicates success.
+ * All other values represent an error condition.
+ */
+KMF_RETURN
+KMF_VerifyCertWithCert(KMF_HANDLE_T handle,
+ const KMF_DATA *CertToBeVerified,
+ const KMF_DATA *SignerCert)
+{
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (CertToBeVerified == NULL ||
+ SignerCert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* check the keyUsage of signer's certificate */
+ ret = check_key_usage(handle, SignerCert, KMF_KU_SIGN_CERT);
+ if (ret != KMF_OK)
+ return (ret);
+
+ ret = VerifyCertWithCert(handle, CertToBeVerified, SignerCert);
+ return (ret);
+}
+
+/*
+ *
+ * Name: KMF_VerifyDataWithCert
+ *
+ * Description:
+ * This function verifies the signature of a block of data using a signer
+ * certificate.
+ *
+ * Parameters:
+ * handle(input) - opaque handle for KMF session
+ * indata(input) - pointer to the block of data whose signature
+ * is to be verified
+ * insig(input) - pointer to the signature to be verified
+ * SignerCert(input) - pointer to signer cert for verification
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_VerifyDataWithCert(KMF_HANDLE_T handle,
+ KMF_DATA *indata,
+ KMF_DATA *insig,
+ const KMF_DATA *SignerCert)
+{
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (SignerCert == NULL ||
+ indata == NULL || insig == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* check the keyUsage of signer's certificate */
+ ret = check_key_usage(handle, SignerCert, KMF_KU_SIGN_DATA);
+ if (ret != KMF_OK)
+ return (ret);
+
+ return (VerifyDataWithCert(handle, indata, insig, SignerCert));
+}
+
+/*
+ * Name: KMF_EncryptWithCert
+ *
+ * Description:
+ * Uses the public key from the cert to encrypt the plaintext
+ * into the ciphertext.
+ *
+ * Parameters:
+ * handle(input) - opaque handle for KMF session
+ * cert(input) - pointer to a DER encoded certificate for encryption
+ * by using its public key
+ * plaintext(input) - pointer to the plaintext to be encrypted
+ * ciphertext(output) - pointer to the ciphertext contains
+ * encrypted data
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_EncryptWithCert(KMF_HANDLE_T handle,
+ KMF_DATA *cert,
+ KMF_DATA *plaintext,
+ KMF_DATA *ciphertext)
+{
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (cert == NULL ||
+ plaintext == NULL || ciphertext == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* check the keyUsage of the certificate */
+ ret = check_key_usage(handle, cert, KMF_KU_ENCRYPT_DATA);
+ if (ret != KMF_OK)
+ return (ret);
+
+ return (EncryptWithCert(handle, cert, plaintext, ciphertext));
+}
+
+/*
+ * Name: KMF_DecryptWithCert
+ *
+ * Description:
+ * Uses the private key associated with the cert to decrypt
+ * the ciphertext into the plaintext.
+ *
+ * Parameters:
+ * handle(input) - opaque handle for KMF session
+ * params(input) - contains parameters to be used to find the private
+ * key for decryption
+ * cert(input) - pointer to a DER encoded certificate for decryption
+ * by using its private key
+ * ciphertext(input) - pointer to the ciphertext contains to be
+ * decrypted data
+ * plaintext(output) - pointer to the plaintext after decryption
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_DecryptWithCert(KMF_HANDLE_T handle,
+ KMF_CRYPTOWITHCERT_PARAMS *params,
+ KMF_DATA *cert,
+ KMF_DATA *ciphertext,
+ KMF_DATA *plaintext)
+{
+ KMF_RETURN ret;
+ KMF_KEY_HANDLE Signkey;
+ KMF_X509_CERTIFICATE *x509cert = NULL;
+ KMF_X509_SPKI *spki_ptr;
+ KMF_PLUGIN *plugin;
+ KMF_ALGORITHM_INDEX AlgorithmId;
+
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (cert == NULL ||
+ plaintext == NULL || ciphertext == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* check the keyUsage of the certificate */
+ ret = check_key_usage(handle, cert, KMF_KU_ENCRYPT_DATA);
+ if (ret != KMF_OK)
+ return (ret);
+
+ /*
+ * Retrieve the private key from the keystore based on
+ * the certificate.
+ */
+ ret = find_private_key_by_cert(handle, params, cert, &Signkey);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ /* Decode the cert so we can get the alogorithm */
+ ret = DerDecodeSignedCertificate(cert, &x509cert);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ spki_ptr = &x509cert->certificate.subjectPublicKeyInfo;
+ AlgorithmId = X509_AlgorithmOidToAlgId((KMF_OID *)
+ &spki_ptr->algorithm.algorithm);
+
+ /* DSA does not support decrypt */
+ if (AlgorithmId == KMF_ALGID_DSA) {
+ ret = KMF_ERR_BAD_ALGORITHM;
+ goto cleanup;
+ }
+
+ plugin = FindPlugin(handle, Signkey.kstype);
+
+ if (plugin != NULL && plugin->funclist->DecryptData != NULL) {
+ ret = plugin->funclist->DecryptData(handle,
+ &Signkey, &spki_ptr->algorithm.algorithm,
+ ciphertext, plaintext);
+ } else {
+ ret = KMF_ERR_PLUGIN_NOTFOUND;
+ }
+
+cleanup:
+ KMF_FreeKMFKey(handle, &Signkey);
+ KMF_FreeSignedCert(x509cert);
+ free(x509cert);
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *target,
+ KMF_DATA *pcert)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (target == NULL || pcert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, target->kstype);
+
+ if (plugin != NULL && plugin->funclist->StoreCert != NULL) {
+ return (plugin->funclist->StoreCert(handle, target, pcert));
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+}
+
+KMF_RETURN
+KMF_ImportCert(KMF_HANDLE_T handle, KMF_IMPORTCERT_PARAMS *target)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (target == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, target->kstype);
+
+ if (plugin != NULL && plugin->funclist->ImportCert != NULL) {
+ return (plugin->funclist->ImportCert(handle, target));
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+}
+
+KMF_RETURN
+KMF_DeleteCertFromKeystore(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *target)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (target == NULL ||
+ (target->find_cert_validity < KMF_ALL_CERTS) ||
+ (target->find_cert_validity > KMF_EXPIRED_CERTS))
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, target->kstype);
+
+ if (plugin != NULL && plugin->funclist->DeleteCert != NULL) {
+ return (plugin->funclist->DeleteCert(handle, target));
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+}
+
+/*
+ * This function gets the CRL URI entries from the certificate's Distribution
+ * points extension, and downloads the CRL file. The function also returns
+ * the URI string and the format of the CRL file. The caller should free
+ * the space allocated for the returned URI string.
+ */
+static KMF_RETURN
+cert_get_crl(KMF_HANDLE_T handle, const KMF_DATA *cert, char *proxy,
+ char *filename, char **retn_uri, KMF_ENCODE_FORMAT *format)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509EXT_CRLDISTPOINTS crl_dps;
+ boolean_t done = B_FALSE;
+ char uri[1024];
+ char *proxyname = NULL;
+ char *proxy_port_s = NULL;
+ int proxy_port = 0;
+ int i, j;
+ char *path = NULL;
+
+ if (handle == NULL || cert == NULL || filename == NULL ||
+ retn_uri == NULL || format == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Get the proxy info */
+ if (proxy != NULL) {
+ proxyname = strtok(proxy, ":");
+ proxy_port_s = strtok(NULL, "\0");
+ if (proxy_port_s != NULL) {
+ proxy_port = strtol(proxy_port_s, NULL, 0);
+ } else {
+ proxy_port = 8080; /* default */
+ }
+ }
+
+ /*
+ * Get the CRL URI from the certificate's CRL Distribution
+ * Points extension and download the CRL file. There maybe more than
+ * one CRL URI entries in the DP extension, so we will continue
+ * the process until a CRL file is sucessfully downloaded or we
+ * are running out the CRL URI's.
+ */
+ ret = KMF_GetCertCRLDistributionPointsExt((const KMF_DATA *)cert,
+ &crl_dps);
+ if (ret != KMF_OK)
+ goto out;
+
+ for (i = 0; i < crl_dps.number; i++) {
+ KMF_CRL_DIST_POINT *dp = &(crl_dps.dplist[i]);
+ KMF_GENERALNAMES *fullname = &(dp->name.full_name);
+ KMF_DATA *data;
+
+ if (done)
+ break;
+ for (j = 0; j < fullname->number; j++) {
+ data = &(fullname->namelist[j].name);
+ (void) memcpy(uri, data->Data, data->Length);
+ uri[data->Length] = '\0';
+ ret = KMF_DownloadCRL(handle, uri, proxyname,
+ proxy_port, 30, filename, format);
+ if (ret == KMF_OK) {
+ done = B_TRUE;
+ path = malloc(data->Length + 1);
+ if (path == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) strncpy(path, uri, data->Length);
+ *retn_uri = path;
+ break;
+ }
+ }
+ }
+
+out:
+ KMF_FreeCRLDistributionPoints(&crl_dps);
+ return (ret);
+}
+
+static KMF_RETURN
+cert_crl_check(KMF_HANDLE_T handle,
+ KMF_VALIDATECERT_PARAMS *params,
+ KMF_DATA *user_cert,
+ KMF_DATA *issuer_cert)
+{
+ KMF_POLICY_RECORD *policy;
+ KMF_RETURN ret = KMF_OK;
+ KMF_IMPORTCRL_PARAMS icrl_params;
+ KMF_FINDCERTINCRL_PARAMS fcrl_params;
+ KMF_OPENSSL_PARAMS ssl_params;
+ KMF_VERIFYCRL_PARAMS vcrl_params;
+ char user_certfile[MAXPATHLEN];
+ char crlfile_tmp[MAXPATHLEN];
+ KMF_CHECKCRLDATE_PARAMS ccrldate_params;
+ char *basefilename = NULL;
+ char *dir = NULL;
+ char *crlfilename = NULL;
+ char *proxy = NULL;
+ char *uri = NULL;
+ KMF_ENCODE_FORMAT format;
+
+ if (handle == NULL || params == NULL ||
+ user_cert == NULL || issuer_cert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ policy = handle->policy;
+
+ (void) memset(&icrl_params, 0, sizeof (icrl_params));
+ (void) memset(&vcrl_params, 0, sizeof (vcrl_params));
+ (void) memset(&ccrldate_params, 0, sizeof (ccrldate_params));
+ (void) memset(&fcrl_params, 0, sizeof (fcrl_params));
+ (void) memset(&ssl_params, 0, sizeof (ssl_params));
+
+ /*
+ * If the get-crl-uri policy is TRUE, then download the CRL
+ * file first. The newly downloaded file will be stored in the
+ * NSS internal database for NSS keystore, and stored in a file for
+ * the File-based CRL plugins (OpenSSL and PKCS11).
+ *
+ * For file-based plugins, if the get-crl-uri policy is FALSE,
+ * then the caller should provide a CRL file in the policy.
+ * Also, after this step is done, the "crlfilename" variable should
+ * contain the proper CRL file to be used for the rest of CRL
+ * validation process.
+ */
+ basefilename = policy->validation_info.crl_info.basefilename;
+ dir = policy->validation_info.crl_info.directory;
+ if (policy->validation_info.crl_info.get_crl_uri) {
+ /*
+ * Create a temporary file to hold the new CRL file initially.
+ */
+ (void) strlcpy(crlfile_tmp, CRLFILE_TEMPNAME,
+ sizeof (crlfile_tmp));
+ if (mkstemp(crlfile_tmp) == -1) {
+ ret = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+
+ /*
+ * Get the URI entry from the certificate's CRL distribution
+ * points extension and download the CRL file.
+ */
+ proxy = policy->validation_info.crl_info.proxy;
+ ret = cert_get_crl(handle, user_cert, proxy, crlfile_tmp,
+ &uri, &format);
+ if (ret != KMF_OK) {
+ (void) unlink(crlfile_tmp);
+ goto cleanup;
+ }
+
+ /* Cache the CRL file. */
+ if (params->kstype == KMF_KEYSTORE_NSS) {
+ /*
+ * For NSS keystore, import this CRL file into th
+ * internal database.
+ */
+ icrl_params.kstype = KMF_KEYSTORE_NSS;
+ icrl_params.nssparms.slotlabel = NULL;
+ icrl_params.nssparms.crlfile = crlfile_tmp;
+ icrl_params.nssparms.crl_check = B_FALSE;
+ ret = KMF_ImportCRL(handle, &icrl_params);
+ (void) unlink(crlfile_tmp);
+ if (ret != KMF_OK)
+ goto cleanup;
+ } else {
+ /*
+ * For File-based CRL plugin's, find the cache
+ * location from the CRL policy's attributes and
+ * cache it.
+ */
+ if (basefilename == NULL)
+ basefilename = basename(uri);
+
+ crlfilename = get_fullpath(dir == NULL ? "./" : dir,
+ basefilename);
+ if (crlfilename == NULL) {
+ (void) unlink(crlfile_tmp);
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto cleanup;
+ }
+
+ if (rename(crlfile_tmp, crlfilename) == -1) {
+ (void) unlink(crlfile_tmp);
+ ret = KMF_ERR_WRITE_FILE;
+ goto cleanup;
+ }
+ }
+ } else {
+ /*
+ * If the get_crl_uri policy is FALSE, for File-based CRL
+ * plugins, get the input CRL file from the policy.
+ */
+ if (params->kstype != KMF_KEYSTORE_NSS) {
+ if (basefilename == NULL) {
+ ret = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ crlfilename = get_fullpath(dir == NULL ? "./" : dir,
+ basefilename);
+ if (crlfilename == NULL) {
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto cleanup;
+ }
+ }
+ }
+
+ /*
+ * Check the CRL signature if needed.
+ */
+ if (!policy->validation_info.crl_info.ignore_crl_sign) {
+ /*
+ * NSS CRL is not file based, and its signature
+ * has been verified during CRL import.
+ */
+ if (params->kstype != KMF_KEYSTORE_NSS) {
+ vcrl_params.crl_name = crlfilename;
+ vcrl_params.tacert = issuer_cert;
+
+ ret = KMF_VerifyCRLFile(handle, &vcrl_params);
+ if (ret != KMF_OK) {
+ goto cleanup;
+ }
+ }
+ }
+
+ /*
+ * Check the CRL validity if needed.
+ */
+ if (!policy->validation_info.crl_info.ignore_crl_date) {
+ /*
+ * This is for file-based CRL, but not for NSS CRL.
+ */
+ if (params->kstype != KMF_KEYSTORE_NSS) {
+ ccrldate_params.crl_name = crlfilename;
+
+ ret = KMF_CheckCRLDate(handle, &ccrldate_params);
+ if (ret != KMF_OK) {
+ goto cleanup;
+ }
+ }
+ }
+
+ /*
+ * Check the CRL revocation for the certificate.
+ */
+ fcrl_params.kstype = params->kstype;
+ switch (params->kstype) {
+ case KMF_KEYSTORE_NSS:
+ fcrl_params.certLabel = params->certLabel;
+ break;
+ case KMF_KEYSTORE_PK11TOKEN:
+ /*
+ * Create temporary file to hold the user certificate.
+ */
+ (void) strlcpy(user_certfile, CERTFILE_TEMPNAME,
+ sizeof (user_certfile));
+ if (mkstemp(user_certfile) == -1) {
+ ret = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+
+ ret = KMF_CreateCertFile(user_cert, KMF_FORMAT_ASN1,
+ user_certfile);
+ if (ret != KMF_OK) {
+ goto cleanup;
+ }
+
+ ssl_params.certfile = user_certfile;
+ ssl_params.crlfile = crlfilename;
+ fcrl_params.sslparms = ssl_params;
+ break;
+ case KMF_KEYSTORE_OPENSSL:
+ ssl_params.certfile = params->ks_opt_u.openssl_opts.certfile;
+ ssl_params.crlfile = crlfilename;
+ fcrl_params.sslparms = ssl_params;
+ break;
+ default:
+ ret = KMF_ERR_PLUGIN_NOTFOUND;
+ goto cleanup;
+ }
+
+ ret = KMF_FindCertInCRL(handle, &fcrl_params);
+ if (ret == KMF_ERR_NOT_REVOKED) {
+ ret = KMF_OK;
+ }
+
+cleanup:
+ (void) unlink(user_certfile);
+
+ if (crlfilename != NULL)
+ free(crlfilename);
+
+ if (uri != NULL)
+ free(uri);
+
+ return (ret);
+}
+
+static KMF_RETURN
+cert_ocsp_check(KMF_HANDLE_T handle,
+ KMF_VALIDATECERT_PARAMS *params,
+ KMF_DATA *user_cert,
+ KMF_DATA *issuer_cert,
+ KMF_DATA *response)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_POLICY_RECORD *policy;
+ KMF_FINDCERT_PARAMS fc_target;
+ KMF_OCSPRESPONSE_PARAMS_INPUT resp_params_in;
+ KMF_OCSPRESPONSE_PARAMS_OUTPUT resp_params_out;
+ KMF_DATA *new_response = NULL;
+ boolean_t ignore_response_sign = B_FALSE;
+ uint32_t ltime;
+ KMF_DATA *signer_cert = NULL;
+ KMF_BIGINT sernum = { NULL, 0 };
+
+ if (handle == NULL || params == NULL || user_cert == NULL ||
+ issuer_cert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ policy = handle->policy;
+
+ /*
+ * Get the response lifetime from policy.
+ */
+ if (policy->VAL_OCSP_BASIC.response_lifetime != NULL &&
+ (str2lifetime(policy->VAL_OCSP_BASIC.response_lifetime, &ltime)
+ < 0))
+ return (KMF_ERR_OCSP_RESPONSE_LIFETIME);
+
+ /*
+ * Get the ignore_response_sign policy.
+ *
+ * If ignore_response_sign is FALSE, we need to verify the response.
+ * Find the OCSP Responder certificate if it is specified in the OCSP
+ * policy.
+ */
+ ignore_response_sign = policy->VAL_OCSP_BASIC.ignore_response_sign;
+
+ if (ignore_response_sign == B_FALSE &&
+ policy->VAL_OCSP.has_resp_cert == B_TRUE) {
+ char *signer_name;
+ KMF_OPENSSL_PARAMS ssl_params;
+ KMF_X509_DER_CERT signer_retrcert;
+ uchar_t *bytes = NULL;
+ size_t bytelen;
+ uint32_t num = 0;
+
+ if (policy->VAL_OCSP_RESP_CERT.name == NULL ||
+ policy->VAL_OCSP_RESP_CERT.serial == NULL)
+ return (KMF_ERR_POLICY_NOT_FOUND);
+
+ signer_cert = malloc(sizeof (KMF_DATA));
+ if (signer_cert == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) memset(signer_cert, 0, sizeof (KMF_DATA));
+
+ signer_name = policy->VAL_OCSP_RESP_CERT.name;
+ ret = KMF_HexString2Bytes(
+ (uchar_t *)policy->VAL_OCSP_RESP_CERT.serial,
+ &bytes, &bytelen);
+ if (ret != KMF_OK || bytes == NULL) {
+ ret = KMF_ERR_OCSP_POLICY;
+ goto out;
+ }
+
+ sernum.val = bytes;
+ sernum.len = bytelen;
+
+ (void) memset(&fc_target, 0, sizeof (fc_target));
+ (void) memset(&ssl_params, 0, sizeof (ssl_params));
+
+ fc_target.subject = signer_name;
+ fc_target.serial = &sernum;
+
+ switch (params->kstype) {
+ case KMF_KEYSTORE_NSS:
+ fc_target.kstype = KMF_KEYSTORE_NSS;
+ params->nssparms.slotlabel =
+ params->nssparms.slotlabel;
+ break;
+
+ case KMF_KEYSTORE_OPENSSL:
+ fc_target.kstype = KMF_KEYSTORE_OPENSSL;
+ ssl_params.dirpath =
+ params->sslparms.dirpath == NULL ?
+ "./" : params->sslparms.dirpath;
+ fc_target.sslparms = ssl_params;
+ break;
+
+ case KMF_KEYSTORE_PK11TOKEN:
+ fc_target.kstype = KMF_KEYSTORE_PK11TOKEN;
+ break;
+ default:
+ ret = KMF_ERR_BAD_PARAMETER;
+ goto out;
+ break;
+ }
+
+ num = 0;
+ ret = KMF_FindCert(handle, &fc_target, NULL, &num);
+ if (ret != KMF_OK || num != 1) {
+ if (num == 0)
+ ret = KMF_ERR_CERT_NOT_FOUND;
+ if (num > 0)
+ ret = KMF_ERR_CERT_MULTIPLE_FOUND;
+ goto out;
+ }
+
+ (void) memset(&signer_retrcert, 0, sizeof (KMF_X509_DER_CERT));
+ ret = KMF_FindCert(handle, &fc_target, &signer_retrcert, &num);
+ if (ret == KMF_OK) {
+ signer_cert->Length =
+ signer_retrcert.certificate.Length;
+ signer_cert->Data = signer_retrcert.certificate.Data;
+ } else {
+ goto out;
+ }
+ }
+
+ /*
+ * If the caller provides an OCSP response, we will use it directly.
+ * Otherwise, we will try to fetch an OCSP response for the given
+ * certificate now.
+ */
+ if (response == NULL) {
+ new_response = (KMF_DATA *) malloc(sizeof (KMF_DATA));
+ if (new_response == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ new_response->Data = NULL;
+ new_response->Length = 0;
+
+ ret = KMF_GetOCSPForCert(handle, user_cert, issuer_cert,
+ new_response);
+ if (ret != KMF_OK)
+ goto out;
+ }
+
+ /*
+ * Process the OCSP response and retrieve the certificate status.
+ */
+ resp_params_in.issuer_cert = issuer_cert;
+ resp_params_in.user_cert = user_cert;
+ resp_params_in.signer_cert = signer_cert;
+ resp_params_in.response =
+ response == NULL ? new_response : response;
+ resp_params_in.response_lifetime = ltime;
+ resp_params_in.ignore_response_sign = ignore_response_sign;
+
+ ret = KMF_GetOCSPStatusForCert(handle, &resp_params_in,
+ &resp_params_out);
+ if (ret == KMF_OK) {
+ switch (resp_params_out.cert_status) {
+ case OCSP_GOOD:
+ break;
+ case OCSP_UNKNOWN:
+ ret = KMF_ERR_OCSP_UNKNOWN_CERT;
+ break;
+ case OCSP_REVOKED:
+ ret = KMF_ERR_OCSP_REVOKED;
+ break;
+ }
+ }
+
+out:
+ if (new_response) {
+ KMF_FreeData(new_response);
+ free(new_response);
+ }
+
+ if (signer_cert) {
+ KMF_FreeData(signer_cert);
+ free(signer_cert);
+ }
+
+ if (sernum.val != NULL)
+ free(sernum.val);
+
+ return (ret);
+}
+
+static KMF_RETURN
+cert_ku_check(KMF_HANDLE_T handle, KMF_DATA *cert)
+{
+ KMF_POLICY_RECORD *policy;
+ KMF_X509EXT_KEY_USAGE keyusage;
+ KMF_RETURN ret = KMF_OK;
+
+ if (handle == NULL || cert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ policy = handle->policy;
+ (void) memset(&keyusage, 0, sizeof (keyusage));
+ ret = KMF_GetCertKeyUsageExt(cert, &keyusage);
+
+ if (ret == KMF_ERR_EXTENSION_NOT_FOUND) {
+ if (policy->ku_bits) {
+ /* keyusage is not set in cert but is set in policy */
+ return (KMF_ERR_KEYUSAGE);
+ } else {
+ /* no keyusage set in both cert and policy */
+ return (KMF_OK);
+ }
+ }
+
+ if (ret != KMF_OK) {
+ /* real error */
+ return (ret);
+ }
+
+ /*
+ * Rule: if the KU bit is set in policy, the corresponding KU bit
+ * must be set in the certificate (but not vice versa).
+ */
+ if ((policy->ku_bits & keyusage.KeyUsageBits) == policy->ku_bits) {
+ return (KMF_OK);
+ } else {
+ return (KMF_ERR_KEYUSAGE);
+ }
+
+}
+
+static KMF_RETURN
+cert_eku_check(KMF_HANDLE_T handle, KMF_DATA *cert)
+{
+ KMF_POLICY_RECORD *policy;
+ KMF_X509EXT_BASICCONSTRAINTS constraint;
+ KMF_BOOL critical = B_FALSE;
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509EXT_EKU eku;
+ uint16_t cert_eku = 0, policy_eku = 0;
+ int i;
+
+ if (handle == NULL || cert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ policy = handle->policy;
+ (void) memset(&constraint, 0, sizeof (constraint));
+
+ ret = KMF_GetCertBasicConstraintExt(cert,
+ &critical, &constraint);
+
+ if ((ret != KMF_ERR_EXTENSION_NOT_FOUND) && (ret != KMF_OK)) {
+ /* real error */
+ return (ret);
+ }
+
+ if (constraint.cA) {
+ /* EKU extension appears only in end entity certificates */
+ return (KMF_ERR_KEYUSAGE);
+ }
+
+ ret = KMF_GetCertEKU(cert, &eku);
+ if ((ret != KMF_ERR_EXTENSION_NOT_FOUND) && (ret != KMF_OK)) {
+ /* real error */
+ return (ret);
+ }
+
+ if (ret == KMF_ERR_EXTENSION_NOT_FOUND) {
+ cert_eku = 0;
+ } else {
+ /*
+ * Build the EKU bitmap based on the certificate
+ */
+ for (i = 0; i < eku.nEKUs; i++) {
+ if (IsEqualOid(&eku.keyPurposeIdList[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_ServerAuth)) {
+ cert_eku |= KMF_EKU_SERVERAUTH;
+ } else if (IsEqualOid(&eku.keyPurposeIdList[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_ClientAuth)) {
+ cert_eku |= KMF_EKU_CLIENTAUTH;
+ } else if (IsEqualOid(&eku.keyPurposeIdList[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_CodeSigning)) {
+ cert_eku |= KMF_EKU_CODESIGNING;
+ } else if (IsEqualOid(&eku.keyPurposeIdList[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_EmailProtection)) {
+ cert_eku |= KMF_EKU_EMAIL;
+ } else if (IsEqualOid(&eku.keyPurposeIdList[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_TimeStamping)) {
+ cert_eku |= KMF_EKU_TIMESTAMP;
+ } else if (IsEqualOid(&eku.keyPurposeIdList[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning)) {
+ cert_eku |= KMF_EKU_OCSPSIGNING;
+ } else if (!policy->ignore_unknown_ekus) {
+ return (KMF_ERR_KEYUSAGE);
+ }
+ } /* for */
+ }
+
+ /*
+ * Build the EKU bitmap based on the policy
+ */
+ for (i = 0; i < policy->eku_set.eku_count; i++) {
+ if (IsEqualOid(&policy->eku_set.ekulist[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_ServerAuth)) {
+ policy_eku |= KMF_EKU_SERVERAUTH;
+ } else if (IsEqualOid(&policy->eku_set.ekulist[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_ClientAuth)) {
+ policy_eku |= KMF_EKU_CLIENTAUTH;
+ } else if (IsEqualOid(&policy->eku_set.ekulist[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_CodeSigning)) {
+ policy_eku |= KMF_EKU_CODESIGNING;
+ } else if (IsEqualOid(&policy->eku_set.ekulist[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_EmailProtection)) {
+ policy_eku |= KMF_EKU_EMAIL;
+ } else if (IsEqualOid(&policy->eku_set.ekulist[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_TimeStamping)) {
+ policy_eku |= KMF_EKU_TIMESTAMP;
+ } else if (IsEqualOid(&policy->eku_set.ekulist[i],
+ (KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning)) {
+ policy_eku |= KMF_EKU_OCSPSIGNING;
+ } else if (!policy->ignore_unknown_ekus) {
+ return (KMF_ERR_KEYUSAGE);
+ }
+ } /* for */
+
+ /*
+ * Rule: if the EKU OID is set in policy, the corresponding EKU OID
+ * must be set in the certificate (but not vice versa).
+ */
+ if ((policy_eku & cert_eku) == policy_eku) {
+ return (KMF_OK);
+ } else {
+ return (KMF_ERR_KEYUSAGE);
+ }
+}
+
+static KMF_RETURN
+kmf_find_issuer_cert(KMF_HANDLE_T handle,
+ KMF_VALIDATECERT_PARAMS *params,
+ char *user_issuer,
+ KMF_DATA *issuer_cert)
+{
+
+ KMF_RETURN ret = KMF_OK;
+ KMF_FINDCERT_PARAMS fc_target;
+ KMF_OPENSSL_PARAMS ssl_params;
+ KMF_X509_DER_CERT *certlist = NULL;
+ uint32_t i, num = 0;
+ time_t t_notbefore;
+ time_t t_notafter;
+ time_t latest;
+ KMF_DATA tmp_cert = {0, NULL};
+
+ if (handle == NULL || params == NULL ||
+ user_issuer == NULL || issuer_cert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&fc_target, 0, sizeof (fc_target));
+ (void) memset(&ssl_params, 0, sizeof (ssl_params));
+
+ fc_target.subject = user_issuer;
+
+ switch (params->kstype) {
+ case KMF_KEYSTORE_NSS:
+ fc_target.kstype = KMF_KEYSTORE_NSS;
+ fc_target.nssparms.slotlabel = params->nssparms.slotlabel;
+ break;
+
+ case KMF_KEYSTORE_OPENSSL:
+ fc_target.kstype = KMF_KEYSTORE_OPENSSL;
+ /* setup dirpath to search for TA in a directory */
+ if (params->sslparms.dirpath == NULL) {
+ ssl_params.dirpath = "./";
+ } else {
+ ssl_params.dirpath = params->sslparms.dirpath;
+ }
+ ssl_params.certfile = NULL;
+ fc_target.sslparms = ssl_params;
+ break;
+
+ case KMF_KEYSTORE_PK11TOKEN:
+ fc_target.kstype = KMF_KEYSTORE_PK11TOKEN;
+ break;
+ default:
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ num = 0;
+ ret = KMF_FindCert(handle, &fc_target, NULL, &num);
+ if (ret == KMF_OK && num > 0) {
+ certlist = (KMF_X509_DER_CERT *)malloc(num *
+ sizeof (KMF_X509_DER_CERT));
+
+ if (certlist == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ (void) memset(certlist, 0, num *
+ sizeof (KMF_X509_DER_CERT));
+
+ ret = KMF_FindCert(handle, &fc_target, certlist, &num);
+ if (ret != KMF_OK) {
+ free(certlist);
+ certlist = NULL;
+ goto out;
+ }
+ } else {
+ goto out;
+ }
+
+ if (num == 1) {
+ /* only one issuer cert is found */
+ tmp_cert.Length = certlist[0].certificate.Length;
+ tmp_cert.Data = certlist[0].certificate.Data;
+ } else {
+ /*
+ * More than one issuer certs are found. We will
+ * pick the latest one.
+ */
+ latest = 0;
+ for (i = 0; i < num; i++) {
+ ret = KMF_GetCertValidity(&certlist[i].certificate,
+ &t_notbefore, &t_notafter);
+ if (ret != KMF_OK) {
+ ret = KMF_ERR_VALIDITY_PERIOD;
+ goto out;
+ }
+
+ if (t_notbefore > latest) {
+ tmp_cert.Length =
+ certlist[i].certificate.Length;
+ tmp_cert.Data =
+ certlist[i].certificate.Data;
+ latest = t_notbefore;
+ }
+
+ }
+ }
+
+ issuer_cert->Length = tmp_cert.Length;
+ issuer_cert->Data = malloc(tmp_cert.Length);
+ if (issuer_cert->Data == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) memcpy(issuer_cert->Data, tmp_cert.Data,
+ tmp_cert.Length);
+
+out:
+ if (certlist != NULL) {
+ for (i = 0; i < num; i++)
+ KMF_FreeKMFCert(handle, &certlist[i]);
+ free(certlist);
+ }
+
+ return (ret);
+
+}
+
+static KMF_RETURN
+kmf_find_ta_cert(KMF_HANDLE_T handle,
+ KMF_VALIDATECERT_PARAMS *params,
+ KMF_DATA *ta_cert,
+ KMF_X509_NAME *user_issuerDN)
+{
+
+ KMF_POLICY_RECORD *policy;
+ KMF_RETURN ret = KMF_OK;
+ KMF_FINDCERT_PARAMS fc_target;
+ KMF_OPENSSL_PARAMS ssl_params;
+ uint32_t num = 0;
+ char *ta_name;
+ KMF_BIGINT serial = { NULL, 0 };
+ uchar_t *bytes = NULL;
+ size_t bytelen;
+ KMF_X509_DER_CERT ta_retrCert;
+ char *ta_subject = NULL;
+ KMF_X509_NAME ta_subjectDN;
+
+ if (handle == NULL || params == NULL ||
+ ta_cert == NULL || user_issuerDN == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ policy = handle->policy;
+ ta_name = policy->ta_name;
+
+ ret = KMF_HexString2Bytes((uchar_t *)policy->ta_serial,
+ &bytes, &bytelen);
+ if (ret != KMF_OK || bytes == NULL) {
+ ret = KMF_ERR_TA_POLICY;
+ goto out;
+ }
+
+ (void) memset(&fc_target, 0, sizeof (fc_target));
+ (void) memset(&ssl_params, 0, sizeof (ssl_params));
+
+ serial.val = bytes;
+ serial.len = bytelen;
+ fc_target.serial = &serial;
+ fc_target.subject = ta_name;
+
+ switch (params->kstype) {
+ case KMF_KEYSTORE_NSS:
+ fc_target.kstype = KMF_KEYSTORE_NSS;
+ fc_target.nssparms.slotlabel = params->nssparms.slotlabel;
+ break;
+
+ case KMF_KEYSTORE_OPENSSL:
+ fc_target.kstype = KMF_KEYSTORE_OPENSSL;
+ /* setup dirpath to search for TA in a directory */
+ if (params->sslparms.dirpath == NULL) {
+ ssl_params.dirpath = "./";
+ } else {
+ ssl_params.dirpath = params->sslparms.dirpath;
+ }
+ ssl_params.certfile = NULL;
+ fc_target.sslparms = ssl_params;
+ break;
+
+ case KMF_KEYSTORE_PK11TOKEN:
+ fc_target.kstype = KMF_KEYSTORE_PK11TOKEN;
+ break;
+ default:
+ ret = KMF_ERR_PLUGIN_NOTFOUND;
+ goto out;
+ }
+
+ num = 0;
+ ret = KMF_FindCert(handle, &fc_target, NULL, &num);
+ if (ret != KMF_OK || num != 1) {
+ if (num == 0)
+ ret = KMF_ERR_CERT_NOT_FOUND;
+ if (num > 1)
+ ret = KMF_ERR_CERT_MULTIPLE_FOUND;
+ goto out;
+ }
+
+ (void) memset(&ta_retrCert, 0, sizeof (KMF_X509_DER_CERT));
+
+ ret = KMF_FindCert(handle, &fc_target, &ta_retrCert, &num);
+ if (ret == KMF_OK) {
+ ta_cert->Length = ta_retrCert.certificate.Length;
+ ta_cert->Data = malloc(ta_retrCert.certificate.Length);
+ if (ta_cert->Data == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) memcpy(ta_cert->Data, ta_retrCert.certificate.Data,
+ ta_retrCert.certificate.Length);
+ } else {
+ goto out;
+ }
+
+ /*
+ * The found TA's name must be matching with issuer name in
+ * subscriber's certificate.
+ */
+ (void) memset(&ta_subjectDN, 0, sizeof (ta_subjectDN));
+
+ ret = KMF_GetCertSubjectNameString(handle, ta_cert, &ta_subject);
+ if (ret != KMF_OK)
+ goto out;
+
+ ret = KMF_DNParser(ta_subject, &ta_subjectDN);
+ if (ret != KMF_OK)
+ goto out;
+
+ ret = KMF_CompareRDNs(user_issuerDN, &ta_subjectDN);
+ KMF_FreeDN(&ta_subjectDN);
+
+out:
+ if (ta_retrCert.certificate.Data)
+ KMF_FreeKMFCert(handle, &ta_retrCert);
+
+ if ((ret != KMF_OK) && (ta_cert->Data != NULL))
+ free(ta_cert->Data);
+
+ if (serial.val != NULL)
+ free(serial.val);
+
+ if (ta_subject)
+ free(ta_subject);
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_ValidateCert(KMF_HANDLE_T handle,
+ KMF_VALIDATECERT_PARAMS *params,
+ int *result)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_FINDCERT_PARAMS fc_target;
+ KMF_OPENSSL_PARAMS ssl_params;
+ KMF_X509_DER_CERT user_retrCert;
+ KMF_DATA ta_cert = {0, NULL};
+ KMF_DATA user_cert = {0, NULL};
+ KMF_DATA issuer_cert = {0, NULL};
+ uint32_t num = 0;
+ char *user_issuer = NULL, *user_subject = NULL;
+ KMF_X509_NAME user_issuerDN, user_subjectDN;
+ boolean_t self_signed = B_FALSE;
+ KMF_POLICY_RECORD *policy;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if ((params == NULL) || (result == NULL))
+ return (KMF_ERR_BAD_PARAMETER);
+
+ policy = handle->policy;
+
+ *result = KMF_CERT_VALIDATE_OK;
+ (void) memset(&fc_target, 0, sizeof (fc_target));
+ (void) memset(&ssl_params, 0, sizeof (ssl_params));
+ (void) memset(&user_issuerDN, 0, sizeof (user_issuerDN));
+ (void) memset(&user_subjectDN, 0, sizeof (user_subjectDN));
+
+ fc_target.kstype = params->kstype;
+ fc_target.certLabel = params->certLabel;
+ fc_target.issuer = params->issuer;
+ fc_target.subject = params->subject;
+ fc_target.idstr = params->idstr;
+ fc_target.serial = params->serial;
+ if (params->kstype == KMF_KEYSTORE_NSS)
+ fc_target.ks_opt_u.nss_opts = params->ks_opt_u.nss_opts;
+ else if (params->kstype == KMF_KEYSTORE_OPENSSL)
+ fc_target.ks_opt_u.openssl_opts = params->ks_opt_u.openssl_opts;
+ else if (params->kstype == KMF_KEYSTORE_PK11TOKEN)
+ fc_target.ks_opt_u.pkcs11_opts = params->ks_opt_u.pkcs11_opts;
+ else
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+
+ /*
+ * Find the Subscriber's certificate based on the input parameter
+ */
+ ret = KMF_FindCert(handle, &fc_target, NULL, &num);
+ if (ret != KMF_OK || num != 1) {
+ (*result) = (*result) | KMF_CERT_VALIDATE_ERR_USER;
+ if (num == 0)
+ ret = KMF_ERR_CERT_NOT_FOUND;
+ if (num > 1)
+ ret = KMF_ERR_CERT_MULTIPLE_FOUND;
+ goto out;
+ }
+
+ (void) memset(&user_retrCert, 0, sizeof (KMF_X509_DER_CERT));
+
+ ret = KMF_FindCert(handle, &fc_target, &user_retrCert, &num);
+ if (ret == KMF_OK) {
+ user_cert.Length = user_retrCert.certificate.Length;
+ user_cert.Data = user_retrCert.certificate.Data;
+ } else {
+ *result |= KMF_CERT_VALIDATE_ERR_USER;
+ goto out;
+ }
+
+ if ((ret = KMF_GetCertIssuerNameString(handle, &user_cert,
+ &user_issuer)) != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_USER;
+ goto out;
+ }
+
+ if ((ret = KMF_DNParser(user_issuer, &user_issuerDN)) != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_USER;
+ goto out;
+ }
+
+ if ((ret = KMF_GetCertSubjectNameString(handle, &user_cert,
+ &user_subject)) != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_USER;
+ KMF_FreeDN(&user_issuerDN);
+ goto out;
+ }
+
+ if ((ret = KMF_DNParser(user_subject, &user_subjectDN)) != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_USER;
+ KMF_FreeDN(&user_issuerDN);
+ goto out;
+ }
+
+ if ((KMF_CompareRDNs(&user_issuerDN, &user_subjectDN)) == 0) {
+ /*
+ * this is a self-signed cert
+ */
+ self_signed = B_TRUE;
+ }
+
+ KMF_FreeDN(&user_subjectDN);
+
+ /*
+ * Check KeyUsage extension of the subscriber's certificate
+ */
+ ret = cert_ku_check(handle, &user_cert);
+ if (ret != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_KEYUSAGE;
+ goto out;
+ }
+
+ /*
+ * Validate Extended KeyUsage extension
+ */
+ ret = cert_eku_check(handle, &user_cert);
+ if (ret != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_EXT_KEYUSAGE;
+ goto out;
+ }
+
+ /*
+ * Check the certificate's validity period
+ *
+ * This step is needed when "ignore_date" in policy is set
+ * to false.
+ */
+ if (!policy->ignore_date) {
+ /*
+ * Validate expiration date
+ */
+ ret = KMF_CheckCertDate(handle, &user_cert);
+ if (ret != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_TIME;
+ goto out;
+ }
+ }
+
+ /*
+ * When "ignore_trust_anchor" in policy is set to FALSE,
+ * we will try to find the TA cert based on the TA policy
+ * attributes.
+ *
+ * TA's subject name (ta_name) and serial number (ta_serial)
+ * are defined as optional attributes in policy dtd, but they
+ * should exist in policy when "ignore_trust_anchor" is set
+ * to FALSE. The policy verification code has enforced that.
+ */
+ if (policy->ignore_trust_anchor) {
+ goto check_revocation;
+ }
+
+ ret = kmf_find_ta_cert(handle, params, &ta_cert, &user_issuerDN);
+ if (ret != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_TA;
+ goto out;
+ }
+
+ /*
+ * Verify the signature of subscriber's certificate using
+ * TA certificate.
+ */
+ if (self_signed) {
+ ret = KMF_VerifyCertWithCert(handle,
+ &user_cert, &user_cert);
+ } else {
+ ret = KMF_VerifyCertWithCert(handle,
+ &user_cert, &ta_cert);
+ }
+ if (ret != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_SIGNATURE;
+ goto out;
+ }
+
+check_revocation:
+ /*
+ * Check certificate revocation
+ */
+ if (self_signed) {
+ /* skip revocation checking */
+ goto out;
+ }
+
+ /*
+ * When CRL or OCSP revocation method is set in the policy,
+ * we will try to find the issuer of the subscriber certificate
+ * using the issuer name of the subscriber certificate. The
+ * issuer certificate will be used to do the CRL checking
+ * and OCSP checking.
+ */
+ if (!(policy->revocation & KMF_REVOCATION_METHOD_CRL) &&
+ !(policy->revocation & KMF_REVOCATION_METHOD_OCSP)) {
+ goto out;
+ }
+
+ ret = kmf_find_issuer_cert(handle, params, user_issuer,
+ &issuer_cert);
+ if (ret != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_ISSUER;
+ goto out;
+ }
+
+ if (policy->revocation & KMF_REVOCATION_METHOD_CRL) {
+ ret = cert_crl_check(handle, params,
+ &user_cert, &issuer_cert);
+ if (ret != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_CRL;
+ goto out;
+ }
+ }
+
+ if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
+ ret = cert_ocsp_check(handle, params,
+ &user_cert, &issuer_cert, params->ocsp_response);
+ if (ret != KMF_OK) {
+ *result |= KMF_CERT_VALIDATE_ERR_OCSP;
+ goto out;
+ }
+ }
+
+out:
+ if (user_retrCert.certificate.Data)
+ KMF_FreeKMFCert(handle, &user_retrCert);
+
+ if (user_issuer) {
+ KMF_FreeDN(&user_issuerDN);
+ free(user_issuer);
+ }
+
+ if (user_subject)
+ free(user_subject);
+
+ if (ta_cert.Data)
+ free(ta_cert.Data);
+
+ if (issuer_cert.Data)
+ free(issuer_cert.Data);
+
+ return (ret);
+
+}
+
+KMF_RETURN
+KMF_CreateCertFile(KMF_DATA *certdata, KMF_ENCODE_FORMAT format,
+ char *certfile)
+{
+ KMF_RETURN rv = KMF_OK;
+ int fd = -1;
+ KMF_DATA pemdata = {NULL, 0};
+
+ if (certdata == NULL || certfile == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (format != KMF_FORMAT_PEM && format != KMF_FORMAT_ASN1)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (format == KMF_FORMAT_PEM) {
+ int len;
+ rv = KMF_Der2Pem(KMF_CERT,
+ certdata->Data, certdata->Length,
+ &pemdata.Data, &len);
+ if (rv != KMF_OK)
+ goto cleanup;
+ pemdata.Length = (size_t)len;
+ }
+
+ if ((fd = open(certfile, O_CREAT |O_RDWR, 0644)) == -1) {
+ rv = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ if (format == KMF_FORMAT_PEM) {
+ if (write(fd, pemdata.Data, pemdata.Length) !=
+ pemdata.Length) {
+ rv = KMF_ERR_WRITE_FILE;
+ }
+ } else {
+ if (write(fd, certdata->Data, certdata->Length) !=
+ certdata->Length) {
+ rv = KMF_ERR_WRITE_FILE;
+ }
+ }
+
+cleanup:
+ if (fd != -1)
+ (void) close(fd);
+
+ KMF_FreeData(&pemdata);
+
+ return (rv);
+}
+
+KMF_RETURN
+KMF_IsCertFile(KMF_HANDLE_T handle, char *filename, KMF_ENCODE_FORMAT *pformat)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN (*IsCertFileFn)(void *, char *, KMF_ENCODE_FORMAT *);
+
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (filename == NULL || pformat == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * This framework function is actually implemented in the openssl
+ * plugin library, so we find the function address and call it.
+ */
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ if (plugin == NULL || plugin->dldesc == NULL) {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ IsCertFileFn = (KMF_RETURN(*)())dlsym(plugin->dldesc,
+ "OpenSSL_IsCertFile");
+ if (IsCertFileFn == NULL) {
+ return (KMF_ERR_FUNCTION_NOT_FOUND);
+ }
+
+ return (IsCertFileFn(handle, filename, pformat));
+}
+
+/*
+ * This function checks the validity period of a der-encoded certificate.
+ */
+KMF_RETURN
+KMF_CheckCertDate(KMF_HANDLE_T handle, KMF_DATA *cert)
+{
+ KMF_RETURN rv;
+ struct tm *gmt;
+ time_t t_now;
+ time_t t_notbefore;
+ time_t t_notafter;
+ KMF_POLICY_RECORD *policy;
+ uint32_t adj;
+
+ CLEAR_ERROR(handle, rv);
+ if (rv != KMF_OK)
+ return (rv);
+
+ if (cert == NULL || cert->Data == NULL ||
+ cert->Length == 0)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ policy = handle->policy;
+ rv = KMF_GetCertValidity(cert, &t_notbefore, &t_notafter);
+ if (rv != KMF_OK)
+ return (rv);
+
+ /*
+ * Get the current time. The time returned from time() is local which
+ * cannot be used directly. It must be converted to UTC/GMT first.
+ */
+ t_now = time(NULL);
+ gmt = gmtime(&t_now);
+ t_now = mktime(gmt);
+
+ /*
+ * Adjust the validity time
+ */
+ if (policy->validity_adjusttime != NULL) {
+ if (str2lifetime(policy->validity_adjusttime, &adj) < 0)
+ return (KMF_ERR_VALIDITY_PERIOD);
+ } else {
+ adj = 0;
+ }
+
+ t_notafter += adj;
+ t_notbefore -= adj;
+
+ if (t_now <= t_notafter && t_now >= t_notbefore) {
+ rv = KMF_OK;
+ } else {
+ rv = KMF_ERR_VALIDITY_PERIOD;
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+KMF_ExportPK12(KMF_HANDLE_T handle,
+ KMF_EXPORTP12_PARAMS *params,
+ char *filename)
+{
+ KMF_RETURN rv;
+ KMF_PLUGIN *plugin;
+ KMF_KEYSTORE_TYPE kstype;
+ KMF_X509_DER_CERT *certlist = NULL;
+ KMF_KEY_HANDLE *keys = NULL;
+ uint32_t numkeys;
+ uint32_t numcerts;
+ int i;
+
+ CLEAR_ERROR(handle, rv);
+ if (rv != KMF_OK)
+ return (rv);
+
+ if (params == NULL || filename == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ kstype = params->kstype;
+ if (kstype == KMF_KEYSTORE_PK11TOKEN) {
+ KMF_FINDCERT_PARAMS fcargs;
+
+ (void) memset(&fcargs, 0, sizeof (fcargs));
+
+ fcargs.kstype = kstype;
+ fcargs.certLabel = params->certLabel;
+ fcargs.issuer = params->issuer;
+ fcargs.subject = params->subject;
+ fcargs.serial = params->serial;
+ fcargs.idstr = params->idstr;
+
+ /*
+ * Special processing because PKCS11 doesn't have
+ * a native PKCS12 operation.
+ */
+ rv = KMF_FindCert(handle, &fcargs, NULL, &numcerts);
+ if (rv == KMF_OK && numcerts > 0) {
+ certlist = (KMF_X509_DER_CERT *)malloc(numcerts *
+ sizeof (KMF_X509_DER_CERT));
+ if (certlist == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(certlist, 0, numcerts *
+ sizeof (KMF_X509_DER_CERT));
+ rv = KMF_FindCert(handle, &fcargs,
+ certlist, &numcerts);
+ if (rv != KMF_OK) {
+ free(certlist);
+ return (rv);
+ }
+ } else {
+ return (rv);
+ }
+
+ numkeys = 0;
+ for (i = 0; i < numcerts; i++) {
+ KMF_CRYPTOWITHCERT_PARAMS fkparms;
+ KMF_KEY_HANDLE newkey;
+
+ fkparms.kstype = kstype;
+ fkparms.format = KMF_FORMAT_RAWKEY;
+ fkparms.cred = params->cred;
+ fkparms.certLabel = certlist[i].kmf_private.label;
+
+ rv = find_private_key_by_cert(handle, &fkparms,
+ &certlist[i].certificate, &newkey);
+ if (rv == KMF_OK) {
+ numkeys++;
+ keys = realloc(keys,
+ numkeys * sizeof (KMF_KEY_HANDLE));
+ if (keys == NULL) {
+ free(certlist);
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+ keys[numkeys - 1] = newkey;
+ } else if (rv == KMF_ERR_KEY_NOT_FOUND) {
+ /* it is OK if a key is not found */
+ rv = KMF_OK;
+ }
+ }
+ if (rv == KMF_OK) {
+ /*
+ * Switch the keystore type to use OpenSSL for
+ * exporting the raw cert and key data as PKCS12.
+ */
+ kstype = KMF_KEYSTORE_OPENSSL;
+ } else {
+ rv = KMF_ERR_KEY_NOT_FOUND;
+ goto out;
+ }
+ }
+ plugin = FindPlugin(handle, kstype);
+ if (plugin != NULL && plugin->funclist->ExportP12 != NULL) {
+ rv = plugin->funclist->ExportP12(handle,
+ params, numcerts, certlist,
+ numkeys, keys, filename);
+ } else {
+ rv = KMF_ERR_PLUGIN_NOTFOUND;
+ }
+
+out:
+ if (certlist != NULL) {
+ for (i = 0; i < numcerts; i++)
+ KMF_FreeKMFCert(handle, &certlist[i]);
+ free(certlist);
+ }
+ if (keys != NULL) {
+ for (i = 0; i < numkeys; i++)
+ KMF_FreeKMFKey(handle, &keys[i]);
+ free(keys);
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+KMF_ImportPK12(KMF_HANDLE_T handle, char *filename,
+ KMF_CREDENTIAL *cred,
+ KMF_DATA **certs, int *ncerts,
+ KMF_RAW_KEY_DATA **rawkeys, int *nkeys)
+{
+ KMF_RETURN rv;
+ KMF_PLUGIN *plugin;
+ KMF_RETURN (*openpkcs12)(KMF_HANDLE *,
+ char *, KMF_CREDENTIAL *,
+ KMF_DATA **, int *,
+ KMF_RAW_KEY_DATA **, int *);
+
+ CLEAR_ERROR(handle, rv);
+ if (rv != KMF_OK)
+ return (rv);
+
+ if (filename == NULL ||
+ cred == NULL ||
+ certs == NULL || ncerts == NULL ||
+ rawkeys == NULL || nkeys == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * Use the pkcs12 reader from the OpenSSL plugin.
+ */
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ if (plugin == NULL || plugin->dldesc == NULL) {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ openpkcs12 = (KMF_RETURN(*)())dlsym(plugin->dldesc,
+ "openssl_read_pkcs12");
+ if (openpkcs12 == NULL) {
+ return (KMF_ERR_FUNCTION_NOT_FOUND);
+ }
+
+ /* Use OpenSSL interfaces to get raw key and cert data */
+ rv = openpkcs12(handle, filename, cred, certs, ncerts,
+ rawkeys, nkeys);
+
+ return (rv);
+}
+
+
+KMF_BOOL
+IsEqualOid(KMF_OID *Oid1, KMF_OID *Oid2)
+{
+ return ((Oid1->Length == Oid2->Length) &&
+ !memcmp(Oid1->Data, Oid2->Data, Oid1->Length));
+}
+
+static KMF_RETURN
+copy_algoid(KMF_X509_ALGORITHM_IDENTIFIER *destid,
+ KMF_X509_ALGORITHM_IDENTIFIER *srcid)
+{
+ KMF_RETURN ret = KMF_OK;
+ if (!destid || !srcid)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ destid->algorithm.Length = srcid->algorithm.Length;
+ destid->algorithm.Data = malloc(destid->algorithm.Length);
+ if (destid->algorithm.Data == NULL)
+ return (KMF_ERR_MEMORY);
+
+ (void) memcpy(destid->algorithm.Data, srcid->algorithm.Data,
+ destid->algorithm.Length);
+
+ destid->parameters.Length = srcid->parameters.Length;
+ if (destid->parameters.Length > 0) {
+ destid->parameters.Data = malloc(destid->parameters.Length);
+ if (destid->parameters.Data == NULL)
+ return (KMF_ERR_MEMORY);
+
+ (void) memcpy(destid->parameters.Data, srcid->parameters.Data,
+ destid->parameters.Length);
+ } else {
+ destid->parameters.Data = NULL;
+ }
+ return (ret);
+}
+
+KMF_RETURN
+SignCert(KMF_HANDLE_T handle,
+ const KMF_DATA *SubjectCert,
+ KMF_KEY_HANDLE *Signkey,
+ KMF_DATA *SignedCert)
+{
+ KMF_X509_CERTIFICATE *subj_cert = NULL;
+ KMF_DATA data_to_sign = {0, NULL};
+ KMF_DATA signed_data = {0, NULL};
+ KMF_RETURN ret = KMF_OK;
+ KMF_ALGORITHM_INDEX algid;
+
+ if (!SignedCert)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ SignedCert->Length = 0;
+ SignedCert->Data = NULL;
+
+ if (!SubjectCert)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (!SubjectCert->Data || !SubjectCert->Length)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * Shortcut - just extract the already encoded TBS cert data from
+ * the original data buffer. Since we haven't changed anything,
+ * there is no need to re-encode it.
+ */
+ ret = ExtractX509CertParts((KMF_DATA *)SubjectCert,
+ &data_to_sign, NULL);
+ if (ret != KMF_OK) {
+ goto cleanup;
+ }
+
+ /* Estimate the signed data length generously */
+ signed_data.Length = data_to_sign.Length*2;
+ signed_data.Data = calloc(1, signed_data.Length);
+ if (!signed_data.Data) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * If we got here OK, decode into a structure and then re-encode
+ * the complete certificate.
+ */
+ ret = DerDecodeSignedCertificate(SubjectCert, &subj_cert);
+ if (ret != KMF_OK) {
+ goto cleanup;
+ }
+
+ /* We are re-signing this cert, so clear out old signature data */
+ if (subj_cert->signature.algorithmIdentifier.algorithm.Length == 0) {
+ KMF_FreeAlgOID(&subj_cert->signature.algorithmIdentifier);
+ ret = copy_algoid(&subj_cert->signature.algorithmIdentifier,
+ &subj_cert->certificate.signature);
+ }
+
+ if (ret)
+ goto cleanup;
+
+ /* Sign the data */
+ ret = KMF_SignDataWithKey(handle, Signkey,
+ CERT_ALG_OID(subj_cert),
+ &data_to_sign, &signed_data);
+
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ algid = X509_AlgorithmOidToAlgId(CERT_SIG_OID(subj_cert));
+
+ /*
+ * For DSA, KMF_SignDataWithKey() returns a 40-bytes decoded
+ * signature. So we must encode the signature correctly.
+ */
+ if (algid == KMF_ALGID_SHA1WithDSA) {
+
+ KMF_DATA signature;
+
+ ret = DerEncodeDSASignature(&signed_data, &signature);
+ KMF_FreeData(&signed_data);
+
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ subj_cert->signature.encrypted = signature;
+ } else {
+ subj_cert->signature.encrypted = signed_data;
+ }
+
+ /* Now, re-encode the cert with the new signature */
+ ret = DerEncodeSignedCertificate(subj_cert, SignedCert);
+
+cleanup:
+ /* Cleanup & return */
+ if (ret != KMF_OK)
+ KMF_FreeData(SignedCert);
+
+ KMF_FreeData(&data_to_sign);
+
+ if (subj_cert != NULL) {
+ KMF_FreeSignedCert(subj_cert);
+ free(subj_cert);
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+VerifyCertWithKey(KMF_HANDLE_T handle,
+ KMF_DATA *derkey,
+ const KMF_DATA *CertToBeVerified)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_CERTIFICATE *signed_cert = NULL;
+ KMF_X509_SPKI spki;
+ KMF_DATA data_to_verify = {0, NULL};
+ KMF_DATA signed_data = {0, NULL};
+ KMF_DATA signature = { 0, NULL };
+ KMF_ALGORITHM_INDEX algid;
+
+ /* check the caller and do other setup for this SPI call */
+ if (handle == NULL || CertToBeVerified == NULL ||
+ derkey == NULL || derkey->Data == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&spki, 0, sizeof (KMF_X509_SPKI));
+
+ ret = ExtractX509CertParts((KMF_DATA *)CertToBeVerified,
+ &data_to_verify, &signed_data);
+
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ ret = DerDecodeSPKI(derkey, &spki);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ /* Decode the signer cert so we can get the Algorithm data */
+ ret = DerDecodeSignedCertificate(CertToBeVerified, &signed_cert);
+ if (ret != KMF_OK)
+ return (ret);
+
+ algid = X509_AlgorithmOidToAlgId(CERT_SIG_OID(signed_cert));
+
+ if (algid == KMF_ALGID_NONE)
+ return (KMF_ERR_BAD_ALGORITHM);
+
+ if (algid == KMF_ALGID_SHA1WithDSA) {
+ ret = DerDecodeDSASignature(&signed_data, &signature);
+ if (ret != KMF_OK)
+ goto cleanup;
+ } else {
+ signature.Data = signed_data.Data;
+ signature.Length = signed_data.Length;
+ }
+
+ ret = PKCS_VerifyData(handle, algid, &spki,
+ &data_to_verify, &signature);
+
+cleanup:
+ if (data_to_verify.Data != NULL)
+ free(data_to_verify.Data);
+
+ if (signed_data.Data != NULL)
+ free(signed_data.Data);
+
+ if (signed_cert) {
+ KMF_FreeSignedCert(signed_cert);
+ free(signed_cert);
+ }
+ if (algid == KMF_ALGID_SHA1WithDSA) {
+ free(signature.Data);
+ }
+
+ KMF_FreeAlgOID(&spki.algorithm);
+ KMF_FreeData(&spki.subjectPublicKey);
+
+ return (ret);
+}
+
+KMF_RETURN
+VerifyDataWithKey(KMF_HANDLE_T handle,
+ KMF_DATA *derkey,
+ KMF_ALGORITHM_INDEX sigAlg,
+ KMF_DATA *indata,
+ KMF_DATA *insig)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_SPKI spki;
+
+ if (!indata || !insig || !derkey || !derkey->Data)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ ret = DerDecodeSPKI(derkey, &spki);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ ret = PKCS_VerifyData(handle, sigAlg, &spki, indata, insig);
+
+cleanup:
+ KMF_FreeAlgOID(&spki.algorithm);
+ KMF_FreeData(&spki.subjectPublicKey);
+
+ return (ret);
+}
+
+KMF_RETURN
+VerifyCertWithCert(KMF_HANDLE_T handle,
+ const KMF_DATA *CertToBeVerifiedData,
+ const KMF_DATA *SignerCertData)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_CERTIFICATE *SignerCert = NULL;
+ KMF_X509_CERTIFICATE *ToBeVerifiedCert = NULL;
+ KMF_X509_SPKI *pubkey;
+ KMF_DATA data_to_verify = {0, NULL};
+ KMF_DATA signed_data = {0, NULL};
+ KMF_DATA signature;
+ KMF_ALGORITHM_INDEX algid;
+
+ if (!CertToBeVerifiedData ||
+ !CertToBeVerifiedData->Data ||
+ !CertToBeVerifiedData->Length)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (!SignerCertData ||
+ !SignerCertData->Data ||
+ !SignerCertData->Length)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Decode the cert into parts for verification */
+ ret = ExtractX509CertParts((KMF_DATA *)CertToBeVerifiedData,
+ &data_to_verify, &signed_data);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ /* Decode the signer cert so we can get the SPKI data */
+ ret = DerDecodeSignedCertificate(SignerCertData, &SignerCert);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ /*
+ * TODO ! Validate the SignerCert to make sure it is OK to be
+ * used to verify other certs. Or - should this be done the calling
+ * application?
+ */
+ /* ValidateCert(SignerCert); */
+
+ /* Get the public key info from the signer certificate */
+ pubkey = &SignerCert->certificate.subjectPublicKeyInfo;
+
+ /* Decode the to-be-verified cert so we know what algorithm to use */
+ ret = DerDecodeSignedCertificate(CertToBeVerifiedData,
+ &ToBeVerifiedCert);
+
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ algid = X509_AlgorithmOidToAlgId(CERT_SIG_OID(ToBeVerifiedCert));
+
+ if (algid == KMF_ALGID_SHA1WithDSA) {
+ ret = DerDecodeDSASignature(&signed_data, &signature);
+ if (ret != KMF_OK)
+ goto cleanup;
+ } else {
+ signature.Data = signed_data.Data;
+ signature.Length = signed_data.Length;
+ }
+
+ ret = PKCS_VerifyData(handle, algid, pubkey,
+ &data_to_verify, &signature);
+
+cleanup:
+ KMF_FreeData(&data_to_verify);
+ KMF_FreeData(&signed_data);
+
+ if (SignerCert) {
+ KMF_FreeSignedCert(SignerCert);
+ free(SignerCert);
+ }
+
+ if (ToBeVerifiedCert) {
+ KMF_FreeSignedCert(ToBeVerifiedCert);
+ free(ToBeVerifiedCert);
+ }
+
+ if (algid == KMF_ALGID_SHA1WithDSA) {
+ free(signature.Data);
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+VerifyDataWithCert(KMF_HANDLE_T handle,
+ KMF_DATA *indata,
+ KMF_DATA *insig,
+ const KMF_DATA *SignerCertData)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_CERTIFICATE *SignerCert = NULL;
+ KMF_X509_SPKI *pubkey;
+ KMF_ALGORITHM_INDEX algid;
+
+ if (!indata ||
+ !indata->Data ||
+ !indata->Length)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (!insig ||
+ !insig->Data ||
+ !insig->Length)
+ return (KMF_ERR_BAD_PARAMETER);
+
+
+ if (!SignerCertData ||
+ !SignerCertData->Data ||
+ !SignerCertData->Length)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Decode the signer cert so we can get the SPKI data */
+ ret = DerDecodeSignedCertificate(SignerCertData, &SignerCert);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ /* Get the public key info from the signer certificate */
+ pubkey = &SignerCert->certificate.subjectPublicKeyInfo;
+
+ algid = X509_AlgorithmOidToAlgId(CERT_ALG_OID(SignerCert));
+ if (algid == KMF_ALGID_NONE) {
+ ret = KMF_ERR_BAD_ALGORITHM;
+ } else {
+ ret = PKCS_VerifyData(handle, algid,
+ pubkey, indata, insig);
+ }
+
+cleanup:
+ if (SignerCert) {
+ KMF_FreeSignedCert(SignerCert);
+ free(SignerCert);
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+SignCsr(KMF_HANDLE_T handle,
+ const KMF_DATA *SubjectCsr,
+ KMF_KEY_HANDLE *Signkey,
+ KMF_X509_ALGORITHM_IDENTIFIER *algo,
+ KMF_DATA *SignedCsr)
+{
+
+ KMF_CSR_DATA subj_csr;
+ KMF_TBS_CSR *tbs_csr = NULL;
+ KMF_DATA signed_data = {0, NULL};
+ KMF_RETURN ret = KMF_OK;
+
+ if (!SignedCsr)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ SignedCsr->Length = 0;
+ SignedCsr->Data = NULL;
+
+ if (!SubjectCsr)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (!SubjectCsr->Data || !SubjectCsr->Length)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&subj_csr, 0, sizeof (subj_csr));
+ /* Estimate the signed data length generously */
+ signed_data.Length = SubjectCsr->Length*2;
+ signed_data.Data = calloc(1, signed_data.Length);
+ if (!signed_data.Data) {
+ ret = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ /* Sign the data */
+ ret = KMF_SignDataWithKey(handle, Signkey, &algo->algorithm,
+ (KMF_DATA *)SubjectCsr, &signed_data);
+
+ if (KMF_OK != ret)
+ goto cleanup;
+
+ /*
+ * If we got here OK, decode into a structure and then re-encode
+ * the complete CSR.
+ */
+ ret = DerDecodeTbsCsr(SubjectCsr, &tbs_csr);
+ if (ret)
+ goto cleanup;
+
+ (void) memcpy(&subj_csr.csr, tbs_csr, sizeof (KMF_TBS_CSR));
+
+ ret = copy_algoid(&subj_csr.signature.algorithmIdentifier, algo);
+ if (ret)
+ goto cleanup;
+
+ subj_csr.signature.encrypted = signed_data;
+
+ /* Now, re-encode the CSR with the new signature */
+ ret = DerEncodeSignedCsr(&subj_csr, SignedCsr);
+ if (ret != KMF_OK) {
+ KMF_FreeData(SignedCsr);
+ goto cleanup;
+ }
+
+ /* Cleanup & return */
+cleanup:
+ free(tbs_csr);
+
+ KMF_FreeTBSCSR(&subj_csr.csr);
+
+ KMF_FreeAlgOID(&subj_csr.signature.algorithmIdentifier);
+ KMF_FreeData(&signed_data);
+
+ return (ret);
+}
+
+KMF_RETURN
+EncryptWithCert(KMF_HANDLE_T handle,
+ KMF_DATA *cert,
+ KMF_DATA *plaintext,
+ KMF_DATA *ciphertext)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_CERTIFICATE *x509cert = NULL;
+ KMF_X509_SPKI *pubkey;
+ KMF_OID *alg;
+ KMF_ALGORITHM_INDEX algid;
+
+ /* Decode the cert so we can get the SPKI data */
+ if ((ret = DerDecodeSignedCertificate(cert, &x509cert)) != KMF_OK)
+ return (ret);
+
+ /* Get the public key info from the certificate */
+ pubkey = &x509cert->certificate.subjectPublicKeyInfo;
+
+ /* Use the algorithm in SPKI to encrypt data */
+ alg = &pubkey->algorithm.algorithm;
+
+ algid = X509_AlgorithmOidToAlgId(alg);
+
+ /* DSA does not support encrypt */
+ if (algid == KMF_ALGID_DSA || algid == KMF_ALGID_NONE) {
+ KMF_FreeSignedCert(x509cert);
+ free(x509cert);
+ return (KMF_ERR_BAD_ALGORITHM);
+ }
+
+ ret = PKCS_EncryptData(handle, algid, pubkey, plaintext, ciphertext);
+ KMF_FreeSignedCert(x509cert);
+ free(x509cert);
+
+ return (ret);
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/client.c b/usr/src/lib/libkmf/libkmf/common/client.c
new file mode 100644
index 0000000000..15c158312e
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/client.c
@@ -0,0 +1,954 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * File: CLIENT.C
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <kmfapi.h>
+#include <kmfapiP.h>
+#include <libxml2/libxml/uri.h>
+
+extern int errno;
+
+#define OCSP_BUFSIZE 1024
+
+typedef enum {
+ KMF_RESPONSE_OCSP = 1,
+ KMF_RESPONSE_FILE = 2
+} KMF_RESPONSE_TYPE;
+
+#define TEMP_TEMPLATE "temp.XXXXXX"
+
+/*
+ * This function will establish a socket to the host on the specified port.
+ * If succeed, it return a socket descriptor; otherwise, return -1.
+ */
+static int init_socket(char *host, short port)
+{
+ struct sockaddr_in sin;
+ struct hostent *hp, hrec;
+ int sockfd, opt, herrno;
+ char hostbuf[BUFSIZ];
+
+ sin.sin_family = PF_INET;
+ sin.sin_port = htons(port);
+ if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
+ if ((hp = gethostbyname_r(host, &hrec, hostbuf,
+ sizeof (hostbuf), &herrno)) == NULL) {
+ return (-1);
+ }
+ (void) memcpy((char *)&sin.sin_addr, hp->h_addr,
+ hp->h_length);
+ }
+
+ if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+ return (-1);
+ }
+
+ opt = 1;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
+ sizeof (opt)) < 0) {
+ (void) close(sockfd);
+ return (-1);
+ }
+
+ if (connect(sockfd, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+ (void) close(sockfd);
+ return (-1);
+ }
+
+ return (sockfd);
+}
+
+/*
+ * This function will connect to host on the port.
+ * If succeed, return a socket descriptor; otherwise, return 0.
+ */
+static int
+connect_to_server(char *host, short port)
+{
+ int retry = 1;
+ int sd = 0;
+
+ while (retry) {
+ if ((sd = init_socket(host, port)) == -1) {
+ if (errno == ECONNREFUSED) {
+ retry = 1;
+ (void) sleep(1);
+ } else {
+ retry = 0;
+ }
+ } else {
+ retry = 0;
+ }
+ }
+ return (sd);
+}
+
+static KMF_RETURN
+send_ocsp_request(int sock, char *reqfile, char *hostname)
+{
+ KMF_RETURN ret = KMF_OK;
+ int filefd, bytes, n, total = 0;
+ char buf[OCSP_BUFSIZE];
+ struct stat s;
+ char req_header[256];
+ static char req_format[] =
+"POST %s HTTP/1.0\r\n\
+Content-Type: application/ocsp-request\r\n\
+Content-Length: %d\r\n\r\n";
+
+ if ((filefd = open(reqfile, O_RDONLY)) == -1) {
+ ret = KMF_ERR_OPEN_FILE;
+ return (ret);
+ }
+
+ /* open the request file */
+ if (fstat(filefd, &s) < 0) {
+ ret = KMF_ERR_OPEN_FILE;
+ return (ret);
+ }
+
+
+ /* Send http header */
+ if (hostname != NULL) {
+ (void) snprintf(req_header, 256, req_format, hostname,
+ s.st_size);
+ } else {
+ (void) snprintf(req_header, 256, req_format, "/", s.st_size);
+ }
+ bytes = strlen(req_header);
+
+ if ((n = write(sock, req_header, bytes)) < 0) {
+ ret = KMF_ERR_SEND_REQUEST;
+ goto exit;
+ }
+
+ /* Send the request content */
+ while ((bytes = read(filefd, buf, OCSP_BUFSIZE)) > 0) {
+ if ((n = write(sock, buf, bytes)) < 0) {
+ ret = KMF_ERR_SEND_REQUEST;
+ goto exit;
+ }
+ total += n;
+ (void) memset(buf, 0, sizeof (buf));
+ }
+
+exit:
+ (void) close(filefd);
+ return (ret);
+}
+
+
+/*
+ * Perform a write that can handle EINTR.
+ */
+static int
+looping_write(int fd, void *buf, int len)
+{
+ char *p = buf;
+ int cc, len2 = 0;
+
+ if (len == 0)
+ return (0);
+ do {
+ cc = write(fd, p, len);
+ if (cc < 0) {
+ if (errno == EINTR)
+ continue;
+ return (cc);
+ } else if (cc == 0) {
+ return (len2);
+ } else {
+ p += cc;
+ len2 += cc;
+ len -= cc;
+ }
+ } while (len > 0);
+
+ return (len2);
+}
+
+/*
+ * This function will get the response from the server, check the http status
+ * line, and write the response content to a file. If this is a OCSP response,
+ * it will check the content type also.
+ */
+static KMF_RETURN
+get_encoded_response(int sock, KMF_RESPONSE_TYPE resptype, int filefd,
+ unsigned int maxsecs)
+{
+ int ret = KMF_OK;
+ char *buf = NULL;
+ int buflen = 0;
+ int offset = 0;
+ int search_offset;
+ const int buf_incre = OCSP_BUFSIZE; /* 1 KB at a time */
+ const int maxBufSize = 8 * buf_incre; /* 8 KB max */
+ const char *CRLF = "\r\n";
+ const char *headerEndMark = "\r\n\r\n";
+ const char *httpprotocol = "HTTP/";
+ const int CRLFlen = strlen(CRLF);
+ const int marklen = strlen(headerEndMark);
+ const int httplen = strlen(httpprotocol);
+ char *headerEnd = NULL;
+ boolean_t EOS = B_FALSE;
+ const char *httpcode = NULL;
+ const char *contenttype = NULL;
+ int contentlength = 0;
+ int bytes = 0;
+ char *statusLineEnd = NULL;
+ char *space = NULL;
+ char *nextHeader = NULL;
+ struct pollfd pfd;
+ int sock_flag;
+ int poll_ret;
+ boolean_t timeout = B_FALSE;
+
+ /* set O_NONBLOCK flag on socket */
+ if ((sock_flag = fcntl(sock, F_GETFL, 0)) == -1) {
+ return (KMF_ERR_RECV_RESPONSE);
+ }
+ sock_flag |= O_NONBLOCK;
+ if (fcntl(sock, F_SETFL, sock_flag) == -1) {
+ return (KMF_ERR_RECV_RESPONSE);
+ }
+
+ /* set up poll */
+ pfd.fd = sock;
+ pfd.events = POLLIN;
+
+ /*
+ * First read HTTP status line and headers. We will read up to at
+ * least the end of the HTTP headers
+ */
+ do {
+ if ((buflen - offset) < buf_incre) {
+ buflen += buf_incre;
+ buf = realloc(buf, buflen + 1);
+ if (buf == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ }
+
+ pfd.revents = 0;
+ poll_ret = poll(&pfd, 1, maxsecs * MILLISEC);
+ if (poll_ret == 0) {
+ timeout = B_TRUE;
+ break;
+ } else if (poll_ret < 0) {
+ ret = KMF_ERR_RECV_RESPONSE;
+ goto out;
+ } else {
+ if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ ret = KMF_ERR_RECV_RESPONSE;
+ goto out;
+ }
+ }
+
+ bytes = read(sock, buf + offset, buf_incre);
+ if (bytes < 0) {
+ if (errno == EWOULDBLOCK) { /* no data this time */
+ continue;
+ } else {
+ ret = KMF_ERR_RECV_RESPONSE;
+ goto out;
+ }
+ } else if (bytes == 0) { /* no more data */
+ EOS = B_TRUE;
+ } else { /* bytes > 0 */
+ search_offset = (offset - marklen) > 0 ?
+ offset - marklen : 0;
+ offset += bytes;
+ *(buf + offset) = '\0'; /* NULL termination */
+
+ headerEnd = strstr((const char *)buf + search_offset,
+ headerEndMark);
+ }
+
+ } while ((!headerEnd) && (EOS == B_FALSE) && (buflen < maxBufSize));
+
+ if (timeout == B_TRUE) {
+ ret = KMF_ERR_RECV_TIMEOUT;
+ goto out;
+ } else if (headerEnd == NULL) {
+ /* could not find the end of headers */
+ ret = KMF_ERR_BAD_HTTP_RESPONSE;
+ goto out;
+ }
+
+ /*
+ * Parse the HTTP status line, which will look like this:
+ * "HTTP/1.1 200 OK".
+ */
+ statusLineEnd = strstr((const char *)buf, CRLF);
+ if (statusLineEnd == NULL) {
+ ret = KMF_ERR_BAD_HTTP_RESPONSE;
+ goto out;
+ }
+ *statusLineEnd = '\0';
+
+ space = strchr((const char *)buf, ' ');
+ if (space == NULL ||
+ (strncasecmp((const char *)buf, httpprotocol, httplen) != 0)) {
+ ret = KMF_ERR_BAD_HTTP_RESPONSE;
+ goto out;
+ }
+
+ /*
+ * Check the HTTP status code. If it is not 200, the HTTP response
+ * is not good.
+ */
+ httpcode = space + 1;
+ space = strchr(httpcode, ' ');
+ if (space == NULL) {
+ ret = KMF_ERR_BAD_HTTP_RESPONSE;
+ goto out;
+ }
+
+ *space = 0;
+ if (strcmp(httpcode, "200") != 0) {
+ ret = KMF_ERR_BAD_HTTP_RESPONSE;
+ goto out;
+ }
+
+ /*
+ * Parse the HTTP headers in the buffer. Save content-type and
+ * content-length only.
+ */
+ nextHeader = statusLineEnd + CRLFlen;
+ *headerEnd = '\0'; /* terminate */
+ do {
+ char *thisHeaderEnd = NULL;
+ char *value = NULL;
+ char *colon = strchr(nextHeader, ':');
+
+ if (colon == NULL) {
+ ret = KMF_ERR_BAD_HTTP_RESPONSE;
+ goto out;
+ }
+ *colon = '\0';
+
+ value = colon + 1;
+ if (*value != ' ') {
+ ret = KMF_ERR_BAD_HTTP_RESPONSE;
+ goto out;
+ }
+ value++;
+
+ thisHeaderEnd = strstr(value, CRLF);
+ if (thisHeaderEnd != NULL)
+ *thisHeaderEnd = '\0';
+
+ if (strcasecmp(nextHeader, "content-type") == 0) {
+ contenttype = value;
+ } else if (strcasecmp(nextHeader, "content-length") == 0) {
+ contentlength = atoi(value);
+ }
+
+ if (thisHeaderEnd != NULL) {
+ nextHeader = thisHeaderEnd + CRLFlen;
+ } else {
+ nextHeader = NULL;
+ }
+
+ } while (nextHeader && (nextHeader < (headerEnd + CRLFlen)));
+
+ /* Check the contenttype if this is an OCSP response */
+ if (resptype == KMF_RESPONSE_OCSP) {
+ if (contenttype == NULL) {
+ ret = KMF_ERR_BAD_HTTP_RESPONSE;
+ goto out;
+ } else if (strcasecmp(contenttype,
+ "application/ocsp-response") != 0) {
+ ret = KMF_ERR_BAD_HTTP_RESPONSE;
+ goto out;
+ }
+ }
+
+ /* Now we are ready to read the body of the response */
+ offset = offset - (int)(headerEnd - (const char *)buf) - marklen;
+ if (offset) {
+ /* move all data to the beginning of the buffer */
+ (void) memmove(buf, headerEnd + marklen, offset);
+ }
+
+ /* resize buffer to only what's needed to hold the current response */
+ buflen = (1 + (offset-1) / buf_incre) * buf_incre;
+
+ while ((EOS == B_FALSE) &&
+ ((contentlength == 0) || (offset < contentlength)) &&
+ (buflen < maxBufSize)) {
+ /* we still need to receive more content data */
+ if ((buflen - offset) < buf_incre) {
+ buflen += buf_incre;
+ buf = realloc(buf, buflen + 1);
+ if (buf == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ }
+
+ pfd.revents = 0;
+ poll_ret = poll(&pfd, 1, maxsecs * MILLISEC);
+ if (poll_ret == 0) {
+ timeout = B_TRUE;
+ break;
+ } else if (poll_ret < 0) {
+ ret = KMF_ERR_RECV_RESPONSE;
+ goto out;
+ } else {
+ if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ ret = KMF_ERR_RECV_RESPONSE;
+ goto out;
+ }
+ }
+
+ bytes = read(sock, buf + offset, buf_incre);
+ if (bytes < 0) {
+ if (errno == EWOULDBLOCK) {
+ continue;
+ } else {
+ ret = KMF_ERR_RECV_RESPONSE;
+ goto out;
+ }
+ } else if (bytes == 0) { /* no more data */
+ EOS = B_TRUE;
+ } else {
+ offset += bytes;
+ }
+ }
+
+ if (timeout == B_TRUE) {
+ ret = KMF_ERR_RECV_TIMEOUT;
+ goto out;
+ } else if (((contentlength != 0) && (offset < contentlength)) ||
+ offset == 0) {
+ ret = KMF_ERR_BAD_HTTP_RESPONSE;
+ goto out;
+ }
+
+ /* write to the file */
+ if (looping_write(filefd, buf, offset) != offset) {
+ ret = KMF_ERR_WRITE_FILE;
+ }
+
+out:
+ free(buf);
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetEncodedOCSPResponse(KMF_HANDLE_T handle, char *reqfile, char *hostname,
+ int port, char *proxy, int proxy_port, char *respfile,
+ unsigned int maxsecs)
+{
+ KMF_RETURN ret = KMF_OK;
+ int sock, respfd;
+ char http_hostname[256];
+ int final_proxy_port, final_port;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (hostname == NULL || reqfile == NULL || respfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ final_proxy_port = (proxy_port == 0 || proxy_port == -1) ?
+ 80 : proxy_port;
+ final_port = (port == 0 || port == -1) ? 80 : port;
+
+ /* Connect to server */
+ if (proxy != NULL) {
+ sock = connect_to_server(proxy, final_proxy_port);
+ } else {
+ sock = connect_to_server(hostname, final_port);
+ }
+
+ if (sock == -1) {
+ return (KMF_ERR_CONNECT_SERVER);
+ }
+
+ /* Send the OCSP request */
+ if (proxy != NULL) {
+ (void) snprintf(http_hostname, sizeof (http_hostname),
+ "http://%s:%d", hostname, final_port);
+ ret = send_ocsp_request(sock, reqfile, http_hostname);
+ } else {
+ ret = send_ocsp_request(sock, reqfile, NULL);
+ }
+
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+ /* Retrieve the OCSP response */
+ if (maxsecs == 0) {
+ maxsecs = 30; /* default poll time limit is 30 seconds */
+ }
+
+ if ((respfd = open(respfile, O_CREAT |O_RDWR | O_EXCL, 0600)) == -1) {
+ ret = KMF_ERR_OPEN_FILE;
+ } else {
+ ret = get_encoded_response(sock, KMF_RESPONSE_OCSP,
+ respfd, maxsecs);
+ (void) close(respfd);
+ }
+
+out:
+ (void) close(sock);
+ return (ret);
+}
+
+static KMF_RETURN
+send_download_request(int sock, char *hostname, int port, boolean_t is_proxy,
+ char *loc)
+{
+ KMF_RETURN ret = KMF_OK;
+ char url[256];
+ char req_header[1024];
+ static char req_format[] =
+"GET %s HTTP/1.0\r\n\
+Host: %s:%d\r\n\
+Accept: */*\r\n\r\n";
+
+ if (is_proxy) {
+ (void) snprintf(url, sizeof (url), "http://%s:%d/%s",
+ hostname, port, loc);
+ } else {
+ (void) snprintf(url, sizeof (url), "/%s", loc);
+ }
+
+ (void) snprintf(req_header, sizeof (req_header), req_format, url,
+ hostname, port);
+
+ if (write(sock, req_header, strlen(req_header)) < 0) {
+ ret = KMF_ERR_SEND_REQUEST;
+ }
+
+ return (ret);
+}
+
+static KMF_RETURN
+download_file(char *uri, char *proxy, int proxy_port,
+ unsigned int maxsecs, int filefd)
+{
+ KMF_RETURN ret = KMF_OK;
+ xmlURIPtr uriptr;
+ int sock;
+ boolean_t is_proxy;
+ int final_proxy_port;
+ char *hostname = NULL;
+ char *path = NULL;
+ int port;
+
+ if (uri == NULL || filefd == -1)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Parse URI */
+ uriptr = xmlParseURI(uri);
+ if (uriptr == NULL) {
+ ret = KMF_ERR_BAD_URI;
+ goto out;
+ }
+
+ if (uriptr->scheme == NULL ||
+ strncasecmp(uriptr->scheme, "http", 4) != 0) {
+ ret = KMF_ERR_BAD_URI; /* we support http only */
+ goto out;
+ }
+
+ /* get the host name */
+ hostname = uriptr->server;
+ if (hostname == NULL) {
+ ret = KMF_ERR_BAD_URI;
+ goto out;
+ }
+
+ /* get the port number */
+ port = uriptr->port;
+ if (port == 0) {
+ port = 80;
+ }
+
+ /* Get the path */
+ path = uriptr->path;
+ if (path == NULL) {
+ ret = KMF_ERR_BAD_URI;
+ goto out;
+ }
+
+ /* Connect to server */
+ if (proxy != NULL) {
+ final_proxy_port = (proxy_port == 0 || proxy_port == -1) ?
+ 80 : proxy_port;
+ is_proxy = B_TRUE;
+ sock = connect_to_server(proxy, final_proxy_port);
+ } else {
+ is_proxy = B_FALSE;
+ sock = connect_to_server(hostname, port);
+ }
+ if (sock == -1) {
+ ret = KMF_ERR_CONNECT_SERVER;
+ goto out;
+ }
+
+ /* Send the request */
+ ret = send_download_request(sock, hostname, port, is_proxy, path);
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+ /* Retrieve the response */
+ ret = get_encoded_response(sock, KMF_RESPONSE_FILE, filefd,
+ maxsecs == 0 ? 30 : maxsecs);
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+out:
+ if (uriptr != NULL)
+ xmlFreeURI(uriptr);
+
+ if (sock != -1)
+ (void) close(sock);
+
+ return (ret);
+}
+
+
+KMF_RETURN
+KMF_DownloadCRL(KMF_HANDLE_T handle, char *uri, char *proxy, int proxy_port,
+ unsigned int maxsecs, char *crlfile, KMF_ENCODE_FORMAT *pformat)
+{
+ KMF_RETURN ret = KMF_OK;
+ char *filename = NULL;
+ char tempfn[MAXPATHLEN];
+ boolean_t temp_created = B_FALSE;
+ mode_t old_mode;
+ int fd = -1, tmpfd = -1;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (uri == NULL || crlfile == NULL || pformat == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if ((fd = open(crlfile, O_CREAT |O_RDWR | O_EXCL, 0644)) == -1)
+ return (KMF_ERR_OPEN_FILE);
+
+ /*
+ * Download the file and save it to a temp file. To make rename()
+ * happy, the temp file needs to be created in the same directory as
+ * the target file.
+ */
+ if ((filename = strdup(crlfile)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) snprintf(tempfn, MAXPATHLEN, "%s/%s", dirname(filename),
+ TEMP_TEMPLATE);
+ old_mode = umask(077);
+ tmpfd = mkstemp(tempfn);
+ (void) umask(old_mode);
+ if (tmpfd == -1) {
+ ret = KMF_ERR_INTERNAL;
+ goto out;
+ } else {
+ temp_created = B_TRUE;
+ }
+
+ ret = download_file(uri, proxy, proxy_port, maxsecs, tmpfd);
+ (void) close(tmpfd);
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+ /* Check if it is a CRL file and get its format */
+ if (KMF_IsCRLFile(handle, tempfn, pformat) != KMF_OK) {
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto out;
+ }
+
+ /* Finally, change the temp filename to the target crlfile */
+ if (rename(tempfn, crlfile) == -1) {
+ ret = KMF_ERR_WRITE_FILE;
+ goto out;
+ }
+
+out:
+ if (filename != NULL)
+ free(filename);
+
+ if (ret != KMF_OK && temp_created == B_TRUE)
+ (void) unlink(tempfn);
+
+ if (fd != -1)
+ (void) close(fd);
+
+ return (ret);
+}
+
+
+KMF_RETURN
+KMF_DownloadCert(KMF_HANDLE_T handle, char *uri, char *proxy, int proxy_port,
+ unsigned int maxsecs, char *certfile, KMF_ENCODE_FORMAT *pformat)
+{
+ KMF_RETURN ret = KMF_OK;
+ char *filename = NULL;
+ char tempfn[MAXPATHLEN];
+ boolean_t temp_created = B_FALSE;
+ mode_t old_mode;
+ int fd = -1, tmpfd = -1;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (uri == NULL || certfile == NULL || pformat == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if ((fd = open(certfile, O_CREAT |O_RDWR | O_EXCL, 0644)) == -1)
+ return (KMF_ERR_OPEN_FILE);
+
+ /*
+ * Download the file and save it to a temp file. To make rename()
+ * happy, the temp file needs to be created in the same directory as
+ * the target file.
+ */
+ if ((filename = strdup(certfile)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) snprintf(tempfn, MAXPATHLEN, "%s/%s", dirname(filename),
+ TEMP_TEMPLATE);
+
+ old_mode = umask(077);
+ tmpfd = mkstemp(tempfn);
+ (void) umask(old_mode);
+ if (tmpfd == -1) {
+ ret = KMF_ERR_INTERNAL;
+ goto out;
+ } else {
+ temp_created = B_TRUE;
+ }
+
+ ret = download_file(uri, proxy, proxy_port, maxsecs, tmpfd);
+ (void) close(tmpfd);
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+ /* Check if it is a Cert file and get its format */
+ if (KMF_IsCertFile(handle, tempfn, pformat) != KMF_OK) {
+ ret = KMF_ERR_BAD_CERTFILE;
+ goto out;
+ }
+
+ /* Finally, change the temp filename to the target filename */
+ if (rename(tempfn, certfile) == -1) {
+ ret = KMF_ERR_WRITE_FILE;
+ goto out;
+ }
+
+out:
+ if (filename != NULL)
+ free(filename);
+
+ if (ret != KMF_OK && temp_created == B_TRUE)
+ (void) unlink(tempfn);
+
+ if (fd != -1)
+ (void) close(fd);
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetOCSPForCert(KMF_HANDLE_T handle,
+ KMF_DATA *user_cert,
+ KMF_DATA *ta_cert,
+ KMF_DATA *response)
+{
+ KMF_POLICY_RECORD *policy;
+ KMF_RETURN ret = KMF_OK;
+ KMF_OCSPREQUEST_PARAMS req_params;
+ char *hostname = NULL, *host_uri = NULL, *proxyname = NULL;
+ char *proxy_port_s = NULL;
+ int host_port = 0, proxy_port = 0;
+ char ocsp_reqname[MAXPATHLEN];
+ char ocsp_respname[MAXPATHLEN];
+ KMF_X509EXT_AUTHINFOACCESS aia;
+ int i;
+ boolean_t found = B_FALSE;
+ KMF_X509EXT_ACCESSDESC *access_info;
+ xmlURIPtr uriptr = NULL;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (user_cert == NULL ||
+ ta_cert == NULL || response == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ policy = handle->policy;
+
+ /* Create an OCSP request */
+ req_params.issuer_cert = ta_cert;
+ req_params.user_cert = user_cert;
+
+ /*
+ * Create temporary files to hold the OCSP request & response data.
+ */
+ (void) strlcpy(ocsp_reqname, OCSPREQ_TEMPNAME,
+ sizeof (ocsp_reqname));
+ if (mkstemp(ocsp_reqname) == -1) {
+ return (KMF_ERR_INTERNAL);
+ }
+
+ (void) strlcpy(ocsp_respname, OCSPRESP_TEMPNAME,
+ sizeof (ocsp_respname));
+ if (mkstemp(ocsp_respname) == -1) {
+ return (KMF_ERR_INTERNAL);
+ }
+
+ ret = KMF_CreateOCSPRequest(handle, &req_params, ocsp_reqname);
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+ if (policy->VAL_OCSP_BASIC.uri_from_cert == 0) {
+ if (policy->VAL_OCSP_BASIC.responderURI == NULL) {
+ ret = KMF_ERR_OCSP_POLICY;
+ goto out;
+ }
+ host_uri = policy->VAL_OCSP_BASIC.responderURI;
+
+ } else {
+ /*
+ * Get the responder URI from certificate
+ * Authority Information Access
+ * thru OID_PKIX_AD_OCSP
+ */
+ ret = KMF_GetCertAuthInfoAccessExt(user_cert, &aia);
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+ for (i = 0; i < aia.numberOfAccessDescription; i++) {
+ access_info = &aia.AccessDesc[i];
+ if (IsEqualOid(&access_info->AccessMethod,
+ (KMF_OID *)&KMFOID_PkixAdOcsp)) {
+ host_uri =
+ (char *)access_info->AccessLocation.Data;
+ found = B_TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ ret = KMF_ERR_OCSP_POLICY;
+ goto out;
+ }
+ }
+
+ /* Parse the URI string; get the hostname and port */
+ uriptr = xmlParseURI(host_uri);
+ if (uriptr == NULL) {
+ ret = KMF_ERR_BAD_URI;
+ goto out;
+ }
+
+ if (strncasecmp(uriptr->scheme, "http", 4) != 0) {
+ ret = KMF_ERR_BAD_URI; /* we support http only */
+ goto out;
+ }
+
+ hostname = uriptr->server;
+ if (hostname == NULL) {
+ ret = KMF_ERR_BAD_URI;
+ goto out;
+ }
+
+ host_port = uriptr->port;
+ if (host_port == 0)
+ host_port = 80;
+
+ /* get the proxy info */
+ if (policy->VAL_OCSP_BASIC.proxy != NULL) {
+ char *last;
+ proxyname =
+ strtok_r(policy->VAL_OCSP_BASIC.proxy, ":", &last);
+ proxy_port_s = strtok_r(NULL, "\0", &last);
+ if (proxy_port_s != NULL) {
+ proxy_port = strtol(proxy_port_s, NULL, 0);
+ } else {
+ proxy_port = 8080; /* default */
+ }
+ }
+
+ /*
+ * Send the request to an OCSP responder and receive an
+ * OCSP response.
+ */
+ ret = KMF_GetEncodedOCSPResponse(handle, ocsp_reqname,
+ hostname, host_port, proxyname, proxy_port,
+ ocsp_respname, 30);
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+ ret = KMF_ReadInputFile(handle, ocsp_respname, response);
+
+out:
+ (void) unlink(ocsp_reqname);
+ (void) unlink(ocsp_respname);
+
+ if (uriptr != NULL)
+ xmlFreeURI(uriptr);
+
+ return (ret);
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/csrcrlop.c b/usr/src/lib/libkmf/libkmf/common/csrcrlop.c
new file mode 100644
index 0000000000..4c8a700994
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/csrcrlop.c
@@ -0,0 +1,563 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright(c) 1995-2000 Intel Corporation. All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <link.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include <ber_der.h>
+#include <kmfapiP.h>
+
+#include <pem_encode.h>
+#include <libgen.h>
+#include <cryptoutil.h>
+
+
+/*
+ *
+ * Name: KMF_SetCSRPubKey
+ *
+ * Description:
+ * This function converts the specified plugin public key to SPKI form,
+ * and save it in the KMF_CSR_DATA internal structure
+ *
+ * Parameters:
+ * KMFkey(input) - pointer to the KMF_KEY_HANDLE structure containing the
+ * public key generated by the plug-in CreateKeypair
+ * Csr(input/output) - pointer to a KMF_CSR_DATA structure containing
+ * SPKI
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_SetCSRPubKey(KMF_HANDLE_T handle,
+ KMF_KEY_HANDLE *KMFKey,
+ KMF_CSR_DATA *Csr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_SPKI *spki_ptr;
+ KMF_PLUGIN *plugin;
+ KMF_DATA KeyData = {NULL, 0};
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (KMFKey == NULL || Csr == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* The keystore must extract the pubkey data */
+ plugin = FindPlugin(handle, KMFKey->kstype);
+ if (plugin != NULL && plugin->funclist->EncodePubkeyData != NULL) {
+ ret = plugin->funclist->EncodePubkeyData(handle,
+ KMFKey, &KeyData);
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ spki_ptr = &Csr->csr.subjectPublicKeyInfo;
+
+ ret = DerDecodeSPKI(&KeyData, spki_ptr);
+
+ KMF_FreeData(&KeyData);
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_SetCSRVersion(KMF_CSR_DATA *CsrData, uint32_t version)
+{
+ if (CsrData == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * From RFC 3280:
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ */
+ if (version != 0 && version != 1 && version != 2)
+ return (KMF_ERR_BAD_PARAMETER);
+ return (set_integer(&CsrData->csr.version, (void *)&version,
+ sizeof (uint32_t)));
+}
+
+KMF_RETURN
+KMF_SetCSRSubjectName(KMF_CSR_DATA *CsrData,
+ KMF_X509_NAME *subject_name_ptr)
+{
+ if (CsrData != NULL && subject_name_ptr != NULL)
+ CsrData->csr.subject = *subject_name_ptr;
+ else
+ return (KMF_ERR_BAD_PARAMETER);
+
+ return (KMF_OK);
+}
+
+KMF_RETURN
+KMF_CreateCSRFile(KMF_DATA *csrdata, KMF_ENCODE_FORMAT format,
+ char *csrfile)
+{
+ KMF_RETURN rv = KMF_OK;
+ int fd = -1;
+ KMF_DATA pemdata = {NULL, 0};
+
+ if (csrdata == NULL || csrfile == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (format != KMF_FORMAT_PEM && format != KMF_FORMAT_ASN1)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (format == KMF_FORMAT_PEM) {
+ int len;
+ rv = KMF_Der2Pem(KMF_CSR,
+ csrdata->Data, csrdata->Length,
+ &pemdata.Data, &len);
+ if (rv != KMF_OK)
+ goto cleanup;
+ pemdata.Length = (size_t)len;
+ }
+
+ if ((fd = open(csrfile, O_CREAT |O_RDWR, 0644)) == -1) {
+ rv = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ if (format == KMF_FORMAT_PEM) {
+ if (write(fd, pemdata.Data, pemdata.Length) !=
+ pemdata.Length) {
+ rv = KMF_ERR_WRITE_FILE;
+ }
+ } else {
+ if (write(fd, csrdata->Data, csrdata->Length) !=
+ csrdata->Length) {
+ rv = KMF_ERR_WRITE_FILE;
+ }
+ }
+
+cleanup:
+ if (fd != -1)
+ (void) close(fd);
+
+ KMF_FreeData(&pemdata);
+
+ return (rv);
+}
+
+KMF_RETURN
+KMF_SetCSRExtension(KMF_CSR_DATA *Csr,
+ KMF_X509_EXTENSION *extn)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSIONS *exts;
+
+ if (Csr == NULL || extn == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ exts = &Csr->csr.extensions;
+
+ ret = add_an_extension(exts, extn);
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_SetCSRSignatureAlgorithm(KMF_CSR_DATA *CsrData,
+ KMF_ALGORITHM_INDEX sigAlg)
+{
+ KMF_OID *alg;
+
+ if (CsrData == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ alg = X509_AlgIdToAlgorithmOid(sigAlg);
+
+ if (alg != NULL) {
+ (void) copy_data((KMF_DATA *)
+ &CsrData->signature.algorithmIdentifier.algorithm,
+ (KMF_DATA *)alg);
+ (void) copy_data(
+ &CsrData->signature.algorithmIdentifier.parameters,
+ &CsrData->csr.subjectPublicKeyInfo.algorithm.parameters);
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ return (KMF_OK);
+}
+
+KMF_RETURN
+KMF_SetCSRSubjectAltName(KMF_CSR_DATA *Csr,
+ char *altname, int critical,
+ KMF_GENERALNAMECHOICES alttype)
+{
+ KMF_RETURN ret = KMF_OK;
+
+ if (Csr == NULL || altname == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ ret = KMF_SetAltName(&Csr->csr.extensions,
+ (KMF_OID *)&KMFOID_SubjectAltName, critical, alttype,
+ altname);
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_SetCSRKeyUsage(KMF_CSR_DATA *CSRData,
+ int critical, uint16_t kubits)
+{
+ KMF_RETURN ret = KMF_OK;
+
+ if (CSRData == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ ret = set_key_usage_extension(
+ &CSRData->csr.extensions,
+ critical, kubits);
+
+ return (ret);
+}
+
+/*
+ *
+ * Name: KMF_SignCSR
+ *
+ * Description:
+ * This function signs a CSR and returns the result as a
+ * signed, encoded CSR in SignedCsr
+ *
+ * Parameters:
+ * tbsCsr(input) - pointer to a KMF_DATA structure containing a
+ * DER encoded TBS CSR data
+ * Signkey(input) - pointer to the KMF_KEY_HANDLE structure containing
+ * the private key generated by the plug-in CreateKeypair
+ * algo(input) - contains algorithm info needed for signing
+ * SignedCsr(output) - pointer to the KMF_DATA structure containing
+ * the signed CSR
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_SignCSR(KMF_HANDLE_T handle,
+ const KMF_CSR_DATA *tbsCsr,
+ KMF_KEY_HANDLE *Signkey,
+ KMF_DATA *SignedCsr)
+{
+ KMF_RETURN err;
+ KMF_DATA csrdata = { NULL, 0 };
+
+ CLEAR_ERROR(handle, err);
+ if (err != KMF_OK)
+ return (err);
+
+ if (tbsCsr == NULL ||
+ Signkey == NULL || SignedCsr == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ SignedCsr->Data = NULL;
+ SignedCsr->Length = 0;
+
+ err = DerEncodeTbsCsr((KMF_TBS_CSR *)&tbsCsr->csr, &csrdata);
+ if (err == KMF_OK) {
+ err = SignCsr(handle, &csrdata, Signkey,
+ (KMF_X509_ALGORITHM_IDENTIFIER *)
+ &tbsCsr->signature.algorithmIdentifier,
+ SignedCsr);
+ }
+
+ if (err != KMF_OK) {
+ KMF_FreeData(SignedCsr);
+ }
+ KMF_FreeData(&csrdata);
+ return (err);
+}
+
+KMF_RETURN
+KMF_ImportCRL(KMF_HANDLE_T handle, KMF_IMPORTCRL_PARAMS *params)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ switch (params->kstype) {
+ case KMF_KEYSTORE_NSS:
+ plugin = FindPlugin(handle, params->kstype);
+ break;
+
+ case KMF_KEYSTORE_OPENSSL:
+ case KMF_KEYSTORE_PK11TOKEN: /* PKCS#11 CRL is file-based */
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ break;
+ default:
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ if (plugin != NULL && plugin->funclist->ImportCRL != NULL) {
+ return (plugin->funclist->ImportCRL(handle, params));
+ }
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+}
+
+KMF_RETURN
+KMF_DeleteCRL(KMF_HANDLE_T handle, KMF_DELETECRL_PARAMS *params)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ switch (params->kstype) {
+ case KMF_KEYSTORE_NSS:
+ plugin = FindPlugin(handle, params->kstype);
+ break;
+
+ case KMF_KEYSTORE_OPENSSL:
+ case KMF_KEYSTORE_PK11TOKEN: /* PKCS#11 CRL is file-based */
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ break;
+ default:
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ if (plugin != NULL && plugin->funclist->DeleteCRL != NULL) {
+ return (plugin->funclist->DeleteCRL(handle, params));
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+}
+
+KMF_RETURN
+KMF_ListCRL(KMF_HANDLE_T handle, KMF_LISTCRL_PARAMS *params, char **crldata)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (params == NULL || crldata == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ switch (params->kstype) {
+ case KMF_KEYSTORE_NSS:
+ plugin = FindPlugin(handle, params->kstype);
+ break;
+
+ case KMF_KEYSTORE_OPENSSL:
+ case KMF_KEYSTORE_PK11TOKEN: /* PKCS#11 CRL is file-based */
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ break;
+ default:
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ if (plugin != NULL && plugin->funclist->ListCRL != NULL) {
+ return (plugin->funclist->ListCRL(handle, params, crldata));
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+}
+
+KMF_RETURN
+KMF_FindCRL(KMF_HANDLE_T handle, KMF_FINDCRL_PARAMS *params,
+ char **CRLNameList, int *CRLCount)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (params == NULL ||
+ CRLCount == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, params->kstype);
+ if (plugin != NULL && plugin->funclist->FindCRL != NULL) {
+ return (plugin->funclist->FindCRL(handle, params,
+ CRLNameList, CRLCount));
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+}
+
+KMF_RETURN
+KMF_FindCertInCRL(KMF_HANDLE_T handle, KMF_FINDCERTINCRL_PARAMS *params)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ switch (params->kstype) {
+ case KMF_KEYSTORE_NSS:
+ plugin = FindPlugin(handle, params->kstype);
+ break;
+
+ case KMF_KEYSTORE_OPENSSL:
+ case KMF_KEYSTORE_PK11TOKEN: /* PKCS#11 CRL is file-based */
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ break;
+ default:
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ if (plugin != NULL && plugin->funclist->FindCertInCRL != NULL) {
+ return (plugin->funclist->FindCertInCRL(handle, params));
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+}
+
+KMF_RETURN
+KMF_VerifyCRLFile(KMF_HANDLE_T handle,
+ KMF_VERIFYCRL_PARAMS *params)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN (*verifyCRLFile)(KMF_HANDLE_T,
+ KMF_VERIFYCRL_PARAMS *);
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ if (plugin == NULL || plugin->dldesc == NULL) {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ verifyCRLFile = (KMF_RETURN(*)())dlsym(plugin->dldesc,
+ "OpenSSL_VerifyCRLFile");
+
+ if (verifyCRLFile == NULL) {
+ return (KMF_ERR_FUNCTION_NOT_FOUND);
+ }
+
+ return (verifyCRLFile(handle, params));
+}
+
+KMF_RETURN
+KMF_CheckCRLDate(KMF_HANDLE_T handle, KMF_CHECKCRLDATE_PARAMS *params)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN (*checkCRLDate)(void *,
+ KMF_CHECKCRLDATE_PARAMS *params);
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ if (plugin == NULL || plugin->dldesc == NULL) {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ checkCRLDate = (KMF_RETURN(*)())dlsym(plugin->dldesc,
+ "OpenSSL_CheckCRLDate");
+
+ if (checkCRLDate == NULL) {
+ return (KMF_ERR_FUNCTION_NOT_FOUND);
+ }
+
+ return (checkCRLDate(handle, params));
+
+}
+
+KMF_RETURN
+KMF_IsCRLFile(KMF_HANDLE_T handle, char *filename, KMF_ENCODE_FORMAT *pformat)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN (*IsCRLFileFn)(void *, char *, KMF_ENCODE_FORMAT *);
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (filename == NULL || pformat == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * This framework function is actually implemented in the openssl
+ * plugin library, so we find the function address and call it.
+ */
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ if (plugin == NULL || plugin->dldesc == NULL) {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ IsCRLFileFn = (KMF_RETURN(*)())dlsym(plugin->dldesc,
+ "OpenSSL_IsCRLFile");
+ if (IsCRLFileFn == NULL) {
+ return (KMF_ERR_FUNCTION_NOT_FOUND);
+ }
+
+ return (IsCRLFileFn(handle, filename, pformat));
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/generalop.c b/usr/src/lib/libkmf/libkmf/common/generalop.c
new file mode 100644
index 0000000000..1617acc119
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/generalop.c
@@ -0,0 +1,1742 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright(c) 1995-2000 Intel Corporation. All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <thread.h>
+
+#include <ber_der.h>
+#include <kmfapiP.h>
+
+#include <pem_encode.h>
+#include <rdn_parser.h>
+#include <libxml2/libxml/uri.h>
+#include <libgen.h>
+#include <cryptoutil.h>
+
+static uchar_t pkcs11_initialized = 0;
+mutex_t init_lock = DEFAULTMUTEX;
+extern int errno;
+
+typedef struct {
+ KMF_RETURN code;
+ char *message;
+} kmf_error_map;
+
+static kmf_error_map kmf_errcodes[] = {
+ {KMF_OK, "KMF_OK"},
+ {KMF_ERR_BAD_PARAMETER, "KMF_ERR_BAD_PARAMETER"},
+ {KMF_ERR_BAD_KEY_FORMAT, "KMF_ERR_BAD_KEY_FORMAT"},
+ {KMF_ERR_BAD_ALGORITHM, "KMF_ERR_BAD_ALGORITHM"},
+ {KMF_ERR_MEMORY, "KMF_ERR_MEMORY"},
+ {KMF_ERR_ENCODING, "KMF_ERR_ENCODING"},
+ {KMF_ERR_PLUGIN_INIT, "KMF_ERR_PLUGIN_INIT"},
+ {KMF_ERR_PLUGIN_NOTFOUND, "KMF_ERR_PLUGIN_NOTFOUND"},
+ {KMF_ERR_INTERNAL, "KMF_ERR_INTERNAL"},
+ {KMF_ERR_BAD_CERT_FORMAT, "KMF_ERR_BAD_CERT_FORMAT"},
+ {KMF_ERR_KEYGEN_FAILED, "KMF_ERR_KEYGEN_FAILED"},
+ {KMF_ERR_UNINITIALIZED, "KMF_ERR_UNINITIALIZED"},
+ {KMF_ERR_ISSUER, "KMF_ERR_ISSUER"},
+ {KMF_ERR_NOT_REVOKED, "KMF_ERR_NOT_REVOKED"},
+ {KMF_ERR_CERT_NOT_FOUND, "KMF_ERR_CERT_NOT_FOUND"},
+ {KMF_ERR_CRL_NOT_FOUND, "KMF_ERR_CRL_NOT_FOUND"},
+ {KMF_ERR_RDN_PARSER, "KMF_ERR_RDN_PARSER"},
+ {KMF_ERR_RDN_ATTR, "KMF_ERR_RDN_ATTR"},
+ {KMF_ERR_SLOTNAME, "KMF_ERR_SLOTNAME"},
+ {KMF_ERR_EMPTY_CRL, "KMF_ERR_EMPTY_CRL"},
+ {KMF_ERR_BUFFER_SIZE, "KMF_ERR_BUFFER_SIZE"},
+ {KMF_ERR_AUTH_FAILED, "KMF_ERR_AUTH_FAILED"},
+ {KMF_ERR_TOKEN_SELECTED, "KMF_ERR_TOKEN_SELECTED"},
+ {KMF_ERR_NO_TOKEN_SELECTED, "KMF_ERR_NO_TOKEN_SELECTED"},
+ {KMF_ERR_TOKEN_NOT_PRESENT, "KMF_ERR_TOKEN_NOT_PRESENT"},
+ {KMF_ERR_EXTENSION_NOT_FOUND, "KMF_ERR_EXTENSION_NOT_FOUND"},
+ {KMF_ERR_POLICY_ENGINE, "KMF_ERR_POLICY_ENGINE"},
+ {KMF_ERR_POLICY_DB_FORMAT, "KMF_ERR_POLICY_DB_FORMAT"},
+ {KMF_ERR_POLICY_NOT_FOUND, "KMF_ERR_POLICY_NOT_FOUND"},
+ {KMF_ERR_POLICY_DB_FILE, "KMF_ERR_POLICY_DB_FILE"},
+ {KMF_ERR_POLICY_NAME, "KMF_ERR_POLICY_NAME"},
+ {KMF_ERR_OCSP_POLICY, "KMF_ERR_OCSP_POLICY"},
+ {KMF_ERR_TA_POLICY, "KMF_ERR_TA_POLICY"},
+ {KMF_ERR_KEY_NOT_FOUND, "KMF_ERR_KEY_NOT_FOUND"},
+ {KMF_ERR_OPEN_FILE, "KMF_ERR_OPEN_FILE"},
+ {KMF_ERR_OCSP_BAD_ISSUER, "KMF_ERR_OCSP_BAD_ISSUER"},
+ {KMF_ERR_OCSP_BAD_CERT, "KMF_ERR_OCSP_BAD_CERT"},
+ {KMF_ERR_OCSP_CREATE_REQUEST, "KMF_ERR_OCSP_CREATE_REQUEST"},
+ {KMF_ERR_CONNECT_SERVER, "KMF_ERR_CONNECT_SERVER"},
+ {KMF_ERR_SEND_REQUEST, "KMF_ERR_SEND_REQUEST"},
+ {KMF_ERR_OCSP_CERTID, "KMF_ERR_OCSP_CERTID"},
+ {KMF_ERR_OCSP_MALFORMED_RESPONSE, "KMF_ERR_OCSP_MALFORMED_RESPONSE"},
+ {KMF_ERR_OCSP_RESPONSE_STATUS, "KMF_ERR_OCSP_RESPONSE_STATUS"},
+ {KMF_ERR_OCSP_NO_BASIC_RESPONSE, "KMF_ERR_OCSP_NO_BASIC_RESPONSE"},
+ {KMF_ERR_OCSP_BAD_SIGNER, "KMF_ERR_OCSP_BAD_SIGNER"},
+ {KMF_ERR_OCSP_RESPONSE_SIGNATURE, "KMF_ERR_OCSP_RESPONSE_SIGNATURE"},
+ {KMF_ERR_OCSP_UNKNOWN_CERT, "KMF_ERR_OCSP_UNKNOWN_CERT"},
+ {KMF_ERR_OCSP_STATUS_TIME_INVALID, "KMF_ERR_OCSP_STATUS_TIME_INVALID"},
+ {KMF_ERR_BAD_HTTP_RESPONSE, "KMF_ERR_BAD_HTTP_RESPONSE"},
+ {KMF_ERR_RECV_RESPONSE, "KMF_ERR_RECV_RESPONSE"},
+ {KMF_ERR_RECV_TIMEOUT, "KMF_ERR_RECV_TIMEOUT"},
+ {KMF_ERR_DUPLICATE_KEYFILE, "KMF_ERR_DUPLICATE_KEYFILE"},
+ {KMF_ERR_AMBIGUOUS_PATHNAME, "KMF_ERR_AMBIGUOUS_PATHNAME"},
+ {KMF_ERR_FUNCTION_NOT_FOUND, "KMF_ERR_FUNCTION_NOT_FOUND"},
+ {KMF_ERR_PKCS12_FORMAT, "KMF_ERR_PKCS12_FORMAT"},
+ {KMF_ERR_BAD_KEY_TYPE, "KMF_ERR_BAD_KEY_TYPE"},
+ {KMF_ERR_BAD_KEY_CLASS, "KMF_ERR_BAD_KEY_CLASS"},
+ {KMF_ERR_BAD_KEY_SIZE, "KMF_ERR_BAD_KEY_SIZE"},
+ {KMF_ERR_BAD_HEX_STRING, "KMF_ERR_BAD_HEX_STRING"},
+ {KMF_ERR_KEYUSAGE, "KMF_ERR_KEYUSAGE"},
+ {KMF_ERR_VALIDITY_PERIOD, "KMF_ERR_VALIDITY_PERIOD"},
+ {KMF_ERR_OCSP_REVOKED, "KMF_ERR_OCSP_REVOKED"},
+ {KMF_ERR_CERT_MULTIPLE_FOUND, "KMF_ERR_CERT_MULTIPLE_FOUND"},
+ {KMF_ERR_WRITE_FILE, "KMF_ERR_WRITE_FILE"},
+ {KMF_ERR_BAD_URI, "KMF_ERR_BAD_URI"},
+ {KMF_ERR_BAD_CRLFILE, "KMF_ERR_BAD_CRLFILE"},
+ {KMF_ERR_BAD_CERTFILE, "KMF_ERR_BAD_CERTFILE"},
+ {KMF_ERR_GETKEYVALUE_FAILED, "KMF_ERR_GETKEYVALUE_FAILED"},
+ {KMF_ERR_BAD_KEYHANDLE, "KMF_ERR_BAD_KEYHANDLE"},
+ {KMF_ERR_BAD_OBJECT_TYPE, "KMF_ERR_BAD_OBJECT_TYPE"},
+ {KMF_ERR_OCSP_RESPONSE_LIFETIME, "KMF_ERR_OCSP_RESPONSE_LIFETIME"},
+ {KMF_ERR_UNKNOWN_CSR_ATTRIBUTE, "KMF_ERR_UNKNOWN_CSR_ATTRIBUTE"},
+ {KMF_ERR_UNINITIALIZED_TOKEN, "KMF_ERR_UNINITIALIZED_TOKEN"},
+ {KMF_ERR_INCOMPLETE_TBS_CERT, "KMF_ERR_INCOMPLETE_TBS_CERT"},
+ {KMF_ERR_MISSING_ERRCODE, "KMF_ERR_MISSING_ERRCODE"},
+ {KMF_KEYSTORE_ALREADY_INITIALIZED, "KMF_KEYSTORE_ALREADY_INITIALIZED"}
+};
+
+
+static void free_extensions(KMF_X509_EXTENSIONS *extns);
+
+int
+is_pk11_ready()
+{
+ return (pkcs11_initialized);
+}
+
+/*
+ * Private method for searching the plugin list for the correct
+ * Plugin to use.
+ */
+KMF_PLUGIN *
+FindPlugin(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE kstype)
+{
+ KMF_PLUGIN_LIST *node;
+
+ if (handle == NULL)
+ return (NULL);
+
+ node = handle->plugins;
+
+ while (node != NULL && node->plugin->type != kstype)
+ node = node->next;
+
+ /* If it is NULL, that is indication enough of an error */
+ return (node ? node->plugin : NULL);
+}
+
+static KMF_RETURN
+InitializePlugin(KMF_KEYSTORE_TYPE kstype, char *path, KMF_PLUGIN **plugin)
+{
+ KMF_PLUGIN *p = NULL;
+ KMF_PLUGIN_FUNCLIST *(*sym)();
+
+ if (path == NULL || plugin == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ *plugin = NULL;
+
+ p = (KMF_PLUGIN *)malloc(sizeof (KMF_PLUGIN));
+ if (p == NULL)
+ return (KMF_ERR_MEMORY);
+
+ p->type = kstype;
+ p->path = strdup(path);
+ if (p->path == NULL) {
+ free(p);
+ return (KMF_ERR_MEMORY);
+ }
+ p->dldesc = dlopen(path, RTLD_NOW | RTLD_GROUP | RTLD_PARENT);
+ if (p->dldesc == NULL) {
+ free(p->path);
+ free(p);
+ return (KMF_ERR_PLUGIN_INIT);
+ }
+
+ sym = (KMF_PLUGIN_FUNCLIST *(*)())dlsym(p->dldesc,
+ KMF_PLUGIN_INIT_SYMBOL);
+ if (sym == NULL) {
+ (void) dlclose(p->dldesc);
+ free(p->path);
+ free(p);
+ return (KMF_ERR_PLUGIN_INIT);
+ }
+
+ /* Get the function list */
+ if ((p->funclist = (*sym)()) == NULL) {
+ (void) dlclose(p->dldesc);
+ free(p->path);
+ free(p);
+ return (KMF_ERR_PLUGIN_INIT);
+ }
+
+ *plugin = p;
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+AddPlugin(KMF_HANDLE_T handle, KMF_PLUGIN *plugin)
+{
+ KMF_PLUGIN_LIST *n;
+
+ if (handle == NULL || plugin == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* If the head is NULL, create it */
+ if (handle->plugins == NULL) {
+ handle->plugins = (KMF_PLUGIN_LIST *)malloc(
+ sizeof (KMF_PLUGIN_LIST));
+ if (handle->plugins == NULL)
+ return (KMF_ERR_MEMORY);
+ handle->plugins->plugin = plugin;
+ handle->plugins->next = NULL;
+ } else {
+ /* walk the list to find the tail */
+ n = handle->plugins;
+ while (n->next != NULL)
+ n = n->next;
+ n->next = (KMF_PLUGIN_LIST *)malloc(sizeof (KMF_PLUGIN_LIST));
+ if (n->next == NULL)
+ return (KMF_ERR_MEMORY);
+
+ n->next->plugin = plugin;
+ n->next->next = NULL;
+ }
+ return (0);
+}
+
+static void
+DestroyPlugin(KMF_PLUGIN *plugin)
+{
+ if (plugin) {
+ if (plugin->path)
+ free(plugin->path);
+ free(plugin);
+ }
+}
+
+static void
+Cleanup_KMF_Handle(KMF_HANDLE_T handle)
+{
+ if (handle != NULL) {
+ while (handle->plugins != NULL) {
+ KMF_PLUGIN_LIST *next = handle->plugins->next;
+
+ DestroyPlugin(handle->plugins->plugin);
+
+ free(handle->plugins);
+
+ handle->plugins = next;
+ }
+
+ KMF_FreePolicyRecord(handle->policy);
+ free(handle->policy);
+ }
+ free(handle);
+}
+
+void
+Cleanup_PK11_Session(KMF_HANDLE_T handle)
+{
+ if (handle != NULL) {
+ /* Close active session on a pkcs11 token */
+ if (handle->pk11handle != NULL) {
+ (void) C_CloseSession(handle->pk11handle);
+ handle->pk11handle = NULL;
+ }
+ }
+}
+
+KMF_RETURN
+KMF_Initialize(KMF_HANDLE_T *outhandle, char *policyfile, char *policyname)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *handle = NULL;
+ KMF_PLUGIN *pluginrec = NULL;
+
+ if (outhandle == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ *outhandle = NULL;
+ handle = (KMF_HANDLE *)malloc(sizeof (KMF_HANDLE));
+ if (handle == NULL)
+ return (KMF_ERR_MEMORY);
+
+ (void) memset(handle, 0, sizeof (KMF_HANDLE));
+ handle->plugins = NULL;
+
+ (void) mutex_lock(&init_lock);
+ if (!pkcs11_initialized) {
+ CK_RV rv = C_Initialize(NULL);
+ if ((rv != CKR_OK) &&
+ (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
+ ret = KMF_ERR_UNINITIALIZED;
+ (void) mutex_unlock(&init_lock);
+ goto errout;
+ } else {
+ pkcs11_initialized = 1;
+ }
+ }
+ (void) mutex_unlock(&init_lock);
+
+ /* Initialize the handle with the policy */
+ ret = KMF_SetPolicy((void *)handle,
+ policyfile == NULL ? KMF_DEFAULT_POLICY_FILE : policyfile,
+ policyname == NULL ? KMF_DEFAULT_POLICY_NAME : policyname);
+ if (ret != KMF_OK)
+ goto errout;
+
+ /* Create a record for the plugin */
+ if ((ret = InitializePlugin(KMF_KEYSTORE_NSS,
+ KMF_PLUGIN_PATH "kmf_nss.so.1", &pluginrec)) != KMF_OK)
+ goto errout;
+
+ /* Add it to the handle */
+ if (pluginrec != NULL) {
+ if ((ret = AddPlugin(handle, pluginrec)))
+ goto errout;
+ }
+ if ((ret = InitializePlugin(KMF_KEYSTORE_OPENSSL,
+ KMF_PLUGIN_PATH "kmf_openssl.so.1", &pluginrec)) != KMF_OK)
+ goto errout;
+
+ /* Add it to the handle */
+ if (pluginrec != NULL)
+ if ((ret = AddPlugin(handle, pluginrec)))
+ goto errout;
+
+ if ((ret = InitializePlugin(KMF_KEYSTORE_PK11TOKEN,
+ KMF_PLUGIN_PATH "kmf_pkcs11.so.1", &pluginrec)) != KMF_OK)
+ goto errout;
+
+ /* Add it to the handle */
+ if (pluginrec != NULL)
+ if ((ret = AddPlugin(handle, pluginrec)))
+ goto errout;
+
+ CLEAR_ERROR(handle, ret);
+errout:
+ if (ret != KMF_OK) {
+ Cleanup_KMF_Handle(handle);
+ handle = NULL;
+ }
+
+ *outhandle = (KMF_HANDLE_T)handle;
+ return (ret);
+}
+
+KMF_RETURN
+KMF_ConfigureKeystore(KMF_HANDLE_T handle, KMF_CONFIG_PARAMS *params)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, params->kstype);
+ if (plugin == NULL)
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+
+ if (plugin->funclist->ConfigureKeystore != NULL)
+ return (plugin->funclist->ConfigureKeystore(handle, params));
+ else
+ /* return KMF_OK, if the plugin does not have an entry */
+ return (KMF_OK);
+}
+
+KMF_RETURN
+KMF_Finalize(KMF_HANDLE_T handle)
+{
+ KMF_RETURN ret = KMF_OK;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (pkcs11_initialized) {
+ Cleanup_PK11_Session(handle);
+ }
+ Cleanup_KMF_Handle(handle);
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetKMFErrorString(KMF_RETURN errcode, char **errmsg)
+{
+ KMF_RETURN ret = KMF_OK;
+ int i, maxerr;
+
+ if (errmsg == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ *errmsg = NULL;
+ maxerr = sizeof (kmf_errcodes) / sizeof (kmf_error_map);
+
+ for (i = 0; i < maxerr && errcode != kmf_errcodes[i].code; i++);
+
+ if (i == maxerr)
+ return (KMF_ERR_MISSING_ERRCODE);
+ else {
+ *errmsg = strdup(kmf_errcodes[i].message);
+ if ((*errmsg) == NULL)
+ return (KMF_ERR_MEMORY);
+ }
+ return (ret);
+}
+
+KMF_RETURN
+KMF_GetPluginErrorString(KMF_HANDLE_T handle, char **msgstr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_PLUGIN *plugin;
+
+ if (handle == NULL || msgstr == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ *msgstr = NULL;
+
+ if (handle->lasterr.errcode == 0) {
+ return (KMF_ERR_MISSING_ERRCODE);
+ }
+
+ if (handle->lasterr.kstype == -1) { /* System error */
+ char *str = strerror(handle->lasterr.errcode);
+ if (str != NULL) {
+ *msgstr = strdup(str);
+ if ((*msgstr) == NULL)
+ return (KMF_ERR_MEMORY);
+ }
+ return (KMF_OK);
+ }
+
+ plugin = FindPlugin(handle, handle->lasterr.kstype);
+ if (plugin == NULL)
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+
+ if (plugin->funclist->GetErrorString != NULL) {
+ ret = plugin->funclist->GetErrorString(handle, msgstr);
+ } else {
+ return (KMF_ERR_FUNCTION_NOT_FOUND);
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_DNParser(char *string, KMF_X509_NAME *name)
+{
+ KMF_RETURN err;
+
+ if (string == NULL || name == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ err = ParseDistinguishedName(string, (int)strlen(string), name);
+ return (err);
+}
+
+KMF_RETURN
+KMF_DN2Der(KMF_X509_NAME *dn, KMF_DATA *der)
+{
+ KMF_RETURN rv;
+
+ if (dn == NULL || der == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = DerEncodeName(dn, der);
+ return (rv);
+}
+
+#define SET_SYS_ERROR(h, c) h->lasterr.kstype = -1; h->lasterr.errcode = c;
+
+KMF_RETURN
+KMF_ReadInputFile(KMF_HANDLE_T handle, char *filename, KMF_DATA *pdata)
+{
+ struct stat s;
+ long nread, total = 0;
+ int fd;
+ unsigned char *buf = NULL;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+
+ if (filename == NULL || pdata == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if ((fd = open(filename, O_RDONLY)) < 0) {
+ SET_SYS_ERROR(handle, errno);
+ return (KMF_ERR_OPEN_FILE);
+ }
+
+ if (fstat(fd, &s) < 0) {
+ SET_SYS_ERROR(handle, errno);
+ (void) close(fd);
+ return (KMF_ERR_OPEN_FILE);
+ }
+
+ if ((buf = (unsigned char *) malloc(s.st_size)) == NULL) {
+ (void) close(fd);
+ return (KMF_ERR_MEMORY);
+ }
+
+ do {
+ nread = read(fd, buf+total, s.st_size-total);
+ if (nread < 0) {
+ SET_SYS_ERROR(handle, errno);
+ (void) close(fd);
+ free(buf);
+ return (KMF_ERR_INTERNAL);
+ }
+ total += nread;
+ } while (total < s.st_size);
+
+ pdata->Data = buf;
+ pdata->Length = s.st_size;
+ (void) close(fd);
+ return (KMF_OK);
+}
+
+/*
+ *
+ * Name: KMF_Der2Pem
+ *
+ * Description:
+ * Function for converting DER encoded format to PEM encoded format
+ *
+ * Parameters:
+ * type(input) - CERTIFICATE or CSR
+ * data(input) - pointer to the DER encoded data
+ * len(input) - length of input data
+ * out(output) - contains the output buffer address to be returned
+ * outlen(output) - pointer to the returned output length
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_Der2Pem(KMF_OBJECT_TYPE type, unsigned char *data,
+ int len, unsigned char **out, int *outlen)
+{
+
+ KMF_RETURN err;
+ if (data == NULL || out == NULL || outlen == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ err = Der2Pem(type, data, len, out, outlen);
+ return (err);
+
+}
+
+/*
+ *
+ * Name: KMF_Pem2Der
+ *
+ * Description:
+ * Function for converting PEM encoded format to DER encoded format
+ *
+ * Parameters:
+ * in(input) - pointer to the PEM encoded data
+ * inlen(input) - length of input data
+ * out(output) - contains the output buffer address to be returned
+ * outlen(output) - pointer to the returned output length
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_Pem2Der(unsigned char *in, int inlen,
+ unsigned char **out, int *outlen)
+{
+ KMF_RETURN err;
+ if (in == NULL || out == NULL || outlen == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ err = Pem2Der(in, inlen, out, outlen);
+ return (err);
+}
+
+char *
+KMF_OID2String(KMF_OID *oid)
+{
+ char numstr[128];
+ uint32_t number;
+ int numshift;
+ uint32_t i, string_length;
+ uchar_t *cp;
+ char *bp;
+
+ /* First determine the size of the string */
+ string_length = 0;
+ number = 0;
+ numshift = 0;
+ cp = (unsigned char *)oid->Data;
+
+ number = (uint32_t)cp[0];
+ (void) sprintf(numstr, "%d ", number/40);
+
+ string_length += strlen(numstr);
+ (void) sprintf(numstr, "%d ", number%40);
+
+ string_length += strlen(numstr);
+
+ for (i = 1; i < oid->Length; i++) {
+ if ((uint32_t)(numshift+7) < (sizeof (uint32_t)*8)) {
+ number = (number << 7) | (cp[i] & 0x7f);
+ numshift += 7;
+ } else {
+ return (NULL);
+ }
+
+ if ((cp[i] & 0x80) == 0) {
+ (void) sprintf(numstr, "%d ", number);
+ string_length += strlen(numstr);
+ number = 0;
+ numshift = 0;
+ }
+ }
+ /*
+ * If we get here, we've calculated the length of "n n n ... n ". Add 4
+ * here for "{ " and "}\0".
+ */
+ string_length += 4;
+ if ((bp = (char *)malloc(string_length))) {
+ number = (uint32_t)cp[0];
+
+ (void) sprintf(numstr, "%d.", number/40);
+ (void) strcpy(bp, numstr);
+
+ (void) sprintf(numstr, "%d.", number%40);
+ (void) strcat(bp, numstr);
+
+ number = 0;
+ cp = (unsigned char *) oid->Data;
+ for (i = 1; i < oid->Length; i++) {
+ number = (number << 7) | (cp[i] & 0x7f);
+ if ((cp[i] & 0x80) == 0) {
+ (void) sprintf(numstr, "%d", number);
+ (void) strcat(bp, numstr);
+ number = 0;
+ if (i+1 < oid->Length)
+ (void) strcat(bp, ".");
+ }
+ }
+ }
+ return (bp);
+}
+
+KMF_RETURN
+KMF_GetFileFormat(char *filename, KMF_ENCODE_FORMAT *fmt)
+{
+ int f;
+ KMF_RETURN ret = KMF_OK;
+ uchar_t buf[16];
+
+ if (filename == NULL || !strlen(filename) || fmt == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ *fmt = 0;
+ if ((f = open(filename, O_RDONLY)) == -1) {
+ return (KMF_ERR_OPEN_FILE);
+ }
+
+ if (read(f, buf, 8) != 8) {
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (memcmp(buf, "-----BEG", 8) == 0) {
+ *fmt = KMF_FORMAT_PEM;
+ } else if (buf[0] == 0x30 && (buf[1] & 0x80)) {
+ if ((buf[1] & 0xFF) == 0x80 &&
+ (buf[2] & 0xFF) == 0x02 &&
+ (buf[5] & 0xFF) == 0x30) {
+ *fmt = KMF_FORMAT_PKCS12;
+ } else if ((buf[1] & 0xFF) == 0x82 &&
+ (buf[4] & 0xFF) == 0x02 &&
+ (buf[7] & 0xFF) == 0x30) {
+ *fmt = KMF_FORMAT_PKCS12;
+ /* It is most likely a generic ASN.1 encoded file */
+ } else {
+ *fmt = KMF_FORMAT_ASN1;
+ }
+ } else {
+ /* Cannot determine this file format */
+ *fmt = 0;
+ ret = KMF_ERR_ENCODING;
+ }
+end:
+ (void) close(f);
+ return (ret);
+}
+
+KMF_RETURN
+KMF_HexString2Bytes(unsigned char *hexstr, unsigned char **bytes,
+ size_t *outlen)
+{
+ KMF_RETURN ret = KMF_OK;
+ unsigned char *buf = NULL;
+ int len, stringlen;
+ int i;
+ unsigned char ch;
+
+ if (hexstr == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (hexstr[0] == '0' &&
+ ((hexstr[1] == 'x') || (hexstr[1] == 'X')))
+ hexstr += 2;
+
+ for (i = 0; i < strlen((char *)hexstr) && isxdigit(hexstr[i]); i++);
+ /*
+ * If all the characters are not legitimate hex chars,
+ * return an error.
+ */
+ if (i != strlen((char *)hexstr))
+ return (KMF_ERR_BAD_HEX_STRING);
+ stringlen = i;
+ len = (i / 2) + (i % 2);
+
+ buf = malloc(len);
+ if (buf == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+ (void) memset(buf, 0, len);
+
+ for (i = 0; i < stringlen; i++) {
+ ch = (unsigned char) *hexstr;
+ hexstr++;
+ if ((ch >= '0') && (ch <= '9'))
+ ch -= '0';
+ else if ((ch >= 'A') && (ch <= 'F'))
+ ch = ch - 'A' + 10;
+ else if ((ch >= 'a') && (ch <= 'f'))
+ ch = ch - 'a' + 10;
+ else {
+ ret = KMF_ERR_BAD_HEX_STRING;
+ goto out;
+ }
+
+ if (i & 1) {
+ buf[i/2] |= ch;
+ } else {
+ buf[i/2] = (ch << 4);
+ }
+ }
+
+ *bytes = buf;
+ *outlen = len;
+out:
+ if (buf != NULL && ret != KMF_OK) {
+ free(buf);
+ }
+ return (ret);
+}
+
+void
+KMF_FreeDN(KMF_X509_NAME *name)
+{
+ KMF_X509_RDN *newrdn = NULL;
+ KMF_X509_TYPE_VALUE_PAIR *av = NULL;
+ int i, j;
+
+ if (name && name->numberOfRDNs) {
+ for (i = 0; i < name->numberOfRDNs; i++) {
+ newrdn = &name->RelativeDistinguishedName[i];
+ for (j = 0; j < newrdn->numberOfPairs; j++) {
+ av = &newrdn->AttributeTypeAndValue[j];
+ KMF_FreeData(&av->type);
+ KMF_FreeData(&av->value);
+ }
+ free(newrdn->AttributeTypeAndValue);
+ newrdn->numberOfPairs = 0;
+ newrdn->AttributeTypeAndValue = NULL;
+ }
+ free(name->RelativeDistinguishedName);
+ name->numberOfRDNs = 0;
+ name->RelativeDistinguishedName = NULL;
+ }
+}
+
+void
+KMF_FreeKMFCert(KMF_HANDLE_T handle, KMF_X509_DER_CERT *kmf_cert)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return;
+
+ if (kmf_cert == NULL)
+ return;
+
+ plugin = FindPlugin(handle, kmf_cert->kmf_private.keystore_type);
+
+ if (plugin != NULL && plugin->funclist->FreeKMFCert != NULL) {
+ plugin->funclist->FreeKMFCert(handle, kmf_cert);
+ }
+}
+
+void
+KMF_FreeData(KMF_DATA *datablock)
+{
+ if (datablock != NULL && datablock->Data != NULL) {
+ free(datablock->Data);
+ datablock->Data = NULL;
+ datablock->Length = 0;
+ }
+}
+
+void
+KMF_FreeAlgOID(KMF_X509_ALGORITHM_IDENTIFIER *algoid)
+{
+ if (algoid == NULL)
+ return;
+ KMF_FreeData(&algoid->algorithm);
+ KMF_FreeData(&algoid->parameters);
+}
+
+void
+KMF_FreeExtension(KMF_X509_EXTENSION *exptr)
+{
+ if (exptr == NULL)
+ return;
+
+ KMF_FreeData((KMF_DATA *)&exptr->extnId);
+ KMF_FreeData(&exptr->BERvalue);
+
+ if (exptr->value.tagAndValue) {
+ KMF_FreeData(&exptr->value.tagAndValue->value);
+ free(exptr->value.tagAndValue);
+ }
+}
+
+void
+KMF_FreeTBSCSR(KMF_TBS_CSR *tbscsr)
+{
+ if (tbscsr) {
+ KMF_FreeData(&tbscsr->version);
+
+ KMF_FreeDN(&tbscsr->subject);
+
+ KMF_FreeAlgOID(&tbscsr->subjectPublicKeyInfo.algorithm);
+ KMF_FreeData(&tbscsr->subjectPublicKeyInfo.subjectPublicKey);
+
+ free_extensions(&tbscsr->extensions);
+ }
+}
+
+void
+KMF_FreeSignedCSR(KMF_CSR_DATA *csr)
+{
+ if (csr) {
+ KMF_FreeTBSCSR(&csr->csr);
+
+ KMF_FreeAlgOID(&csr->signature.algorithmIdentifier);
+ KMF_FreeData(&csr->signature.encrypted);
+ }
+}
+
+static void
+free_validity(KMF_X509_VALIDITY *validity)
+{
+ if (validity == NULL)
+ return;
+ KMF_FreeData(&validity->notBefore.time);
+ KMF_FreeData(&validity->notAfter.time);
+}
+
+static void
+free_extensions(KMF_X509_EXTENSIONS *extns)
+{
+ int i;
+ KMF_X509_EXTENSION *exptr;
+
+ if (extns && extns->numberOfExtensions > 0) {
+ for (i = 0; i < extns->numberOfExtensions; i++) {
+ exptr = &extns->extensions[i];
+ KMF_FreeExtension(exptr);
+ }
+ free(extns->extensions);
+ extns->numberOfExtensions = 0;
+ extns->extensions = NULL;
+ }
+}
+
+void
+KMF_FreeTBSCert(KMF_X509_TBS_CERT *tbscert)
+{
+ if (tbscert) {
+ KMF_FreeData(&tbscert->version);
+ KMF_FreeBigint(&tbscert->serialNumber);
+ KMF_FreeAlgOID(&tbscert->signature);
+
+ KMF_FreeDN(&tbscert->issuer);
+ KMF_FreeDN(&tbscert->subject);
+
+ free_validity(&tbscert->validity);
+
+ KMF_FreeData(&tbscert->issuerUniqueIdentifier);
+ KMF_FreeData(&tbscert->subjectUniqueIdentifier);
+
+ KMF_FreeAlgOID(&tbscert->subjectPublicKeyInfo.algorithm);
+ KMF_FreeData(&tbscert->subjectPublicKeyInfo.subjectPublicKey);
+
+ free_extensions(&tbscert->extensions);
+
+ KMF_FreeData(&tbscert->issuerUniqueIdentifier);
+ KMF_FreeData(&tbscert->subjectUniqueIdentifier);
+ }
+}
+
+void
+KMF_FreeSignedCert(KMF_X509_CERTIFICATE *certptr)
+{
+ if (!certptr)
+ return;
+
+ KMF_FreeTBSCert(&certptr->certificate);
+
+ KMF_FreeAlgOID(&certptr->signature.algorithmIdentifier);
+ KMF_FreeData(&certptr->signature.encrypted);
+}
+
+void
+KMF_FreeString(char *pstr)
+{
+ if (pstr != NULL)
+ free(pstr);
+}
+
+void
+free_keyidlist(KMF_OID *oidlist, int len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ KMF_FreeData((KMF_DATA *)&oidlist[i]);
+ }
+ free(oidlist);
+}
+
+void
+KMF_FreeEKU(KMF_X509EXT_EKU *eptr)
+{
+ if (eptr && eptr->nEKUs > 0 &&
+ eptr->keyPurposeIdList != NULL)
+ free_keyidlist(eptr->keyPurposeIdList, eptr->nEKUs);
+}
+
+void
+KMF_FreeSPKI(KMF_X509_SPKI *spki)
+{
+ if (spki != NULL) {
+ KMF_FreeAlgOID(&spki->algorithm);
+ KMF_FreeData(&spki->subjectPublicKey);
+ }
+}
+
+void
+KMF_FreeKMFKey(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return;
+
+ if (key == NULL)
+ return;
+
+ plugin = FindPlugin(handle, key->kstype);
+ if (plugin != NULL && plugin->funclist->DeleteKey != NULL) {
+ (void) plugin->funclist->DeleteKey(handle, NULL, key, FALSE);
+ }
+
+ if (key == NULL)
+ return;
+
+ if (key->keylabel)
+ free(key->keylabel);
+
+ if (key->israw) {
+ KMF_FreeRawKey(key->keyp);
+ free(key->keyp);
+ }
+
+ (void) memset(key, 0, sizeof (KMF_KEY_HANDLE));
+}
+
+void
+KMF_FreeBigint(KMF_BIGINT *big)
+{
+ if (big != NULL && big->val != NULL) {
+ free(big->val);
+ big->val = NULL;
+ big->len = 0;
+ }
+}
+
+static void
+free_raw_rsa(KMF_RAW_RSA_KEY *key)
+{
+ if (key == NULL)
+ return;
+ KMF_FreeBigint(&key->mod);
+ KMF_FreeBigint(&key->pubexp);
+ KMF_FreeBigint(&key->priexp);
+ KMF_FreeBigint(&key->prime1);
+ KMF_FreeBigint(&key->prime2);
+ KMF_FreeBigint(&key->exp1);
+ KMF_FreeBigint(&key->exp2);
+ KMF_FreeBigint(&key->coef);
+}
+
+static void
+free_raw_dsa(KMF_RAW_DSA_KEY *key)
+{
+ if (key == NULL)
+ return;
+ KMF_FreeBigint(&key->prime);
+ KMF_FreeBigint(&key->subprime);
+ KMF_FreeBigint(&key->base);
+ KMF_FreeBigint(&key->value);
+}
+
+static void
+free_raw_sym(KMF_RAW_SYM_KEY *key)
+{
+ if (key == NULL)
+ return;
+ KMF_FreeBigint(&key->keydata);
+}
+
+void
+KMF_FreeRawKey(KMF_RAW_KEY_DATA *key)
+{
+ if (key == NULL)
+ return;
+
+ switch (key->keytype) {
+ case KMF_RSA:
+ free_raw_rsa(&key->rawdata.rsa);
+ break;
+ case KMF_DSA:
+ free_raw_dsa(&key->rawdata.dsa);
+ break;
+ case KMF_AES:
+ case KMF_RC4:
+ case KMF_DES:
+ case KMF_DES3:
+ free_raw_sym(&key->rawdata.sym);
+ break;
+ }
+}
+
+void
+KMF_FreeRawSymKey(KMF_RAW_SYM_KEY *key)
+{
+ if (key == NULL)
+ return;
+ KMF_FreeBigint(&key->keydata);
+ free(key);
+}
+
+/*
+ * This function frees the space allocated for the name portion of a
+ * KMF_CRL_DIST_POINT.
+ */
+void
+free_dp_name(KMF_CRL_DIST_POINT *dp)
+{
+ KMF_GENERALNAMES *fullname;
+ KMF_DATA *urldata;
+ int i;
+
+ if (dp == NULL)
+ return;
+
+ /* For phase 1, we only need to free the fullname space. */
+ fullname = &(dp->name.full_name);
+ if (fullname->number == 0)
+ return;
+
+ for (i = 0; i < fullname->number; i++) {
+ urldata = &(fullname->namelist[fullname->number - 1].name);
+ KMF_FreeData(urldata);
+ }
+
+ free(fullname->namelist);
+}
+
+/*
+ * This function frees the space allocated for a KMF_CRL_DIST_POINT.
+ */
+void
+free_dp(KMF_CRL_DIST_POINT *dp)
+{
+ if (dp == NULL)
+ return;
+
+ free_dp_name(dp);
+ KMF_FreeData(&(dp->reasons));
+ /* Need not to free crl_issuer space at phase 1 */
+}
+
+/*
+ * This function frees space for a KMF_X509EXT_CRLDISTPOINTS internally.
+ */
+void
+KMF_FreeCRLDistributionPoints(KMF_X509EXT_CRLDISTPOINTS *crl_dps)
+{
+ int i;
+
+ if (crl_dps == NULL)
+ return;
+
+ for (i = 0; i < crl_dps->number; i++)
+ free_dp(&(crl_dps->dplist[i]));
+
+ free(crl_dps->dplist);
+}
+
+KMF_RETURN
+KMF_CreateOCSPRequest(KMF_HANDLE_T handle, KMF_OCSPREQUEST_PARAMS *params,
+ char *reqfile)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN (*createReqFn)(void *, KMF_OCSPREQUEST_PARAMS *params,
+ char *reqfile);
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+
+ if (params == NULL ||
+ reqfile == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * This framework function is actually implemented in the openssl
+ * plugin library, so we find the function address and call it.
+ */
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ if (plugin == NULL || plugin->dldesc == NULL) {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ createReqFn = (KMF_RETURN(*)())dlsym(plugin->dldesc,
+ "OpenSSL_CreateOCSPRequest");
+ if (createReqFn == NULL) {
+ return (KMF_ERR_FUNCTION_NOT_FOUND);
+ }
+
+ return (createReqFn(handle, params, reqfile));
+}
+
+KMF_RETURN
+KMF_GetOCSPStatusForCert(KMF_HANDLE_T handle,
+ KMF_OCSPRESPONSE_PARAMS_INPUT *params_in,
+ KMF_OCSPRESPONSE_PARAMS_OUTPUT *params_out)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN (*getCertStatusFn)(void *,
+ KMF_OCSPRESPONSE_PARAMS_INPUT *params_in,
+ KMF_OCSPRESPONSE_PARAMS_OUTPUT *params_out);
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+
+ if (params_in == NULL ||
+ params_out == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * This framework function is actually implemented in the openssl
+ * plugin library, so we find the function address and call it.
+ */
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ if (plugin == NULL || plugin->dldesc == NULL) {
+ return (KMF_ERR_INTERNAL);
+ }
+
+ getCertStatusFn = (KMF_RETURN(*)())dlsym(plugin->dldesc,
+ "OpenSSL_GetOCSPStatusForCert");
+ if (getCertStatusFn == NULL) {
+ return (KMF_ERR_INTERNAL);
+ }
+
+ return (getCertStatusFn(handle, params_in, params_out));
+}
+
+KMF_RETURN
+KMF_String2OID(char *oidstring, KMF_OID *oid)
+{
+ KMF_RETURN rv = KMF_OK;
+ char *cp, *bp, *startp;
+ int numbuf;
+ int onumbuf;
+ int nbytes, index;
+ int len;
+ unsigned char *op;
+
+ if (oidstring == NULL || oid == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ len = strlen(oidstring);
+
+ bp = oidstring;
+ cp = bp;
+ /* Skip over leading space */
+ while ((bp < &cp[len]) && isspace(*bp))
+ bp++;
+
+ startp = bp;
+ nbytes = 0;
+
+ /*
+ * The first two numbers are chewed up by the first octet.
+ */
+ if (sscanf(bp, "%d", &numbuf) != 1)
+ return (KMF_ERR_BAD_PARAMETER);
+ while ((bp < &cp[len]) && isdigit(*bp))
+ bp++;
+ while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.'))
+ bp++;
+ if (sscanf(bp, "%d", &numbuf) != 1)
+ return (KMF_ERR_BAD_PARAMETER);
+ while ((bp < &cp[len]) && isdigit(*bp))
+ bp++;
+ while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.'))
+ bp++;
+ nbytes++;
+
+ while (isdigit(*bp)) {
+ if (sscanf(bp, "%d", &numbuf) != 1)
+ return (KMF_ERR_BAD_PARAMETER);
+ while (numbuf) {
+ nbytes++;
+ numbuf >>= 7;
+ }
+ while ((bp < &cp[len]) && isdigit(*bp))
+ bp++;
+ while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.'))
+ bp++;
+ }
+
+ oid->Length = nbytes;
+ oid->Data = malloc(oid->Length);
+ if (oid->Data == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+ (void) memset(oid->Data, 0, oid->Length);
+
+ op = oid->Data;
+
+ bp = startp;
+ (void) sscanf(bp, "%d", &numbuf);
+
+ while (isdigit(*bp)) bp++;
+ while (isspace(*bp) || *bp == '.') bp++;
+
+ onumbuf = 40 * numbuf;
+ (void) sscanf(bp, "%d", &numbuf);
+ onumbuf += numbuf;
+ *op = (unsigned char) onumbuf;
+ op++;
+
+ while (isdigit(*bp)) bp++;
+ while (isspace(*bp) || *bp == '.') bp++;
+ while (isdigit(*bp)) {
+ (void) sscanf(bp, "%d", &numbuf);
+ nbytes = 0;
+ /* Have to fill in the bytes msb-first */
+ onumbuf = numbuf;
+ while (numbuf) {
+ nbytes++;
+ numbuf >>= 7;
+ }
+ numbuf = onumbuf;
+ op += nbytes;
+ index = -1;
+ while (numbuf) {
+ op[index] = (unsigned char)numbuf & 0x7f;
+ if (index != -1)
+ op[index] |= 0x80;
+ index--;
+ numbuf >>= 7;
+ }
+ while (isdigit(*bp)) bp++;
+ while (isspace(*bp) || *bp == '.') bp++;
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+encode_rid(char *name, KMF_DATA *derdata)
+{
+ KMF_RETURN rv = KMF_OK;
+
+ if (name == NULL || derdata == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = KMF_String2OID(name, (KMF_OID *)derdata);
+
+ return (rv);
+}
+
+static KMF_RETURN
+encode_ipaddr(char *name, KMF_DATA *derdata)
+{
+ KMF_RETURN rv = KMF_OK;
+ size_t len;
+ in_addr_t v4;
+ in6_addr_t v6;
+ uint8_t *ptr;
+
+ if (name == NULL || derdata == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ v4 = inet_addr(name);
+ if (v4 == (in_addr_t)-1) {
+ ptr = (uint8_t *)&v6;
+ if (inet_pton(AF_INET6, name, ptr) != 1)
+ return (KMF_ERR_ENCODING);
+ len = sizeof (v6);
+ } else {
+ ptr = (uint8_t *)&v4;
+ len = sizeof (v4);
+ }
+
+ derdata->Data = malloc(len);
+ if (derdata->Data == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memcpy(derdata->Data, ptr, len);
+ derdata->Length = len;
+
+ return (rv);
+}
+
+static KMF_RETURN
+verify_uri_format(char *uristring)
+{
+ KMF_RETURN ret = KMF_OK;
+ xmlURIPtr uriptr = NULL;
+
+ /* Parse the URI string; get the hostname and port */
+ uriptr = xmlParseURI(uristring);
+ if (uriptr == NULL) {
+ ret = KMF_ERR_BAD_URI;
+ goto out;
+ }
+
+ if (uriptr->scheme == NULL || !strlen(uriptr->scheme)) {
+ ret = KMF_ERR_BAD_URI;
+ goto out;
+ }
+
+ if (uriptr->server == NULL || !strlen(uriptr->server)) {
+ ret = KMF_ERR_BAD_URI;
+ goto out;
+ }
+out:
+ if (uriptr != NULL)
+ xmlFreeURI(uriptr);
+ return (ret);
+}
+
+static KMF_RETURN
+encode_altname(char *namedata,
+ KMF_GENERALNAMECHOICES nametype, KMF_DATA *encodedname)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_NAME dnname;
+ uchar_t tagval;
+ BerElement *asn1 = NULL;
+ BerValue *extdata;
+
+ if (namedata == NULL || encodedname == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * Encode the namedata according to rules in RFC 3280 for GeneralName.
+ * The input "namedata" is assumed to be an ASCII string representation
+ * of the AltName, we need to convert it to correct ASN.1 here before
+ * adding it to the cert.
+ */
+ switch (nametype) {
+ case GENNAME_RFC822NAME: /* rfc 822 */
+ /* IA5String, no encoding needed */
+ encodedname->Data = (uchar_t *)strdup(namedata);
+ if (encodedname->Data == NULL)
+ return (KMF_ERR_MEMORY);
+ encodedname->Length = strlen(namedata);
+ tagval = (0x80 | nametype);
+ break;
+ case GENNAME_DNSNAME: /* rfc 1034 */
+ encodedname->Data = (uchar_t *)strdup(namedata);
+ if (encodedname->Data == NULL)
+ return (KMF_ERR_MEMORY);
+ encodedname->Length = strlen(namedata);
+ tagval = (0x80 | nametype);
+ break;
+ case GENNAME_URI: /* rfc 1738 */
+ ret = verify_uri_format(namedata);
+ if (ret != KMF_OK)
+ return (ret);
+ /* IA5String, no encoding needed */
+ encodedname->Data = (uchar_t *)strdup(namedata);
+ if (encodedname->Data == NULL)
+ return (KMF_ERR_MEMORY);
+ encodedname->Length = strlen(namedata);
+ tagval = (0x80 | nametype);
+ break;
+ case GENNAME_IPADDRESS:
+ ret = encode_ipaddr(namedata, encodedname);
+ tagval = (0x80 | nametype);
+ break;
+ case GENNAME_REGISTEREDID:
+ ret = encode_rid(namedata, encodedname);
+ tagval = (0x80 | nametype);
+ break;
+ case GENNAME_DIRECTORYNAME:
+ ret = KMF_DNParser(namedata, &dnname);
+ if (ret == KMF_OK) {
+ ret = KMF_DN2Der(&dnname, encodedname);
+ }
+ (void) KMF_FreeDN(&dnname);
+ tagval = (0xA0 | nametype);
+ break;
+ default:
+ /* unsupported */
+ return (KMF_ERR_BAD_PARAMETER);
+
+ }
+ if (ret != KMF_OK) {
+ KMF_FreeData(encodedname);
+ return (ret);
+ }
+
+ if ((asn1 = kmfder_alloc()) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (kmfber_printf(asn1, "Tl",
+ tagval, encodedname->Length) == -1)
+ goto cleanup;
+
+ if (kmfber_write(asn1, (char *)encodedname->Data,
+ encodedname->Length, 0) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+ if (kmfber_flatten(asn1, &extdata) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ KMF_FreeData(encodedname);
+ encodedname->Data = (uchar_t *)extdata->bv_val;
+ encodedname->Length = extdata->bv_len;
+
+ free(extdata);
+
+cleanup:
+ if (asn1)
+ kmfber_free(asn1, 1);
+
+ if (ret != KMF_OK)
+ KMF_FreeData(encodedname);
+
+ return (ret);
+}
+
+KMF_X509_EXTENSION *
+FindExtn(KMF_X509_EXTENSIONS *exts, KMF_OID *oid)
+{
+ KMF_X509_EXTENSION *foundextn = NULL;
+ int i;
+
+ if (exts == NULL || oid == NULL)
+ return (NULL);
+
+ for (i = 0; i < exts->numberOfExtensions; i++) {
+ if (IsEqualOid(oid, &exts->extensions[i].extnId)) {
+ foundextn = &exts->extensions[i];
+ break;
+ }
+ }
+ return (foundextn);
+}
+
+KMF_RETURN
+GetSequenceContents(char *data, size_t len,
+ char **contents, size_t *outlen)
+{
+ KMF_RETURN ret = KMF_OK;
+ BerElement *exasn1 = NULL;
+ BerValue oldextn;
+ int tag;
+ size_t oldsize;
+ char *olddata = NULL;
+
+ if (data == NULL || contents == NULL || outlen == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * Decode the sequence of general names
+ */
+ oldextn.bv_val = data;
+ oldextn.bv_len = len;
+
+ if ((exasn1 = kmfder_init(&oldextn)) == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ /*
+ * Unwrap the sequence to find the size of the block
+ * of GeneralName items in the set.
+ *
+ * Peek at the tag and length ("tl"),
+ * then consume them ("{").
+ */
+ if (kmfber_scanf(exasn1, "tl{", &tag, &oldsize) == KMFBER_DEFAULT ||
+ oldsize == 0) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ olddata = malloc(oldsize);
+ if (olddata == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) memset(olddata, 0, oldsize);
+ /*
+ * Read the entire blob of GeneralNames, we don't
+ * need to interpret them now.
+ */
+ if (kmfber_read(exasn1, olddata, oldsize) != oldsize) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+out:
+ if (exasn1 != NULL)
+ kmfber_free(exasn1, 1);
+
+ if (ret != KMF_OK) {
+ *contents = NULL;
+ *outlen = 0;
+ if (olddata != NULL)
+ free(olddata);
+ } else {
+ *contents = olddata;
+ *outlen = oldsize;
+ }
+ return (ret);
+}
+
+KMF_RETURN
+add_an_extension(KMF_X509_EXTENSIONS *exts, KMF_X509_EXTENSION *newextn)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSION *extlist;
+
+ if (exts == NULL || newextn == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ extlist = malloc(sizeof (KMF_X509_EXTENSION) *
+ (exts->numberOfExtensions + 1));
+ if (extlist == NULL)
+ return (KMF_ERR_MEMORY);
+
+ (void) memcpy(extlist, exts->extensions,
+ exts->numberOfExtensions * sizeof (KMF_X509_EXTENSION));
+
+ (void) memcpy(&extlist[exts->numberOfExtensions], newextn,
+ sizeof (KMF_X509_EXTENSION));
+
+ free(exts->extensions);
+ exts->numberOfExtensions++;
+ exts->extensions = extlist;
+
+ return (ret);
+}
+
+KMF_RETURN
+KMF_SetAltName(KMF_X509_EXTENSIONS *extensions,
+ KMF_OID *oid,
+ int critical,
+ KMF_GENERALNAMECHOICES nametype,
+ char *namedata)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_X509_EXTENSION subjAltName;
+ KMF_DATA dername = { NULL, 0 };
+ BerElement *asn1 = NULL;
+ BerValue *extdata;
+ char *olddata = NULL;
+ KMF_X509_EXTENSION *foundextn = NULL;
+ size_t oldsize = 0;
+
+ if (extensions == NULL || oid == NULL || namedata == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ ret = encode_altname(namedata, nametype, &dername);
+
+ if (ret != KMF_OK)
+ return (ret);
+
+ (void) memset(&subjAltName, 0, sizeof (subjAltName));
+
+ ret = copy_data(&subjAltName.extnId, oid);
+ if (ret != KMF_OK)
+ goto out;
+ /*
+ * Check to see if this cert already has a subjectAltName.
+ */
+ foundextn = FindExtn(extensions, oid);
+
+ if (foundextn != NULL) {
+ ret = GetSequenceContents(
+ (char *)foundextn->BERvalue.Data,
+ foundextn->BERvalue.Length,
+ &olddata, &oldsize);
+ if (ret != KMF_OK)
+ goto out;
+ }
+
+ /*
+ * Assume (!!) that the namedata given is already properly encoded.
+ */
+ if ((asn1 = kmfder_alloc()) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (kmfber_printf(asn1, "{") == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ /* Write the old extension data first */
+ if (olddata != NULL && oldsize > 0) {
+ if (kmfber_write(asn1, olddata, oldsize, 0) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+ }
+
+ /* Now add the new name to the list */
+ if (kmfber_write(asn1, (char *)dername.Data, dername.Length, 0) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ /* Now close the sequence */
+ if (kmfber_printf(asn1, "}") == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+ if (kmfber_flatten(asn1, &extdata) == -1) {
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ /*
+ * If we are just adding to an existing list of altNames,
+ * just replace the BER data associated with the found extension.
+ */
+ if (foundextn != NULL) {
+ free(foundextn->BERvalue.Data);
+ foundextn->critical = critical;
+ foundextn->BERvalue.Data = (uchar_t *)extdata->bv_val;
+ foundextn->BERvalue.Length = extdata->bv_len;
+ } else {
+ subjAltName.critical = critical;
+ subjAltName.format = KMF_X509_DATAFORMAT_ENCODED;
+ subjAltName.BERvalue.Data = (uchar_t *)extdata->bv_val;
+ subjAltName.BERvalue.Length = extdata->bv_len;
+ ret = add_an_extension(extensions, &subjAltName);
+ if (ret != KMF_OK)
+ free(subjAltName.BERvalue.Data);
+ }
+
+ free(extdata);
+out:
+ if (olddata != NULL)
+ free(olddata);
+
+ KMF_FreeData(&dername);
+ if (ret != KMF_OK)
+ KMF_FreeData(&subjAltName.extnId);
+ if (asn1 != NULL)
+ kmfber_free(asn1, 1);
+ return (ret);
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/keyop.c b/usr/src/lib/libkmf/libkmf/common/keyop.c
new file mode 100644
index 0000000000..abe0082306
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/keyop.c
@@ -0,0 +1,375 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright(c) 1995-2000 Intel Corporation. All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <link.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ber_der.h>
+#include <kmfapiP.h>
+#include <libgen.h>
+#include <cryptoutil.h>
+
+/*
+ *
+ * Name: KMF_SignDataWithKey
+ *
+ * Description:
+ * This function signs a block of data using the private key
+ * and returns the signature in output
+ *
+ * Parameters:
+ * handle(input) - opaque handle for KMF session
+ * key(input) - contains private key handle needed for signing
+ * AlgOID(input) - contains algorithm to be used for signing
+ * tobesigned(input) - pointer to a KMF_DATA structure containing
+ * the data to be signed
+ * output(output) - pointer to the KMF_DATA structure containing the
+ * signed data
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_SignDataWithKey(KMF_HANDLE_T handle,
+ KMF_KEY_HANDLE *key,
+ KMF_OID *AlgOID,
+ KMF_DATA *tobesigned,
+ KMF_DATA *output)
+{
+ KMF_RETURN ret;
+ KMF_PLUGIN *plugin;
+ KMF_ALGORITHM_INDEX AlgId;
+ KMF_DATA signature = {0, NULL};
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (key == NULL || AlgOID == NULL ||
+ tobesigned == NULL || output == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * The plugin must be based on the key since private keys
+ * cannot be extracted.
+ */
+ plugin = FindPlugin(handle, key->kstype);
+ if (plugin != NULL && plugin->funclist->SignData != NULL) {
+ ret = plugin->funclist->SignData(handle, key,
+ AlgOID, tobesigned, output);
+ if (ret != KMF_OK)
+ goto cleanup;
+
+ AlgId = X509_AlgorithmOidToAlgId(AlgOID);
+
+ /*
+ * For DSA, NSS returns an encoded signature. Decode the
+ * signature as DSA signature should be 40-byte long.
+ */
+ if ((AlgId == KMF_ALGID_SHA1WithDSA) &&
+ (plugin->type == KMF_KEYSTORE_NSS)) {
+ ret = DerDecodeDSASignature(output, &signature);
+ if (ret != KMF_OK) {
+ goto cleanup;
+ } else {
+ output->Length = signature.Length;
+ (void) memcpy(output->Data, signature.Data,
+ signature.Length);
+ }
+ } else if (AlgId == KMF_ALGID_NONE) {
+ ret = KMF_ERR_BAD_ALGORITHM;
+ }
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+cleanup:
+ if (signature.Data)
+ free(signature.Data);
+ return (ret);
+}
+
+/*
+ *
+ * Name: KMF_VerifyDataWithKey
+ *
+ * Description:
+ * This function verifies the signature of a block of data
+ * using the input public key
+ *
+ * Parameters:
+ * handle(input) - opaque handle for KMF session
+ * KMFKey(input) - holds public key information for verification
+ * sigAlg(input) - algorithm to verify
+ * indata(input) - pointer to the block of data whose signature
+ * is to be verified
+ * insig(input) - pointer to the signature to be verified
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_VerifyDataWithKey(KMF_HANDLE_T handle,
+ KMF_KEY_HANDLE *KMFKey,
+ KMF_ALGORITHM_INDEX sigAlg,
+ KMF_DATA *indata,
+ KMF_DATA *insig)
+{
+ KMF_RETURN err;
+ KMF_DATA derkey = {0, NULL};
+ KMF_PLUGIN *plugin;
+
+ CLEAR_ERROR(handle, err);
+ if (err != KMF_OK)
+ return (err);
+
+ if (KMFKey == NULL ||
+ indata == NULL || insig == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, KMFKey->kstype);
+
+ /* Retrieve public key data from keystore */
+ if (plugin != NULL && plugin->funclist->EncodePubkeyData != NULL) {
+ err = plugin->funclist->EncodePubkeyData(handle,
+ KMFKey, &derkey);
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ err = VerifyDataWithKey(handle, &derkey, sigAlg, indata, insig);
+
+ if (derkey.Data != NULL)
+ free(derkey.Data);
+
+ return (err);
+}
+
+KMF_RETURN
+KMF_CreateKeypair(KMF_HANDLE_T handle,
+ KMF_CREATEKEYPAIR_PARAMS *params,
+ KMF_KEY_HANDLE *privKey,
+ KMF_KEY_HANDLE *pubKey)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (params == NULL ||
+ privKey == NULL || pubKey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(privKey, 0, sizeof (KMF_KEY_HANDLE));
+ (void) memset(pubKey, 0, sizeof (KMF_KEY_HANDLE));
+ plugin = FindPlugin(handle, params->kstype);
+
+ if (plugin != NULL && plugin->funclist->CreateKeypair != NULL) {
+ return (plugin->funclist->CreateKeypair(handle, params,
+ privKey, pubKey));
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+}
+
+KMF_RETURN
+KMF_DeleteKeyFromKeystore(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params,
+ KMF_KEY_HANDLE *key)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_PLUGIN *plugin;
+
+ CLEAR_ERROR(handle, rv);
+ if (rv != KMF_OK)
+ return (rv);
+
+ if (key == NULL || params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, params->kstype);
+ if (plugin != NULL && plugin->funclist->DeleteKey != NULL) {
+ rv = plugin->funclist->DeleteKey(handle, params, key, TRUE);
+ } else {
+ rv = KMF_ERR_PLUGIN_NOTFOUND;
+ }
+
+ if (rv == KMF_OK) {
+ if (key->keylabel != NULL)
+ free(key->keylabel);
+
+ if (key->israw && key->keyp != NULL) {
+ if (key->keyclass == KMF_ASYM_PUB ||
+ key->keyclass == KMF_ASYM_PRI) {
+ KMF_FreeRawKey(key->keyp);
+ free(key->keyp);
+ } else if (key->keyclass == KMF_SYMMETRIC) {
+ KMF_FreeRawSymKey(key->keyp);
+ }
+ /* Else we don't know how to free the memory. */
+ }
+
+ (void) memset(key, 0, sizeof (KMF_KEY_HANDLE));
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+KMF_SignCertRecord(KMF_HANDLE_T handle, KMF_KEY_HANDLE *kmfprikey,
+ KMF_X509_CERTIFICATE *CertData, KMF_DATA *signedCert)
+{
+ KMF_RETURN ret;
+ KMF_DATA unsignedCert;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (kmfprikey == NULL ||
+ CertData == NULL || signedCert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ ret = KMF_EncodeCertRecord(CertData, &unsignedCert);
+ if (ret == KMF_OK)
+ ret = KMF_SignCertWithKey(handle, &unsignedCert, kmfprikey,
+ signedCert);
+
+ KMF_FreeData(&unsignedCert);
+ return (ret);
+}
+
+KMF_RETURN
+KMF_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms,
+ KMF_KEY_HANDLE *keys, uint32_t *numkeys)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (parms == NULL || numkeys == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, parms->kstype);
+
+ if (plugin != NULL && plugin->funclist->FindKey != NULL) {
+ return (plugin->funclist->FindKey(handle, parms,
+ keys, numkeys));
+ }
+
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+}
+
+KMF_RETURN
+KMF_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params,
+ KMF_RAW_KEY_DATA *rawkey)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (params == NULL || rawkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Find the private key from the keystore */
+ plugin = FindPlugin(handle, params->kstype);
+
+ if (plugin != NULL && plugin->funclist->StorePrivateKey != NULL) {
+ return (plugin->funclist->StorePrivateKey(handle,
+ params, rawkey));
+ }
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+}
+
+KMF_RETURN
+KMF_CreateSymKey(KMF_HANDLE_T handle, KMF_CREATESYMKEY_PARAMS *params,
+ KMF_KEY_HANDLE *symkey)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (params == NULL ||
+ symkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, params->kstype);
+ if (plugin != NULL && plugin->funclist->CreateSymKey != NULL) {
+ return (plugin->funclist->CreateSymKey(handle, params,
+ symkey));
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+}
+
+KMF_RETURN
+KMF_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey,
+ KMF_RAW_SYM_KEY *rkey)
+{
+ KMF_PLUGIN *plugin;
+ KMF_RETURN ret;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ if (symkey == NULL || rkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ plugin = FindPlugin(handle, symkey->kstype);
+ if (plugin != NULL &&
+ plugin->funclist->GetSymKeyValue != NULL) {
+ return (plugin->funclist->GetSymKeyValue(handle,
+ symkey, rkey));
+ } else {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/kmfoids.c b/usr/src/lib/libkmf/libkmf/common/kmfoids.c
new file mode 100644
index 0000000000..9f2e6dff14
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/kmfoids.c
@@ -0,0 +1,375 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright(c) 1995-2000 Intel Corporation. All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <kmfapi.h>
+
+/* From X.520 */
+static uint8_t
+OID_ObjectClass[] = { OID_ATTR_TYPE, 0 },
+OID_AliasedEntryName[] = { OID_ATTR_TYPE, 1 },
+OID_KnowledgeInformation[] = { OID_ATTR_TYPE, 2 },
+OID_CommonName[] = { OID_ATTR_TYPE, 3 },
+OID_Surname[] = { OID_ATTR_TYPE, 4 },
+OID_SerialNumber[] = { OID_ATTR_TYPE, 5 },
+OID_CountryName[] = { OID_ATTR_TYPE, 6 },
+OID_LocalityName[] = { OID_ATTR_TYPE, 7 },
+OID_StateProvinceName[] = { OID_ATTR_TYPE, 8 },
+OID_CollectiveStateProvinceName[] = { OID_ATTR_TYPE, 8, 1 },
+OID_StreetAddress[] = { OID_ATTR_TYPE, 9 },
+OID_CollectiveStreetAddress[] = { OID_ATTR_TYPE, 9, 1 },
+OID_OrganizationName[] = { OID_ATTR_TYPE, 10 },
+OID_CollectiveOrganizationName[] = { OID_ATTR_TYPE, 10, 1 },
+OID_OrganizationalUnitName[] = { OID_ATTR_TYPE, 11 },
+OID_CollectiveOrganizationalUnitName[] = { OID_ATTR_TYPE, 11, 1 },
+OID_Title[] = { OID_ATTR_TYPE, 12 },
+OID_Description[] = { OID_ATTR_TYPE, 13 },
+OID_SearchGuide[] = { OID_ATTR_TYPE, 14 },
+OID_BusinessCategory[] = { OID_ATTR_TYPE, 15 },
+OID_PostalAddress[] = { OID_ATTR_TYPE, 16 },
+OID_CollectivePostalAddress[] = { OID_ATTR_TYPE, 16, 1 },
+OID_PostalCode[] = { OID_ATTR_TYPE, 17 },
+OID_CollectivePostalCode[] = { OID_ATTR_TYPE, 17, 1 },
+OID_PostOfficeBox[] = { OID_ATTR_TYPE, 18 },
+OID_CollectivePostOfficeBox[] = { OID_ATTR_TYPE, 18, 1 },
+OID_PhysicalDeliveryOfficeName[] = { OID_ATTR_TYPE, 19 },
+OID_CollectivePhysicalDeliveryOfficeName[] = { OID_ATTR_TYPE, 19, 1 },
+OID_TelephoneNumber[] = { OID_ATTR_TYPE, 20 },
+OID_CollectiveTelephoneNumber[] = { OID_ATTR_TYPE, 20, 1 },
+OID_TelexNumber[] = { OID_ATTR_TYPE, 21 },
+OID_CollectiveTelexNumber[] = { OID_ATTR_TYPE, 21, 1 },
+OID_TelexTerminalIdentifier[] = { OID_ATTR_TYPE, 22 },
+OID_CollectiveTelexTerminalIdentifier[] = { OID_ATTR_TYPE, 22, 1 },
+OID_FacsimileTelephoneNumber[] = { OID_ATTR_TYPE, 23 },
+OID_CollectiveFacsimileTelephoneNumber[] = { OID_ATTR_TYPE, 23, 1 },
+OID_X_121Address[] = { OID_ATTR_TYPE, 24 },
+OID_InternationalISDNNumber[] = { OID_ATTR_TYPE, 25 },
+OID_CollectiveInternationalISDNNumber[] = { OID_ATTR_TYPE, 25, 1 },
+OID_RegisteredAddress[] = { OID_ATTR_TYPE, 26 },
+OID_DestinationIndicator[] = { OID_ATTR_TYPE, 27 },
+OID_PreferredDeliveryMethod[] = { OID_ATTR_TYPE, 28 },
+OID_PresentationAddress[] = { OID_ATTR_TYPE, 29 },
+OID_SupportedApplicationContext[] = { OID_ATTR_TYPE, 30 },
+OID_Member[] = { OID_ATTR_TYPE, 31 },
+OID_Owner[] = { OID_ATTR_TYPE, 32 },
+OID_RoleOccupant[] = { OID_ATTR_TYPE, 33 },
+OID_SeeAlso[] = { OID_ATTR_TYPE, 34 },
+OID_UserPassword[] = { OID_ATTR_TYPE, 35 },
+OID_UserCertificate[] = { OID_ATTR_TYPE, 36 },
+OID_CACertificate[] = { OID_ATTR_TYPE, 37 },
+OID_AuthorityRevocationList[] = { OID_ATTR_TYPE, 38 },
+OID_CertificateRevocationList[] = { OID_ATTR_TYPE, 39 },
+OID_CrossCertificatePair[] = { OID_ATTR_TYPE, 40 },
+OID_Name[] = { OID_ATTR_TYPE, 41 },
+OID_GivenName[] = { OID_ATTR_TYPE, 42 },
+OID_Initials[] = { OID_ATTR_TYPE, 43 },
+OID_GenerationQualifier[] = { OID_ATTR_TYPE, 44 },
+OID_UniqueIdentifier[] = { OID_ATTR_TYPE, 45 },
+OID_DNQualifier[] = { OID_ATTR_TYPE, 46 },
+OID_EnhancedSearchGuide[] = { OID_ATTR_TYPE, 47 },
+OID_ProtocolInformation[] = { OID_ATTR_TYPE, 48 },
+OID_DistinguishedName[] = { OID_ATTR_TYPE, 49 },
+OID_UniqueMember[] = { OID_ATTR_TYPE, 50 },
+OID_HouseIdentifier[] = { OID_ATTR_TYPE, 51 }
+/* OID_SupportedAlgorithms[] = { OID_ATTR_TYPE, 52 }, */
+/* OID_DeltaRevocationList[] = { OID_ATTR_TYPE, 53 }, */
+/* OID_AttributeCertificate[] = { OID_ATTR_TYPE, 58 } */
+;
+
+/* From PKCS 9 */
+static uint8_t
+OID_EmailAddress[] = { OID_PKCS_9, 1 },
+OID_UnstructuredName[] = { OID_PKCS_9, 2 },
+OID_ContentType[] = { OID_PKCS_9, 3 },
+OID_MessageDigest[] = { OID_PKCS_9, 4 },
+OID_SigningTime[] = { OID_PKCS_9, 5 },
+OID_CounterSignature[] = { OID_PKCS_9, 6 },
+OID_ChallengePassword[] = { OID_PKCS_9, 7 },
+OID_UnstructuredAddress[] = { OID_PKCS_9, 8 },
+OID_ExtendedCertificateAttributes[] = { OID_PKCS_9, 9 },
+OID_ExtensionRequest[] = { OID_PKCS_9, 14 };
+
+/* From PKIX 1 */
+/* Standard Extensions */
+static uint8_t
+OID_SubjectDirectoryAttributes[] = { OID_EXTENSION, 9 },
+OID_SubjectKeyIdentifier[] = { OID_EXTENSION, 14 },
+OID_KeyUsage[] = { OID_EXTENSION, 15 },
+OID_PrivateKeyUsagePeriod[] = { OID_EXTENSION, 16 },
+OID_SubjectAltName[] = { OID_EXTENSION, 17 },
+OID_IssuerAltName[] = { OID_EXTENSION, 18 },
+OID_BasicConstraints[] = { OID_EXTENSION, 19 },
+OID_CrlNumber[] = { OID_EXTENSION, 20 },
+OID_CrlReason[] = { OID_EXTENSION, 21 },
+OID_HoldInstructionCode[] = { OID_EXTENSION, 23 },
+OID_InvalidityDate[] = { OID_EXTENSION, 24 },
+OID_DeltaCrlIndicator[] = { OID_EXTENSION, 27 },
+OID_IssuingDistributionPoints[] = { OID_EXTENSION, 28 },
+
+/* OID_CertificateIssuer[] = { OID_EXTENSION, 29 }, */
+OID_NameConstraints[] = { OID_EXTENSION, 30 },
+OID_CrlDistributionPoints[] = { OID_EXTENSION, 31 },
+OID_CertificatePolicies[] = { OID_EXTENSION, 32 },
+OID_PolicyMappings[] = { OID_EXTENSION, 33 },
+/* 34 deprecated */
+OID_AuthorityKeyIdentifier[] = { OID_EXTENSION, 35 },
+OID_PolicyConstraints[] = { OID_EXTENSION, 36 },
+OID_ExtKeyUsage[] = { OID_EXTENSION, 37 }
+;
+
+/* PKIX-defined extended key purpose OIDs */
+static uint8_t
+OID_QT_CPSuri[] = { OID_PKIX_QT_CPS },
+OID_QT_Unotice[] = { OID_PKIX_QT_UNOTICE },
+
+OID_KP_ServerAuth[] = { OID_PKIX_KP, 1 },
+OID_KP_ClientAuth[] = { OID_PKIX_KP, 2 },
+OID_KP_CodeSigning[] = { OID_PKIX_KP, 3 },
+OID_KP_EmailProtection[] = { OID_PKIX_KP, 4 },
+OID_KP_IPSecEndSystem[] = { OID_PKIX_KP, 5 },
+OID_KP_IPSecTunnel[] = { OID_PKIX_KP, 6 },
+OID_KP_IPSecUser[] = { OID_PKIX_KP, 7 },
+OID_KP_TimeStamping[] = { OID_PKIX_KP, 8 },
+OID_KP_OCSPSigning[] = { OID_PKIX_KP, 9 }
+;
+
+/* From PKIX 1 */
+static uint8_t
+OID_AuthorityInfoAccess[] = { OID_PKIX_PE, 1};
+
+const KMF_OID
+KMFOID_AuthorityInfoAccess = {OID_PKIX_LENGTH + 2, OID_AuthorityInfoAccess};
+
+static uint8_t
+OID_PkixAdOcsp[] = {OID_PKIX_AD, 1};
+
+const KMF_OID
+KMFOID_PkixAdOcsp = {OID_PKIX_AD_LENGTH + 1, OID_PkixAdOcsp};
+
+static uint8_t
+OID_PkixAdCaIssuers[] = {OID_PKIX_AD, 2};
+
+const KMF_OID
+KMFOID_PkixAdCaIssuers = {OID_PKIX_AD_LENGTH + 1, OID_PkixAdCaIssuers};
+
+/*
+ * From RFC 1274
+ */
+static uint8_t
+OID_userid[] = {OID_PILOT, 1},
+OID_RFC822mailbox[] = {OID_PILOT, 3},
+OID_domainComponent[] = {OID_PILOT, 25};
+
+const KMF_OID
+KMFOID_userid = {OID_PILOT_LENGTH + 1, OID_userid},
+KMFOID_RFC822mailbox = {OID_PILOT_LENGTH + 1, OID_RFC822mailbox},
+KMFOID_domainComponent = {OID_PILOT_LENGTH + 1, OID_domainComponent},
+KMFOID_ObjectClass = {OID_ATTR_TYPE_LENGTH+1, OID_ObjectClass},
+KMFOID_AliasedEntryName = {OID_ATTR_TYPE_LENGTH+1, OID_AliasedEntryName},
+KMFOID_KnowledgeInformation = {OID_ATTR_TYPE_LENGTH+1,
+ OID_KnowledgeInformation},
+KMFOID_CommonName = {OID_ATTR_TYPE_LENGTH+1, OID_CommonName},
+KMFOID_Surname = {OID_ATTR_TYPE_LENGTH+1, OID_Surname},
+KMFOID_SerialNumber = {OID_ATTR_TYPE_LENGTH+1, OID_SerialNumber},
+KMFOID_CountryName = {OID_ATTR_TYPE_LENGTH+1, OID_CountryName},
+KMFOID_LocalityName = {OID_ATTR_TYPE_LENGTH+1, OID_LocalityName},
+KMFOID_StateProvinceName = {OID_ATTR_TYPE_LENGTH+1, OID_StateProvinceName},
+KMFOID_CollectiveStateProvinceName = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectiveStateProvinceName},
+KMFOID_StreetAddress = {OID_ATTR_TYPE_LENGTH+1, OID_StreetAddress},
+KMFOID_CollectiveStreetAddress = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectiveStreetAddress},
+KMFOID_OrganizationName = {OID_ATTR_TYPE_LENGTH+1, OID_OrganizationName},
+KMFOID_CollectiveOrganizationName = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectiveOrganizationName},
+KMFOID_OrganizationalUnitName = {OID_ATTR_TYPE_LENGTH+1,
+ OID_OrganizationalUnitName},
+KMFOID_CollectiveOrganizationalUnitName = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectiveOrganizationalUnitName},
+KMFOID_Title = {OID_ATTR_TYPE_LENGTH+1, OID_Title},
+KMFOID_Description = {OID_ATTR_TYPE_LENGTH+1, OID_Description},
+KMFOID_SearchGuide = {OID_ATTR_TYPE_LENGTH+1, OID_SearchGuide},
+KMFOID_BusinessCategory = {OID_ATTR_TYPE_LENGTH+1, OID_BusinessCategory},
+KMFOID_PostalAddress = {OID_ATTR_TYPE_LENGTH+1, OID_PostalAddress},
+KMFOID_CollectivePostalAddress = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectivePostalAddress},
+KMFOID_PostalCode = {OID_ATTR_TYPE_LENGTH+1, OID_PostalCode},
+KMFOID_CollectivePostalCode = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectivePostalCode},
+KMFOID_PostOfficeBox = {OID_ATTR_TYPE_LENGTH+1, OID_PostOfficeBox},
+KMFOID_CollectivePostOfficeBox = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectivePostOfficeBox},
+KMFOID_PhysicalDeliveryOfficeName = {OID_ATTR_TYPE_LENGTH+1,
+ OID_PhysicalDeliveryOfficeName},
+KMFOID_CollectivePhysicalDeliveryOfficeName = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectivePhysicalDeliveryOfficeName},
+KMFOID_TelephoneNumber = {OID_ATTR_TYPE_LENGTH+1, OID_TelephoneNumber},
+KMFOID_CollectiveTelephoneNumber = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectiveTelephoneNumber},
+KMFOID_TelexNumber = {OID_ATTR_TYPE_LENGTH+1, OID_TelexNumber},
+KMFOID_CollectiveTelexNumber = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectiveTelexNumber},
+KMFOID_TelexTerminalIdentifier = {OID_ATTR_TYPE_LENGTH+1,
+ OID_TelexTerminalIdentifier},
+KMFOID_CollectiveTelexTerminalIdentifier = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectiveTelexTerminalIdentifier},
+KMFOID_FacsimileTelephoneNumber = {OID_ATTR_TYPE_LENGTH+1,
+ OID_FacsimileTelephoneNumber},
+KMFOID_CollectiveFacsimileTelephoneNumber = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectiveFacsimileTelephoneNumber},
+KMFOID_X_121Address = {OID_ATTR_TYPE_LENGTH+1, OID_X_121Address},
+KMFOID_InternationalISDNNumber = {OID_ATTR_TYPE_LENGTH+1,
+ OID_InternationalISDNNumber},
+KMFOID_CollectiveInternationalISDNNumber = {OID_ATTR_TYPE_LENGTH+2,
+ OID_CollectiveInternationalISDNNumber},
+KMFOID_RegisteredAddress = {OID_ATTR_TYPE_LENGTH+1, OID_RegisteredAddress},
+KMFOID_DestinationIndicator = {OID_ATTR_TYPE_LENGTH+1,
+ OID_DestinationIndicator},
+KMFOID_PreferredDeliveryMethod = {OID_ATTR_TYPE_LENGTH+1,
+ OID_PreferredDeliveryMethod},
+KMFOID_PresentationAddress = {OID_ATTR_TYPE_LENGTH+1,
+ OID_PresentationAddress},
+KMFOID_SupportedApplicationContext = {OID_ATTR_TYPE_LENGTH+1,
+ OID_SupportedApplicationContext},
+KMFOID_Member = {OID_ATTR_TYPE_LENGTH+1, OID_Member},
+KMFOID_Owner = {OID_ATTR_TYPE_LENGTH+1, OID_Owner},
+KMFOID_RoleOccupant = {OID_ATTR_TYPE_LENGTH+1, OID_RoleOccupant},
+KMFOID_SeeAlso = {OID_ATTR_TYPE_LENGTH+1, OID_SeeAlso},
+KMFOID_UserPassword = {OID_ATTR_TYPE_LENGTH+1, OID_UserPassword},
+KMFOID_UserCertificate = {OID_ATTR_TYPE_LENGTH+1, OID_UserCertificate},
+KMFOID_CACertificate = {OID_ATTR_TYPE_LENGTH+1, OID_CACertificate},
+KMFOID_AuthorityRevocationList = {OID_ATTR_TYPE_LENGTH+1,
+ OID_AuthorityRevocationList},
+KMFOID_CertificateRevocationList = {OID_ATTR_TYPE_LENGTH+1,
+ OID_CertificateRevocationList},
+KMFOID_CrossCertificatePair = {OID_ATTR_TYPE_LENGTH+1,
+ OID_CrossCertificatePair},
+KMFOID_Name = {OID_ATTR_TYPE_LENGTH+1, OID_Name},
+KMFOID_GivenName = {OID_ATTR_TYPE_LENGTH+1, OID_GivenName},
+KMFOID_Initials = {OID_ATTR_TYPE_LENGTH+1, OID_Initials},
+KMFOID_GenerationQualifier = {OID_ATTR_TYPE_LENGTH+1, OID_GenerationQualifier},
+KMFOID_UniqueIdentifier = {OID_ATTR_TYPE_LENGTH+1, OID_UniqueIdentifier},
+KMFOID_DNQualifier = {OID_ATTR_TYPE_LENGTH+1, OID_DNQualifier},
+KMFOID_EnhancedSearchGuide = {OID_ATTR_TYPE_LENGTH+1, OID_EnhancedSearchGuide},
+KMFOID_ProtocolInformation = {OID_ATTR_TYPE_LENGTH+1, OID_ProtocolInformation},
+KMFOID_DistinguishedName = {OID_ATTR_TYPE_LENGTH+1, OID_DistinguishedName},
+KMFOID_UniqueMember = {OID_ATTR_TYPE_LENGTH+1, OID_UniqueMember},
+KMFOID_HouseIdentifier = {OID_ATTR_TYPE_LENGTH+1, OID_HouseIdentifier},
+KMFOID_EmailAddress = {OID_PKCS_9_LENGTH+1, OID_EmailAddress},
+KMFOID_UnstructuredName = {OID_PKCS_9_LENGTH+1, OID_UnstructuredName},
+KMFOID_ContentType = {OID_PKCS_9_LENGTH+1, OID_ContentType},
+KMFOID_MessageDigest = {OID_PKCS_9_LENGTH+1, OID_MessageDigest},
+KMFOID_SigningTime = {OID_PKCS_9_LENGTH+1, OID_SigningTime},
+KMFOID_CounterSignature = {OID_PKCS_9_LENGTH+1, OID_CounterSignature},
+KMFOID_ChallengePassword = {OID_PKCS_9_LENGTH+1, OID_ChallengePassword},
+KMFOID_UnstructuredAddress = {OID_PKCS_9_LENGTH+1, OID_UnstructuredAddress},
+KMFOID_ExtendedCertificateAttributes = {OID_PKCS_9_LENGTH+1,
+ OID_ExtendedCertificateAttributes},
+KMFOID_ExtensionRequest = {OID_PKCS_9_LENGTH + 1, OID_ExtensionRequest};
+
+static uint8_t
+OID_AuthorityKeyID[] = { OID_EXTENSION, 1 },
+OID_VerisignCertificatePolicy[] = { OID_EXTENSION, 3 },
+OID_KeyUsageRestriction[] = { OID_EXTENSION, 4 };
+
+const KMF_OID
+KMFOID_AuthorityKeyID = {OID_EXTENSION_LENGTH+1, OID_AuthorityKeyID},
+
+KMFOID_VerisignCertificatePolicy = {OID_EXTENSION_LENGTH+1,
+ OID_VerisignCertificatePolicy},
+
+KMFOID_KeyUsageRestriction = {OID_EXTENSION_LENGTH+1,
+ OID_KeyUsageRestriction},
+
+KMFOID_SubjectDirectoryAttributes = {OID_EXTENSION_LENGTH+1,
+ OID_SubjectDirectoryAttributes},
+
+KMFOID_SubjectKeyIdentifier = {OID_EXTENSION_LENGTH+1,
+ OID_SubjectKeyIdentifier },
+KMFOID_KeyUsage = {OID_EXTENSION_LENGTH+1, OID_KeyUsage },
+
+KMFOID_PrivateKeyUsagePeriod = {OID_EXTENSION_LENGTH+1,
+ OID_PrivateKeyUsagePeriod},
+KMFOID_SubjectAltName = {OID_EXTENSION_LENGTH+1, OID_SubjectAltName },
+KMFOID_IssuerAltName = {OID_EXTENSION_LENGTH+1, OID_IssuerAltName },
+KMFOID_BasicConstraints = {OID_EXTENSION_LENGTH+1, OID_BasicConstraints },
+
+KMFOID_CrlNumber = {OID_EXTENSION_LENGTH+1, OID_CrlNumber},
+
+KMFOID_CrlReason = {OID_EXTENSION_LENGTH+1, OID_CrlReason},
+
+KMFOID_HoldInstructionCode = {OID_EXTENSION_LENGTH+1, OID_HoldInstructionCode},
+
+KMFOID_InvalidityDate = {OID_EXTENSION_LENGTH+1, OID_InvalidityDate},
+
+KMFOID_DeltaCrlIndicator = {OID_EXTENSION_LENGTH+1, OID_DeltaCrlIndicator},
+
+KMFOID_IssuingDistributionPoints = {OID_EXTENSION_LENGTH+1,
+ OID_IssuingDistributionPoints},
+
+KMFOID_NameConstraints = {OID_EXTENSION_LENGTH+1,
+ OID_NameConstraints},
+
+KMFOID_CrlDistributionPoints = {OID_EXTENSION_LENGTH+1,
+ OID_CrlDistributionPoints},
+
+KMFOID_CertificatePolicies = {OID_EXTENSION_LENGTH+1,
+ OID_CertificatePolicies},
+
+KMFOID_PolicyMappings = {OID_EXTENSION_LENGTH+1, OID_PolicyMappings},
+
+KMFOID_PolicyConstraints = {OID_EXTENSION_LENGTH+1, OID_PolicyConstraints},
+
+KMFOID_AuthorityKeyIdentifier = {OID_EXTENSION_LENGTH+1,
+ OID_AuthorityKeyIdentifier},
+
+KMFOID_ExtendedKeyUsage = {OID_EXTENSION_LENGTH+1, OID_ExtKeyUsage},
+
+KMFOID_PKIX_PQ_CPSuri = {OID_PKIX_QT_CPS_LENGTH, OID_QT_CPSuri},
+
+KMFOID_PKIX_PQ_Unotice = {OID_PKIX_QT_UNOTICE_LENGTH, OID_QT_Unotice},
+
+/* Extended Key Usage OIDs */
+KMFOID_PKIX_KP_ServerAuth = {OID_PKIX_KP_LENGTH + 1, OID_KP_ServerAuth},
+
+KMFOID_PKIX_KP_ClientAuth = {OID_PKIX_KP_LENGTH + 1, OID_KP_ClientAuth},
+
+KMFOID_PKIX_KP_CodeSigning = {OID_PKIX_KP_LENGTH + 1, OID_KP_CodeSigning},
+
+KMFOID_PKIX_KP_EmailProtection = {OID_PKIX_KP_LENGTH + 1,
+ OID_KP_EmailProtection},
+
+KMFOID_PKIX_KP_IPSecEndSystem = {OID_PKIX_KP_LENGTH + 1, OID_KP_IPSecEndSystem},
+
+KMFOID_PKIX_KP_IPSecTunnel = {OID_PKIX_KP_LENGTH + 1, OID_KP_IPSecTunnel},
+
+KMFOID_PKIX_KP_IPSecUser = {OID_PKIX_KP_LENGTH + 1, OID_KP_IPSecUser},
+
+KMFOID_PKIX_KP_TimeStamping = {OID_PKIX_KP_LENGTH + 1, OID_KP_TimeStamping},
+
+KMFOID_PKIX_KP_OCSPSigning = {OID_PKIX_KP_LENGTH + 1, OID_KP_OCSPSigning};
diff --git a/usr/src/cmd/cmd-crypto/pktool/derparse.h b/usr/src/lib/libkmf/libkmf/common/llib-lkmf
index 2ff36d2163..114e823e4d 100644
--- a/usr/src/cmd/cmd-crypto/pktool/derparse.h
+++ b/usr/src/lib/libkmf/libkmf/common/llib-lkmf
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,36 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#ifndef _PKTOOL_DERPARSE_H
-#define _PKTOOL_DERPARSE_H
-
#pragma ident "%Z%%M% %I% %E% SMI"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef LBER_OID
-#define LBER_OID 0x06
-#endif
-
-#ifndef LBER_PRINTABLE_STRING
-#define LBER_PRINTABLE_STRING 0x13
-#endif
-
-#ifndef LBER_IA5STRING
-#define LBER_IA5STRING 0x16
-#endif
-
-extern void rdnseq_to_str(uchar_t *from, size_t from_sz, char *to,
- size_t to_sz);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PKTOOL_DERPARSE_H */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+#include <kmfapi.h>
+#include <kmfpolicy.h>
diff --git a/usr/src/lib/libkmf/libkmf/common/mapfile-vers b/usr/src/lib/libkmf/libkmf/common/mapfile-vers
new file mode 100644
index 0000000000..6de1bf01f5
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/mapfile-vers
@@ -0,0 +1,288 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate_1.1 {
+ global:
+ DigestData;
+ GetIDFromSPKI;
+ KMF_AddCertEKU;
+ KMF_AddPolicyToDB;
+ KMF_CheckCRLDate;
+ KMF_CheckCertDate;
+ KMF_CompareRDNs;
+ KMF_ConfigureKeystore;
+ KMF_CreateCSRFile;
+ KMF_CreateCertFile;
+ KMF_CreateKeypair;
+ KMF_CreateOCSPRequest;
+ KMF_CreateSymKey;
+ KMF_DN2Der;
+ KMF_DNParser;
+ KMF_DecryptWithCert;
+ KMF_DeleteCRL;
+ KMF_DeleteCertFromKeystore;
+ KMF_DeleteKeyFromKeystore;
+ KMF_DeletePolicyFromDB;
+ KMF_Der2Pem;
+ KMF_DownloadCRL;
+ KMF_DownloadCert;
+ KMF_EncodeCertRecord;
+ KMF_EncryptWithCert;
+ KMF_ExportPK12;
+ KMF_Finalize;
+ KMF_FindCRL;
+ KMF_FindCert;
+ KMF_FindCertInCRL;
+ KMF_FindKey;
+ KMF_FreeAlgOID;
+ KMF_FreeBigint;
+ KMF_FreeCRLDistributionPoints;
+ KMF_FreeDN;
+ KMF_FreeData;
+ KMF_FreeEKU;
+ KMF_FreeEKUPolicy;
+ KMF_FreeExtension;
+ KMF_FreeKMFCert;
+ KMF_FreeKMFKey;
+ KMF_FreePolicyRecord;
+ KMF_FreeRawKey;
+ KMF_FreeRawSymKey;
+ KMF_FreeSPKI;
+ KMF_FreeSignedCSR;
+ KMF_FreeSignedCert;
+ KMF_FreeString;
+ KMF_FreeTBSCSR;
+ KMF_FreeTBSCert;
+ KMF_GetCertAuthInfoAccessExt;
+ KMF_GetCertBasicConstraintExt;
+ KMF_GetCertCriticalExtensions;
+ KMF_GetCertCRLDistributionPointsExt;
+ KMF_GetCertEKU;
+ KMF_GetCertEmailString;
+ KMF_GetCertEndDateString;
+ KMF_GetCertExtensionData;
+ KMF_GetCertExtensionString;
+ KMF_GetCertIDData;
+ KMF_GetCertIDString;
+ KMF_GetCertIssuerNameString;
+ KMF_GetCertKeyUsageExt;
+ KMF_GetCertNonCriticalExtensions;
+ KMF_GetCertPoliciesExt;
+ KMF_GetCertPubKeyAlgString;
+ KMF_GetCertPubKeyDataString;
+ KMF_GetCertSerialNumberString;
+ KMF_GetCertSignatureAlgString;
+ KMF_GetCertStartDateString;
+ KMF_GetCertSubjectNameString;
+ KMF_GetCertValidity;
+ KMF_GetCertVersionString;
+ KMF_GetEncodedOCSPResponse;
+ KMF_GetFileFormat;
+ KMF_GetKMFErrorString;
+ KMF_GetOCSPForCert;
+ KMF_GetOCSPStatusForCert;
+ KMF_GetPluginErrorString;
+ KMF_GetPolicy;
+ KMF_GetSymKeyValue;
+ KMF_HexString2Bytes;
+ KMF_ImportCRL;
+ KMF_ImportCert;
+ KMF_ImportPK12;
+ KMF_Initialize;
+ KMF_IsCRLFile;
+ KMF_IsCertFile;
+ KMF_ListCRL;
+ KMF_OID2EKUString;
+ KMF_OID2String;
+ KMF_PK11TokenLookup;
+ KMF_Pem2Der;
+ KMF_ReadInputFile;
+ KMF_SelectToken;
+ KMF_SetCSRExtension;
+ KMF_SetCSRKeyUsage;
+ KMF_SetCSRPubKey;
+ KMF_SetCSRSignatureAlgorithm;
+ KMF_SetCSRSubjectAltName;
+ KMF_SetCSRSubjectName;
+ KMF_SetCSRVersion;
+ KMF_SetCertBasicConstraintExt;
+ KMF_SetCertExtension;
+ KMF_SetCertIssuerAltName;
+ KMF_SetCertIssuerName;
+ KMF_SetCertKeyUsage;
+ KMF_SetCertPubKey;
+ KMF_SetCertSerialNumber;
+ KMF_SetCertSignatureAlgorithm;
+ KMF_SetCertSubjectAltName;
+ KMF_SetCertSubjectName;
+ KMF_SetCertValidityTimes;
+ KMF_SetCertVersion;
+ KMF_SetPolicy;
+ KMF_SetTokenPin;
+ KMF_SignCSR;
+ KMF_SignCertRecord;
+ KMF_SignCertWithCert;
+ KMF_SignCertWithKey;
+ KMF_SignDataWithCert;
+ KMF_SignDataWithKey;
+ KMF_StoreCert;
+ KMF_StorePrivateKey;
+ KMF_String2OID;
+ KMF_StringToKeyUsage;
+ KMF_ValidateCert;
+ KMF_VerifyCRLFile;
+ KMF_VerifyCertWithCert;
+ KMF_VerifyCertWithKey;
+ KMF_VerifyDataWithCert;
+ KMF_VerifyDataWithKey;
+ KMF_VerifyPolicy;
+ KMFOID_AliasedEntryName;
+ KMFOID_AuthorityInfoAccess;
+ KMFOID_AuthorityKeyID;
+ KMFOID_AuthorityKeyIdentifier;
+ KMFOID_AuthorityRevocationList;
+ KMFOID_BasicConstraints;
+ KMFOID_BusinessCategory;
+ KMFOID_CACertificate;
+ KMFOID_CertificatePolicies;
+ KMFOID_CertificateRevocationList;
+ KMFOID_ChallengePassword;
+ KMFOID_CollectiveFacsimileTelephoneNumber;
+ KMFOID_CollectiveInternationalISDNNumber;
+ KMFOID_CollectiveOrganizationName;
+ KMFOID_CollectiveOrganizationalUnitName;
+ KMFOID_CollectivePhysicalDeliveryOfficeName;
+ KMFOID_CollectivePostOfficeBox;
+ KMFOID_CollectivePostalAddress;
+ KMFOID_CollectivePostalCode;
+ KMFOID_CollectiveStateProvinceName;
+ KMFOID_CollectiveStreetAddress;
+ KMFOID_CollectiveTelephoneNumber;
+ KMFOID_CollectiveTelexNumber;
+ KMFOID_CollectiveTelexTerminalIdentifier;
+ KMFOID_CommonName;
+ KMFOID_ContentType;
+ KMFOID_CounterSignature;
+ KMFOID_CountryName;
+ KMFOID_CrlDistributionPoints;
+ KMFOID_CrlNumber;
+ KMFOID_CrlReason;
+ KMFOID_CrossCertificatePair;
+ KMFOID_DNQualifier;
+ KMFOID_DeltaCrlIndicator;
+ KMFOID_Description;
+ KMFOID_DestinationIndicator;
+ KMFOID_DistinguishedName;
+ KMFOID_EmailAddress;
+ KMFOID_EnhancedSearchGuide;
+ KMFOID_ExtendedCertificateAttributes;
+ KMFOID_ExtendedKeyUsage;
+ KMFOID_ExtensionRequest;
+ KMFOID_FacsimileTelephoneNumber;
+ KMFOID_GenerationQualifier;
+ KMFOID_GivenName;
+ KMFOID_HoldInstructionCode;
+ KMFOID_HouseIdentifier;
+ KMFOID_Initials;
+ KMFOID_InternationalISDNNumber;
+ KMFOID_InvalidityDate;
+ KMFOID_IssuerAltName;
+ KMFOID_IssuingDistributionPoints;
+ KMFOID_KeyUsage;
+ KMFOID_KeyUsageRestriction;
+ KMFOID_KnowledgeInformation;
+ KMFOID_LocalityName;
+ KMFOID_Member;
+ KMFOID_MessageDigest;
+ KMFOID_Name;
+ KMFOID_NameConstraints;
+ KMFOID_ObjectClass;
+ KMFOID_OrganizationName;
+ KMFOID_OrganizationalUnitName;
+ KMFOID_Owner;
+ KMFOID_PKIX_KP_ClientAuth;
+ KMFOID_PKIX_KP_CodeSigning;
+ KMFOID_PKIX_KP_EmailProtection;
+ KMFOID_PKIX_KP_IPSecEndSystem;
+ KMFOID_PKIX_KP_IPSecTunnel;
+ KMFOID_PKIX_KP_IPSecUser;
+ KMFOID_PKIX_KP_OCSPSigning;
+ KMFOID_PKIX_KP_ServerAuth;
+ KMFOID_PKIX_KP_TimeStamping;
+ KMFOID_PKIX_PQ_CPSuri;
+ KMFOID_PKIX_PQ_Unotice;
+ KMFOID_PhysicalDeliveryOfficeName;
+ KMFOID_PkixAdCaIssuers;
+ KMFOID_PkixAdOcsp;
+ KMFOID_PolicyConstraints;
+ KMFOID_PolicyMappings;
+ KMFOID_PostOfficeBox;
+ KMFOID_PostalAddress;
+ KMFOID_PostalCode;
+ KMFOID_PreferredDeliveryMethod;
+ KMFOID_PresentationAddress;
+ KMFOID_PrivateKeyUsagePeriod;
+ KMFOID_ProtocolInformation;
+ KMFOID_RFC822mailbox;
+ KMFOID_RegisteredAddress;
+ KMFOID_RoleOccupant;
+ KMFOID_SearchGuide;
+ KMFOID_SeeAlso;
+ KMFOID_SerialNumber;
+ KMFOID_SigningTime;
+ KMFOID_StateProvinceName;
+ KMFOID_StreetAddress;
+ KMFOID_SubjectAltName;
+ KMFOID_SubjectDirectoryAttributes;
+ KMFOID_SubjectKeyIdentifier;
+ KMFOID_SupportedApplicationContext;
+ KMFOID_Surname;
+ KMFOID_TelephoneNumber;
+ KMFOID_TelexNumber;
+ KMFOID_TelexTerminalIdentifier;
+ KMFOID_Title;
+ KMFOID_UniqueIdentifier;
+ KMFOID_UniqueMember;
+ KMFOID_UnstructuredAddress;
+ KMFOID_UnstructuredName;
+ KMFOID_UserCertificate;
+ KMFOID_UserPassword;
+ KMFOID_VerisignCertificatePolicy;
+ KMFOID_X_121Address;
+ KMFOID_domainComponent;
+ KMFOID_userid;
+ PKCS_GetDefaultSignatureMode;
+ PKCS_GetAlgorithmMap;
+ X509_AlgIdToAlgorithmOid;
+ X509_AlgorithmOidToAlgId;
+ kmf_ekuname2oid;
+ kmf_string2oid;
+ ku2str;
+ parsePolicyElement;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libkmf/libkmf/common/pem_encode.c b/usr/src/lib/libkmf/libkmf/common/pem_encode.c
new file mode 100644
index 0000000000..cc19a852f5
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/pem_encode.c
@@ -0,0 +1,628 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* pem_encode.c - PEM encoding routines */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <kmfapi.h>
+#include <pem_encode.h>
+
+static unsigned char data_bin2ascii[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+abcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static unsigned char data_ascii2bin[128] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
+ 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
+ 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
+ 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+};
+
+#define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f])
+#define conv_ascii2bin(a) (data_ascii2bin[(a)&0x7f])
+
+
+void
+PEM_EncodeInit(PEM_ENCODE_CTX *ctx)
+{
+ ctx->length = 48;
+ ctx->num = 0;
+ ctx->line_num = 0;
+}
+
+int
+PEM_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen)
+{
+ int i, ret = 0;
+ unsigned long l;
+
+ for (i = dlen; i > 0; i -= 3) {
+ if (i >= 3) {
+ l = (((unsigned long)f[0])<<16L)|
+ (((unsigned long)f[1])<< 8L)|f[2];
+ *(t++) = conv_bin2ascii(l>>18L);
+ *(t++) = conv_bin2ascii(l>>12L);
+ *(t++) = conv_bin2ascii(l>> 6L);
+ *(t++) = conv_bin2ascii(l);
+ } else {
+ l = ((unsigned long)f[0])<<16L;
+ if (i == 2)
+ l |= ((unsigned long)f[1]<<8L);
+
+ *(t++) = conv_bin2ascii(l>>18L);
+ *(t++) = conv_bin2ascii(l>>12L);
+ *(t++) = (i == 1)?'=':conv_bin2ascii(l>> 6L);
+ *(t++) = '=';
+ }
+ ret += 4;
+ f += 3;
+ }
+
+ *t = '\0';
+ return (ret);
+}
+
+void
+PEM_EncodeUpdate(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl,
+ unsigned char *in, int inl)
+{
+ int i, j;
+ unsigned int total = 0;
+
+ *outl = 0;
+ if (inl == 0)
+ return;
+ if ((ctx->num+inl) < ctx->length) {
+ (void) memcpy(&(ctx->enc_data[ctx->num]), in, inl);
+ ctx->num += inl;
+ return;
+ }
+ if (ctx->num != 0) {
+ i = ctx->length-ctx->num;
+ (void) memcpy(&(ctx->enc_data[ctx->num]), in, i);
+ in += i;
+ inl -= i;
+ j = PEM_EncodeBlock(out, ctx->enc_data, ctx->length);
+ ctx->num = 0;
+ out += j;
+ *(out++) = '\n';
+ *out = '\0';
+ total = j+1;
+ }
+
+ while (inl >= ctx->length) {
+ j = PEM_EncodeBlock(out, in, ctx->length);
+ in += ctx->length;
+ inl -= ctx->length;
+ out += j;
+ *(out++) = '\n';
+ *out = '\0';
+ total += j+1;
+ }
+
+ if (inl != 0)
+ (void) memcpy(&(ctx->enc_data[0]), in, inl);
+ ctx->num = inl;
+ *outl = total;
+}
+
+void
+PEM_EncodeFinal(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl)
+{
+ unsigned int ret = 0;
+
+ if (ctx->num != 0) {
+ ret = PEM_EncodeBlock(out, ctx->enc_data, ctx->num);
+ out[ret++] = '\n';
+ out[ret] = '\0';
+ ctx->num = 0;
+ }
+ *outl = ret;
+}
+
+KMF_RETURN
+Der2Pem(KMF_OBJECT_TYPE type, unsigned char *data,
+ int len, unsigned char **out, int *outlen)
+{
+
+
+ int nlen, n, i, j, outl;
+ unsigned char *buf = NULL, *p = NULL;
+ PEM_ENCODE_CTX ctx;
+ char *name = NULL;
+
+ if (data == NULL || len == 0 || out == NULL || outlen == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (type == KMF_CERT)
+ name = PEM_STRING_X509;
+ else if (type == KMF_CSR)
+ name = PEM_STRING_X509_REQ;
+ else if (type == KMF_CRL)
+ name = PEM_STRING_X509_CRL;
+ else
+ return (KMF_ERR_BAD_OBJECT_TYPE);
+
+
+ PEM_EncodeInit(&ctx);
+ nlen = strlen(name);
+
+ buf = malloc(PEM_BUFSIZE*8);
+ if (buf == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ p = buf;
+ (void) memcpy(p, "-----BEGIN ", 11);
+ p += 11;
+ (void) memcpy(p, name, nlen);
+ p += nlen;
+ (void) memcpy(p, "-----\n", 6);
+ p += 6;
+
+ i = j = 0;
+ while (len > 0) {
+ n = (int)((len > (PEM_BUFSIZE*5))?(PEM_BUFSIZE*5):len);
+ PEM_EncodeUpdate(&ctx, p, &outl, &(data[j]), n);
+ i += outl;
+ len -= n;
+ j += n;
+ p += outl;
+ }
+
+ PEM_EncodeFinal(&ctx, p, &outl);
+
+ if (outl > 0)
+ p += outl;
+
+ (void) memcpy(p, "-----END ", 9);
+ p += 9;
+ (void) memcpy(p, name, nlen);
+ p += nlen;
+ (void) memcpy(p, "-----\n", 6);
+ p += 6;
+
+ *out = buf;
+ *outlen = i+outl+nlen*2+11+6+9+6;
+
+ return (KMF_OK);
+
+}
+
+int
+PEM_DecodeBlock(unsigned char *t, const unsigned char *f, int n)
+{
+ int i, ret = 0, a, b, c, d;
+ unsigned long l;
+
+ /* trim white space from the start of the line. */
+ while ((conv_ascii2bin(*f) == B64_WS) && (n > 0)) {
+ f++;
+ n--;
+ }
+
+ /*
+ * strip off stuff at the end of the line
+ * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF
+ */
+ while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n-1]))))
+ n--;
+
+ if (n%4 != 0) {
+ return (-1);
+ }
+
+ for (i = 0; i < n; i += 4) {
+ a = conv_ascii2bin(*(f++));
+ b = conv_ascii2bin(*(f++));
+ c = conv_ascii2bin(*(f++));
+ d = conv_ascii2bin(*(f++));
+ if ((a & 0x80) || (b & 0x80) ||
+ (c & 0x80) || (d & 0x80))
+ return (-1);
+ l = ((((unsigned long)a)<<18L)|
+ (((unsigned long)b)<<12L)|
+ (((unsigned long)c)<< 6L)|
+ (((unsigned long)d)));
+ *(t++) = (unsigned char)(l>>16L)&0xff;
+ *(t++) = (unsigned char)(l>> 8L)&0xff;
+ *(t++) = (unsigned char)(l)&0xff;
+ ret += 3;
+ }
+ return (ret);
+}
+
+void
+PEM_DecodeInit(PEM_ENCODE_CTX *ctx)
+{
+ ctx->length = 30;
+ ctx->num = 0;
+ ctx->line_num = 0;
+ ctx->expect_nl = 0;
+}
+
+/*
+ * -1 for error
+ * 0 for last line
+ * 1 for full line
+ */
+int
+PEM_DecodeUpdate(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl,
+ unsigned char *in, int inl)
+{
+ int seof = -1, eof = 0, rv = -1, ret = 0;
+ int i, v, tmp, n, ln, exp_nl;
+ unsigned char *d;
+
+ n = ctx->num;
+ d = ctx->enc_data;
+ ln = ctx->line_num;
+ exp_nl = ctx->expect_nl;
+
+ /* last line of input. */
+ if ((inl == 0) || ((n == 0) && (conv_ascii2bin(in[0]) == B64_EOF))) {
+ rv = 0;
+ goto end;
+ }
+
+ /* We parse the input data */
+ for (i = 0; i < inl; i++) {
+ /* If the current line is > 80 characters, scream alot */
+ if (ln >= 80) {
+ rv = -1;
+ goto end;
+ }
+
+ /* Get char and put it into the buffer */
+ tmp = *(in++);
+ v = conv_ascii2bin(tmp);
+ /* only save the good data :-) */
+ if (!B64_NOT_BASE64(v)) {
+ d[n++] = tmp;
+ ln++;
+ } else if (v == B64_ERROR) {
+ rv = -1;
+ goto end;
+ }
+
+ /*
+ * have we seen a '=' which is 'definitly' the last
+ * input line. seof will point to the character that
+ * holds it. and eof will hold how many characters to
+ * chop off.
+ */
+ if (tmp == '=') {
+ if (seof == -1) seof = n;
+ eof++;
+ }
+
+ if (v == B64_CR) {
+ ln = 0;
+ if (exp_nl)
+ continue;
+ }
+
+ /* eoln */
+ if (v == B64_EOLN) {
+ ln = 0;
+ if (exp_nl) {
+ exp_nl = 0;
+ continue;
+ }
+ }
+ exp_nl = 0;
+
+ /*
+ * If we are at the end of input and it looks like a
+ * line, process it.
+ */
+ if (((i+1) == inl) && (((n&3) == 0) || eof)) {
+ v = B64_EOF;
+ /*
+ * In case things were given us in really small
+ * records (so two '=' were given in separate
+ * updates), eof may contain the incorrect number
+ * of ending bytes to skip, so let's redo the count
+ */
+ eof = 0;
+ if (d[n-1] == '=') eof++;
+ if (d[n-2] == '=') eof++;
+ /* There will never be more than two '=' */
+ }
+
+ if ((v == B64_EOF) || (n >= 64)) {
+ /*
+ * This is needed to work correctly on 64 byte input
+ * lines. We process the line and then need to
+ * accept the '\n'
+ */
+ if ((v != B64_EOF) && (n >= 64))
+ exp_nl = 1;
+ if (n > 0) {
+ v = PEM_DecodeBlock(out, d, n);
+ if (v < 0) {
+ rv = 0;
+ goto end;
+ }
+ n = 0;
+ ret += (v-eof);
+ } else {
+ eof = 1;
+ v = 0;
+ }
+
+ /*
+ * This is the case where we have had a short
+ * but valid input line
+ */
+ if ((v < ctx->length) && eof) {
+ rv = 0;
+ goto end;
+ } else
+ ctx->length = v;
+
+ if (seof >= 0) {
+ rv = 0;
+ goto end;
+ }
+ out += v;
+ }
+ }
+ rv = 1;
+end:
+ *outl = ret;
+ ctx->num = n;
+ ctx->line_num = ln;
+ ctx->expect_nl = exp_nl;
+ return (rv);
+}
+
+int
+PEM_DecodeFinal(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl)
+{
+ int i;
+
+ *outl = 0;
+ if (ctx->num != 0) {
+ i = PEM_DecodeBlock(out, ctx->enc_data, ctx->num);
+ if (i < 0)
+ return (-1);
+ ctx->num = 0;
+ *outl = i;
+ return (1);
+ } else
+ return (1);
+}
+
+static int
+get_line(unsigned char *in, char *buf)
+{
+
+ int i = 0;
+ int len = 0;
+
+ while ((in[i] != '\n')) {
+ buf[i] = in[i];
+ i++;
+ len++;
+ }
+
+ return (len);
+}
+
+KMF_RETURN
+Pem2Der(unsigned char *in, int inlen,
+ unsigned char **out, int *outlen)
+{
+ int kmf_rv = 0;
+ PEM_ENCODE_CTX ctx;
+ int i, k, bl = 0;
+ char buf[2048];
+ char *nameB;
+ unsigned char *dataB;
+ int total = 0;
+
+ if (in == NULL || inlen == 0 || out == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(buf, 0, sizeof (buf));
+
+ for (;;) {
+ /*
+ * get a line (ended at '\n'), which returns
+ * number of bytes in the line
+ */
+ i = get_line(in, buf);
+ if (i <= 0) {
+ kmf_rv = KMF_ERR_ENCODING;
+ goto err;
+ }
+
+ while ((i >= 0) && (buf[i] <= ' ')) i--;
+ buf[++i] = '\n';
+ buf[++i] = '\0';
+ total += i;
+
+ if (strncmp(buf, "-----BEGIN ", 11) == 0) {
+ i = strlen(&(buf[11]));
+ if (strncmp(&(buf[11+i-6]), "-----\n", 6) != 0) {
+ continue;
+ }
+
+ if ((nameB = malloc(i+9)) == NULL) {
+ kmf_rv = KMF_ERR_MEMORY;
+ goto err;
+ }
+
+ (void) memcpy(nameB, &(buf[11]), i-6);
+ nameB[i-6] = '\0';
+ break;
+ }
+ }
+
+ bl = 0;
+ if ((dataB = malloc(2048)) == NULL) {
+ kmf_rv = KMF_ERR_MEMORY;
+ goto err;
+ }
+
+ dataB[0] = '\0';
+
+ for (;;) {
+ (void) memset(buf, 0, 1024);
+ i = get_line(in+total, buf);
+
+ if (i <= 0) break;
+
+ while ((i >= 0) && (buf[i] <= ' '))
+ i--;
+
+ buf[++i] = '\n';
+ buf[++i] = '\0';
+ total += i;
+
+ if (buf[0] == '\n') break;
+ if ((dataB = realloc(dataB, bl+i+9)) == NULL) {
+ kmf_rv = KMF_ERR_MEMORY;
+ goto err;
+ }
+
+ if (strncmp(buf, "-----END ", 9) == 0) {
+ break;
+ }
+
+ (void) memcpy(&(dataB[bl]), buf, i);
+ dataB[bl+i] = '\0';
+ bl += i;
+ }
+
+ i = strlen(nameB);
+ if ((strncmp(buf, "-----END ", 9) != 0) ||
+ (strncmp(nameB, &(buf[9]), i) != 0) ||
+ (strncmp(&(buf[9+i]), "-----", 5) != 0)) {
+ kmf_rv = KMF_ERR_ENCODING;
+ goto err;
+ }
+
+ PEM_DecodeInit(&ctx);
+ i = PEM_DecodeUpdate(&ctx,
+ (unsigned char *)dataB, &bl, (unsigned char *)dataB, bl);
+
+ if (i < 0) {
+ kmf_rv = KMF_ERR_ENCODING;
+ goto err;
+ }
+
+ i = PEM_DecodeFinal(&ctx, (unsigned char *)&(dataB[bl]), &k);
+ if (i < 0) {
+ kmf_rv = KMF_ERR_ENCODING;
+ goto err;
+ }
+ bl += k;
+
+ if (bl == 0) goto err;
+ *out = (unsigned char *)dataB;
+ *outlen = bl;
+
+err:
+ free(nameB);
+ if (kmf_rv != KMF_OK)
+ free(dataB);
+
+ return (kmf_rv);
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/pk11keys.c b/usr/src/lib/libkmf/libkmf/common/pk11keys.c
new file mode 100644
index 0000000000..adbcf64224
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/pk11keys.c
@@ -0,0 +1,735 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * File: KEYS.C
+ *
+ * Copyright (c) 1995-2000 Intel Corporation. All rights reserved.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <kmfapiP.h>
+#include <security/cryptoki.h>
+
+#include <algorithm.h>
+#include <ber_der.h>
+
+#define MAX_PUBLIC_KEY_TEMPLATES (20)
+#define MAX_PRIVATE_KEY_TEMPLATES (24)
+#define MAX_SECRET_KEY_TEMPLATES (24)
+
+static KMF_RETURN
+create_pk11_session(CK_SESSION_HANDLE *sessionp, CK_MECHANISM_TYPE wanted_mech,
+ CK_FLAGS wanted_flags)
+{
+ CK_RV rv;
+ KMF_RETURN kmf_rv = KMF_OK;
+ CK_SLOT_ID_PTR pSlotList;
+ CK_ULONG pulCount;
+ CK_MECHANISM_INFO info;
+ int i;
+
+ if (!is_pk11_ready()) {
+ rv = C_Initialize(NULL);
+ if ((rv != CKR_OK) &&
+ (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
+ kmf_rv = KMF_ERR_UNINITIALIZED;
+ goto out;
+ }
+ }
+
+ rv = C_GetSlotList(0, NULL, &pulCount);
+ if (rv != CKR_OK) {
+ kmf_rv = KMF_ERR_UNINITIALIZED;
+ goto out;
+ }
+
+ pSlotList = (CK_SLOT_ID_PTR) malloc(pulCount * sizeof (CK_SLOT_ID));
+ if (pSlotList == NULL) {
+ kmf_rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ rv = C_GetSlotList(0, pSlotList, &pulCount);
+ if (rv != CKR_OK) {
+ kmf_rv = KMF_ERR_UNINITIALIZED;
+ goto out;
+ }
+
+ for (i = 0; i < pulCount; i++) {
+ rv = C_GetMechanismInfo(pSlotList[i], wanted_mech, &info);
+ if (rv == CKR_OK && (info.flags & wanted_flags))
+ break;
+ }
+ if (i < pulCount) {
+ rv = C_OpenSession(pSlotList[i], CKF_SERIAL_SESSION,
+ NULL, NULL, sessionp);
+
+ if (rv != CKR_OK) {
+ kmf_rv = KMF_ERR_UNINITIALIZED;
+ }
+ } else {
+ kmf_rv = KMF_ERR_UNINITIALIZED;
+ }
+
+out:
+ if (pSlotList != NULL)
+ free(pSlotList);
+ return (kmf_rv);
+
+}
+
+/*
+ * Name: PKCS_AddTemplate
+ *
+ * Description:
+ * Adds a CK_ATTRIBUTE value to an existing array of CK_ATTRIBUTES. Will
+ * not expand the array beyond the maximum specified size.
+ *
+ * Returns:
+ * TRUE - Attribute value succesfully added.
+ * FALSE - Maximum array size would be exceded.
+ */
+static int
+PKCS_AddTemplate(CK_ATTRIBUTE *pTemplate,
+ CK_ULONG *ckNumTemplates,
+ CK_ULONG ckMaxTemplates,
+ CK_ATTRIBUTE_TYPE ckAttribCode,
+ CK_BYTE * pckBuffer,
+ CK_ULONG ckBufferLen)
+{
+ if (*ckNumTemplates >= ckMaxTemplates) {
+ return (FALSE);
+ }
+
+ pTemplate[*ckNumTemplates].type = ckAttribCode;
+ pTemplate[*ckNumTemplates].pValue = pckBuffer;
+ pTemplate[*ckNumTemplates].ulValueLen = ckBufferLen;
+ (*ckNumTemplates)++;
+
+ return (TRUE);
+}
+
+/*
+ * Convert an SPKI data record to PKCS#11
+ * public key object.
+ */
+static KMF_RETURN
+PKCS_CreatePublicKey(
+ const KMF_X509_SPKI *pKey,
+ CK_SESSION_HANDLE ckSession,
+ CK_OBJECT_HANDLE *pckPublicKey)
+{
+ KMF_RETURN mrReturn = KMF_OK;
+ CK_RV ckRv;
+
+ CK_ATTRIBUTE ckTemplate[MAX_PUBLIC_KEY_TEMPLATES];
+ CK_ULONG ckNumTemplates = 0;
+
+ /* Common object attributes */
+ CK_OBJECT_CLASS ckObjClass = CKO_PUBLIC_KEY;
+ CK_BBOOL ckToken = 0;
+ CK_BBOOL ckPrivate = 0;
+
+ /* Common key attributes */
+ CK_KEY_TYPE ckKeyType;
+ CK_BBOOL ckDerive = CK_FALSE;
+
+ /* Common public key attributes */
+ CK_BBOOL ckEncrypt = 1;
+ CK_BBOOL ckVerify = 1;
+
+ CK_BBOOL ckVerifyRecover = CK_FALSE;
+ CK_BBOOL ckWrap = CK_FALSE;
+
+ /* Key part array */
+ KMF_DATA KeyParts[KMF_MAX_PUBLIC_KEY_PARTS];
+ uint32_t i, uNumKeyParts = KMF_MAX_PUBLIC_KEY_PARTS;
+ KMF_ALGORITHM_INDEX AlgorithmId;
+
+ /* Parse the keyblob */
+ (void) memset(KeyParts, 0, sizeof (KeyParts));
+
+ AlgorithmId = X509_AlgorithmOidToAlgId((KMF_OID *)
+ &pKey->algorithm.algorithm);
+
+ mrReturn = ExtractSPKIData(pKey, AlgorithmId, KeyParts, &uNumKeyParts);
+
+ if (mrReturn != KMF_OK)
+ return (mrReturn);
+
+ /* Fill in the common object attributes */
+ if (!PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_CLASS,
+ (CK_BYTE *)&ckObjClass,
+ sizeof (ckObjClass)) ||
+ !PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_TOKEN,
+ (CK_BYTE *)&ckToken,
+ sizeof (ckToken)) ||
+ !PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_PRIVATE,
+ (CK_BYTE *)&ckPrivate,
+ sizeof (ckPrivate))) {
+ mrReturn = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+
+ /* Fill in the common key attributes */
+ if (!PKCS_ConvertAlgorithmId2PKCSKeyType(AlgorithmId,
+ &ckKeyType)) {
+ goto cleanup;
+ }
+ if (!PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_KEY_TYPE,
+ (CK_BYTE *)&ckKeyType,
+ sizeof (ckKeyType)) ||
+ !PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_DERIVE,
+ (CK_BYTE *)&ckDerive,
+ sizeof (ckDerive))) {
+ mrReturn = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+
+ /* Add common public key attributes */
+ if (!PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_ENCRYPT,
+ (CK_BYTE *)&ckEncrypt,
+ sizeof (ckEncrypt)) ||
+ !PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_VERIFY,
+ (CK_BYTE *)&ckVerify,
+ sizeof (ckVerify)) ||
+ !PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_VERIFY_RECOVER,
+ (CK_BYTE *)&ckVerifyRecover,
+ sizeof (ckVerifyRecover)) ||
+ !PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_WRAP,
+ (CK_BYTE *)&ckWrap,
+ sizeof (ckWrap))) {
+ mrReturn = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+
+ /* Add algorithm specific attributes */
+ switch (ckKeyType) {
+ case CKK_RSA:
+ if (!PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_MODULUS,
+ (CK_BYTE *)KeyParts[KMF_RSA_MODULUS].Data,
+ (CK_ULONG)KeyParts[KMF_RSA_MODULUS].Length) ||
+ !PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_PUBLIC_EXPONENT,
+ (CK_BYTE *)KeyParts[KMF_RSA_PUBLIC_EXPONENT].Data,
+ (CK_ULONG)KeyParts[KMF_RSA_PUBLIC_EXPONENT].Length)) {
+ mrReturn = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+ break;
+ case CKK_DSA:
+ if (!PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_PRIME,
+ (CK_BYTE *)KeyParts[KMF_DSA_PRIME].Data,
+ (CK_ULONG)KeyParts[KMF_DSA_PRIME].Length) ||
+ !PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_SUBPRIME,
+ (CK_BYTE *)KeyParts[KMF_DSA_SUB_PRIME].Data,
+ (CK_ULONG)KeyParts[KMF_DSA_SUB_PRIME].Length) ||
+ !PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_BASE,
+ (CK_BYTE *)KeyParts[KMF_DSA_BASE].Data,
+ (CK_ULONG)KeyParts[KMF_DSA_BASE].Length) ||
+ !PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ MAX_PUBLIC_KEY_TEMPLATES,
+ CKA_VALUE,
+ (CK_BYTE *)KeyParts[KMF_DSA_PUBLIC_VALUE].Data,
+ (CK_ULONG)KeyParts[KMF_DSA_PUBLIC_VALUE].Length)) {
+ mrReturn = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+ break;
+ default:
+ mrReturn = KMF_ERR_BAD_PARAMETER;
+ }
+
+ if (mrReturn == KMF_OK) {
+ /* Instantiate the object */
+ ckRv = C_CreateObject(ckSession,
+ ckTemplate,
+ ckNumTemplates,
+ pckPublicKey);
+ if (ckRv != CKR_OK)
+ mrReturn = KMF_ERR_INTERNAL;
+ }
+
+cleanup:
+ for (i = 0; i < uNumKeyParts; i++) {
+ KMF_FreeData(&KeyParts[i]);
+ }
+
+ return (mrReturn);
+}
+
+/*
+ * PKCS_AcquirePublicKeyHandle
+ *
+ * Given an assymetric key keyblob, attempts to find the appropriate
+ * public key.
+ *
+ * Methods of finding the public key:
+ * - Public Key with data present:
+ * Parses the key and creates a temporary session object.
+ * - Public Key with handle:
+ * The handle is type converted and returned. Validity of the handle is
+ * not checked.
+ * - Public Key with label:
+ * Attempts to find a public key with the corresponding label.
+ */
+static KMF_RETURN
+PKCS_AcquirePublicKeyHandle(CK_SESSION_HANDLE ckSession,
+ const KMF_X509_SPKI *pKey,
+ CK_KEY_TYPE ckRequestedKeyType,
+ CK_OBJECT_HANDLE *pckKeyHandle,
+ KMF_BOOL *pbTemporary)
+{
+ KMF_RETURN mrReturn = KMF_OK;
+
+
+ /* Key searching variables */
+ CK_OBJECT_HANDLE ckKeyHandle;
+ CK_OBJECT_CLASS ckObjClass;
+ CK_KEY_TYPE ckKeyType;
+ CK_ATTRIBUTE ckTemplate[3];
+ CK_ULONG ckNumTemplates;
+ static const CK_ULONG ckMaxTemplates = (sizeof (ckTemplate) /
+ sizeof (CK_ATTRIBUTE));
+ CK_RV ckRv;
+
+ /* Extract the data from the SPKI into individual fields */
+ mrReturn = PKCS_CreatePublicKey(pKey, ckSession, &ckKeyHandle);
+ if (mrReturn != KMF_OK)
+ return (mrReturn);
+
+ *pbTemporary = KMF_TRUE;
+
+ /* Fetch the key class and algorithm from the object */
+ ckNumTemplates = 0;
+ if (!PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ ckMaxTemplates,
+ CKA_CLASS,
+ (CK_BYTE *)&ckObjClass,
+ sizeof (ckObjClass)) ||
+ !PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ ckMaxTemplates,
+ CKA_KEY_TYPE,
+ (CK_BYTE *)&ckKeyType,
+ sizeof (ckKeyType))) {
+ return (KMF_ERR_INTERNAL);
+ }
+ ckRv = C_GetAttributeValue(ckSession,
+ ckKeyHandle,
+ ckTemplate,
+ ckNumTemplates);
+ if (ckRv != CKR_OK) {
+ return (ckRv);
+ }
+
+ /* Make sure the results match the expected values */
+ if ((ckKeyType != ckRequestedKeyType) ||
+ (ckObjClass != CKO_PUBLIC_KEY)) {
+ if (*pbTemporary == KMF_TRUE) {
+ (void) C_DestroyObject(ckSession, ckKeyHandle);
+ }
+
+ return (KMF_ERR_BAD_KEY_FORMAT);
+ }
+
+ /* Set the return values */
+ *pckKeyHandle = ckKeyHandle;
+
+ return (KMF_OK);
+}
+
+KMF_SIGNATURE_MODE
+PKCS_GetDefaultSignatureMode(KMF_ALGORITHM_INDEX AlgId)
+{
+ KMF_SIGNATURE_MODE AlgMode;
+
+ switch (AlgId) {
+ case KMF_ALGID_RSA:
+ case KMF_ALGID_MD5WithRSA:
+ case KMF_ALGID_MD2WithRSA:
+ case KMF_ALGID_SHA1WithRSA:
+ AlgMode = KMF_ALGMODE_PKCS1_EMSA_V15;
+ break;
+ default:
+ AlgMode = KMF_ALGMODE_NONE;
+ break;
+ }
+
+ return (AlgMode);
+}
+
+KMF_RETURN
+PKCS_VerifyData(KMF_HANDLE_T kmfh,
+ KMF_ALGORITHM_INDEX AlgorithmId,
+ KMF_X509_SPKI *keyp,
+ KMF_DATA *data,
+ KMF_DATA *signed_data)
+{
+ KMF_RETURN rv = KMF_OK;
+ PKCS_ALGORITHM_MAP *pAlgMap = NULL;
+ CK_RV ckRv;
+ CK_MECHANISM ckMechanism;
+ CK_OBJECT_HANDLE ckKeyHandle;
+ KMF_BOOL bTempKey;
+ CK_SESSION_HANDLE ckSession = 0;
+
+ if (AlgorithmId == KMF_ALGID_NONE)
+ return (KMF_ERR_BAD_ALGORITHM);
+
+ pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE,
+ AlgorithmId, PKCS_GetDefaultSignatureMode(AlgorithmId));
+
+ if (!pAlgMap)
+ return (KMF_ERR_BAD_ALGORITHM);
+
+ rv = create_pk11_session(&ckSession, pAlgMap->pkcs_mechanism,
+ CKF_VERIFY);
+
+ if (rv != KMF_OK)
+ return (rv);
+
+ /* Fetch the verifying key */
+ rv = PKCS_AcquirePublicKeyHandle(ckSession, keyp,
+ pAlgMap->key_type, &ckKeyHandle, &bTempKey);
+
+ if (rv != KMF_OK) {
+ (void) C_CloseSession(ckSession);
+ return (rv);
+ }
+
+ ckMechanism.mechanism = pAlgMap->pkcs_mechanism;
+ ckMechanism.pParameter = NULL;
+ ckMechanism.ulParameterLen = 0;
+
+ ckRv = C_VerifyInit(ckSession, &ckMechanism, ckKeyHandle);
+ if (ckRv != CKR_OK) {
+ if (bTempKey)
+ (void) C_DestroyObject(ckSession, ckKeyHandle);
+ kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ kmfh->lasterr.errcode = ckRv;
+ (void) C_CloseSession(ckSession);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ ckRv = C_Verify(ckSession,
+ (CK_BYTE *)data->Data,
+ (CK_ULONG)data->Length,
+ (CK_BYTE *)signed_data->Data,
+ (CK_ULONG)signed_data->Length);
+
+ if (ckRv != CKR_OK) {
+ kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ kmfh->lasterr.errcode = ckRv;
+ rv = KMF_ERR_INTERNAL;
+ }
+ if (bTempKey)
+ (void) C_DestroyObject(ckSession, ckKeyHandle);
+
+ (void) C_CloseSession(ckSession);
+ return (rv);
+
+}
+
+KMF_RETURN
+PKCS_EncryptData(KMF_HANDLE_T kmfh,
+ KMF_ALGORITHM_INDEX AlgorithmId,
+ KMF_X509_SPKI *keyp,
+ KMF_DATA *plaintext,
+ KMF_DATA *ciphertext)
+{
+ KMF_RETURN rv = KMF_OK;
+ PKCS_ALGORITHM_MAP *pAlgMap = NULL;
+ CK_RV ckRv;
+ CK_MECHANISM ckMechanism;
+ CK_OBJECT_HANDLE ckKeyHandle;
+ KMF_BOOL bTempKey;
+ CK_SESSION_HANDLE ckSession = NULL;
+ CK_ULONG out_len = 0, in_len = 0, total_encrypted = 0;
+ uint8_t *in_data, *out_data;
+ int i, blocks, block_size;
+ CK_ATTRIBUTE ckTemplate[2];
+ CK_ULONG ckNumTemplates;
+ CK_ULONG ckMaxTemplates = (sizeof (ckTemplate) /
+ sizeof (CK_ATTRIBUTE));
+
+ pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE,
+ AlgorithmId, PKCS_GetDefaultSignatureMode(AlgorithmId));
+
+ if (!pAlgMap)
+ return (KMF_ERR_BAD_ALGORITHM);
+
+ rv = create_pk11_session(&ckSession, pAlgMap->pkcs_mechanism,
+ CKF_ENCRYPT);
+
+ if (rv != KMF_OK)
+ return (rv);
+
+ /* Get the public key used in encryption */
+ rv = PKCS_AcquirePublicKeyHandle(ckSession, keyp,
+ pAlgMap->key_type, &ckKeyHandle, &bTempKey);
+
+ if (rv != KMF_OK) {
+ (void) C_CloseSession(ckSession);
+ return (rv);
+ }
+
+ /* Get the modulus length */
+ ckNumTemplates = 0;
+ if (!PKCS_AddTemplate(ckTemplate,
+ &ckNumTemplates,
+ ckMaxTemplates,
+ CKA_MODULUS,
+ (CK_BYTE *)NULL,
+ sizeof (CK_ULONG))) {
+ if (bTempKey)
+ (void) C_DestroyObject(ckSession, ckKeyHandle);
+ (void) C_CloseSession(ckSession);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ ckRv = C_GetAttributeValue(ckSession,
+ ckKeyHandle,
+ ckTemplate,
+ ckNumTemplates);
+
+ if (ckRv != CKR_OK) {
+ if (bTempKey)
+ (void) C_DestroyObject(ckSession, ckKeyHandle);
+ kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ kmfh->lasterr.errcode = ckRv;
+ (void) C_CloseSession(ckSession);
+ return (KMF_ERR_INTERNAL);
+ }
+ out_len = ckTemplate[0].ulValueLen;
+
+ if (out_len > ciphertext->Length) {
+ if (bTempKey)
+ (void) C_DestroyObject(ckSession, ckKeyHandle);
+ (void) C_CloseSession(ckSession);
+ return (KMF_ERR_BUFFER_SIZE);
+ }
+
+ ckMechanism.mechanism = pAlgMap->pkcs_mechanism;
+ ckMechanism.pParameter = NULL_PTR;
+ ckMechanism.ulParameterLen = 0;
+
+ /* Compute the fixed input data length for single-part encryption */
+ block_size = out_len - 11;
+
+ in_data = plaintext->Data;
+ out_data = ciphertext->Data;
+
+ blocks = plaintext->Length/block_size;
+
+ for (i = 0; i < blocks; i++) {
+ ckRv = C_EncryptInit(ckSession, &ckMechanism, ckKeyHandle);
+ if (ckRv != CKR_OK) {
+ if (bTempKey)
+ (void) C_DestroyObject(ckSession, ckKeyHandle);
+ kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ kmfh->lasterr.errcode = ckRv;
+ (void) C_CloseSession(ckSession);
+ return (KMF_ERR_INTERNAL);
+ }
+ ckRv = C_Encrypt(ckSession, (CK_BYTE_PTR)in_data, block_size,
+ (CK_BYTE_PTR)out_data, &out_len);
+
+ if (ckRv != CKR_OK) {
+ if (bTempKey)
+ (void) C_DestroyObject(ckSession, ckKeyHandle);
+ kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ kmfh->lasterr.errcode = ckRv;
+ (void) C_CloseSession(ckSession);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ out_data += out_len;
+ total_encrypted += out_len;
+ in_data += block_size;
+ }
+
+ if (plaintext->Length % block_size) {
+ /* Encrypt the remaining data */
+ ckRv = C_EncryptInit(ckSession, &ckMechanism, ckKeyHandle);
+ if (ckRv != CKR_OK) {
+ if (bTempKey)
+ (void) C_DestroyObject(ckSession, ckKeyHandle);
+ kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ kmfh->lasterr.errcode = ckRv;
+ (void) C_CloseSession(ckSession);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ in_len = plaintext->Length % block_size;
+ ckRv = C_Encrypt(ckSession, (CK_BYTE_PTR)in_data, in_len,
+ (CK_BYTE_PTR)out_data, &out_len);
+
+ if (ckRv != CKR_OK) {
+ if (bTempKey)
+ (void) C_DestroyObject(ckSession, ckKeyHandle);
+ kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ kmfh->lasterr.errcode = ckRv;
+ (void) C_CloseSession(ckSession);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ out_data += out_len;
+ total_encrypted += out_len;
+ in_data += in_len;
+ }
+
+ ciphertext->Length = total_encrypted;
+
+ if (bTempKey)
+ (void) C_DestroyObject(ckSession, ckKeyHandle);
+
+ (void) C_CloseSession(ckSession);
+ return (rv);
+
+}
+
+CK_RV
+DigestData(CK_SESSION_HANDLE hSession,
+ KMF_DATA *IDInput, KMF_DATA *IDOutput)
+{
+ CK_RV rv = KMF_OK;
+ CK_MECHANISM mechanism = {CKM_SHA_1, NULL, 0};
+
+ rv = C_DigestInit(hSession, &mechanism);
+ if (rv != CKR_OK)
+ return (rv);
+
+ rv = C_Digest(hSession,
+ IDInput->Data, IDInput->Length,
+ IDOutput->Data, (CK_ULONG *)&IDOutput->Length);
+
+ return (rv);
+}
+
+KMF_RETURN
+GetIDFromSPKI(KMF_X509_SPKI *spki,
+ KMF_DATA *ID)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_DATA KeyParts[KMF_MAX_PUBLIC_KEY_PARTS];
+ uint32_t uNumKeyParts = KMF_MAX_PUBLIC_KEY_PARTS;
+ KMF_ALGORITHM_INDEX algId;
+ CK_SESSION_HANDLE hSession = NULL;
+ int i;
+
+ if (ID == NULL || spki == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ ID->Data = (uchar_t *)malloc(SHA1_HASH_LENGTH);
+ if (ID->Data == NULL)
+ return (KMF_ERR_MEMORY);
+
+ ID->Length = SHA1_HASH_LENGTH;
+
+ algId = X509_AlgorithmOidToAlgId(&spki->algorithm.algorithm);
+
+ rv = ExtractSPKIData(spki, algId, KeyParts, &uNumKeyParts);
+ if (rv != KMF_OK)
+ return (rv);
+
+ rv = create_pk11_session(&hSession, CKM_SHA_1, CKF_DIGEST);
+
+ if (rv != KMF_OK)
+ return (rv);
+
+ /* Check the KEY algorithm */
+ if (algId == KMF_ALGID_RSA) {
+ rv = DigestData(hSession,
+ &KeyParts[KMF_RSA_MODULUS],
+ ID);
+ } else if (algId == KMF_ALGID_DSA) {
+ rv = DigestData(hSession,
+ &KeyParts[KMF_DSA_PUBLIC_VALUE],
+ ID);
+ } else {
+ /* We only support RSA and DSA keys for now */
+ rv = KMF_ERR_BAD_ALGORITHM;
+ }
+
+
+ for (i = 0; i < uNumKeyParts; i++) {
+ if (KeyParts[i].Data != NULL)
+ free(KeyParts[i].Data);
+ }
+
+ if (rv != KMF_OK && ID->Data != NULL) {
+ free(ID->Data);
+ ID->Data = NULL;
+ ID->Length = 0;
+ }
+
+ (void) C_CloseSession(hSession);
+ return (rv);
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/pk11tokens.c b/usr/src/lib/libkmf/libkmf/common/pk11tokens.c
new file mode 100644
index 0000000000..f5e9c62c61
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/pk11tokens.c
@@ -0,0 +1,531 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <security/cryptoki.h>
+#include <kmfapi.h>
+#include <kmfapiP.h>
+#include <cryptoutil.h>
+
+/*
+ * memcmp_pad_max() is a specialized version of memcmp() which
+ * compares two pieces of data up to a maximum length. If the
+ * the two data match up the maximum length, they are considered
+ * matching. Trailing blanks do not cause the match to fail if
+ * one of the data is shorted.
+ *
+ * Examples of matches:
+ * "one" |
+ * "one " |
+ * ^maximum length
+ *
+ * "Number One | X" (X is beyond maximum length)
+ * "Number One " |
+ * ^maximum length
+ *
+ * Examples of mismatches:
+ * " one"
+ * "one"
+ *
+ * "Number One X|"
+ * "Number One |"
+ * ^maximum length
+ */
+static int
+memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz)
+{
+ uint_t len, extra_len;
+ char *marker;
+
+ /* No point in comparing anything beyond max_sz */
+ if (d1_len > max_sz)
+ d1_len = max_sz;
+ if (d2_len > max_sz)
+ d2_len = max_sz;
+
+ /* Find shorter of the two data. */
+ if (d1_len <= d2_len) {
+ len = d1_len;
+ extra_len = d2_len;
+ marker = d2;
+ } else { /* d1_len > d2_len */
+ len = d2_len;
+ extra_len = d1_len;
+ marker = d1;
+ }
+
+ /* Have a match in the shortest length of data? */
+ if (memcmp(d1, d2, len) != 0)
+ /* CONSTCOND */
+ return (1);
+
+ /* If the rest of longer data is nulls or blanks, call it a match. */
+ while (len < extra_len)
+ if (!isspace(marker[len++]))
+ /* CONSTCOND */
+ return (1);
+ return (0);
+}
+
+static KMF_RETURN
+kmf_get_token_slots(KMF_HANDLE *handle, CK_SLOT_ID_PTR *slot_list,
+ CK_ULONG *slot_count)
+{
+
+ KMF_RETURN kmf_rv = KMF_OK;
+ CK_RV ck_rv = CKR_OK;
+ CK_ULONG tmp_count = 0;
+ CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
+
+ ck_rv = C_GetSlotList(1, NULL_PTR, &tmp_count);
+ if (ck_rv != CKR_OK) {
+ if (handle != NULL) {
+ handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ handle->lasterr.errcode = ck_rv;
+ }
+ return (KMF_ERR_INTERNAL);
+ }
+
+ if (tmp_count == 0) {
+ *slot_list = NULL_PTR;
+ *slot_count = 0;
+ return (KMF_OK);
+ }
+
+ /* Allocate initial space for the slot list. */
+ if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
+ sizeof (CK_SLOT_ID))) == NULL)
+ return (KMF_ERR_MEMORY);
+
+ /* Then get the slot list itself. */
+ for (;;) {
+ ck_rv = C_GetSlotList(1, tmp_list, &tmp_count);
+ if (ck_rv == CKR_OK) {
+ *slot_list = tmp_list;
+ *slot_count = tmp_count;
+ kmf_rv = KMF_OK;
+ break;
+ }
+
+ if (ck_rv != CKR_BUFFER_TOO_SMALL) {
+ free(tmp_list);
+ if (handle != NULL) {
+ handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ handle->lasterr.errcode = ck_rv;
+ }
+ kmf_rv = KMF_ERR_INTERNAL;
+ break;
+ }
+
+ /*
+ * If the number of slots grew, try again. This
+ * is to be consistent with pktool in ONNV.
+ */
+ if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
+ tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
+ free(tmp_list);
+ kmf_rv = KMF_ERR_MEMORY;
+ break;
+ }
+ tmp_list = tmp2_list;
+ }
+
+ return (kmf_rv);
+}
+
+/*
+ * Returns pointer to either null-terminator or next unescaped colon. The
+ * string to be extracted starts at the beginning and goes until one character
+ * before this pointer. If NULL is returned, the string itself is NULL.
+ */
+static char *
+find_unescaped_colon(char *str)
+{
+ char *end;
+
+ if (str == NULL)
+ return (NULL);
+
+ while ((end = strchr(str, ':')) != NULL) {
+ if (end != str && *(end-1) != '\\')
+ return (end);
+ str = end + 1; /* could point to null-terminator */
+ }
+ if (end == NULL)
+ end = strchr(str, '\0');
+ return (end);
+}
+
+/*
+ * Compresses away any characters escaped with backslash from given string.
+ * The string is altered in-place. Example, "ab\:\\e" becomes "ab:\e".
+ */
+static void
+unescape_str(char *str)
+{
+ boolean_t escaped = B_FALSE;
+ char *mark;
+
+ if (str == NULL)
+ return;
+
+ for (mark = str; *str != '\0'; str++) {
+ if (*str != '\\' || escaped == B_TRUE) {
+ *mark++ = *str;
+ escaped = B_FALSE;
+ } else {
+ escaped = B_TRUE;
+ }
+ }
+ *mark = '\0';
+}
+
+
+/*
+ * Given a colon-separated token specifier, this functions splits it into
+ * its label, manufacturer ID (if any), and serial number (if any). Literal
+ * colons within the label/manuf/serial can be escaped with a backslash.
+ * Fields can left blank and trailing colons can be omitted, however leading
+ * colons are required as placeholders. For example, these are equivalent:
+ * (a) "lbl", "lbl:", "lbl::" (b) "lbl:man", "lbl:man:"
+ * but these are not:
+ * (c) "man", ":man" (d) "ser", "::ser"
+ * Furthermore, the token label is required always.
+ *
+ * The buffer containing the token specifier is altered by replacing the
+ * colons to null-terminators, and pointers returned are pointers into this
+ * string. No new memory is allocated.
+ */
+static int
+parse_token_spec(char *token_spec, char **token_name, char **manuf_id,
+ char **serial_no)
+{
+ char *mark;
+
+ if (token_spec == NULL || *token_spec == '\0') {
+ return (-1);
+ }
+
+ *token_name = NULL;
+ *manuf_id = NULL;
+ *serial_no = NULL;
+
+ /* Token label (required) */
+ mark = find_unescaped_colon(token_spec);
+ *token_name = token_spec;
+ if (*mark != '\0')
+ *mark++ = '\0'; /* mark points to next field, if any */
+ unescape_str(*token_name);
+
+ if (*(*token_name) == '\0') { /* token label is required */
+ return (-1);
+ }
+
+ if (*mark == '\0' || *(mark+1) == '\0') /* no more fields */
+ return (0);
+ token_spec = mark;
+
+ /* Manufacturer identifier (optional) */
+ mark = find_unescaped_colon(token_spec);
+ *manuf_id = token_spec;
+ if (*mark != '\0')
+ *mark++ = '\0'; /* mark points to next field, if any */
+ unescape_str(*manuf_id);
+
+ if (*mark == '\0' || *(mark+1) == '\0') /* no more fields */
+ return (0);
+ token_spec = mark;
+
+ /* Serial number (optional) */
+ mark = find_unescaped_colon(token_spec);
+ *serial_no = token_spec;
+ if (*mark != '\0')
+ *mark++ = '\0'; /* null-terminate, just in case */
+ unescape_str(*serial_no);
+
+ return (0);
+}
+
+/*
+ * Find slots that match a token identifier. Token labels take the
+ * form of:
+ * token_name:manufacturer:serial_number
+ * manufacterer and serial number are optional. If used, the fields
+ * are delimited by the colon ':' character.
+ */
+KMF_RETURN
+KMF_PK11TokenLookup(KMF_HANDLE_T handle, char *label, CK_SLOT_ID *slot_id)
+{
+ KMF_RETURN kmf_rv = KMF_OK;
+ CK_RV rv;
+ CK_SLOT_ID_PTR slot_list = NULL;
+ CK_TOKEN_INFO token_info;
+ CK_ULONG slot_count = 0;
+ int i;
+ uint_t len, max_sz;
+ boolean_t metaslot_status_enabled;
+ boolean_t metaslot_migrate_enabled;
+ char *metaslot_slot_info;
+ char *metaslot_token_info;
+ char *tmplabel = NULL;
+ char *token_name = NULL;
+ char *manuf_id = NULL;
+ char *serial_no = NULL;
+ boolean_t tok_match = B_FALSE,
+ man_match = B_FALSE,
+ ser_match = B_FALSE;
+
+ if (slot_id == NULL || label == NULL || !strlen(label))
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (handle == NULL) {
+ rv = C_Initialize(NULL);
+ if ((rv != CKR_OK) &&
+ (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
+ return (KMF_ERR_UNINITIALIZED);
+ }
+ }
+
+ /*
+ * Parse token specifier into token_name, manuf_id, serial_no.
+ * Token_name is required; manuf_id and serial_no are optional.
+ */
+ tmplabel = strdup(label);
+ if (tmplabel == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (parse_token_spec(tmplabel, &token_name, &manuf_id,
+ &serial_no) < 0) {
+ free(tmplabel);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* Get a list of all slots with tokens present. */
+ kmf_rv = kmf_get_token_slots(handle, &slot_list, &slot_count);
+ if (kmf_rv != KMF_OK) {
+ free(tmplabel);
+ return (kmf_rv);
+ }
+
+ /* If there are no such slots, the desired token won't be found. */
+ if (slot_count == 0) {
+ free(tmplabel);
+ return (KMF_ERR_TOKEN_NOT_PRESENT);
+ }
+
+ /* Search the slot list for the token. */
+ for (i = 0; i < slot_count; i++) {
+ if (C_GetTokenInfo(slot_list[i], &token_info) != CKR_OK) {
+ continue;
+ }
+
+ /* See if the token label matches. */
+ len = strlen(token_name);
+ max_sz = sizeof (token_info.label);
+ if (memcmp_pad_max(&(token_info.label), max_sz, token_name,
+ len, max_sz) == 0)
+ tok_match = B_TRUE;
+ /*
+ * If manufacturer id was given, see if it actually matches.
+ * If no manufacturer id was given, assume match is true.
+ */
+ if (manuf_id) {
+ len = strlen(manuf_id);
+ max_sz = sizeof ((char *)(token_info.manufacturerID));
+ if (memcmp_pad_max(&(token_info.manufacturerID), max_sz,
+ manuf_id, len, max_sz) == 0)
+ man_match = B_TRUE;
+ } else {
+ man_match = B_TRUE;
+ }
+
+ /*
+ * If serial number was given, see if it actually matches.
+ * If no serial number was given, assume match is true.
+ */
+ if (serial_no) {
+ len = strlen(serial_no);
+ max_sz = sizeof ((char *)(token_info.serialNumber));
+ if (memcmp_pad_max(&(token_info.serialNumber), max_sz,
+ serial_no, len, max_sz) == 0)
+ ser_match = B_TRUE;
+ } else {
+ ser_match = B_TRUE;
+ }
+
+ if (tok_match && man_match && ser_match)
+ break; /* found it! */
+ }
+
+ if (i < slot_count) {
+ /* found the desired token from the slotlist */
+ *slot_id = slot_list[i];
+ free(slot_list);
+ free(tmplabel);
+ return (KMF_OK);
+ }
+
+ /*
+ * If we didn't find the token from the slotlist, check if this token
+ * is the one currently hidden by the metaslot. If that's case,
+ * we can just use the metaslot, the slot 0.
+ */
+ kmf_rv = get_metaslot_info(&metaslot_status_enabled,
+ &metaslot_migrate_enabled, &metaslot_slot_info,
+ &metaslot_token_info);
+ if (kmf_rv) {
+ /*
+ * Failed to get the metaslot info. This usually means that
+ * metaslot is disabled from the system.
+ */
+ kmf_rv = KMF_ERR_TOKEN_NOT_PRESENT;
+ } else {
+ max_sz = strlen(metaslot_token_info);
+ if (memcmp_pad_max(metaslot_token_info, max_sz, token_name, len,
+ max_sz) == 0) {
+ *slot_id = slot_list[0];
+ } else {
+ kmf_rv = KMF_ERR_TOKEN_NOT_PRESENT;
+ }
+ free(metaslot_slot_info);
+ free(metaslot_token_info);
+ }
+
+ free(slot_list);
+ free(tmplabel);
+ return (kmf_rv);
+}
+
+KMF_RETURN
+KMF_SetTokenPin(KMF_HANDLE_T handle, KMF_SETPIN_PARAMS *params,
+ KMF_CREDENTIAL *newpin)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_PLUGIN *plugin;
+
+ CLEAR_ERROR(handle, rv);
+ if (rv != KMF_OK)
+ return (rv);
+
+ if (params == NULL || newpin == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * If setting PKCS#11 token look for the slot.
+ */
+ if (params->kstype == KMF_KEYSTORE_PK11TOKEN) {
+ rv = KMF_PK11TokenLookup(NULL, params->tokenname,
+ &params->pkcs11parms.slot);
+ if (rv != KMF_OK)
+ return (rv);
+ }
+
+ plugin = FindPlugin(handle, params->kstype);
+ if (plugin == NULL)
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ if (plugin->funclist->SetTokenPin == NULL)
+ return (KMF_ERR_FUNCTION_NOT_FOUND);
+
+ rv = plugin->funclist->SetTokenPin(handle, params, newpin);
+
+ return (rv);
+}
+
+/*
+ *
+ * Name: KMF_SelectToken
+ *
+ * Description:
+ * This function enables the user of PKCS#11 plugin to select a
+ * particular PKCS#11 token. Valid token label are required in order to
+ * successfully complete this function.
+ * All subsequent KMF APIs, which specify PKCS#11 keystore as
+ * the backend, will be performed at the selected token.
+ *
+ * Parameters:
+ * label(input) - pointer to the token label
+ *
+ * Returns:
+ * A KMF_RETURN value indicating success or specifying a particular
+ * error condition.
+ * The value KMF_OK indicates success. All other values represent
+ * an error condition.
+ *
+ */
+KMF_RETURN
+KMF_SelectToken(KMF_HANDLE_T handle, char *label,
+ int readonly)
+{
+ KMF_RETURN kmf_rv = KMF_OK;
+ CK_RV ck_rv = CKR_OK;
+ CK_SLOT_ID slot_id;
+ CK_SESSION_HANDLE hSession;
+ CK_FLAGS openflags;
+
+ CLEAR_ERROR(handle, kmf_rv);
+ if (kmf_rv != KMF_OK)
+ return (kmf_rv);
+
+ if (label == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (!is_pk11_ready()) {
+ return (KMF_ERR_UNINITIALIZED);
+ }
+
+ /* Only one token can be active per thread */
+ if (handle->pk11handle != NULL) {
+ return (KMF_ERR_TOKEN_SELECTED);
+ }
+
+ /* Find the token with matching label */
+ kmf_rv = KMF_PK11TokenLookup(handle, label, &slot_id);
+ if (kmf_rv != KMF_OK) {
+ return (kmf_rv);
+ }
+
+ openflags = CKF_SERIAL_SESSION;
+ if (!readonly)
+ openflags |= CKF_RW_SESSION;
+
+ /* Open a session then log the user into the token */
+ ck_rv = C_OpenSession(slot_id, openflags, NULL, NULL, &hSession);
+ if (ck_rv != CKR_OK) {
+ handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ handle->lasterr.errcode = ck_rv;
+ return (KMF_ERR_INTERNAL);
+ }
+
+ handle->pk11handle = hSession;
+
+ return (kmf_rv);
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/policy.c b/usr/src/lib/libkmf/libkmf/common/policy.c
new file mode 100644
index 0000000000..5e41f9f42a
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/policy.c
@@ -0,0 +1,1460 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <strings.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <kmfapiP.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+
+typedef struct {
+ char *ekuname;
+ KMF_OID *oid;
+} EKUName2OID;
+
+static EKUName2OID EKUList[] = {
+ {"serverAuth", (KMF_OID *)&KMFOID_PKIX_KP_ServerAuth},
+ {"clientAuth", (KMF_OID *)&KMFOID_PKIX_KP_ClientAuth},
+ {"codeSigning", (KMF_OID *)&KMFOID_PKIX_KP_CodeSigning},
+ {"emailProtection", (KMF_OID *)&KMFOID_PKIX_KP_EmailProtection},
+ {"ipsecEndSystem", (KMF_OID *)&KMFOID_PKIX_KP_IPSecEndSystem},
+ {"ipsecTunnel", (KMF_OID *)&KMFOID_PKIX_KP_IPSecTunnel},
+ {"ipsecUser", (KMF_OID *)&KMFOID_PKIX_KP_IPSecUser},
+ {"timeStamping", (KMF_OID *)&KMFOID_PKIX_KP_TimeStamping},
+ {"OCSPSigning", (KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning}
+};
+
+static int num_ekus = sizeof (EKUList) / sizeof (EKUName2OID);
+
+static void
+addFormatting(xmlNodePtr parent, char *text)
+{
+ xmlNodePtr snode;
+
+ if (parent == NULL || text == NULL)
+ return;
+
+ snode = xmlNewText((const xmlChar *)text);
+ if (snode != NULL) {
+ xmlAddChild(parent, snode);
+ }
+}
+
+static void
+parseOCSPValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo)
+{
+ xmlNodePtr n;
+ char *c;
+ n = node->children;
+ while (n != NULL) {
+ if (!xmlStrcmp((const xmlChar *)n->name,
+ (const xmlChar *)KMF_OCSP_BASIC_ELEMENT)) {
+
+ vinfo->ocsp_info.basic.responderURI =
+ (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_OCSP_RESPONDER_ATTR);
+
+ vinfo->ocsp_info.basic.proxy = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_OCSP_PROXY_ATTR);
+
+ c = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_OCSP_URI_ATTR);
+ if (c != NULL && !strcasecmp(c, "true")) {
+ vinfo->ocsp_info.basic.uri_from_cert = 1;
+ xmlFree(c);
+ }
+
+ vinfo->ocsp_info.basic.response_lifetime =
+ (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_OCSP_RESPONSE_LIFETIME_ATTR);
+
+ c = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_OCSP_IGNORE_SIGN_ATTR);
+ if (c != NULL && !strcasecmp(c, "true")) {
+ vinfo->ocsp_info.basic.ignore_response_sign = 1;
+ xmlFree(c);
+ }
+
+ } else if (!xmlStrcmp((const xmlChar *)n->name,
+ (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT)) {
+
+ vinfo->ocsp_info.resp_cert.name =
+ (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_CERT_NAME_ATTR);
+ vinfo->ocsp_info.resp_cert.serial =
+ (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_CERT_SERIAL_ATTR);
+ vinfo->ocsp_info.has_resp_cert = 1;
+ }
+
+ n = n->next;
+ }
+
+}
+
+/*
+ * Parse the "validation-methods" section of the policy.
+ */
+static void
+parseValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo,
+ KMF_POLICY_RECORD *policy)
+{
+ xmlNodePtr n;
+ char *c;
+ n = node->children;
+ while (n != NULL) {
+ if (!xmlStrcmp((const xmlChar *)n->name,
+ (const xmlChar *)KMF_OCSP_ELEMENT)) {
+
+ parseOCSPValidation(n, &policy->validation_info);
+ policy->revocation |= KMF_REVOCATION_METHOD_OCSP;
+
+
+ } else if (!xmlStrcmp((const xmlChar *)n->name,
+ (const xmlChar *)KMF_CRL_ELEMENT)) {
+
+ vinfo->crl_info.basefilename = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_CRL_BASENAME_ATTR);
+
+ vinfo->crl_info.directory = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_CRL_DIRECTORY_ATTR);
+
+ c = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_CRL_GET_URI_ATTR);
+ if (c != NULL && !strcasecmp(c, "true")) {
+ vinfo->crl_info.get_crl_uri = 1;
+ } else {
+ vinfo->crl_info.get_crl_uri = 0;
+ }
+ xmlFree(c);
+
+ vinfo->crl_info.proxy = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_CRL_PROXY_ATTR);
+
+ c = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_CRL_IGNORE_SIGN_ATTR);
+ if (c != NULL && !strcasecmp(c, "true")) {
+ vinfo->crl_info.ignore_crl_sign = 1;
+ } else {
+ vinfo->crl_info.ignore_crl_sign = 0;
+ }
+ xmlFree(c);
+
+ c = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_CRL_IGNORE_DATE_ATTR);
+ if (c != NULL && !strcasecmp(c, "true")) {
+ vinfo->crl_info.ignore_crl_date = 1;
+ } else {
+ vinfo->crl_info.ignore_crl_date = 0;
+ }
+ xmlFree(c);
+
+ policy->revocation |= KMF_REVOCATION_METHOD_CRL;
+ }
+
+ n = n->next;
+ }
+}
+
+char *
+ku2str(uint32_t bitfield)
+{
+ if (bitfield & KMF_digitalSignature)
+ return ("digitalSignature");
+
+ if (bitfield & KMF_nonRepudiation)
+ return ("nonRepudiation");
+
+ if (bitfield & KMF_keyEncipherment)
+ return ("keyEncipherment");
+
+ if (bitfield & KMF_dataEncipherment)
+ return ("dataEncipherment");
+
+ if (bitfield & KMF_keyAgreement)
+ return ("keyAgreement");
+
+ if (bitfield & KMF_keyCertSign)
+ return ("keyCertSign");
+
+ if (bitfield & KMF_cRLSign)
+ return ("cRLSign");
+
+ if (bitfield & KMF_encipherOnly)
+ return ("encipherOnly");
+
+ if (bitfield & KMF_decipherOnly)
+ return ("decipherOnly");
+
+ return (NULL);
+}
+
+uint16_t
+KMF_StringToKeyUsage(char *kustring)
+{
+ if (kustring == NULL || !strlen(kustring))
+ return (0);
+ if (strcasecmp(kustring, "digitalSignature") == 0)
+ return (KMF_digitalSignature);
+ if (strcasecmp(kustring, "nonRepudiation") == 0)
+ return (KMF_nonRepudiation);
+ if (strcasecmp(kustring, "keyEncipherment") == 0)
+ return (KMF_keyEncipherment);
+ if (strcasecmp(kustring, "dataEncipherment") == 0)
+ return (KMF_dataEncipherment);
+ if (strcasecmp(kustring, "keyAgreement") == 0)
+ return (KMF_keyAgreement);
+ if (strcasecmp(kustring, "keyCertSign") == 0)
+ return (KMF_keyCertSign);
+ if (strcasecmp(kustring, "cRLSign") == 0)
+ return (KMF_cRLSign);
+ if (strcasecmp(kustring, "encipherOnly") == 0)
+ return (KMF_encipherOnly);
+ if (strcasecmp(kustring, "decipherOnly") == 0)
+ return (KMF_decipherOnly);
+
+ return (0);
+}
+
+static void
+parseKeyUsageSet(xmlNodePtr node, uint32_t *kubits)
+{
+ xmlNodePtr n;
+ char *c;
+
+ n = node->children;
+ while (n != NULL) {
+ if (!xmlStrcmp((const xmlChar *)n->name,
+ (const xmlChar *)KMF_KEY_USAGE_ELEMENT)) {
+ c = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_KEY_USAGE_USE_ATTR);
+ if (c) {
+ *kubits |= KMF_StringToKeyUsage(c);
+ xmlFree(c);
+ }
+ }
+
+ n = n->next;
+ }
+}
+
+static KMF_OID *
+dup_oid(KMF_OID *oldoid)
+{
+ KMF_OID *oid;
+
+ oid = malloc(sizeof (KMF_OID));
+ if (oid == NULL)
+ return (NULL);
+
+ oid->Length = oldoid->Length;
+ oid->Data = malloc(oid->Length);
+ if (oid->Data == NULL) {
+ free(oid);
+ return (NULL);
+ }
+ (void) memcpy(oid->Data, oldoid->Data, oid->Length);
+
+ return (oid);
+}
+
+KMF_OID *
+kmf_ekuname2oid(char *ekuname)
+{
+ KMF_OID *oid;
+ int i;
+
+ if (ekuname == NULL)
+ return (NULL);
+
+ for (i = 0; i < num_ekus; i++) {
+ if (strcasecmp(EKUList[i].ekuname, ekuname) == 0) {
+ oid = dup_oid(EKUList[i].oid);
+ return (oid);
+ }
+ }
+
+ return (NULL);
+}
+
+char *
+KMF_OID2EKUString(KMF_OID *oid)
+{
+ int i;
+ for (i = 0; i < num_ekus; i++) {
+ if (oid->Length == EKUList[i].oid->Length &&
+ !memcmp(oid->Data, EKUList[i].oid->Data, oid->Length)) {
+ return (EKUList[i].ekuname);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * Convert a human-readable OID string of the form "1.2.3.4" or
+ * "1 2 3 4" into a KMF_OID value.
+ */
+KMF_OID *
+kmf_string2oid(char *oidstring)
+{
+ KMF_OID *oid = NULL;
+ char *cp, *bp, *startp;
+ int numbuf;
+ int onumbuf;
+ int nbytes, index;
+ int len;
+ unsigned char *op;
+
+ if (oidstring == NULL)
+ return (NULL);
+
+ len = strlen(oidstring);
+
+ bp = oidstring;
+ cp = bp;
+ /* Skip over leading space */
+ while ((bp < &cp[len]) && isspace(*bp))
+ bp++;
+
+ startp = bp;
+ nbytes = 0;
+
+ /*
+ * The first two numbers are chewed up by the first octet.
+ */
+ if (sscanf(bp, "%d", &numbuf) != 1)
+ return (NULL);
+ while ((bp < &cp[len]) && isdigit(*bp))
+ bp++;
+ while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.'))
+ bp++;
+ if (sscanf(bp, "%d", &numbuf) != 1)
+ return (NULL);
+ while ((bp < &cp[len]) && isdigit(*bp))
+ bp++;
+ while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.'))
+ bp++;
+ nbytes++;
+
+ while (isdigit(*bp)) {
+ if (sscanf(bp, "%d", &numbuf) != 1)
+ return (NULL);
+ while (numbuf) {
+ nbytes++;
+ numbuf >>= 7;
+ }
+ while ((bp < &cp[len]) && isdigit(*bp))
+ bp++;
+ while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.'))
+ bp++;
+ }
+
+ oid = malloc(sizeof (KMF_OID));
+ if (oid == NULL)
+ return (NULL);
+
+ oid->Length = nbytes;
+ oid->Data = malloc(oid->Length);
+ if (oid->Data == NULL) {
+ free(oid);
+ return (NULL);
+ }
+ (void) memset(oid->Data, 0, oid->Length);
+
+ op = oid->Data;
+
+ bp = startp;
+ (void) sscanf(bp, "%d", &numbuf);
+
+ while (isdigit(*bp)) bp++;
+ while (isspace(*bp) || *bp == '.') bp++;
+
+ onumbuf = 40 * numbuf;
+ (void) sscanf(bp, "%d", &numbuf);
+ onumbuf += numbuf;
+ *op = (unsigned char) onumbuf;
+ op++;
+
+ while (isdigit(*bp)) bp++;
+ while (isspace(*bp) || *bp == '.') bp++;
+ while (isdigit(*bp)) {
+ (void) sscanf(bp, "%d", &numbuf);
+ nbytes = 0;
+ /* Have to fill in the bytes msb-first */
+ onumbuf = numbuf;
+ while (numbuf) {
+ nbytes++;
+ numbuf >>= 7;
+ }
+ numbuf = onumbuf;
+ op += nbytes;
+ index = -1;
+ while (numbuf) {
+ op[index] = (unsigned char)numbuf & 0x7f;
+ if (index != -1)
+ op[index] |= 0x80;
+ index--;
+ numbuf >>= 7;
+ }
+ while (isdigit(*bp)) bp++;
+ while (isspace(*bp) || *bp == '.') bp++;
+ }
+
+ return (oid);
+}
+
+static KMF_RETURN
+parseExtKeyUsage(xmlNodePtr node, KMF_EKU_POLICY *ekus)
+{
+ xmlNodePtr n;
+ char *c;
+ KMF_RETURN ret = KMF_OK;
+ boolean_t found = FALSE;
+
+ n = node->children;
+ while (n != NULL && ret == KMF_OK) {
+ KMF_OID *newoid = NULL;
+
+ if (!xmlStrcmp((const xmlChar *)n->name,
+ (const xmlChar *)KMF_EKU_NAME_ELEMENT)) {
+ c = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_EKU_NAME_ATTR);
+ if (c != NULL) {
+ newoid = kmf_ekuname2oid(c);
+ xmlFree(c);
+ found = TRUE;
+ }
+ } else if (!xmlStrcmp((const xmlChar *)n->name,
+ (const xmlChar *)KMF_EKU_OID_ELEMENT)) {
+ c = (char *)xmlGetProp(n,
+ (const xmlChar *)KMF_EKU_OID_ATTR);
+ if (c != NULL) {
+ newoid = kmf_string2oid(c);
+ xmlFree(c);
+ found = TRUE;
+ }
+ } else {
+ n = n->next;
+ if ((n == NULL) && (!found))
+ ret = KMF_ERR_POLICY_DB_FORMAT;
+ continue;
+ }
+
+ if (newoid != NULL) {
+ ekus->eku_count++;
+ ekus->ekulist = realloc(ekus->ekulist,
+ ekus->eku_count * sizeof (KMF_OID));
+ if (ekus->ekulist != NULL) {
+ ekus->ekulist[ekus->eku_count-1].Length =
+ newoid->Length;
+ ekus->ekulist[ekus->eku_count-1].Data =
+ malloc(newoid->Length);
+ if (ekus->ekulist[ekus->eku_count-1].Data ==
+ NULL) {
+ ret = KMF_ERR_MEMORY;
+ } else {
+ (void) memcpy(
+ ekus->ekulist[ekus->eku_count-1].
+ Data,
+ newoid->Data, newoid->Length);
+ }
+ } else {
+ ret = KMF_ERR_MEMORY;
+ }
+ KMF_FreeData(newoid);
+ free(newoid);
+ } else {
+ ret = KMF_ERR_POLICY_DB_FORMAT;
+ }
+
+ n = n->next;
+ }
+
+ return (ret);
+}
+
+int
+parsePolicyElement(xmlNodePtr node, KMF_POLICY_RECORD *policy)
+{
+ int ret = 0;
+ xmlNodePtr n = node->xmlChildrenNode;
+ char *c;
+
+ if (node->type == XML_ELEMENT_NODE) {
+ if (node->properties != NULL) {
+ policy->name = (char *)xmlGetProp(node,
+ (const xmlChar *)KMF_POLICY_NAME_ATTR);
+
+ c = (char *)xmlGetProp(node,
+ (const xmlChar *)KMF_OPTIONS_IGNORE_DATE_ATTR);
+ if (c && !strcasecmp(c, "true")) {
+ policy->ignore_date = 1;
+ xmlFree((xmlChar *)c);
+ }
+
+ c = (char *)xmlGetProp(node,
+ (const xmlChar *)KMF_OPTIONS_IGNORE_UNKNOWN_EKUS);
+ if (c && !strcasecmp(c, "true")) {
+ policy->ignore_unknown_ekus = 1;
+ xmlFree(c);
+ }
+
+ c = (char *)xmlGetProp(node,
+ (const xmlChar *)KMF_OPTIONS_IGNORE_TRUST_ANCHOR);
+ if (c && !strcasecmp(c, "true")) {
+ policy->ignore_trust_anchor = 1;
+ xmlFree(c);
+ }
+
+ c = (char *)xmlGetProp(node,
+ (const xmlChar *)KMF_OPTIONS_VALIDITY_ADJUSTTIME);
+ if (c) {
+ policy->validity_adjusttime = c;
+ } else {
+ policy->validity_adjusttime = NULL;
+ }
+
+ policy->ta_name = (char *)xmlGetProp(node,
+ (const xmlChar *)KMF_POLICY_TA_NAME_ATTR);
+
+ policy->ta_serial = (char *)xmlGetProp(node,
+ (const xmlChar *)KMF_POLICY_TA_SERIAL_ATTR);
+ }
+
+ n = node->children;
+ while (n != NULL) {
+ if (!xmlStrcmp((const xmlChar *)n->name,
+ (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT))
+ parseValidation(n, &policy->validation_info,
+ policy);
+ else if (!xmlStrcmp((const xmlChar *)n->name,
+ (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT))
+ parseKeyUsageSet(n, &policy->ku_bits);
+ else if (!xmlStrcmp((const xmlChar *)n->name,
+ (const xmlChar *)KMF_EKU_ELEMENT)) {
+ ret = parseExtKeyUsage(n, &policy->eku_set);
+ if (ret != KMF_OK)
+ return (ret);
+ }
+
+ n = n->next;
+ }
+ }
+
+ return (ret);
+}
+
+static int
+newprop(xmlNodePtr node, char *attrname, char *src)
+{
+ xmlAttrPtr newattr;
+
+ if (src != NULL && strlen(src)) {
+ newattr = xmlNewProp(node, (const xmlChar *)attrname,
+ (xmlChar *)src);
+ if (newattr == NULL) {
+ xmlUnlinkNode(node);
+ xmlFreeNode(node);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Add CRL policy information to the XML tree.
+ * Return non-zero on any failure, else 0 for success.
+ *
+ * This function is called only when the KMF_REVOCATION_METHOD_CRL flag is on.
+ */
+static int
+AddCRLNodes(xmlNodePtr node, KMF_CRL_POLICY *crlinfo)
+{
+ xmlNodePtr n;
+
+ addFormatting(node, "\t\t");
+ n = xmlNewChild(node, NULL, (const xmlChar *)"crl", NULL);
+ if (n == NULL)
+ return (-1);
+
+ if (crlinfo->basefilename &&
+ newprop(n, KMF_CRL_BASENAME_ATTR, crlinfo->basefilename))
+ return (-1);
+
+ if (crlinfo->directory &&
+ newprop(n, KMF_CRL_DIRECTORY_ATTR, crlinfo->directory))
+ return (-1);
+
+ if (crlinfo->get_crl_uri &&
+ newprop(n, KMF_CRL_GET_URI_ATTR, "TRUE")) {
+ return (-1);
+ }
+
+ if (crlinfo->proxy &&
+ newprop(n, KMF_CRL_PROXY_ATTR, crlinfo->proxy))
+ return (-1);
+
+ if (crlinfo->ignore_crl_sign &&
+ newprop(n, KMF_CRL_IGNORE_SIGN_ATTR, "TRUE")) {
+ return (-1);
+ }
+
+ if (crlinfo->ignore_crl_date &&
+ newprop(n, KMF_CRL_IGNORE_DATE_ATTR, "TRUE")) {
+ return (-1);
+ }
+
+ addFormatting(node, "\n");
+ return (0);
+}
+
+/*
+ * Add OCSP information to the policy tree.
+ * Return non-zero on any failure, else 0 for success.
+ *
+ * This function is called only when the KMF_REVOCATION_METHOD_OCSP flag is on.
+ */
+static int
+AddOCSPNodes(xmlNodePtr parent, KMF_OCSP_POLICY *ocsp)
+{
+ int ret = 0;
+ xmlNodePtr n_ocsp, n_basic, n_resp;
+ KMF_OCSP_BASIC_POLICY *basic;
+ KMF_RESP_CERT_POLICY *resp_cert;
+
+ basic = &(ocsp->basic);
+ resp_cert = &(ocsp->resp_cert);
+
+ if (basic->responderURI != NULL || basic->uri_from_cert == B_TRUE) {
+
+ addFormatting(parent, "\t\t");
+
+ /* basic node */
+ n_ocsp = xmlNewChild(parent, NULL,
+ (const xmlChar *)KMF_OCSP_ELEMENT, NULL);
+ if (n_ocsp == NULL)
+ return (-1);
+ addFormatting(n_ocsp, "\n\t\t\t");
+
+ n_basic = xmlNewChild(n_ocsp, NULL,
+ (const xmlChar *)KMF_OCSP_BASIC_ELEMENT, NULL);
+ if (n_basic == NULL)
+ return (-1);
+ if (basic->responderURI && newprop(n_basic,
+ KMF_OCSP_RESPONDER_ATTR, basic->responderURI))
+ return (-1);
+ if (basic->proxy &&
+ newprop(n_basic, KMF_OCSP_PROXY_ATTR, basic->proxy))
+ return (-1);
+ if (basic->uri_from_cert &&
+ newprop(n_basic, KMF_OCSP_URI_ATTR, "TRUE"))
+ return (-1);
+ if (basic->response_lifetime &&
+ newprop(n_basic, KMF_OCSP_RESPONSE_LIFETIME_ATTR,
+ basic->response_lifetime))
+ return (-1);
+ if (basic->ignore_response_sign &&
+ newprop(n_basic, KMF_OCSP_IGNORE_SIGN_ATTR, "TRUE"))
+ return (-1);
+
+ addFormatting(n_ocsp, "\n\t\t\t");
+
+ /* responder cert node */
+ if (ocsp->has_resp_cert) {
+ n_resp = xmlNewChild(n_ocsp, NULL,
+ (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT,
+ NULL);
+ if (n_resp == NULL)
+ return (-1);
+ if (newprop(n_resp, KMF_CERT_NAME_ATTR,
+ resp_cert->name))
+ return (-1);
+ if (newprop(n_resp, KMF_CERT_SERIAL_ATTR,
+ resp_cert->serial))
+ return (-1);
+ }
+ addFormatting(n_ocsp, "\n\t\t");
+ }
+
+ addFormatting(parent, "\n");
+ return (ret);
+}
+
+/*
+ * Add validation method information to the policy tree.
+ * Return non-zero on any failure, else 0 for success.
+ */
+static int
+AddValidationNodes(xmlNodePtr parent, KMF_POLICY_RECORD *policy)
+{
+ xmlNodePtr mnode;
+ int ret = 0;
+
+ addFormatting(parent, "\t");
+ mnode = xmlNewChild(parent, NULL,
+ (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT, NULL);
+ if (mnode == NULL)
+ return (-1);
+
+ addFormatting(mnode, "\n");
+
+ if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
+ ret = AddOCSPNodes(mnode, &(policy->validation_info.ocsp_info));
+ if (ret != KMF_OK)
+ goto end;
+ }
+
+ if (policy->revocation & KMF_REVOCATION_METHOD_CRL) {
+ ret = AddCRLNodes(mnode, &(policy->validation_info.crl_info));
+ if (ret != KMF_OK)
+ goto end;
+ }
+
+ addFormatting(mnode, "\t");
+ addFormatting(parent, "\n");
+
+end:
+ if (ret != 0) {
+ xmlUnlinkNode(mnode);
+ xmlFreeNode(mnode);
+ }
+ return (ret);
+
+}
+
+/*
+ * Add Key Usage information to the policy tree.
+ * Return non-zero on any failure, else 0 for success.
+ */
+static KMF_RETURN
+AddKeyUsageNodes(xmlNodePtr parent, uint32_t kubits)
+{
+ int ret = KMF_OK;
+ int i;
+
+ xmlNodePtr kuset, kunode;
+
+ if (kubits == 0)
+ return (0);
+
+ addFormatting(parent, "\n\t");
+ kuset = xmlNewChild(parent, NULL,
+ (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT, NULL);
+ if (kuset == NULL)
+ return (KMF_ERR_POLICY_ENGINE);
+
+ for (i = KULOWBIT; i <= KUHIGHBIT && ret == KMF_OK; i++) {
+ char *s = ku2str((kubits & (1<<i)));
+ if (s != NULL) {
+ addFormatting(kuset, "\n\t\t");
+
+ kunode = xmlNewChild(kuset, NULL,
+ (const xmlChar *)KMF_KEY_USAGE_ELEMENT, NULL);
+ if (kunode == NULL)
+ ret = KMF_ERR_POLICY_ENGINE;
+
+ else if (newprop(kunode, KMF_KEY_USAGE_USE_ATTR, s))
+ ret = KMF_ERR_POLICY_ENGINE;
+ }
+ }
+ addFormatting(kuset, "\n\t");
+ addFormatting(parent, "\n");
+
+ if (ret != KMF_OK) {
+ xmlUnlinkNode(kuset);
+ xmlFreeNode(kuset);
+ }
+
+ return (ret);
+}
+
+/*
+ * Add Extended-Key-Usage information to the policy tree.
+ * Return non-zero on any failure, else 0 for success.
+ */
+static KMF_RETURN
+AddExtKeyUsageNodes(xmlNodePtr parent, KMF_EKU_POLICY *ekus)
+{
+ KMF_RETURN ret = KMF_OK;
+ xmlNodePtr n, kunode;
+ int i;
+
+ if (ekus != NULL && ekus->eku_count > 0) {
+ addFormatting(parent, "\n\t");
+ n = xmlNewChild(parent, NULL,
+ (const xmlChar *)KMF_EKU_ELEMENT, NULL);
+ if (n == NULL)
+ return (KMF_ERR_POLICY_ENGINE);
+
+ for (i = 0; i < ekus->eku_count; i++) {
+ char *s = KMF_OID2String(&ekus->ekulist[i]);
+ if (s != NULL) {
+ addFormatting(n, "\n\t\t");
+ kunode = xmlNewChild(n, NULL,
+ (const xmlChar *)KMF_EKU_OID_ELEMENT,
+ NULL);
+ if (kunode == NULL)
+ ret = KMF_ERR_POLICY_ENGINE;
+
+ else if (newprop(kunode, KMF_EKU_OID_ATTR, s))
+ ret = KMF_ERR_POLICY_ENGINE;
+ free(s);
+ } else {
+ ret = KMF_ERR_POLICY_ENGINE;
+ }
+ }
+ addFormatting(n, "\n\t");
+ addFormatting(parent, "\n");
+ }
+
+ if (ret != KMF_OK) {
+ xmlUnlinkNode(n);
+ xmlFreeNode(n);
+ }
+ return (ret);
+}
+
+void
+KMF_FreeEKUPolicy(KMF_EKU_POLICY *ekus)
+{
+ if (ekus->eku_count > 0) {
+ int i;
+ for (i = 0; i < ekus->eku_count; i++) {
+ KMF_FreeData(&ekus->ekulist[i]);
+ }
+ free(ekus->ekulist);
+ }
+}
+
+#define FREE_POLICY_STR(s) if (s != NULL) free(s);
+
+void
+KMF_FreePolicyRecord(KMF_POLICY_RECORD *policy)
+{
+ if (policy == NULL)
+ return;
+
+ FREE_POLICY_STR(policy->name)
+ FREE_POLICY_STR(policy->VAL_OCSP_BASIC.responderURI)
+ FREE_POLICY_STR(policy->VAL_OCSP_BASIC.proxy)
+ FREE_POLICY_STR(policy->VAL_OCSP_BASIC.response_lifetime)
+ FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.name)
+ FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.serial)
+ FREE_POLICY_STR(policy->validation_info.crl_info.basefilename)
+ FREE_POLICY_STR(policy->validation_info.crl_info.directory)
+ FREE_POLICY_STR(policy->validation_info.crl_info.proxy)
+ FREE_POLICY_STR(policy->validity_adjusttime)
+ FREE_POLICY_STR(policy->ta_name)
+ FREE_POLICY_STR(policy->ta_serial)
+
+ KMF_FreeEKUPolicy(&policy->eku_set);
+
+ (void) memset(policy, 0, sizeof (KMF_POLICY_RECORD));
+}
+
+/*
+ * KMF_GetPolicy
+ *
+ * Find a policy record in the database.
+ */
+KMF_RETURN
+KMF_GetPolicy(char *filename, char *policy_name, KMF_POLICY_RECORD *plc)
+{
+ KMF_RETURN ret = KMF_OK;
+ xmlParserCtxtPtr ctxt;
+ xmlDocPtr doc = NULL;
+ xmlNodePtr cur, node;
+ int found = 0;
+
+ if (filename == NULL || policy_name == NULL || plc == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(plc, 0, sizeof (KMF_POLICY_RECORD));
+
+ /* Create a parser context */
+ ctxt = xmlNewParserCtxt();
+ if (ctxt == NULL)
+ return (KMF_ERR_POLICY_DB_FORMAT);
+
+ /* Read the policy DB and verify it against the schema. */
+ doc = xmlCtxtReadFile(ctxt, filename, NULL,
+ XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
+ if (doc == NULL || ctxt->valid == 0) {
+ ret = KMF_ERR_POLICY_DB_FORMAT;
+ goto out;
+ }
+
+ cur = xmlDocGetRootElement(doc);
+ if (cur == NULL) {
+ ret = KMF_ERR_POLICY_DB_FORMAT;
+ goto out;
+ }
+
+ node = cur->xmlChildrenNode;
+ while (node != NULL && !found) {
+ char *c;
+ /*
+ * Search for the policy that matches the given name.
+ */
+ if (!xmlStrcmp((const xmlChar *)node->name,
+ (const xmlChar *)KMF_POLICY_ELEMENT)) {
+ /* Check the name attribute */
+ c = (char *)xmlGetProp(node,
+ (const xmlChar *)KMF_POLICY_NAME_ATTR);
+
+ /* If a match, parse the rest of the data */
+ if (c != NULL) {
+ if (strcmp(c, policy_name) == 0) {
+ ret = parsePolicyElement(node, plc);
+ found = (ret == KMF_OK);
+ }
+ xmlFree(c);
+ }
+ }
+ node = node->next;
+ }
+
+ if (!found) {
+ ret = KMF_ERR_POLICY_NOT_FOUND;
+ goto out;
+ }
+
+out:
+ if (ctxt != NULL)
+ xmlFreeParserCtxt(ctxt);
+
+ if (doc != NULL)
+ xmlFreeDoc(doc);
+
+ return (ret);
+}
+
+/*
+ * KMF_SetPolicy
+ *
+ * Set the policy record in the handle. This searches
+ * the policy DB for the named policy. If it is not found
+ * or an error occurred in processing, the existing policy
+ * is kept and an error code is returned.
+ */
+KMF_RETURN
+KMF_SetPolicy(KMF_HANDLE_T handle, char *policyfile, char *policyname)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_POLICY_RECORD *newpolicy = NULL;
+
+ CLEAR_ERROR(handle, ret);
+ if (ret != KMF_OK)
+ return (ret);
+
+ newpolicy = malloc(sizeof (KMF_POLICY_RECORD));
+ if (newpolicy == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(newpolicy, 0, sizeof (KMF_POLICY_RECORD));
+
+ ret = KMF_GetPolicy(
+ policyfile == NULL ? KMF_DEFAULT_POLICY_FILE : policyfile,
+ policyname == NULL ? KMF_DEFAULT_POLICY_NAME : policyname,
+ newpolicy);
+ if (ret != KMF_OK)
+ goto out;
+
+ ret = KMF_VerifyPolicy(newpolicy);
+ if (ret != KMF_OK)
+ goto out;
+
+ /* release the existing policy data (if any). */
+ if (handle->policy != NULL) {
+ KMF_FreePolicyRecord(handle->policy);
+ free(handle->policy);
+ }
+
+ handle->policy = newpolicy;
+
+out:
+ /* Cleanup any data allocated before the error occurred */
+ if (ret != KMF_OK) {
+ KMF_FreePolicyRecord(newpolicy);
+ free(newpolicy);
+ }
+
+ return (ret);
+}
+
+
+static KMF_RETURN
+deletePolicyNode(xmlNodePtr node, char *policy_name)
+{
+ KMF_RETURN ret = KMF_OK;
+ int found = 0;
+ xmlNodePtr dnode = NULL;
+
+ while (node != NULL && !found) {
+ char *c;
+ /*
+ * Search for the policy that matches the given name.
+ */
+ if (!xmlStrcmp((const xmlChar *)node->name,
+ (const xmlChar *)KMF_POLICY_ELEMENT)) {
+ /* Check the name attribute */
+ c = (char *)xmlGetProp(node,
+ (const xmlChar *)KMF_POLICY_NAME_ATTR);
+
+ /* If a match, parse the rest of the data */
+ if (c != NULL) {
+ if (strcmp(c, policy_name) == 0) {
+ found = 1;
+ dnode = node;
+ }
+ xmlFree(c);
+ }
+ }
+ if (!found)
+ node = node->next;
+ }
+
+ if (found && dnode != NULL) {
+ /* Unlink the node */
+ xmlUnlinkNode(dnode);
+
+ /* Delete it from the document tree */
+ xmlFreeNode(dnode);
+ } else {
+ ret = KMF_ERR_POLICY_NOT_FOUND;
+ }
+
+ return (ret);
+}
+
+/*
+ * update_policyfile
+ *
+ * Attempt to do a "safe" file update as follows:
+ * 1. Lock the original file.
+ * 2. Create and write to a temporary file
+ * 3. Replace the original file with the temporary file.
+ */
+static KMF_RETURN
+update_policyfile(xmlDocPtr doc, char *filename)
+{
+ KMF_RETURN ret = KMF_OK;
+ FILE *pfile, *tmpfile;
+ char tmpfilename[MAXPATHLEN];
+ char *p;
+ int prefix_len, tmpfd;
+ mode_t old_mode;
+
+ /*
+ * Open and lock the DB file. First try to open an existing file,
+ * if that fails, open it as if it were new.
+ */
+ if ((pfile = fopen(filename, "r+")) == NULL && errno == ENOENT)
+ pfile = fopen(filename, "w+");
+
+ if (pfile == NULL)
+ return (KMF_ERR_POLICY_DB_FILE);
+
+ if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
+ (void) fclose(pfile);
+ return (KMF_ERR_POLICY_DB_FILE);
+ }
+
+ /*
+ * Create a temporary file to hold the new data.
+ */
+ (void) memset(tmpfilename, 0, sizeof (tmpfilename));
+ p = (char *)strrchr(filename, '/');
+ if (p == NULL) {
+ /*
+ * filename contains basename only so we
+ * create a temp file in current directory.
+ */
+ if (strlcpy(tmpfilename, TMPFILE_TEMPLATE,
+ sizeof (tmpfilename)) >= sizeof (tmpfilename))
+ return (KMF_ERR_INTERNAL);
+ } else {
+ /*
+ * create a temp file in the same directory
+ * as the policy file.
+ */
+ prefix_len = p - filename;
+ (void) strncpy(tmpfilename, filename, prefix_len);
+ (void) strncat(tmpfilename, "/", 1);
+ (void) strncat(tmpfilename, TMPFILE_TEMPLATE,
+ sizeof (TMPFILE_TEMPLATE));
+ }
+
+ old_mode = umask(077);
+ tmpfd = mkstemp(tmpfilename);
+ (void) umask(old_mode);
+ if (tmpfd == -1) {
+ return (KMF_ERR_POLICY_DB_FILE);
+ }
+
+ if ((tmpfile = fdopen(tmpfd, "w")) == NULL) {
+ (void) close(tmpfd);
+ (void) unlink(tmpfilename);
+ (void) fclose(pfile);
+ return (KMF_ERR_POLICY_DB_FILE);
+ }
+
+ /*
+ * Write the new info to the temporary file.
+ */
+ if (xmlDocFormatDump(tmpfile, doc, 1) == -1) {
+ (void) fclose(pfile);
+ (void) fclose(tmpfile);
+ (void) unlink(tmpfilename);
+ return (KMF_ERR_POLICY_ENGINE);
+ }
+
+ (void) fclose(pfile);
+
+ if (fchmod(tmpfd,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
+ (void) close(tmpfd);
+ (void) unlink(tmpfilename);
+ return (KMF_ERR_POLICY_DB_FILE);
+ }
+ if (fclose(tmpfile) != 0)
+ return (KMF_ERR_POLICY_DB_FILE);
+
+ /*
+ * Replace the original file with the updated tempfile.
+ */
+ if (rename(tmpfilename, filename) == -1) {
+ ret = KMF_ERR_POLICY_DB_FILE;
+ }
+
+ if (ret != KMF_OK) {
+ /* try to remove the tmp file */
+ (void) unlink(tmpfilename);
+ }
+
+ return (ret);
+}
+
+/*
+ * DeletePolicyFromDB
+ *
+ * Find a policy by name and remove it from the policy DB file.
+ * If the policy is not found, return an error.
+ */
+KMF_RETURN
+KMF_DeletePolicyFromDB(char *policy_name, char *dbfilename)
+{
+ KMF_RETURN ret;
+ xmlParserCtxtPtr ctxt = NULL;
+ xmlDocPtr doc = NULL;
+ xmlNodePtr cur, node;
+
+ if (policy_name == NULL || dbfilename == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * Cannot delete the default policy record from the system
+ * default policy database (/etc/security/kmfpolicy.xml).
+ */
+ if (strcmp(dbfilename, KMF_DEFAULT_POLICY_FILE) == 0 &&
+ strcmp(policy_name, KMF_DEFAULT_POLICY_NAME) == 0)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Make sure the policy file exists */
+ if (access(dbfilename, R_OK | W_OK))
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Read the policy DB and verify it against the schema. */
+ ctxt = xmlNewParserCtxt();
+ if (ctxt == NULL)
+ return (KMF_ERR_POLICY_DB_FORMAT);
+
+ doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
+ XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
+ if (doc == NULL || ctxt->valid == 0) {
+ ret = KMF_ERR_POLICY_DB_FORMAT;
+ goto end;
+ }
+
+ cur = xmlDocGetRootElement(doc);
+ if (cur == NULL) {
+ xmlFreeDoc(doc);
+ return (KMF_ERR_POLICY_DB_FORMAT);
+ }
+ node = cur->xmlChildrenNode;
+
+ ret = deletePolicyNode(node, policy_name);
+
+ if (ret == KMF_OK)
+ ret = update_policyfile(doc, dbfilename);
+
+end:
+ if (ctxt != NULL)
+ xmlFreeParserCtxt(ctxt);
+
+ if (doc != NULL)
+ xmlFreeDoc(doc);
+
+ return (ret);
+}
+
+/*
+ * Add a new policy node to the Policy DB XML tree.
+ */
+static KMF_RETURN
+addPolicyNode(xmlNodePtr pnode, KMF_POLICY_RECORD *policy)
+{
+ KMF_RETURN ret = KMF_OK;
+
+ if (pnode != NULL && policy != NULL) {
+ if (newprop(pnode, KMF_POLICY_NAME_ATTR, policy->name) != 0) {
+ ret = KMF_ERR_POLICY_ENGINE;
+ goto out;
+ }
+ if (policy->ignore_date) {
+ if (newprop(pnode, KMF_OPTIONS_IGNORE_DATE_ATTR,
+ "TRUE")) {
+ ret = KMF_ERR_POLICY_ENGINE;
+ goto out;
+ }
+ }
+
+ if (policy->ignore_unknown_ekus) {
+ if (newprop(pnode, KMF_OPTIONS_IGNORE_UNKNOWN_EKUS,
+ "TRUE")) {
+ ret = KMF_ERR_POLICY_ENGINE;
+ goto out;
+ }
+ }
+
+ if (policy->ignore_trust_anchor) {
+ if (newprop(pnode, KMF_OPTIONS_IGNORE_TRUST_ANCHOR,
+ "TRUE")) {
+ ret = KMF_ERR_POLICY_ENGINE;
+ goto out;
+ }
+ }
+
+ if (policy->validity_adjusttime) {
+ if (newprop(pnode, KMF_OPTIONS_VALIDITY_ADJUSTTIME,
+ policy->validity_adjusttime)) {
+ ret = KMF_ERR_POLICY_ENGINE;
+ goto out;
+ }
+ }
+
+ if (newprop(pnode, KMF_POLICY_TA_NAME_ATTR,
+ policy->ta_name) != 0) {
+ ret = KMF_ERR_POLICY_ENGINE;
+ goto out;
+ }
+
+ if (newprop(pnode, KMF_POLICY_TA_SERIAL_ATTR,
+ policy->ta_serial) != 0) {
+ ret = KMF_ERR_POLICY_ENGINE;
+ goto out;
+ }
+
+ /* Add a text node for readability */
+ addFormatting(pnode, "\n");
+
+ if (ret = AddValidationNodes(pnode, policy)) {
+ goto out;
+ }
+
+ if ((ret = AddKeyUsageNodes(pnode, policy->ku_bits))) {
+ goto out;
+ }
+
+ if ((ret = AddExtKeyUsageNodes(pnode, &policy->eku_set))) {
+ goto out;
+ }
+ } else {
+ ret = KMF_ERR_BAD_PARAMETER;
+ }
+out:
+ if (ret != KMF_OK && pnode != NULL) {
+ xmlUnlinkNode(pnode);
+ xmlFreeNode(pnode);
+ }
+
+ return (ret);
+}
+
+
+KMF_RETURN
+KMF_VerifyPolicy(KMF_POLICY_RECORD *policy)
+{
+ KMF_RETURN ret = KMF_OK;
+ boolean_t has_ta;
+
+ if (policy->name == NULL || !strlen(policy->name))
+ return (KMF_ERR_POLICY_NAME);
+
+ /* Check the TA related policy */
+ if (policy->ta_name != NULL && policy->ta_serial != NULL) {
+ has_ta = B_TRUE;
+ } else if (policy->ta_name == NULL && policy->ta_serial == NULL) {
+ has_ta = B_FALSE;
+ } else {
+ /*
+ * If the TA cert is set, then both name and serial number
+ * need to be specified.
+ */
+ return (KMF_ERR_TA_POLICY);
+ }
+
+ if (has_ta == B_FALSE && policy->ignore_trust_anchor == B_FALSE)
+ return (KMF_ERR_TA_POLICY);
+
+ if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
+ /*
+ * For OCSP, either use a fixed responder or use the
+ * value from the cert, but not both.
+ */
+ if ((policy->VAL_OCSP_BASIC.responderURI == NULL &&
+ policy->VAL_OCSP_BASIC.uri_from_cert == B_FALSE) ||
+ (policy->VAL_OCSP_BASIC.responderURI != NULL &&
+ policy->VAL_OCSP_BASIC.uri_from_cert == B_TRUE))
+ return (KMF_ERR_OCSP_POLICY);
+
+ /*
+ * If the OCSP responder cert is set, then both name and serial
+ * number need to be specified.
+ */
+ if ((policy->VAL_OCSP_RESP_CERT.name != NULL &&
+ policy->VAL_OCSP_RESP_CERT.serial == NULL) ||
+ (policy->VAL_OCSP_RESP_CERT.name == NULL &&
+ policy->VAL_OCSP_RESP_CERT.serial != NULL))
+ return (KMF_ERR_OCSP_POLICY);
+ }
+
+ return (ret);
+}
+
+/*
+ * Update the KMF policy file by creating a new XML Policy doc tree
+ * from the data in the KMF_POLICY_RECORD structure. If "check_policy"
+ * is true, then we check the policy sanity also.
+ */
+KMF_RETURN
+KMF_AddPolicyToDB(KMF_POLICY_RECORD *policy, char *dbfilename,
+ boolean_t check_policy)
+{
+ KMF_RETURN ret = KMF_OK;
+ xmlDocPtr doc = NULL;
+ xmlNodePtr root, node;
+ xmlParserCtxtPtr ctxt = NULL;
+
+ if (policy == NULL || dbfilename == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (check_policy == B_TRUE) {
+ if (ret = KMF_VerifyPolicy(policy))
+ return (ret);
+ }
+
+ /* If the policyDB exists, load it into memory */
+ if (!access(dbfilename, R_OK)) {
+
+ /* Create a parser context */
+ ctxt = xmlNewParserCtxt();
+ if (ctxt == NULL)
+ return (KMF_ERR_POLICY_DB_FORMAT);
+
+ doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
+ XML_PARSE_DTDVALID | XML_PARSE_NOERROR |
+ XML_PARSE_NOWARNING);
+ if (doc == NULL || ctxt->valid == 0) {
+ ret = KMF_ERR_POLICY_DB_FORMAT;
+ goto out;
+ }
+
+ root = xmlDocGetRootElement(doc);
+ if (root == NULL) {
+ ret = KMF_ERR_POLICY_DB_FORMAT;
+ goto out;
+ }
+
+ node = root->xmlChildrenNode;
+ /*
+ * If the DB has an existing policy of the
+ * same name, delete it from the tree.
+ */
+ ret = deletePolicyNode(node, policy->name);
+ if (ret == KMF_ERR_POLICY_NOT_FOUND)
+ ret = KMF_OK;
+ } else {
+ /* Initialize a new DB tree */
+ doc = xmlNewDoc((const xmlChar *)"1.0");
+ if (doc == NULL)
+ return (KMF_ERR_POLICY_ENGINE);
+
+ /*
+ * Add the DOCTYPE header to the tree so the
+ * DTD link is embedded
+ */
+ doc->intSubset = xmlCreateIntSubset(doc,
+ (const xmlChar *)KMF_POLICY_ROOT,
+ NULL, (const xmlChar *)KMF_POLICY_DTD);
+
+ root = xmlNewDocNode(doc, NULL,
+ (const xmlChar *)KMF_POLICY_ROOT, NULL);
+ if (root != NULL) {
+ xmlDocSetRootElement(doc, root);
+ }
+ }
+
+ /* Append the new policy info to the root node. */
+ if (root != NULL) {
+ xmlNodePtr pnode;
+
+ pnode = xmlNewChild(root, NULL,
+ (const xmlChar *)KMF_POLICY_ELEMENT, NULL);
+
+ ret = addPolicyNode(pnode, policy);
+ /* If that worked, update the DB file. */
+ if (ret == KMF_OK)
+ ret = update_policyfile(doc, dbfilename);
+ } else {
+ ret = KMF_ERR_POLICY_ENGINE;
+ }
+
+
+out:
+ if (ctxt != NULL)
+ xmlFreeParserCtxt(ctxt);
+
+ if (doc != NULL)
+ xmlFreeDoc(doc);
+
+ return (ret);
+}
diff --git a/usr/src/lib/libkmf/libkmf/common/rdn_parser.c b/usr/src/lib/libkmf/libkmf/common/rdn_parser.c
new file mode 100644
index 0000000000..ae944a7d7a
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/rdn_parser.c
@@ -0,0 +1,546 @@
+/*
+ * 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
+ */
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * File: rdn_parser.c
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#include <strings.h>
+#include <stdlib.h>
+#include <kmfapi.h>
+#include <kmfapiP.h>
+#include <ber_der.h>
+#include <rdn_parser.h>
+#include <stdio.h>
+#include <values.h>
+
+/*
+ * The order here is important. The OIDs are arranged in order of
+ * significance. The CN is the most specific value, the C (country)
+ * is less specific, etc. Add to this list with care.
+ */
+static const struct NameToKind name2kinds[] = {
+{ "CN", OID_AVA_COMMON_NAME, (KMF_OID *)&KMFOID_CommonName},
+{ "SN", OID_AVA_SURNAME, (KMF_OID *)&KMFOID_Surname},
+{ "GN", OID_AVA_GIVEN_NAME, (KMF_OID *)&KMFOID_GivenName},
+{ "emailAddress", OID_PKCS9_EMAIL_ADDRESS, (KMF_OID *)&KMFOID_EmailAddress},
+{ "E", OID_PKCS9_EMAIL_ADDRESS, (KMF_OID *)&KMFOID_EmailAddress},
+{ "MAIL", OID_RFC1274_MAIL, (KMF_OID *)&KMFOID_RFC822mailbox},
+{ "STREET", OID_AVA_STREET_ADDRESS, (KMF_OID *)&KMFOID_StreetAddress},
+{ "UID", OID_RFC1274_UID, (KMF_OID *)&KMFOID_userid},
+{ "OU", OID_AVA_ORGANIZATIONAL_UNIT_NAME,
+ (KMF_OID *)&KMFOID_OrganizationalUnitName},
+{ "O", OID_AVA_ORGANIZATION_NAME, (KMF_OID *)&KMFOID_OrganizationName},
+{ "L", OID_AVA_LOCALITY, (KMF_OID *)&KMFOID_LocalityName},
+{ "ST", OID_AVA_STATE_OR_PROVINCE,
+ (KMF_OID *)&KMFOID_StateProvinceName},
+{ "C", OID_AVA_COUNTRY_NAME, (KMF_OID *)&KMFOID_CountryName},
+{ "DC", OID_AVA_DC, (KMF_OID *)&KMFOID_domainComponent},
+{ 0, OID_UNKNOWN, NULL}
+};
+
+static KMF_BOOL
+IsPrintable(unsigned char *data, unsigned len)
+{
+ unsigned char ch, *end;
+
+ end = data + len;
+ while (data < end) {
+ ch = *data++;
+ if (!IS_PRINTABLE(ch)) {
+ return (B_FALSE);
+ }
+ }
+ return (B_TRUE);
+}
+
+static KMF_BOOL
+Is7Bit(unsigned char *data, unsigned len)
+{
+ unsigned char ch, *end;
+
+ end = data + len;
+ while (data < end) {
+ ch = *data++;
+ if ((ch & 0x80)) {
+ return (B_FALSE);
+ }
+ }
+ return (B_TRUE);
+}
+
+static void
+skipSpace(char **pbp, char *endptr)
+{
+ char *bp = *pbp;
+ while (bp < endptr && OPTIONAL_SPACE(*bp)) {
+ bp++;
+ }
+ *pbp = bp;
+}
+
+static KMF_RETURN
+scanTag(char **pbp, char *endptr, char *tagBuf, int tagBufSize)
+{
+ char *bp, *tagBufp;
+ int taglen;
+
+ if (tagBufSize <= 0)
+ return (KMF_ERR_INTERNAL);
+
+ /* skip optional leading space */
+ skipSpace(pbp, endptr);
+ if (*pbp == endptr) {
+ /* nothing left */
+ return (KMF_ERR_RDN_PARSER);
+ }
+
+ /* fill tagBuf */
+ taglen = 0;
+ bp = *pbp;
+ tagBufp = tagBuf;
+ while (bp < endptr && !OPTIONAL_SPACE(*bp) && (*bp != C_EQUAL)) {
+ if (++taglen >= tagBufSize) {
+ *pbp = bp;
+ return (KMF_ERR_RDN_PARSER);
+ }
+ *tagBufp++ = *bp++;
+ }
+ /* null-terminate tagBuf -- guaranteed at least one space left */
+ *tagBufp++ = 0;
+ *pbp = bp;
+
+ /*
+ * skip trailing spaces till we hit something - should be
+ * an equal sign
+ */
+ skipSpace(pbp, endptr);
+ if (*pbp == endptr) {
+ /* nothing left */
+ return (KMF_ERR_RDN_PARSER);
+ }
+ if (**pbp != C_EQUAL) {
+ /* should be an equal sign */
+ return (KMF_ERR_RDN_PARSER);
+ }
+ /* skip over the equal sign */
+ (*pbp)++;
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+scanVal(char **pbp, char *endptr, char *valBuf, int valBufSize)
+{
+ char *bp, *valBufp;
+ int vallen;
+ boolean_t isQuoted;
+
+ if (valBufSize <= 0)
+ return (KMF_ERR_INTERNAL);
+
+ /* skip optional leading space */
+ skipSpace(pbp, endptr);
+ if (*pbp == endptr) {
+ /* nothing left */
+ return (KMF_ERR_RDN_PARSER);
+ }
+
+ bp = *pbp;
+
+ /* quoted? */
+ if (*bp == C_DOUBLE_QUOTE) {
+ isQuoted = B_TRUE;
+ /* skip over it */
+ bp++;
+ } else {
+ isQuoted = B_FALSE;
+ }
+
+ valBufp = valBuf;
+ vallen = 0;
+ while (bp < endptr) {
+ char c = *bp;
+ if (c == C_BACKSLASH) {
+ /* escape character */
+ bp++;
+ if (bp >= endptr) {
+ /*
+ * escape charater must appear with paired char
+ */
+ *pbp = bp;
+ return (KMF_ERR_RDN_PARSER);
+ }
+ } else if (!isQuoted && SPECIAL_CHAR(c)) {
+ /* unescaped special and not within quoted value */
+ break;
+ } else if (c == C_DOUBLE_QUOTE) {
+ /* reached unescaped double quote */
+ break;
+ }
+ /* append character */
+ vallen++;
+ if (vallen >= valBufSize) {
+ *pbp = bp;
+ return (KMF_ERR_RDN_PARSER);
+ }
+ *valBufp++ = *bp++;
+ }
+
+ /* stip trailing spaces from unquoted values */
+ if (!isQuoted) {
+ if (valBufp > valBuf) {
+ valBufp--;
+ while ((valBufp > valBuf) && OPTIONAL_SPACE(*valBufp)) {
+ valBufp--;
+ }
+ valBufp++;
+ }
+ }
+
+ if (isQuoted) {
+ /* insist that we stopped on a double quote */
+ if (*bp != C_DOUBLE_QUOTE) {
+ *pbp = bp;
+ return (KMF_ERR_RDN_PARSER);
+ }
+ /* skip over the quote and skip optional space */
+ bp++;
+ skipSpace(&bp, endptr);
+ }
+
+ *pbp = bp;
+
+ if (valBufp == valBuf) {
+ /* empty value -- not allowed */
+ return (KMF_ERR_RDN_PARSER);
+ }
+
+ /* null-terminate valBuf -- guaranteed at least one space left */
+ *valBufp++ = 0;
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+CreateRDN(KMF_X509_TYPE_VALUE_PAIR *ava, KMF_X509_RDN *newrdn)
+{
+ /* Each RDN has 1 AttrTypeAndValue */
+ (void) memset(newrdn, 0, sizeof (KMF_X509_RDN));
+ newrdn->numberOfPairs = 1;
+ newrdn->AttributeTypeAndValue = ava;
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+copy_oid(KMF_OID *dst, KMF_OID *src)
+{
+ KMF_RETURN ret = KMF_OK;
+
+ if (dst == NULL || src == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ dst->Data = malloc(src->Length);
+ if (dst->Data == NULL)
+ return (KMF_ERR_MEMORY);
+
+ dst->Length = src->Length;
+ (void) memcpy(dst->Data, src->Data, src->Length);
+
+ return (ret);
+}
+
+static KMF_RETURN
+CreateAVA(KMF_OID *oid, int valueType, char *value,
+ KMF_X509_TYPE_VALUE_PAIR **newava)
+{
+ int rv = KMF_OK;
+ KMF_X509_TYPE_VALUE_PAIR *ava = NULL;
+
+ *newava = NULL;
+ ava = (KMF_X509_TYPE_VALUE_PAIR*) malloc(
+ sizeof (KMF_X509_TYPE_VALUE_PAIR));
+ if (ava == NULL) {
+ return (KMF_ERR_MEMORY);
+ } else {
+ (void) memset(ava, 0, sizeof (KMF_X509_TYPE_VALUE_PAIR));
+ ava->valueType = valueType;
+ ava->value.Data = malloc(strlen(value));
+ if (ava->value.Data == NULL) {
+ free(ava);
+ return (KMF_ERR_MEMORY);
+ }
+ (void) memcpy(ava->value.Data, value, strlen(value));
+ ava->value.Length = strlen(value);
+
+ rv = copy_oid(&ava->type, oid);
+ if (rv != KMF_OK) {
+ /* Illegal AVA type */
+ free(ava->value.Data);
+ free(ava);
+ return (rv);
+ }
+ }
+ *newava = ava;
+
+ return (rv);
+}
+
+static KMF_RETURN
+ParseRdnAttribute(char **pbp, char *endptr, boolean_t singleAVA,
+ KMF_X509_TYPE_VALUE_PAIR **a)
+{
+ KMF_RETURN rv;
+ const struct NameToKind *n2k;
+ int vt;
+ int valLen;
+ char *bp;
+
+ char tagBuf[32];
+ char valBuf[384];
+
+ rv = scanTag(pbp, endptr, tagBuf, sizeof (tagBuf));
+ if (rv != KMF_OK)
+ return (rv);
+ rv = scanVal(pbp, endptr, valBuf, sizeof (valBuf));
+ if (rv != KMF_OK)
+ return (rv);
+
+ /* insist that if we haven't finished we've stopped on a separator */
+ bp = *pbp;
+ if (bp < endptr) {
+ if (singleAVA || (*bp != ',' && *bp != ';')) {
+ *pbp = bp;
+ return (KMF_ERR_RDN_ATTR);
+ }
+ /* ok, skip over separator */
+ bp++;
+ }
+ *pbp = bp;
+
+ for (n2k = name2kinds; n2k->name; n2k++) {
+ if (strcasecmp(n2k->name, tagBuf) == 0) {
+ valLen = strlen(valBuf);
+ if (n2k->kind == OID_AVA_COUNTRY_NAME) {
+ vt = BER_PRINTABLE_STRING;
+ if (valLen != 2) {
+ return (KMF_ERR_RDN_ATTR);
+ }
+ if (!IsPrintable((unsigned char *) valBuf, 2)) {
+ return (KMF_ERR_RDN_ATTR);
+ }
+ } else if ((n2k->kind == OID_PKCS9_EMAIL_ADDRESS) ||
+ (n2k->kind == OID_RFC1274_MAIL)) {
+ vt = BER_IA5STRING;
+ } else {
+ /*
+ * Hack -- for rationale see X.520
+ * DirectoryString defn
+ */
+ if (IsPrintable((unsigned char *)valBuf,
+ valLen)) {
+ vt = BER_PRINTABLE_STRING;
+ } else if (Is7Bit((unsigned char *)valBuf,
+ valLen)) {
+ vt = BER_T61STRING;
+ }
+ }
+ rv = CreateAVA(n2k->OID,
+ vt, (char *)valBuf, a);
+ return (rv);
+ }
+ }
+ /* matched no kind -- invalid tag */
+ return (KMF_ERR_RDN_ATTR);
+}
+
+static int
+rdnavcompare(const void *a, const void *b)
+{
+ KMF_X509_RDN *r1, *r2;
+ KMF_X509_TYPE_VALUE_PAIR *av1, *av2;
+ int i, p1, p2;
+ const struct NameToKind *n2k;
+ KMF_OID *oidrec;
+
+ r1 = (KMF_X509_RDN *)a;
+ r2 = (KMF_X509_RDN *)b;
+
+ av1 = r1->AttributeTypeAndValue;
+ av2 = r2->AttributeTypeAndValue;
+
+ p1 = p2 = MAXINT;
+ /*
+ * The "Name2Kinds" list is ordered by significance.
+ * Compare the "ranking" of each of the OIDs to determine
+ * the result.
+ */
+ for (n2k = name2kinds, i = 0;
+ n2k->name && (p1 == MAXINT || p2 == MAXINT);
+ n2k++, i++) {
+ oidrec = n2k->OID;
+ if (oidrec != NULL) {
+ if (IsEqualOid(&av1->type, oidrec))
+ p1 = i;
+ if (IsEqualOid(&av2->type, oidrec))
+ p2 = i;
+ }
+ }
+
+ if (p1 > p2)
+ return (-1);
+ else if (p1 < p2)
+ return (1);
+ else /* If equal, treat as if it is less than */
+ return (1);
+}
+
+KMF_RETURN
+ParseDistinguishedName(char *buf, int len, KMF_X509_NAME *name)
+{
+ KMF_RETURN rv = KMF_OK;
+ char *bp, *e;
+ KMF_X509_TYPE_VALUE_PAIR *ava = NULL;
+ KMF_X509_RDN rdn;
+
+ (void) memset(name, 0, sizeof (KMF_X509_NAME));
+ e = buf + len;
+ bp = buf;
+ while (bp < e) {
+ rv = ParseRdnAttribute(&bp, e, B_FALSE, &ava);
+ if (rv != KMF_OK) goto loser;
+ rv = CreateRDN(ava, &rdn);
+ if (rv != KMF_OK) goto loser;
+ if (AddRDN(name, &rdn) != KMF_OK) goto loser;
+ skipSpace(&bp, e);
+ }
+
+ /*
+ * Canonicalize the DN by sorting the elements
+ * in little-endian order, as per RFC 1485:
+ * "The name is presented/input in a little-endian
+ * order (most significant component last)."
+ */
+ qsort((void *)name->RelativeDistinguishedName,
+ name->numberOfRDNs,
+ sizeof (KMF_X509_RDN),
+ rdnavcompare);
+
+ /* return result */
+ return (rv);
+
+loser:
+ KMF_FreeDN(name);
+ return (rv);
+}
+
+static KMF_BOOL
+IsEqualData(KMF_DATA *d1, KMF_DATA *d2)
+{
+ return ((d1->Length == d2->Length) &&
+ !memcmp(d1->Data, d2->Data, d1->Length));
+}
+
+/*
+ * Generic routine to compare 2 RDN structures.
+ *
+ * Because the ordering of the AV pairs may not be
+ * the same, we must compare each AV pair individually
+ *
+ * Return 0 if equal, 1 if not.
+ */
+int
+KMF_CompareRDNs(KMF_X509_NAME *name1, KMF_X509_NAME *name2)
+{
+ int i, j;
+ boolean_t avfound;
+ KMF_X509_RDN *r1, *r2;
+ KMF_X509_TYPE_VALUE_PAIR *av1, *av2;
+
+ if (name1 == NULL || name2 == NULL)
+ return (1);
+
+ if (name1->numberOfRDNs != name2->numberOfRDNs)
+ return (1);
+
+ for (i = 0; i < name1->numberOfRDNs; i++) {
+ r1 = (KMF_X509_RDN *)&name1->RelativeDistinguishedName[i];
+ av1 = (KMF_X509_TYPE_VALUE_PAIR *)r1->AttributeTypeAndValue;
+
+ avfound = FALSE;
+ for (j = 0; j < name2->numberOfRDNs && !avfound; j++) {
+ r2 = (KMF_X509_RDN *)
+ &name2->RelativeDistinguishedName[j];
+ av2 = (KMF_X509_TYPE_VALUE_PAIR *)
+ r2->AttributeTypeAndValue;
+
+ avfound = (IsEqualOid(&av1->type, &av2->type) &&
+ IsEqualData(&av1->value, &av2->value));
+ }
+ /*
+ * If the current AV from name1 was not found in name2,
+ * we are done.
+ */
+ if (!avfound)
+ return (1);
+ }
+
+ /* If we got this far, it must be a match */
+ return (0);
+}
diff --git a/usr/src/lib/libkmf/libkmf/i386/Makefile b/usr/src/lib/libkmf/libkmf/i386/Makefile
new file mode 100644
index 0000000000..6dd6b42169
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/i386/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libkmf/libkmf/sparc/Makefile b/usr/src/lib/libkmf/libkmf/sparc/Makefile
new file mode 100644
index 0000000000..6dd6b42169
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/sparc/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libkmf/libkmf/sparcv9/Makefile b/usr/src/lib/libkmf/libkmf/sparcv9/Makefile
new file mode 100644
index 0000000000..dbd1e9ec93
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/sparcv9/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libkmf/plugins/Makefile b/usr/src/lib/libkmf/plugins/Makefile
new file mode 100644
index 0000000000..5b27f7e6da
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/Makefile
@@ -0,0 +1,48 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# KMF Prototype Makefile
+#
+include ../../Makefile.lib
+
+SUBDIRS = kmf_nss kmf_openssl kmf_pkcs11
+
+HDRS=
+HDRDIR= include
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile
new file mode 100644
index 0000000000..5c60729ece
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile
@@ -0,0 +1,47 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS= $(MACH)
+
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+check := TARGET= check
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com
new file mode 100644
index 0000000000..30209c69f9
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com
@@ -0,0 +1,74 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Makefile for KMF Plugins
+#
+
+LIBRARY= kmf_nss.a
+VERS= .1
+
+OBJECTS= nss_spi.o
+
+include $(SRC)/lib/Makefile.lib
+
+MPSDIR= /usr/lib/mps
+KMFINC= -I../../../include -I../../../ber_der/inc
+NSSINC= -I/usr/include/mps
+BERLIB= -lkmf -lkmfberder
+BERLIB64= $(BERLIB)
+
+NSSLIBS= $(BERLIB) -L$(MPSDIR) -R$(MPSDIR) -lnss3 -lnspr4 -lsmime3 -lc
+NSSLIBS64= $(BERLIB64) -L$(MPSDIR)/$(MACH64) -R$(MPSDIR)/$(MACH64) -lnss3 -lnspr4 -lsmime3 -lc
+
+SRCDIR= ../common
+INCDIR= ../../include
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT $(KMFINC) $(NSSINC) \
+ -I$(SFWDIR)/include -I$(INCDIR) -I/usr/include/libxml2
+
+PICS= $(OBJECTS:%=pics/%)
+
+lint:= NSSLIBS = $(BERLIB)
+lint:= NSSLIBS64 = $(BERLIB64)
+
+LDLIBS32 += $(NSSLIBS)
+
+LIBS = $(DYNLIB)
+
+ROOTLIBDIR= $(ROOT)/usr/lib/security
+ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64)
+
+
+.KEEP_STATE:
+
+all: $(LIBS) $(LINTLIB)
+
+lint: lintcheck
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile
new file mode 100644
index 0000000000..aa52c4aefb
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile
@@ -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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+LDLIBS64 += $(NSSLIBS64)
+
+install: $(ROOTLIBS64)
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers
new file mode 100644
index 0000000000..ed84774842
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers
@@ -0,0 +1,56 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate_1.1 {
+ global:
+ KMF_Plugin_Initialize;
+ NSS_FindCert;
+ NSS_FreeKMFCert;
+ NSS_StoreCert;
+ NSS_ImportCert;
+ NSS_ImportCRL;
+ NSS_DeleteCert;
+ NSS_DeleteCRL;
+ NSS_CreateKeypair;
+ NSS_FindKey;
+ NSS_EncodePubKeyData;
+ NSS_SignData;
+ NSS_DeleteKey;
+ NSS_FindCRL;
+ NSS_FindCertInCRL;
+ NSS_GetErrorString;
+ NSS_GetPrikeyByCert;
+ NSS_DecryptData;
+ NSS_ExportP12;
+ NSS_StorePrivateKey;
+ NSS_CreateSymKey;
+ NSS_GetSymKeyValue;
+ NSS_SetTokenPin;
+
+ local:
+ *;
+};
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c b/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c
new file mode 100644
index 0000000000..b23886aaae
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c
@@ -0,0 +1,2508 @@
+/*
+ * 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
+ */
+/*
+ * NSS keystore wrapper
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <synch.h>
+
+#include <kmfapiP.h>
+#include <ber_der.h>
+#include <oidsalg.h>
+/* NSS related headers */
+
+#include <mps/nss.h>
+#include <mps/cert.h>
+#include <mps/certdb.h>
+#include <mps/secoid.h>
+#include <mps/secder.h>
+#include <mps/secerr.h>
+#include <mps/cryptohi.h>
+#include <mps/keyhi.h>
+#include <mps/keythi.h>
+#include <mps/pk11func.h>
+#include <mps/pk11pqg.h>
+#include <mps/pkcs12.h>
+#include <mps/p12plcy.h>
+#include <mps/prerror.h>
+
+#define NSS_OK 0
+
+mutex_t init_lock = DEFAULTMUTEX;
+static int nss_initialized = 0;
+
+KMF_RETURN
+NSS_ConfigureKeystore(KMF_HANDLE_T, KMF_CONFIG_PARAMS *);
+
+KMF_RETURN
+NSS_FindCert(KMF_HANDLE_T,
+ KMF_FINDCERT_PARAMS *params,
+ KMF_X509_DER_CERT *kmf_cert,
+ uint32_t *num_certs);
+
+void
+NSS_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *);
+
+KMF_RETURN
+NSS_StoreCert(KMF_HANDLE_T, KMF_STORECERT_PARAMS *params,
+ KMF_DATA * pcert);
+
+KMF_RETURN
+NSS_ImportCert(KMF_HANDLE_T, KMF_IMPORTCERT_PARAMS *params);
+
+KMF_RETURN
+NSS_DeleteCert(KMF_HANDLE_T, KMF_DELETECERT_PARAMS *params);
+
+KMF_RETURN
+NSS_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *,
+ KMF_KEY_HANDLE *, KMF_KEY_HANDLE *);
+
+KMF_RETURN
+NSS_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *);
+
+KMF_RETURN
+NSS_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+NSS_ImportCRL(KMF_HANDLE_T, KMF_IMPORTCRL_PARAMS *params);
+
+KMF_RETURN
+NSS_DeleteCRL(KMF_HANDLE_T, KMF_DELETECRL_PARAMS *params);
+
+KMF_RETURN
+NSS_FindCRL(KMF_HANDLE_T, KMF_FINDCRL_PARAMS *params,
+ char **CRLNameList, int *CRLCount);
+
+KMF_RETURN
+NSS_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *,
+ KMF_KEY_HANDLE *, uint32_t *);
+
+KMF_RETURN
+NSS_FindCertInCRL(KMF_HANDLE_T, KMF_FINDCERTINCRL_PARAMS *params);
+
+KMF_RETURN
+NSS_GetErrorString(KMF_HANDLE_T, char **);
+
+KMF_RETURN
+NSS_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *,
+ KMF_KEY_HANDLE *, boolean_t);
+
+KMF_RETURN
+NSS_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *,
+ KMF_KEY_HANDLE *, KMF_KEY_ALG);
+
+KMF_RETURN
+NSS_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+NSS_ExportP12(KMF_HANDLE_T,
+ KMF_EXPORTP12_PARAMS *,
+ int, KMF_X509_DER_CERT *,
+ int, KMF_KEY_HANDLE *,
+ char *);
+
+KMF_RETURN
+NSS_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *, KMF_RAW_KEY_DATA *);
+
+KMF_RETURN
+NSS_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *, KMF_KEY_HANDLE *);
+
+KMF_RETURN
+NSS_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *);
+
+KMF_RETURN
+NSS_SetTokenPin(KMF_HANDLE_T, KMF_SETPIN_PARAMS *, KMF_CREDENTIAL *);
+
+static
+KMF_PLUGIN_FUNCLIST nss_plugin_table =
+{
+ 1, /* Version */
+ NSS_ConfigureKeystore,
+ NSS_FindCert,
+ NSS_FreeKMFCert,
+ NSS_StoreCert,
+ NSS_ImportCert,
+ NSS_ImportCRL,
+ NSS_DeleteCert,
+ NSS_DeleteCRL,
+ NSS_CreateKeypair,
+ NSS_FindKey,
+ NSS_EncodePubKeyData,
+ NSS_SignData,
+ NSS_DeleteKey,
+ NULL /* ListCRL */,
+ NSS_FindCRL,
+ NSS_FindCertInCRL,
+ NSS_GetErrorString,
+ NSS_GetPrikeyByCert,
+ NSS_DecryptData,
+ NSS_ExportP12,
+ NSS_StorePrivateKey,
+ NSS_CreateSymKey,
+ NSS_GetSymKeyValue,
+ NSS_SetTokenPin,
+ NULL /* Finalize */
+};
+
+/* additions for importing and exporting PKCS 12 files */
+typedef struct p12uContextStr {
+ char *filename; /* name of file */
+ PRFileDesc *file; /* pointer to file */
+ PRBool error; /* error occurred? */
+ int errorValue; /* which error occurred? */
+} p12uContext;
+
+#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_NSS; \
+ h->lasterr.errcode = c;
+
+KMF_PLUGIN_FUNCLIST *
+KMF_Plugin_Initialize()
+{
+ SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
+ SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
+ SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
+ SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
+ SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
+ SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
+ SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
+
+ return (&nss_plugin_table);
+}
+
+static char *
+/*ARGSUSED*/
+nss_getpassword(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+ if (retry)
+ return (NULL);
+ if (arg != NULL)
+ return ((char *)strdup(arg));
+ else
+ return (NULL);
+}
+
+static KMF_RETURN
+nss_authenticate(KMF_HANDLE_T handle,
+ PK11SlotInfo *nss_slot, KMF_CREDENTIAL *cred)
+{
+
+ SECStatus nssrv = SECSuccess;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ /* If a password was given, try to login to the slot */
+ if (cred == NULL || cred->cred == NULL || cred->credlen == 0 ||
+ nss_slot == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (PK11_IsLoggedIn(nss_slot, NULL)) {
+ return (KMF_OK);
+ }
+
+ PK11_SetPasswordFunc(nss_getpassword);
+ nssrv = PK11_Authenticate(nss_slot, PR_TRUE,
+ (void *)cred->cred);
+
+ if (nssrv != SECSuccess) {
+ SET_ERROR(kmfh, nssrv);
+ PK11_FreeSlot(nss_slot);
+ return (KMF_ERR_AUTH_FAILED);
+ }
+
+ return (KMF_OK);
+}
+
+static SECStatus
+Init_NSS_DBs(const char *configdir,
+ const char *certPrefix,
+ const char *keyPrefix,
+ const char *secmodName)
+{
+ SECStatus rv = NSS_OK;
+
+ (void) mutex_lock(&init_lock);
+
+ /* If another thread already did it, return OK. */
+ if (nss_initialized) {
+ (void) mutex_unlock(&init_lock);
+ return (SECSuccess);
+ }
+
+ rv = NSS_Initialize((configdir && strlen(configdir)) ?
+ configdir : "./", certPrefix,
+ keyPrefix, secmodName ? secmodName : "secmod.db",
+ NSS_INIT_COOPERATE);
+ if (rv != SECSuccess) {
+ goto end;
+ }
+
+ nss_initialized++;
+end:
+ (void) mutex_unlock(&init_lock);
+ return (rv);
+}
+
+/*
+ * When it is called the first time, it will intialize NSS. Once the NSS
+ * is initialized, this function returns KMF_KEYSTORE_ALREADY_INITIALIZED
+ * if it is called again.
+ */
+KMF_RETURN
+NSS_ConfigureKeystore(KMF_HANDLE_T handle, KMF_CONFIG_PARAMS *params)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) mutex_lock(&init_lock);
+ if (nss_initialized == 0) {
+ SECStatus err;
+
+ (void) mutex_unlock(&init_lock);
+ err = Init_NSS_DBs(params->nssconfig.configdir,
+ params->nssconfig.certPrefix,
+ params->nssconfig.keyPrefix,
+ params->nssconfig.secModName);
+ if (err != SECSuccess) {
+ SET_ERROR(kmfh, err);
+ return (KMF_ERR_INTERNAL);
+ }
+ } else {
+ rv = KMF_KEYSTORE_ALREADY_INITIALIZED;
+ (void) mutex_unlock(&init_lock);
+ }
+
+ return (rv);
+}
+
+
+/*
+ * This function sets up the slot to be used for other operations.
+ * This function is basically called by every NSS SPI function.
+ * For those functions that can only be performed in the internal slot, the
+ * boolean "internal_slot_only" argument needs to be TRUE.
+ * A slot pointer will be returned when this function is executed successfully.
+ */
+static KMF_RETURN
+Do_NSS_Init(
+ void *handle,
+ KMF_NSS_PARAMS nss_opts,
+ boolean_t internal_slot_only,
+ PK11SlotInfo **nss_slot)
+{
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ if (!nss_initialized)
+ return (KMF_ERR_PLUGIN_INIT);
+
+ /*
+ * NSS Is already initialized, but we need to find
+ * the right slot.
+ */
+ if (nss_opts.slotlabel == NULL ||
+ strcmp(nss_opts.slotlabel, "internal") == 0) {
+ *nss_slot = PK11_GetInternalKeySlot();
+ } else if (internal_slot_only == TRUE) {
+ return (KMF_ERR_SLOTNAME);
+ } else {
+ *nss_slot = PK11_FindSlotByName(nss_opts.slotlabel);
+ }
+
+ if (*nss_slot == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ return (KMF_ERR_SLOTNAME);
+ }
+
+ /*
+ * If the token was not yet initialized, return an error.
+ */
+ if (PK11_NeedUserInit(*nss_slot)) {
+ return (KMF_ERR_UNINITIALIZED_TOKEN);
+ }
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+nss2kmf_cert(CERTCertificate *nss_cert, KMF_X509_DER_CERT *kmf_cert)
+{
+ kmf_cert->kmf_private.keystore_type = KMF_KEYSTORE_NSS;
+ kmf_cert->kmf_private.flags = KMF_FLAG_CERT_VALID;
+
+ kmf_cert->certificate.Length = nss_cert->derCert.len;
+
+ if ((kmf_cert->certificate.Data = malloc(nss_cert->derCert.len)) ==
+ NULL) {
+ kmf_cert->certificate.Length = 0;
+ return (KMF_ERR_MEMORY);
+ }
+ (void) memcpy(kmf_cert->certificate.Data, nss_cert->derCert.data,
+ nss_cert->derCert.len);
+ if (nss_cert->nickname != NULL)
+ kmf_cert->kmf_private.label =
+ (char *)strdup(nss_cert->nickname);
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+nss_getcert_by_label(KMF_HANDLE *kmfh,
+ char *name, KMF_X509_DER_CERT *kmf_cert,
+ uint32_t *num_certs, KMF_CERT_VALIDITY find_criteria)
+{
+ KMF_RETURN rv = KMF_OK;
+ CERTCertificate *nss_cert;
+ SECCertTimeValidity validity;
+
+ nss_cert = PK11_FindCertFromNickname(name, NULL);
+ if (nss_cert == NULL) {
+ *num_certs = 0;
+ SET_ERROR(kmfh, PORT_GetError());
+ *num_certs = 0;
+ return (KMF_ERR_CERT_NOT_FOUND);
+ } else {
+ *num_certs = 1;
+ }
+
+ switch (find_criteria) {
+ case KMF_ALL_CERTS:
+ break;
+ case KMF_NONEXPIRED_CERTS:
+ validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(),
+ PR_FALSE);
+ if (validity != secCertTimeValid) {
+ /* this is an invalid cert, reject it */
+ *num_certs = 0;
+ CERT_DestroyCertificate(nss_cert);
+ return (KMF_OK);
+ }
+ break;
+ case KMF_EXPIRED_CERTS:
+ validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(),
+ PR_FALSE);
+ if (validity == secCertTimeValid) {
+ /* this is a valid cert, reject it in this case. */
+ *num_certs = 0;
+ CERT_DestroyCertificate(nss_cert);
+ return (KMF_OK);
+ }
+ break;
+ default:
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (kmf_cert != NULL)
+ rv = nss2kmf_cert(nss_cert, kmf_cert);
+
+ /* We copied the data we need, so cleanup the internal record */
+ CERT_DestroyCertificate(nss_cert);
+
+ if (rv != KMF_OK)
+ *num_certs = 0;
+
+ return (rv);
+}
+
+static KMF_RETURN
+nss_find_matching_certs(PK11SlotInfo *slot,
+ char *issuer, char *subject, KMF_BIGINT *serial,
+ CERTCertList **certlist, KMF_CERT_VALIDITY find_criteria)
+{
+ KMF_RETURN rv = KMF_OK;
+ SECStatus ret;
+ CERTCertList *list;
+ CERTCertListNode *node;
+ KMF_X509_NAME issuerDN, subjectDN;
+ boolean_t findIssuer = FALSE;
+ boolean_t findSubject = FALSE;
+ boolean_t findSerial = FALSE;
+
+ if (issuer != NULL && strlen(issuer)) {
+ rv = KMF_DNParser(issuer, &issuerDN);
+ if (rv != KMF_OK)
+ return (rv);
+ findIssuer = TRUE;
+ }
+ if (subject != NULL && strlen(subject)) {
+ rv = KMF_DNParser(subject, &subjectDN);
+ if (rv != KMF_OK)
+ return (rv);
+ findSubject = TRUE;
+ }
+ if (serial != 0 && serial->val != NULL && serial->len > 0)
+ findSerial = TRUE;
+
+ list = PK11_ListCertsInSlot(slot);
+ if (list) {
+ node = CERT_LIST_HEAD(list);
+ while (!CERT_LIST_END(node, list)) {
+ KMF_X509_NAME cmpDN;
+ KMF_DATA der;
+ boolean_t match;
+ CERTCertListNode *freenode;
+
+ if (findIssuer) {
+ der.Data = node->cert->derIssuer.data;
+ der.Length = node->cert->derIssuer.len;
+ rv = DerDecodeName(&der, &cmpDN);
+ if (rv == KMF_OK) {
+ match = !KMF_CompareRDNs(&issuerDN,
+ &cmpDN);
+ KMF_FreeDN(&cmpDN);
+ if (!match)
+ goto delete_and_cont;
+ } else {
+ goto delete_and_cont;
+ }
+ }
+ if (findSubject) {
+ der.Data = node->cert->derSubject.data;
+ der.Length = node->cert->derSubject.len;
+ rv = DerDecodeName(&der, &cmpDN);
+ if (rv == KMF_OK) {
+ match = !KMF_CompareRDNs(&subjectDN,
+ &cmpDN);
+ KMF_FreeDN(&cmpDN);
+ if (!match)
+ goto delete_and_cont;
+ } else {
+ goto delete_and_cont;
+ }
+ }
+ if (findSerial) {
+ SECItem *sernum;
+
+ sernum = &node->cert->serialNumber;
+
+ if (serial->len != sernum->len)
+ goto delete_and_cont;
+
+ if (memcmp(sernum->data, serial->val,
+ serial->len))
+ goto delete_and_cont;
+ }
+
+ /* select the certs using find criteria */
+ switch (find_criteria) {
+ case KMF_ALL_CERTS:
+ break;
+ case KMF_NONEXPIRED_CERTS:
+ ret = CERT_CertTimesValid(node->cert);
+ if (ret == SECFailure) {
+ /* this is an invalid cert */
+ goto skip;
+ }
+ break;
+
+ case KMF_EXPIRED_CERTS:
+ ret = CERT_CertTimesValid(node->cert);
+ if (ret != SECFailure) {
+ /* this is a valid cert */
+ goto skip;
+ }
+ break;
+ }
+skip:
+ node = CERT_LIST_NEXT(node);
+ continue;
+delete_and_cont:
+ freenode = node;
+ node = CERT_LIST_NEXT(node);
+ CERT_RemoveCertListNode(freenode);
+ }
+ }
+
+ if (rv == KMF_OK && certlist != NULL) {
+ *certlist = list;
+ } else {
+ CERT_DestroyCertList(list);
+ }
+ return (rv);
+}
+
+static KMF_RETURN
+convertCertList(void *kmfhandle,
+ CERTCertList *nsscerts, KMF_X509_DER_CERT *kmfcerts,
+ uint32_t *numcerts)
+{
+ KMF_RETURN rv = KMF_OK;
+ CERTCertListNode *node;
+
+ *numcerts = 0;
+
+ for (node = CERT_LIST_HEAD(nsscerts);
+ !CERT_LIST_END(node, nsscerts) && rv == KMF_OK;
+ node = CERT_LIST_NEXT(node), (*numcerts)++) {
+ if (kmfcerts != NULL)
+ rv = nss2kmf_cert(node->cert, &kmfcerts[*numcerts]);
+ }
+
+ /*
+ * If we failed, delete any certs allocated so far.
+ */
+ if (rv != KMF_OK) {
+ int i;
+ for (i = 0; i < *numcerts; i++)
+ KMF_FreeKMFCert(kmfhandle, &kmfcerts[i]);
+ }
+ return (rv);
+}
+
+KMF_RETURN
+NSS_FindCert(KMF_HANDLE_T handle, KMF_FINDCERT_PARAMS *params,
+ KMF_X509_DER_CERT *kmfcerts,
+ uint32_t *num_certs)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTCertList *certlist = NULL;
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ *num_certs = 0;
+ if (params->certLabel) {
+ rv = nss_getcert_by_label(kmfh,
+ params->certLabel,
+ kmfcerts, num_certs, params->find_cert_validity);
+ } else {
+ rv = nss_find_matching_certs(nss_slot,
+ params->issuer, params->subject, params->serial,
+ &certlist, params->find_cert_validity);
+
+ if (rv == KMF_OK && certlist != NULL) {
+ rv = convertCertList(handle,
+ certlist, kmfcerts, num_certs);
+ CERT_DestroyCertList(certlist);
+ }
+ }
+
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (rv == KMF_OK && *num_certs == 0)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+
+ return (rv);
+}
+
+void
+/*ARGSUSED*/
+NSS_FreeKMFCert(KMF_HANDLE_T handle,
+ KMF_X509_DER_CERT *kmf_cert)
+{
+ if (kmf_cert != NULL) {
+ if (kmf_cert->certificate.Data != NULL) {
+ free(kmf_cert->certificate.Data);
+ kmf_cert->certificate.Data = NULL;
+ kmf_cert->certificate.Length = 0;
+ }
+ if (kmf_cert->kmf_private.label != NULL) {
+ free(kmf_cert->kmf_private.label);
+ kmf_cert->kmf_private.label = NULL;
+ }
+ }
+}
+
+KMF_RETURN
+NSS_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params,
+ KMF_DATA *pcert)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ SECStatus nss_rv;
+ CERTCertificate *nss_cert = NULL;
+ CERTCertTrust *nss_trust = NULL;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
+
+ if (pcert == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* NSS only support DER format */
+ if (params == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ nss_cert = CERT_DecodeCertFromPackage((char *)pcert->Data,
+ pcert->Length);
+ if (nss_cert == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto out;
+ }
+
+ nss_rv = PK11_ImportCert(nss_slot, nss_cert, CK_INVALID_HANDLE,
+ params->certLabel, 0);
+ if (nss_rv) {
+ SET_ERROR(kmfh, nss_rv);
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto out;
+ }
+
+ if (params->ks_opt_u.nss_opts.trustflag != NULL &&
+ strlen(params->ks_opt_u.nss_opts.trustflag)) {
+ nss_trust = (CERTCertTrust *) malloc(sizeof (CERTCertTrust));
+ if (nss_trust == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ nss_rv = CERT_DecodeTrustString(nss_trust,
+ params->ks_opt_u.nss_opts.trustflag);
+ if (nss_rv) {
+ SET_ERROR(kmfh, nss_rv);
+ ret = KMF_ERR_BAD_PARAMETER;
+ goto out;
+ }
+
+ nss_rv = CERT_ChangeCertTrust(certHandle, nss_cert, nss_trust);
+ if (nss_rv) {
+ SET_ERROR(kmfh, nss_rv);
+ ret = KMF_ERR_BAD_PARAMETER;
+ }
+ }
+
+out:
+ if (nss_trust != NULL) {
+ free(nss_trust);
+ }
+
+ if (nss_cert != NULL) {
+ CERT_DestroyCertificate(nss_cert);
+ }
+
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ return (ret);
+}
+
+
+KMF_RETURN
+NSS_ImportCert(KMF_HANDLE_T handle, KMF_IMPORTCERT_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_STORECERT_PARAMS scparams;
+ KMF_DATA cert = {NULL, 0};
+ KMF_DATA cert_der = {NULL, 0};
+ KMF_DATA *cptr = NULL;
+ KMF_ENCODE_FORMAT format;
+
+ if (params == NULL || params->certfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * Check if the input cert file is a valid certificate and
+ * auto-detect the file format of it.
+ */
+ ret = KMF_IsCertFile(handle, params->certfile, &format);
+ if (ret != KMF_OK)
+ return (ret);
+
+ ret = KMF_ReadInputFile(handle, params->certfile, &cert);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ /*
+ * If the imported cert is in PEM format, convert it to
+ * DER format in order to store it in NSS token.
+ */
+ if (format == KMF_FORMAT_PEM) {
+ int derlen;
+ ret = KMF_Pem2Der(cert.Data, cert.Length,
+ &cert_der.Data, &derlen);
+ if (ret != KMF_OK) {
+ goto cleanup;
+ }
+ cert_der.Length = (size_t)derlen;
+ cptr = &cert_der;
+ } else {
+ cptr = &cert;
+ }
+
+ (void) memset(&scparams, 0, sizeof (scparams));
+ scparams.kstype = params->kstype;
+ scparams.certLabel = params->certLabel;
+ scparams.nssparms = params->nssparms;
+
+ ret = NSS_StoreCert(handle, &scparams, cptr);
+
+ if (format == KMF_FORMAT_PEM) {
+ KMF_FreeData(&cert_der);
+ }
+
+cleanup:
+ KMF_FreeData(&cert);
+
+ return (ret);
+}
+
+KMF_RETURN
+NSS_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params)
+{
+ KMF_RETURN rv = KMF_OK;
+ int nssrv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CERTCertificate *cert = NULL;
+ PK11SlotInfo *nss_slot = NULL;
+
+ /* check params */
+ if (params == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts,
+ FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ if (params->certLabel) {
+ cert = PK11_FindCertFromNickname(params->certLabel, NULL);
+ if (cert == NULL) {
+ return (KMF_ERR_CERT_NOT_FOUND);
+ }
+
+ switch (params->find_cert_validity) {
+ case KMF_ALL_CERTS:
+ break;
+ case KMF_NONEXPIRED_CERTS:
+ nssrv = CERT_CertTimesValid(cert);
+ if (nssrv == SECFailure) {
+ /* this is an invalid cert - skip it */
+ goto out;
+ }
+ break;
+ case KMF_EXPIRED_CERTS:
+ nssrv = CERT_CertTimesValid(cert);
+ if (nssrv != SECFailure) {
+ /* this is a valid cert - skip it */
+ goto out;
+ }
+ break;
+ }
+ /* delete it from database */
+ nssrv = SEC_DeletePermCertificate(cert);
+ if (nssrv) {
+ SET_ERROR(kmfh, nssrv);
+ rv = KMF_ERR_INTERNAL;
+ }
+ } else {
+ CERTCertListNode *node;
+ CERTCertList *certlist = NULL;
+
+ rv = nss_find_matching_certs(nss_slot,
+ params->issuer, params->subject, params->serial,
+ &certlist, params->find_cert_validity);
+
+ for (node = CERT_LIST_HEAD(certlist);
+ !CERT_LIST_END(node, certlist) && rv == KMF_OK;
+ node = CERT_LIST_NEXT(node)) {
+
+ nssrv = SEC_DeletePermCertificate(node->cert);
+ if (nssrv) {
+ SET_ERROR(kmfh, nssrv);
+ rv = KMF_ERR_INTERNAL;
+ }
+ }
+
+ if (rv == KMF_OK && certlist != NULL) {
+ CERT_DestroyCertList(certlist);
+ } else if (rv == KMF_OK && certlist == NULL) {
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ }
+ }
+out:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (cert != NULL) {
+ CERT_DestroyCertificate(cert);
+ }
+
+ return (rv);
+}
+
+static void
+InitRandom(char *filename)
+{
+ char buf[2048];
+ int fd;
+ PRInt32 count;
+
+ fd = open(filename, O_RDONLY);
+ if (!fd)
+ return;
+
+ count = read(fd, buf, sizeof (buf));
+ if (count > 0) {
+ PK11_RandomUpdate(buf, count);
+ }
+
+ (void) close(fd);
+}
+
+KMF_RETURN
+NSS_CreateKeypair(KMF_HANDLE_T handle,
+ KMF_CREATEKEYPAIR_PARAMS *params,
+ KMF_KEY_HANDLE *privkey,
+ KMF_KEY_HANDLE *pubkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ PK11RSAGenParams rsaparams;
+ void *nssparams;
+ CK_MECHANISM_TYPE mechanism;
+ ulong_t publicExponent = 0x010001;
+ PK11SlotInfo *nss_slot = NULL;
+ SECKEYPrivateKey *NSSprivkey = NULL;
+ SECKEYPublicKey *NSSpubkey = NULL;
+ PQGParams *pqgParams = NULL;
+
+
+ if (params == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ rv = nss_authenticate(handle, nss_slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /* Get some random bits */
+ InitRandom("/dev/urandom");
+ if (params->keytype == KMF_RSA) {
+ rsaparams.keySizeInBits = params->keylength;
+ /*
+ * NSS only allows for a 4 byte exponent.
+ * Ignore the exponent parameter if it is too big.
+ */
+ if (params->rsa_exponent.len > 0 &&
+ params->rsa_exponent.len <= sizeof (publicExponent) &&
+ params->rsa_exponent.val != NULL) {
+ (void) memcpy(&publicExponent,
+ params->rsa_exponent.val,
+ params->rsa_exponent.len);
+ }
+ rsaparams.pe = publicExponent;
+ mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
+ nssparams = &rsaparams;
+ } else if (params->keytype == KMF_DSA) {
+ PQGVerify *pqgVerify = NULL;
+ int ks;
+ SECStatus nssrv, passed;
+
+ mechanism = CKM_DSA_KEY_PAIR_GEN;
+
+ ks = PQG_PBITS_TO_INDEX(params->keylength);
+ nssrv = PK11_PQG_ParamGen(ks, &pqgParams, &pqgVerify);
+ if (nssrv != SECSuccess) {
+ SET_ERROR(kmfh, rv);
+ PK11_PQG_DestroyVerify(pqgVerify);
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+
+ nssrv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &passed);
+ if (nssrv != SECSuccess || passed != SECSuccess) {
+ SET_ERROR(kmfh, rv);
+ rv = KMF_ERR_KEYGEN_FAILED;
+ }
+
+ PK11_PQG_DestroyVerify(pqgVerify);
+
+ if (rv != KMF_OK) {
+ SET_ERROR(kmfh, PORT_GetError());
+ goto cleanup;
+ }
+
+ nssparams = pqgParams;
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ NSSprivkey = PK11_GenerateKeyPair(nss_slot,
+ mechanism, nssparams, &NSSpubkey,
+ PR_TRUE, /* isPermanent */
+ PR_TRUE, /* isSensitive */
+ (void *)params->cred.cred);
+
+ if (NSSprivkey == NULL || NSSpubkey == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ } else {
+ if (params->keylabel != NULL &&
+ strlen(params->keylabel)) {
+ (void) PK11_SetPrivateKeyNickname(NSSprivkey,
+ params->keylabel);
+ (void) PK11_SetPublicKeyNickname(NSSpubkey,
+ params->keylabel);
+ }
+ /* Now, convert it to a KMF_KEY object for the framework */
+ if (privkey != NULL) {
+ privkey->kstype = KMF_KEYSTORE_NSS;
+ privkey->keyalg = params->keytype;
+ privkey->keyclass = KMF_ASYM_PRI;
+ privkey->keylabel =
+ PK11_GetPrivateKeyNickname(NSSprivkey);
+ privkey->keyp = (void *)NSSprivkey;
+ }
+ if (pubkey != NULL) {
+ pubkey->kstype = KMF_KEYSTORE_NSS;
+ pubkey->keyalg = params->keytype;
+ pubkey->keyp = (void *)NSSpubkey;
+ pubkey->keyclass = KMF_ASYM_PUB;
+ pubkey->keylabel =
+ PK11_GetPublicKeyNickname(NSSpubkey);
+ }
+ rv = KMF_OK;
+ }
+cleanup:
+ if (rv != KMF_OK) {
+ if (NSSpubkey)
+ PK11_DeleteTokenPublicKey(NSSpubkey);
+ if (NSSprivkey)
+ PK11_DeleteTokenPrivateKey(NSSprivkey, PR_TRUE);
+
+ privkey->keyp = NULL;
+ pubkey->keyp = NULL;
+ }
+
+ if (pqgParams != NULL)
+ PK11_PQG_DestroyParams(pqgParams);
+
+
+ if (nss_slot != NULL)
+ PK11_FreeSlot(nss_slot);
+
+ return (rv);
+}
+
+KMF_RETURN
+NSS_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_OID *AlgOID, KMF_DATA *tobesigned,
+ KMF_DATA *output)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_ALGORITHM_INDEX AlgId;
+ SECOidTag signAlgTag;
+ SECKEYPrivateKey *NSSprivkey = NULL;
+ SECStatus rv;
+ SECItem signed_data;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ signed_data.data = 0;
+ if (key == NULL || AlgOID == NULL ||
+ tobesigned == NULL || output == NULL ||
+ tobesigned->Data == NULL ||
+ output->Data == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Map the OID to a NSS algorithm */
+ AlgId = X509_AlgorithmOidToAlgId(AlgOID);
+ if (AlgId == KMF_ALGID_NONE)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ NSSprivkey = (SECKEYPrivateKey *)key->keyp;
+
+ if (AlgId == KMF_ALGID_MD5WithRSA)
+ signAlgTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
+ else if (AlgId == KMF_ALGID_MD2WithRSA)
+ signAlgTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
+ else if (AlgId == KMF_ALGID_SHA1WithRSA)
+ signAlgTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+ else if (AlgId == KMF_ALGID_SHA1WithDSA)
+ signAlgTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
+ else
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = SEC_SignData(&signed_data, tobesigned->Data,
+ tobesigned->Length, NSSprivkey, signAlgTag);
+
+ if (rv != 0) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ if (signed_data.len <= output->Length) {
+ (void) memcpy(output->Data, signed_data.data, signed_data.len);
+ output->Length = signed_data.len;
+ } else {
+ output->Length = 0;
+ ret = KMF_ERR_BAD_PARAMETER;
+ }
+ free(signed_data.data);
+
+ return (ret);
+}
+
+KMF_RETURN
+NSS_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *keyp,
+ KMF_DATA *encoded)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ SECItem *rvitem;
+ CERTSubjectPublicKeyInfo *spki = NULL;
+
+ if (keyp == NULL || encoded == NULL || keyp->keyp == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ spki = SECKEY_CreateSubjectPublicKeyInfo(keyp->keyp);
+ if (spki == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ return (KMF_ERR_MEMORY);
+ }
+
+ rvitem = SEC_ASN1EncodeItem(NULL, NULL, spki,
+ CERT_SubjectPublicKeyInfoTemplate);
+
+ if (rvitem != NULL) {
+ encoded->Data = malloc(rvitem->len);
+ if (encoded->Data == NULL) {
+ ret = KMF_ERR_MEMORY;
+ } else {
+ (void) memcpy(encoded->Data, rvitem->data, rvitem->len);
+ encoded->Length = rvitem->len;
+ }
+ SECITEM_FreeItem(rvitem, TRUE);
+ } else {
+ SET_ERROR(kmfh, PORT_GetError());
+ encoded->Data = NULL;
+ encoded->Length = 0;
+ ret = KMF_ERR_ENCODING;
+ }
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+
+ return (ret);
+}
+
+KMF_RETURN
+NSS_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params,
+ KMF_KEY_HANDLE *key, boolean_t delete_token)
+{
+ KMF_RETURN rv = KMF_OK;
+ PK11SlotInfo *nss_slot = NULL;
+
+ /*
+ * "delete_token" means to clear it from the token storage as well
+ * as from memory.
+ */
+ if (key == NULL || key->keyp == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (delete_token) {
+ SECStatus nssrv = SECSuccess;
+ if (key->keyclass != KMF_ASYM_PUB &&
+ key->keyclass != KMF_ASYM_PRI &&
+ key->keyclass != KMF_SYMMETRIC)
+ return (KMF_ERR_BAD_KEY_CLASS);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+ rv = nss_authenticate(handle, nss_slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ if (key->keyclass == KMF_ASYM_PUB) {
+ nssrv = PK11_DeleteTokenPublicKey(
+ (SECKEYPublicKey *)key->keyp);
+ } else if (key->keyclass == KMF_ASYM_PRI) {
+ nssrv = PK11_DeleteTokenPrivateKey(
+ (SECKEYPrivateKey *)key->keyp, PR_TRUE);
+ } else if (key->keyclass == KMF_SYMMETRIC) {
+ nssrv = PK11_DeleteTokenSymKey(
+ (PK11SymKey *) key->keyp);
+ if (nssrv == SECSuccess)
+ PK11_FreeSymKey(
+ (PK11SymKey *) key->keyp);
+ }
+ if (nssrv != SECSuccess) {
+ SET_ERROR(handle, PORT_GetError());
+ rv = KMF_ERR_INTERNAL;
+ }
+ } else {
+ if (key->keyclass == KMF_ASYM_PUB) {
+ SECKEY_DestroyPublicKey((SECKEYPublicKey *)key->keyp);
+ } else if (key->keyclass == KMF_ASYM_PRI) {
+ SECKEY_DestroyPrivateKey((SECKEYPrivateKey *)key->keyp);
+ } else if (key->keyclass == KMF_SYMMETRIC) {
+ PK11_FreeSymKey((PK11SymKey *) key->keyp);
+ } else {
+ return (KMF_ERR_BAD_KEY_CLASS);
+ }
+ }
+ key->keyp = NULL;
+
+ return (rv);
+}
+
+KMF_RETURN
+NSS_ImportCRL(KMF_HANDLE_T handle, KMF_IMPORTCRL_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTSignedCrl *nss_crl = NULL;
+ KMF_ENCODE_FORMAT format;
+ int importOptions;
+ SECItem crlDER;
+ KMF_DATA crl1;
+ KMF_DATA crl2;
+
+ if (params == NULL || params->ks_opt_u.nss_opts.crlfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * Check if the input CRL file is a valid CRL file and auto-detect
+ * the encoded format of the file.
+ */
+ ret = KMF_IsCRLFile(handle, params->ks_opt_u.nss_opts.crlfile,
+ &format);
+ if (ret != KMF_OK)
+ return (ret);
+
+ ret = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, TRUE, &nss_slot);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ /* set importOptions */
+ if (params->ks_opt_u.nss_opts.crl_check == B_FALSE) {
+ importOptions = CRL_IMPORT_DEFAULT_OPTIONS |
+ CRL_IMPORT_BYPASS_CHECKS;
+ } else {
+ importOptions = CRL_IMPORT_DEFAULT_OPTIONS;
+ }
+
+
+ /* Read in the CRL file */
+ crl1.Data = NULL;
+ crl2.Data = NULL;
+ ret = KMF_ReadInputFile(handle, params->ks_opt_u.nss_opts.crlfile,
+ &crl1);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ /* If the input CRL is in PEM format, convert it to DER first. */
+ if (format == KMF_FORMAT_PEM) {
+ int len;
+ ret = KMF_Pem2Der(crl1.Data, crl1.Length,
+ &crl2.Data, &len);
+ if (ret != KMF_OK) {
+ goto out;
+ }
+ crl2.Length = (size_t)len;
+ }
+
+ crlDER.data = format == KMF_FORMAT_ASN1 ? crl1.Data : crl2.Data;
+ crlDER.len = format == KMF_FORMAT_ASN1 ? crl1.Length : crl2.Length;
+
+ nss_crl = PK11_ImportCRL(nss_slot, &crlDER, NULL, SEC_CRL_TYPE,
+ NULL, importOptions, NULL, CRL_DECODE_DEFAULT_OPTIONS);
+
+ if (nss_crl == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto out;
+ }
+
+out:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (crl1.Data != NULL) {
+ free(crl1.Data);
+ }
+
+ if (crl2.Data != NULL) {
+ free(crl2.Data);
+ }
+
+ if (nss_crl != NULL) {
+ SEC_DestroyCrl(nss_crl);
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+NSS_DeleteCRL(KMF_HANDLE_T handle, KMF_DELETECRL_PARAMS *params)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CERTSignedCrl *crl = NULL;
+ CERTCertificate *cert = NULL;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTCrlHeadNode *crlList = NULL;
+ CERTCrlNode *crlNode = NULL;
+ PRArenaPool *arena = NULL;
+ CERTName *name = NULL;
+ CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
+
+ /* check params */
+ if (params == NULL ||
+ (params->ks_opt_u.nss_opts.crl_issuerName == NULL &&
+ params->ks_opt_u.nss_opts.crl_subjName == NULL) ||
+ (params->ks_opt_u.nss_opts.crl_issuerName != NULL &&
+ params->ks_opt_u.nss_opts.crl_subjName != NULL)) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, TRUE,
+ &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /* Find the CRL based on the deletion criteria. */
+ if (params->ks_opt_u.nss_opts.crl_issuerName != NULL) {
+ /*
+ * If the deletion is based on the issuer's certificate
+ * nickname, we will get the issuer's cert first, then
+ * get the CRL from the cert.
+ */
+ cert = CERT_FindCertByNicknameOrEmailAddr(certHandle,
+ params->ks_opt_u.nss_opts.crl_issuerName);
+ if (!cert) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ goto out;
+ }
+
+ crl = SEC_FindCrlByName(certHandle, &cert->derSubject,
+ SEC_CRL_TYPE);
+ if (crl == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ goto out;
+ }
+ } else {
+ /*
+ * If the deletion is based on the CRL's subject name, we will
+ * get all the CRLs from the internal database and search
+ * for the CRL with the same subject name.
+ */
+ boolean_t found = B_FALSE;
+ int nssrv;
+
+ nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE);
+ if (nssrv) {
+ SET_ERROR(kmfh, nssrv);
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ goto out;
+ }
+
+ if (crlList == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ goto out;
+ }
+
+ /* Allocate space for name */
+ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (arena == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ name = PORT_ArenaZAlloc(arena, sizeof (*name));
+ if (name == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+ name->arena = arena;
+
+ crlNode = crlList->first;
+ while (crlNode && !found) {
+ char *asciiname = NULL;
+ SECItem* issuer;
+
+ name = &crlNode->crl->crl.name;
+ if (!name) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ break;
+ }
+
+ asciiname = CERT_NameToAscii(name);
+ if (asciiname == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ break;
+ }
+
+ if (strcmp(params->ks_opt_u.nss_opts.crl_subjName,
+ asciiname) == 0) {
+ found = B_TRUE;
+ issuer = &crlNode->crl->crl.derName;
+ crl = SEC_FindCrlByName(certHandle, issuer,
+ SEC_CRL_TYPE);
+ if (crl == NULL) {
+ /* We found a cert but no CRL */
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ }
+ }
+ PORT_Free(asciiname);
+ crlNode = crlNode->next;
+ }
+
+ if (rv) {
+ goto out;
+ }
+ }
+
+ if (crl) {
+ (void) SEC_DeletePermCRL(crl);
+ }
+
+out:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (crlList != NULL) {
+ PORT_FreeArena(crlList->arena, PR_FALSE);
+ }
+
+ if (arena != NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ if (cert != NULL) {
+ CERT_DestroyCertificate(cert);
+ }
+
+ if (crl != NULL) {
+ SEC_DestroyCrl(crl);
+ }
+
+ return (rv);
+}
+
+
+KMF_RETURN
+NSS_FindCRL(KMF_HANDLE_T handle, KMF_FINDCRL_PARAMS *params,
+ char **CRLNameList, int *CRLCount)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTCrlHeadNode *crlList = NULL;
+ CERTCrlNode *crlNode = NULL;
+ PRArenaPool *arena = NULL;
+ CERTName *name = NULL;
+ SECStatus nssrv;
+ char *asciiname = NULL;
+ int crl_num;
+ int i;
+ CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
+
+ if (CRLCount == NULL || params == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ *CRLCount = 0;
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, TRUE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /* Look up Crls */
+ nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE);
+ if (nssrv) {
+ SET_ERROR(kmfh, rv);
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ goto out;
+ }
+
+ /* Allocate space for name first */
+ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (arena == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ name = PORT_ArenaZAlloc(arena, sizeof (*name));
+ if (name == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+ name->arena = arena;
+
+ /*
+ * Loop thru the crlList and create a crl list with CRL's subject name.
+ */
+ crlNode = crlList->first;
+ crl_num = 0;
+ while (crlNode) {
+ char *subj_name;
+
+ /* Get the CRL subject name */
+ name = &crlNode->crl->crl.name;
+ if (!name) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ break;
+ }
+
+
+ if (CRLNameList != NULL) {
+ asciiname = CERT_NameToAscii(name);
+ if (asciiname == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ break;
+ }
+ subj_name = strdup(asciiname);
+ PORT_Free(asciiname);
+ if (subj_name == NULL) {
+ rv = KMF_ERR_MEMORY;
+ break;
+ }
+ CRLNameList[crl_num] = subj_name;
+ }
+
+ crl_num++;
+ crlNode = crlNode->next;
+ }
+
+ if (rv == KMF_OK) {
+ /* success */
+ *CRLCount = crl_num;
+ }
+
+out:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (crlList != NULL) {
+ PORT_FreeArena(crlList->arena, PR_FALSE);
+ }
+
+ if (arena != NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ /* If failed, free memory allocated for the returning rlist */
+ if (rv && (CRLNameList != NULL)) {
+ for (i = 0; i < crl_num; i++) {
+ free(CRLNameList[i]);
+ }
+ }
+
+ return (rv);
+}
+
+
+KMF_RETURN
+NSS_FindCertInCRL(KMF_HANDLE_T handle, KMF_FINDCERTINCRL_PARAMS *params)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTCertificate *cert = NULL;
+ CERTSignedCrl *crl = NULL;
+ CERTCrlEntry *entry;
+ boolean_t match = B_FALSE;
+ int i;
+ CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
+
+ /* check params */
+ if (params == NULL || params->certLabel == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, TRUE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ cert = CERT_FindCertByNicknameOrEmailAddr(certHandle,
+ params->certLabel);
+ if (!cert) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ goto out;
+ }
+
+ /* Find the CRL with the same issuer as the given certificate. */
+ crl = SEC_FindCrlByName(certHandle, &cert->derIssuer, SEC_CRL_TYPE);
+ if (crl == NULL) {
+ /*
+ * Could not find the CRL issued by the same issuer. This
+ * usually means that the CRL is not installed in the DB.
+ */
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ goto out;
+
+ }
+
+ /* Check if the certificate's serialNumber is revoked in the CRL */
+ i = 0;
+ while ((entry = (crl->crl).entries[i++]) != NULL) {
+ if (SECITEM_CompareItem(&(cert->serialNumber),
+ &(entry->serialNumber)) == SECEqual) {
+ match = B_TRUE;
+ break;
+ }
+ }
+
+ if (!match) {
+ rv = KMF_ERR_NOT_REVOKED;
+ }
+
+out:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (cert != NULL) {
+ CERT_DestroyCertificate(cert);
+ }
+
+ if (crl != NULL) {
+ SEC_DestroyCrl(crl);
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+NSS_GetErrorString(KMF_HANDLE_T handle, char **msgstr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ char *str;
+
+ /* Get the error string in the default language */
+ str = (char *)PR_ErrorToName((PRErrorCode)kmfh->lasterr.errcode);
+
+ if (str != NULL) {
+ *msgstr = (char *)strdup(str);
+ if ((*msgstr) == NULL)
+ ret = KMF_ERR_MEMORY;
+ } else {
+ *msgstr = NULL;
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+NSS_GetPrikeyByCert(KMF_HANDLE_T handle, KMF_CRYPTOWITHCERT_PARAMS *params,
+ KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key,
+ KMF_KEY_ALG keytype)
+{
+ CERTCertificate *nss_cert = NULL;
+ SECKEYPrivateKey* privkey = NULL;
+ PK11SlotInfo *nss_slot = NULL;
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ rv = Do_NSS_Init(handle,
+ params->nssparms, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ rv = nss_authenticate(handle, nss_slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ nss_cert = CERT_DecodeCertFromPackage((char *)SignerCertData->Data,
+ SignerCertData->Length);
+
+ if (nss_cert == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ return (KMF_ERR_BAD_CERT_FORMAT);
+ }
+
+ privkey = PK11_FindPrivateKeyFromCert(nss_slot, nss_cert, NULL);
+ if (privkey == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ return (KMF_ERR_KEY_NOT_FOUND);
+ }
+
+ key->kstype = KMF_KEYSTORE_NSS;
+ key->keyclass = KMF_ASYM_PRI;
+ key->keyalg = keytype;
+ key->keyp = (void *)privkey;
+ key->keylabel = PK11_GetPrivateKeyNickname(privkey);
+
+ CERT_DestroyCertificate(nss_cert);
+
+ return (KMF_OK);
+
+}
+
+KMF_RETURN
+NSS_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_OID *AlgOID, KMF_DATA *ciphertext,
+ KMF_DATA *output)
+{
+ KMF_RETURN ret = KMF_OK;
+ SECKEYPrivateKey *NSSprivkey = NULL;
+ SECStatus rv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ unsigned int in_len = 0, out_len = 0;
+ unsigned int total_decrypted = 0, modulus_len = 0;
+ uint8_t *in_data, *out_data;
+ int i, blocks;
+
+
+ if (key == NULL || AlgOID == NULL ||
+ ciphertext == NULL || output == NULL ||
+ ciphertext->Data == NULL ||
+ output->Data == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ NSSprivkey = (SECKEYPrivateKey *)key->keyp;
+ modulus_len = PK11_GetPrivateModulusLen(NSSprivkey);
+
+ blocks = ciphertext->Length/modulus_len;
+ out_data = output->Data;
+ in_data = ciphertext->Data;
+ out_len = modulus_len - 11;
+ in_len = modulus_len;
+
+ for (i = 0; i < blocks; i++) {
+ rv = PK11_PrivDecryptPKCS1(NSSprivkey, out_data,
+ &out_len, ciphertext->Length, in_data, in_len);
+
+ if (rv != 0) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ out_data += out_len;
+ total_decrypted += out_len;
+ in_data += in_len;
+ }
+
+ output->Length = total_decrypted;
+
+ return (ret);
+}
+
+static KMF_KEY_ALG
+pk11keytype2kmf(CK_KEY_TYPE type)
+{
+ switch (type) {
+ case CKK_RSA:
+ return (KMF_RSA);
+ case CKK_DSA:
+ return (KMF_RSA);
+ case CKK_AES:
+ return (KMF_AES);
+ case CKK_RC4:
+ return (KMF_RC4);
+ case CKK_DES:
+ return (KMF_DES);
+ case CKK_DES3:
+ return (KMF_DES3);
+ default:
+ /* not supported */
+ return (KMF_KEYALG_NONE);
+ }
+}
+
+KMF_RETURN
+NSS_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms,
+ KMF_KEY_HANDLE *keys, uint32_t *numkeys)
+{
+ KMF_RETURN rv;
+ SECKEYPrivateKeyList *prilist;
+ SECKEYPrivateKeyListNode *prinode;
+ SECKEYPublicKeyList *publist;
+ SECKEYPublicKeyListNode *pubnode;
+ PK11SlotInfo *nss_slot = NULL;
+ PK11SymKey *symlist;
+ int count;
+
+ if (handle == NULL || parms == NULL || numkeys == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = Do_NSS_Init(handle,
+ parms->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ rv = nss_authenticate(handle, nss_slot, &parms->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ *numkeys = 0;
+ if (parms->keyclass == KMF_ASYM_PUB) {
+ publist = PK11_ListPublicKeysInSlot(nss_slot, parms->findLabel);
+ if (publist == NULL) {
+ rv = KMF_ERR_KEY_NOT_FOUND;
+ goto cleanup;
+ }
+ } else if (parms->keyclass == KMF_ASYM_PRI) {
+ prilist = PK11_ListPrivKeysInSlot(nss_slot,
+ parms->findLabel, NULL);
+ if (prilist == NULL) {
+ rv = KMF_ERR_KEY_NOT_FOUND;
+ goto cleanup;
+ }
+ } else if (parms->keyclass == KMF_SYMMETRIC) {
+ symlist = PK11_ListFixedKeysInSlot(nss_slot, parms->findLabel,
+ NULL);
+ if (symlist == NULL) {
+ rv = KMF_ERR_KEY_NOT_FOUND;
+ goto cleanup;
+ }
+ } else {
+ rv = KMF_ERR_BAD_KEY_CLASS;
+ goto cleanup;
+ }
+
+ if (parms->keyclass == KMF_ASYM_PUB) {
+ for (count = 0, pubnode = PUBKEY_LIST_HEAD(publist);
+ !PUBKEY_LIST_END(pubnode, publist);
+ pubnode = PUBKEY_LIST_NEXT(pubnode), count++) {
+ if (keys != NULL) {
+ keys[count].kstype = KMF_KEYSTORE_NSS;
+ keys[count].keyclass = KMF_ASYM_PUB;
+ keys[count].keyp = (void *)pubnode->key;
+ keys[count].keylabel =
+ PK11_GetPublicKeyNickname(
+ pubnode->key);
+
+ if (pubnode->key->keyType == rsaKey)
+ keys[count].keyalg = KMF_RSA;
+ else if (pubnode->key->keyType == dsaKey)
+ keys[count].keyalg = KMF_DSA;
+ }
+ }
+ *numkeys = count;
+ } else if (parms->keyclass == KMF_ASYM_PRI) {
+ for (count = 0, prinode = PRIVKEY_LIST_HEAD(prilist);
+ !PRIVKEY_LIST_END(prinode, prilist);
+ prinode = PRIVKEY_LIST_NEXT(prinode), count++) {
+ if (keys != NULL) {
+ keys[count].kstype = KMF_KEYSTORE_NSS;
+ keys[count].keyclass = KMF_ASYM_PRI;
+ keys[count].keyp = (void *)prinode->key;
+ keys[count].keylabel =
+ PK11_GetPrivateKeyNickname(
+ prinode->key);
+
+ if (prinode->key->keyType == rsaKey)
+ keys[count].keyalg = KMF_RSA;
+ else if (prinode->key->keyType == dsaKey)
+ keys[count].keyalg = KMF_DSA;
+ }
+ }
+ *numkeys = count;
+ } else if (parms->keyclass == KMF_SYMMETRIC) {
+ count = 0;
+ while (symlist) {
+ PK11SymKey *symkey = symlist;
+ CK_KEY_TYPE type;
+ KMF_KEY_ALG keyalg;
+
+ type = PK11_GetSymKeyType(symkey);
+ keyalg = pk11keytype2kmf(type);
+
+ /*
+ * If keytype is specified in the searching parameter,
+ * check the keytype and skip the key if its keytype
+ * doesn't match.
+ */
+ symlist = PK11_GetNextSymKey(symkey);
+ if (parms->keytype != KMF_KEYALG_NONE &&
+ parms->keytype != keyalg) {
+ continue;
+ }
+
+ if (keys != NULL) {
+ keys[count].kstype = KMF_KEYSTORE_NSS;
+ keys[count].keyclass = KMF_SYMMETRIC;
+ keys[count].keyp = (void *) symkey;
+ keys[count].keylabel =
+ PK11_GetSymKeyNickname(symkey);
+ keys[count].keyalg = keyalg;
+ } else {
+ PK11_FreeSymKey(symkey);
+ }
+ count++;
+ }
+ *numkeys = count;
+ }
+
+cleanup:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ return (rv);
+}
+
+static SECStatus
+p12u_SwapUnicodeBytes(SECItem *uniItem)
+{
+ unsigned int i;
+ unsigned char a;
+ if ((uniItem == NULL) || (uniItem->len % 2)) {
+ return (SECFailure);
+ }
+ for (i = 0; i < uniItem->len; i += 2) {
+ a = uniItem->data[i];
+ uniItem->data[i] = uniItem->data[i+1];
+ uniItem->data[i+1] = a;
+ }
+ return (SECSuccess);
+}
+
+static PRBool
+p12u_ucs2_ascii_conversion_function(
+ PRBool toUnicode,
+ unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen,
+ PRBool swapBytes)
+{
+ SECItem it = { 0 };
+ SECItem *dup = NULL;
+ PRBool ret;
+
+ it.data = inBuf;
+ it.len = inBufLen;
+ dup = SECITEM_DupItem(&it);
+ /*
+ * If converting Unicode to ASCII, swap bytes before conversion
+ * as neccessary.
+ */
+ if (!toUnicode && swapBytes) {
+ if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
+ SECITEM_ZfreeItem(dup, PR_TRUE);
+ return (PR_FALSE);
+ }
+ }
+ /* Perform the conversion. */
+ ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len,
+ outBuf, maxOutBufLen, outBufLen);
+ if (dup)
+ SECITEM_ZfreeItem(dup, PR_TRUE);
+
+ return (ret);
+}
+
+static PRBool
+p12u_OpenFile(p12uContext *p12ctx, PRBool fileRead)
+{
+ if (!p12ctx || !p12ctx->filename) {
+ return (PR_FALSE);
+ }
+
+ if (fileRead) {
+ p12ctx->file = PR_Open(p12ctx->filename,
+ PR_RDONLY, 0400);
+ } else {
+ p12ctx->file = PR_Open(p12ctx->filename,
+ PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 0600);
+ }
+
+ if (!p12ctx->file) {
+ p12ctx->error = PR_TRUE;
+ return (PR_FALSE);
+ }
+
+ return (PR_TRUE);
+}
+
+static void
+p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile)
+{
+ if (!ppCtx || !(*ppCtx)) {
+ return;
+ }
+
+ if ((*ppCtx)->file != NULL) {
+ PR_Close((*ppCtx)->file);
+ }
+
+ if ((*ppCtx)->filename != NULL) {
+ if (removeFile) {
+ PR_Delete((*ppCtx)->filename);
+ }
+ free((*ppCtx)->filename);
+ }
+
+ free(*ppCtx);
+ *ppCtx = NULL;
+}
+
+static p12uContext *
+p12u_InitContext(PRBool fileImport, char *filename)
+{
+ p12uContext *p12ctx;
+
+ p12ctx = PORT_ZNew(p12uContext);
+ if (!p12ctx) {
+ return (NULL);
+ }
+
+ p12ctx->error = PR_FALSE;
+ p12ctx->errorValue = 0;
+ p12ctx->filename = strdup(filename);
+
+ if (!p12u_OpenFile(p12ctx, fileImport)) {
+ p12u_DestroyContext(&p12ctx, PR_FALSE);
+ return (NULL);
+ }
+
+ return (p12ctx);
+}
+
+static void
+p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len)
+{
+ p12uContext *p12cxt = arg;
+ int writeLen;
+
+ if (!p12cxt || (p12cxt->error == PR_TRUE)) {
+ return;
+ }
+
+ if (p12cxt->file == NULL) {
+ p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
+ p12cxt->error = PR_TRUE;
+ return;
+ }
+
+ writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (int32)len);
+
+ if (writeLen != (int)len) {
+ PR_Close(p12cxt->file);
+ free(p12cxt->filename);
+ p12cxt->filename = NULL;
+ p12cxt->file = NULL;
+ p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
+ p12cxt->error = PR_TRUE;
+ }
+}
+
+#define HANDLE_NSS_ERROR(r) {\
+ SET_ERROR(kmfh, PORT_GetError()); \
+ rv = r; \
+ goto out; }
+
+static KMF_RETURN
+add_cert_to_bag(SEC_PKCS12ExportContext *p12ecx,
+ CERTCertificate *cert, SECItem *pwitem)
+{
+ KMF_RETURN rv = KMF_OK;
+ SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL;
+
+ keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
+ if (PK11_IsFIPS()) {
+ certSafe = keySafe;
+ } else {
+ certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC);
+ }
+
+ if (!certSafe || !keySafe) {
+ rv = KMF_ERR_INTERNAL;
+ goto out;
+ }
+
+ if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert,
+ CERT_GetDefaultCertDB(), keySafe, NULL, PR_TRUE, pwitem,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC)
+ != SECSuccess) {
+ rv = KMF_ERR_INTERNAL;
+ }
+out:
+ return (rv);
+}
+
+/*ARGSUSED*/
+KMF_RETURN
+NSS_ExportP12(KMF_HANDLE_T handle,
+ KMF_EXPORTP12_PARAMS *params,
+ int numcerts, KMF_X509_DER_CERT *certs,
+ int numkeys, KMF_KEY_HANDLE *keylist,
+ char *filename)
+{
+ KMF_RETURN rv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ SEC_PKCS12ExportContext *p12ecx = NULL;
+ p12uContext *p12ctx = NULL;
+ CERTCertList *certlist = NULL;
+ CERTCertificate *nsscert = NULL;
+ CERTCertListNode* node = NULL;
+ PK11SlotInfo *slot = NULL;
+ SECItem pwitem = {NULL, 0};
+
+ rv = Do_NSS_Init(handle,
+ params->nssparms, FALSE, &slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ rv = nss_authenticate(handle, slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /*
+ * Find the certificate(s) first.
+ */
+ if (params->certLabel) {
+ nsscert = PK11_FindCertFromNickname(params->certLabel,
+ NULL);
+ if (nsscert == NULL) {
+ HANDLE_NSS_ERROR(KMF_ERR_CERT_NOT_FOUND)
+ }
+ } else {
+ rv = nss_find_matching_certs(slot,
+ params->issuer,
+ params->subject,
+ params->serial,
+ &certlist, 0);
+
+ if (rv == KMF_OK && certlist == NULL) {
+ return (KMF_ERR_CERT_NOT_FOUND);
+ }
+ if (rv != KMF_OK)
+ return (rv);
+ }
+
+ /*
+ * The KMF_CREDENTIAL holds the password to use for
+ * encrypting the PKCS12 key information.
+ */
+ pwitem.data = (uchar_t *)params->p12cred.cred;
+ pwitem.len = params->p12cred.credlen;
+
+ p12ctx = p12u_InitContext(PR_FALSE, filename);
+ if (!p12ctx) {
+ HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE)
+ }
+
+ PORT_SetUCS2_ASCIIConversionFunction(
+ p12u_ucs2_ascii_conversion_function);
+
+ p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL,
+ slot, NULL);
+ if (!p12ecx) {
+ HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE)
+ }
+
+ if (SEC_PKCS12AddPasswordIntegrity(p12ecx, &pwitem, SEC_OID_SHA1)
+ != SECSuccess) {
+ HANDLE_NSS_ERROR(KMF_ERR_INTERNAL)
+ }
+
+ /*
+ * NSS actually supports storing a list of keys and certs
+ * in the PKCS#12 PDU. Nice feature.
+ */
+ if (certlist != NULL) {
+ for (node = CERT_LIST_HEAD(certlist);
+ !CERT_LIST_END(node, certlist) && rv == KMF_OK;
+ node = CERT_LIST_NEXT(node)) {
+
+ rv = add_cert_to_bag(p12ecx, node->cert, &pwitem);
+ }
+ } else if (nsscert != NULL) {
+ rv = add_cert_to_bag(p12ecx, nsscert, &pwitem);
+ }
+
+ if (SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12ctx)
+ != SECSuccess) {
+ HANDLE_NSS_ERROR(KMF_ERR_ENCODING)
+ }
+out:
+ if (nsscert)
+ CERT_DestroyCertificate(nsscert);
+
+ if (certlist)
+ CERT_DestroyCertList(certlist);
+
+ if (p12ctx)
+ p12u_DestroyContext(&p12ctx, PR_FALSE);
+
+ if (p12ecx)
+ SEC_PKCS12DestroyExportContext(p12ecx);
+
+ return (rv);
+}
+
+#define SETATTR(t, n, atype, value, size) \
+ t[n].type = atype; \
+ t[n].pValue = (CK_BYTE *)value; \
+ t[n].ulValueLen = (CK_ULONG)size;
+
+KMF_RETURN
+NSS_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params,
+ KMF_RAW_KEY_DATA *rawkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ SECStatus ckrv = SECSuccess;
+ PK11SlotInfo *slot = NULL;
+ CERTCertificate *nss_cert = NULL;
+ SECKEYPrivateKeyInfo rpk;
+ SECItem nickname;
+ KMF_DATA derkey = { NULL, 0 };
+ uchar_t ver = 0;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (params == NULL || params->certificate == NULL || rawkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = Do_NSS_Init(handle,
+ params->nssparms, FALSE, &slot);
+
+ if (rv != KMF_OK)
+ return (rv);
+
+ rv = nss_authenticate(handle, slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /*
+ * Decode the cert into an NSS CERT object so we can access the
+ * SPKI and KeyUsage data later.
+ */
+ nss_cert = CERT_DecodeCertFromPackage((char *)params->certificate->Data,
+ params->certificate->Length);
+
+ if (nss_cert == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ (void) memset(&rpk, 0, sizeof (rpk));
+
+ rpk.arena = NULL;
+ rpk.version.type = siUnsignedInteger;
+ rpk.version.data = &ver;
+ rpk.version.len = 1;
+ if (rawkey->keytype == KMF_RSA) {
+
+ rv = DerEncodeRSAPrivateKey(&derkey, &rawkey->rawdata.rsa);
+ if (rv != KMF_OK)
+ goto cleanup;
+
+ rpk.algorithm = nss_cert->subjectPublicKeyInfo.algorithm;
+ rpk.privateKey.data = derkey.Data;
+ rpk.privateKey.len = derkey.Length;
+ rpk.attributes = NULL;
+
+
+ } else if (rawkey->keytype == KMF_DSA) {
+ rv = DerEncodeDSAPrivateKey(&derkey, &rawkey->rawdata.dsa);
+ if (rv != KMF_OK)
+ goto cleanup;
+
+ rpk.algorithm = nss_cert->subjectPublicKeyInfo.algorithm;
+ rpk.privateKey.data = derkey.Data;
+ rpk.privateKey.len = derkey.Length;
+ rpk.attributes = NULL;
+
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ nickname.data = (uchar_t *)params->label;
+ nickname.len = (params->label ? strlen(params->label) : 0);
+
+ ckrv = PK11_ImportPrivateKeyInfo(slot, &rpk,
+ &nickname, &nss_cert->subjectPublicKeyInfo.subjectPublicKey,
+ TRUE, TRUE, nss_cert->keyUsage, NULL);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_INTERNAL;
+ }
+
+cleanup:
+ if (nss_cert != NULL) {
+ CERT_DestroyCertificate(nss_cert);
+ }
+ KMF_FreeData(&derkey);
+ return (rv);
+}
+
+KMF_RETURN
+NSS_CreateSymKey(KMF_HANDLE_T handle,
+ KMF_CREATESYMKEY_PARAMS *params,
+ KMF_KEY_HANDLE *symkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ PK11SlotInfo *nss_slot = NULL;
+ PK11SymKey *nsskey = NULL;
+ CK_MECHANISM_TYPE keyType;
+ SECStatus nssrv;
+ int keySize;
+
+ if (params == NULL || symkey == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ switch (params->keytype) {
+ case KMF_AES:
+ keyType = CKM_AES_KEY_GEN;
+ keySize = params->keylength;
+ if (keySize == 0 || (keySize % 8) != 0)
+ return (KMF_ERR_BAD_KEY_SIZE);
+ break;
+ case KMF_RC4:
+ keyType = CKM_RC4_KEY_GEN;
+ keySize = params->keylength;
+ if (keySize == 0 || (keySize % 8) != 0)
+ return (KMF_ERR_BAD_KEY_SIZE);
+ break;
+ case KMF_DES:
+ keyType = CKM_DES_KEY_GEN;
+ keySize = 0; /* required by PK11_TokenKeyGen() */
+ break;
+ case KMF_DES3:
+ keyType = CKM_DES3_KEY_GEN;
+ keySize = 0; /* required by PK11_TokenKeyGen() */
+ break;
+ default:
+ rv = KMF_ERR_BAD_KEY_TYPE;
+ goto out;
+ }
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ rv = nss_authenticate(handle, nss_slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ nsskey = PK11_TokenKeyGen(nss_slot, keyType, NULL, keySize, NULL,
+ PR_TRUE, (void *)params->cred.cred);
+ if (nsskey == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto out;
+ }
+
+ nssrv = PK11_SetSymKeyNickname(nsskey, params->keylabel);
+ if (nssrv != SECSuccess) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto out;
+ }
+
+ symkey->kstype = KMF_KEYSTORE_NSS;
+ symkey->keyalg = params->keytype;
+ symkey->keyclass = KMF_SYMMETRIC;
+ symkey->israw = FALSE;
+ symkey->keyp = (void *)nsskey;
+
+out:
+ if (nss_slot != NULL)
+ PK11_FreeSlot(nss_slot);
+
+ if (rv != KMF_OK && nsskey != NULL) {
+ PK11_DeleteTokenSymKey(nsskey);
+ PK11_FreeSymKey(nsskey);
+ }
+ return (rv);
+}
+
+KMF_RETURN
+NSS_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey,
+ KMF_RAW_SYM_KEY *rkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ SECItem *value = NULL;
+ PK11SymKey *nsskey;
+ SECStatus nss_rv;
+
+ if (kmfh == NULL)
+ return (KMF_ERR_UNINITIALIZED);
+
+ if (symkey == NULL || rkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ else if (symkey->keyclass != KMF_SYMMETRIC)
+ return (KMF_ERR_BAD_KEY_CLASS);
+
+ if (symkey->israw) {
+ KMF_RAW_KEY_DATA *rawkey = (KMF_RAW_KEY_DATA *)symkey->keyp;
+
+ if (rawkey == NULL ||
+ rawkey->rawdata.sym.keydata.val == NULL ||
+ rawkey->rawdata.sym.keydata.len == 0)
+ return (KMF_ERR_BAD_KEYHANDLE);
+
+ rkey->keydata.len = rawkey->rawdata.sym.keydata.len;
+ if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memcpy(rkey->keydata.val,
+ rawkey->rawdata.sym.keydata.val, rkey->keydata.len);
+ } else {
+ nsskey = (PK11SymKey *)(symkey->keyp);
+ if (nsskey == NULL)
+ return (KMF_ERR_BAD_KEYHANDLE);
+
+ nss_rv = PK11_ExtractKeyValue(nsskey);
+ if (nss_rv != SECSuccess) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_GETKEYVALUE_FAILED;
+ goto out;
+ }
+
+ value = PK11_GetKeyData(nsskey);
+ if (value == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_GETKEYVALUE_FAILED;
+ goto out;
+ }
+
+ if (value->len == 0 || value->data == NULL) {
+ rv = KMF_ERR_GETKEYVALUE_FAILED;
+ goto out;
+ }
+
+ rkey->keydata.val = malloc(value->len);
+ if (rkey->keydata.val == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) memcpy(rkey->keydata.val, value->data, value->len);
+ rkey->keydata.len = value->len;
+ (void) memset(value->data, 0, value->len);
+ }
+out:
+ if (value != NULL)
+ SECITEM_FreeItem(value, PR_TRUE);
+ return (rv);
+}
+
+KMF_RETURN
+NSS_SetTokenPin(KMF_HANDLE_T handle, KMF_SETPIN_PARAMS *params,
+ KMF_CREDENTIAL *newpin)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ int rv;
+ PK11SlotInfo *nss_slot = NULL;
+
+ if (handle == NULL || params == NULL || newpin == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts,
+ FALSE, &nss_slot);
+ /* If it was uninitialized, set it */
+ if (ret == KMF_ERR_UNINITIALIZED_TOKEN) {
+ rv = PK11_InitPin(nss_slot, NULL, newpin->cred);
+ if (rv != SECSuccess) {
+ SET_ERROR(kmfh, PORT_GetError());
+ ret = KMF_ERR_AUTH_FAILED;
+ } else {
+ ret = KMF_OK;
+ }
+ } else if (ret == KMF_OK) {
+ ret = nss_authenticate(handle, nss_slot, &params->cred);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+ rv = PK11_ChangePW(nss_slot,
+ params->cred.cred, newpin->cred);
+ if (rv != SECSuccess) {
+ SET_ERROR(kmfh, PORT_GetError());
+ ret = KMF_ERR_AUTH_FAILED;
+ }
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile
new file mode 100644
index 0000000000..443f78537a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: $(ROOTLIBS)
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile
new file mode 100644
index 0000000000..472ac90a9a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: $(ROOTLIBS)
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile
new file mode 100644
index 0000000000..fe1e843387
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile
@@ -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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../../Makefile.lib.64
+
+LDLIBS += $(NSSLIBS64)
+
+install: $(ROOTLIBS64)
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile
new file mode 100644
index 0000000000..ba73e41d2e
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile
@@ -0,0 +1,46 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+check := TARGET= check
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com
new file mode 100644
index 0000000000..3ae32a00da
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com
@@ -0,0 +1,78 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Makefile for KMF Plugins
+#
+
+LIBRARY= kmf_openssl.a
+VERS= .1
+
+OBJECTS= openssl_spi.o
+
+include $(SRC)/lib/Makefile.lib
+
+LIBLINKS= $(DYNLIB:.so.1=.so)
+SFWDIR= /usr/sfw
+KMFINC= -I../../../include -I../../../ber_der/inc
+BERLIB= -lkmf -lkmfberder
+BERLIB64= $(BERLIB)
+
+OPENSSLLIBS= $(BERLIB) -R$(SFWDIR)/lib -L$(ROOT)/$(SFWDIR)/lib -lcrypto -lcryptoutil -lc
+OPENSSLLIBS64= $(BERLIB64) -R$(SFWDIR)/lib/$(MACH64) -L$(ROOT)/$(SFWDIR)/lib/$(MACH64) \
+ -lcrypto -lcryptoutil -lc
+
+LINTSSLLIBS = $(BERLIB) -L$(ROOT)/$(SFWDIR)/lib -lcrypto -lcryptoutil -lc
+LINTSSLLIBS64= $(BERLIB64) -L$(ROOT)/$(SFWDIR)/lib/$(MACH64) \
+ -lcrypto -lcryptoutil -lc
+
+SRCDIR= ../common
+INCDIR= ../../include
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT $(KMFINC) -I$(ROOT)/$(SFWDIR)/include \
+ -I$(INCDIR) -I/usr/include/libxml2
+
+PICS= $(OBJECTS:%=pics/%)
+SONAME= $(DYNLIB)
+
+lint:= OPENSSLLIBS= $(LINTSSLLIBS)
+lint:= OPENSSLLIBS64= $(LINTSSLLIBS64)
+
+LDLIBS32 += $(OPENSSLLIBS)
+
+ROOTLIBDIR= $(ROOT)/usr/lib/security
+ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64)
+
+.KEEP_STATE:
+
+LIBS = $(DYNLIB)
+all: $(DYNLIB) $(LINTLIB)
+
+lint: lintcheck
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile
new file mode 100644
index 0000000000..d73321747a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile
@@ -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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+LDLIBS += $(OPENSSLLIBS64)
+
+install: $(ROOTLIBS64)
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers
new file mode 100644
index 0000000000..cd910effa4
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers
@@ -0,0 +1,61 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate_1.1 {
+ global:
+ KMF_Plugin_Initialize;
+ OpenSSL_CertGetPrintable;
+ OpenSSL_CheckCRLDate;
+ OpenSSL_CreateKeypair;
+ OpenSSL_CreateOCSPRequest;
+ OpenSSL_CreateSymKey;
+ OpenSSL_DecryptData;
+ OpenSSL_DeleteCRL;
+ OpenSSL_DeleteCert;
+ OpenSSL_DeleteKey;
+ OpenSSL_EncodePubKeyData;
+ OpenSSL_ExportP12;
+ OpenSSL_FindCert;
+ OpenSSL_FindCertInCRL;
+ OpenSSL_FindKey;
+ OpenSSL_FreeKMFCert;
+ OpenSSL_GetErrorString;
+ OpenSSL_GetOCSPStatusForCert;
+ OpenSSL_GetPrikeyByCert;
+ OpenSSL_GetSymKeyValue;
+ OpenSSL_ImportCRL;
+ OpenSSL_IsCRLFile;
+ OpenSSL_IsCertFile;
+ OpenSSL_ListCRL;
+ OpenSSL_SignData;
+ OpenSSL_StoreCert;
+ OpenSSL_StorePrivateKey;
+ OpenSSL_VerifyCRLFile;
+ openssl_read_pkcs12;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c
new file mode 100644
index 0000000000..e088341f01
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c
@@ -0,0 +1,4198 @@
+/*
+ * 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
+ *
+ * OpenSSL keystore wrapper
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <kmfapiP.h>
+#include <ber_der.h>
+#include <oidsalg.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <cryptoutil.h>
+#include <synch.h>
+#include <thread.h>
+
+/* OPENSSL related headers */
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/bn.h>
+#include <openssl/x509.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/x509v3.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/ocsp.h>
+#include <openssl/des.h>
+#include <openssl/rand.h>
+
+#define PRINT_ANY_EXTENSION (\
+ KMF_X509_EXT_KEY_USAGE |\
+ KMF_X509_EXT_CERT_POLICIES |\
+ KMF_X509_EXT_SUBJALTNAME |\
+ KMF_X509_EXT_BASIC_CONSTRAINTS |\
+ KMF_X509_EXT_NAME_CONSTRAINTS |\
+ KMF_X509_EXT_POLICY_CONSTRAINTS |\
+ KMF_X509_EXT_EXT_KEY_USAGE |\
+ KMF_X509_EXT_INHIBIT_ANY_POLICY |\
+ KMF_X509_EXT_AUTH_KEY_ID |\
+ KMF_X509_EXT_SUBJ_KEY_ID |\
+ KMF_X509_EXT_POLICY_MAPPING)
+
+static BIO *bio_err = NULL;
+static uchar_t P[] = { 0x00, 0x8d, 0xf2, 0xa4, 0x94, 0x49, 0x22, 0x76,
+ 0xaa, 0x3d, 0x25, 0x75, 0x9b, 0xb0, 0x68, 0x69,
+ 0xcb, 0xea, 0xc0, 0xd8, 0x3a, 0xfb, 0x8d, 0x0c,
+ 0xf7, 0xcb, 0xb8, 0x32, 0x4f, 0x0d, 0x78, 0x82,
+ 0xe5, 0xd0, 0x76, 0x2f, 0xc5, 0xb7, 0x21, 0x0e,
+ 0xaf, 0xc2, 0xe9, 0xad, 0xac, 0x32, 0xab, 0x7a,
+ 0xac, 0x49, 0x69, 0x3d, 0xfb, 0xf8, 0x37, 0x24,
+ 0xc2, 0xec, 0x07, 0x36, 0xee, 0x31, 0xc8, 0x02,
+ 0x91 };
+
+static uchar_t Q[] = { 0x00, 0xc7, 0x73, 0x21, 0x8c, 0x73, 0x7e, 0xc8,
+ 0xee, 0x99, 0x3b, 0x4f, 0x2d, 0xed, 0x30, 0xf4,
+ 0x8e, 0xda, 0xce, 0x91, 0x5f };
+
+static uchar_t G[] = { 0x00, 0x62, 0x6d, 0x02, 0x78, 0x39, 0xea, 0x0a,
+ 0x13, 0x41, 0x31, 0x63, 0xa5, 0x5b, 0x4c, 0xb5,
+ 0x00, 0x29, 0x9d, 0x55, 0x22, 0x95, 0x6c, 0xef,
+ 0xcb, 0x3b, 0xff, 0x10, 0xf3, 0x99, 0xce, 0x2c,
+ 0x2e, 0x71, 0xcb, 0x9d, 0xe5, 0xfa, 0x24, 0xba,
+ 0xbf, 0x58, 0xe5, 0xb7, 0x95, 0x21, 0x92, 0x5c,
+ 0x9c, 0xc4, 0x2e, 0x9f, 0x6f, 0x46, 0x4b, 0x08,
+ 0x8c, 0xc5, 0x72, 0xaf, 0x53, 0xe6, 0xd7, 0x88,
+ 0x02 };
+
+#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_OPENSSL; \
+ h->lasterr.errcode = c;
+
+#define SET_SYS_ERROR(h, c) h->lasterr.kstype = -1; h->lasterr.errcode = c;
+
+mutex_t init_lock = DEFAULTMUTEX;
+static int ssl_initialized = 0;
+
+KMF_RETURN
+OpenSSL_FindCert(KMF_HANDLE_T,
+ KMF_FINDCERT_PARAMS *,
+ KMF_X509_DER_CERT *,
+ uint32_t *);
+
+void
+OpenSSL_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *);
+
+KMF_RETURN
+OpenSSL_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *, KMF_DATA *);
+
+KMF_RETURN
+OpenSSL_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *);
+
+KMF_RETURN
+OpenSSL_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *,
+ KMF_KEY_HANDLE *, KMF_KEY_HANDLE *);
+
+KMF_RETURN
+OpenSSL_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *);
+
+KMF_RETURN
+OpenSSL_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+OpenSSL_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *,
+ KMF_KEY_HANDLE *, boolean_t);
+
+KMF_RETURN
+OpenSSL_ImportCRL(KMF_HANDLE_T, KMF_IMPORTCRL_PARAMS *);
+
+KMF_RETURN
+OpenSSL_DeleteCRL(KMF_HANDLE_T, KMF_DELETECRL_PARAMS *);
+
+KMF_RETURN
+OpenSSL_ListCRL(KMF_HANDLE_T, KMF_LISTCRL_PARAMS *, char **);
+
+KMF_RETURN
+OpenSSL_FindCertInCRL(KMF_HANDLE_T, KMF_FINDCERTINCRL_PARAMS *);
+
+KMF_RETURN
+OpenSSL_CertGetPrintable(KMF_HANDLE_T, const KMF_DATA *,
+ KMF_PRINTABLE_ITEM, char *);
+
+KMF_RETURN
+OpenSSL_GetErrorString(KMF_HANDLE_T, char **);
+
+KMF_RETURN
+OpenSSL_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *,
+ KMF_KEY_HANDLE *, KMF_KEY_ALG);
+
+KMF_RETURN
+OpenSSL_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+OpenSSL_CreateOCSPRequest(KMF_HANDLE_T, KMF_OCSPREQUEST_PARAMS *,
+ char *reqfile);
+
+KMF_RETURN
+OpenSSL_GetOCSPStatusForCert(KMF_HANDLE_T, KMF_OCSPRESPONSE_PARAMS_INPUT *,
+ KMF_OCSPRESPONSE_PARAMS_OUTPUT *);
+
+KMF_RETURN
+OpenSSL_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *,
+ KMF_KEY_HANDLE *, uint32_t *);
+
+KMF_RETURN
+OpenSSL_ExportP12(KMF_HANDLE_T,
+ KMF_EXPORTP12_PARAMS *,
+ int, KMF_X509_DER_CERT *,
+ int, KMF_KEY_HANDLE *,
+ char *);
+
+KMF_RETURN
+OpenSSL_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *,
+ KMF_RAW_KEY_DATA *);
+
+KMF_RETURN
+OpenSSL_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *,
+ KMF_KEY_HANDLE *);
+
+KMF_RETURN
+OpenSSL_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *);
+
+KMF_RETURN
+OpenSSL_VerifyCRLFile(KMF_HANDLE_T, KMF_VERIFYCRL_PARAMS *);
+
+KMF_RETURN
+OpenSSL_CheckCRLDate(KMF_HANDLE_T, KMF_CHECKCRLDATE_PARAMS *);
+
+static
+KMF_PLUGIN_FUNCLIST openssl_plugin_table =
+{
+ 1, /* Version */
+ NULL, /* ConfigureKeystore */
+ OpenSSL_FindCert,
+ OpenSSL_FreeKMFCert,
+ OpenSSL_StoreCert,
+ NULL, /* ImportCert */
+ OpenSSL_ImportCRL,
+ OpenSSL_DeleteCert,
+ OpenSSL_DeleteCRL,
+ OpenSSL_CreateKeypair,
+ OpenSSL_FindKey,
+ OpenSSL_EncodePubKeyData,
+ OpenSSL_SignData,
+ OpenSSL_DeleteKey,
+ OpenSSL_ListCRL,
+ NULL, /* FindCRL */
+ OpenSSL_FindCertInCRL,
+ OpenSSL_GetErrorString,
+ OpenSSL_GetPrikeyByCert,
+ OpenSSL_DecryptData,
+ OpenSSL_ExportP12,
+ OpenSSL_StorePrivateKey,
+ OpenSSL_CreateSymKey,
+ OpenSSL_GetSymKeyValue,
+ NULL, /* SetTokenPin */
+ NULL /* Finalize */
+};
+
+static mutex_t *lock_cs;
+static long *lock_count;
+
+static void
+/*ARGSUSED*/
+locking_cb(int mode, int type, char *file, int line)
+{
+ if (mode & CRYPTO_LOCK) {
+ (void) mutex_lock(&(lock_cs[type]));
+ lock_count[type]++;
+ } else {
+ (void) mutex_unlock(&(lock_cs[type]));
+ }
+}
+
+static unsigned long
+thread_id()
+{
+ return ((unsigned long)thr_self());
+}
+
+KMF_PLUGIN_FUNCLIST *
+KMF_Plugin_Initialize()
+{
+ int i;
+
+ (void) mutex_lock(&init_lock);
+ if (!ssl_initialized) {
+ OpenSSL_add_all_algorithms();
+
+ /* Enable error strings for reporting */
+ ERR_load_crypto_strings();
+
+ /*
+ * Add support for extension OIDs that are not yet in the
+ * openssl default set.
+ */
+ (void) OBJ_create("2.5.29.30", "nameConstraints",
+ "X509v3 Name Constraints");
+ (void) OBJ_create("2.5.29.33", "policyMappings",
+ "X509v3 Policy Mappings");
+ (void) OBJ_create("2.5.29.36", "policyConstraints",
+ "X509v3 Policy Constraints");
+ (void) OBJ_create("2.5.29.46", "freshestCRL",
+ "X509v3 Freshest CRL");
+ (void) OBJ_create("2.5.29.54", "inhibitAnyPolicy",
+ "X509v3 Inhibit Any-Policy");
+ /*
+ * Set up for thread-safe operation.
+ */
+ lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof (mutex_t));
+ if (lock_cs == NULL) {
+ (void) mutex_unlock(&init_lock);
+ return (NULL);
+ }
+
+ lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof (long));
+ if (lock_count == NULL) {
+ OPENSSL_free(lock_cs);
+ (void) mutex_unlock(&init_lock);
+ return (NULL);
+ }
+
+ for (i = 0; i < CRYPTO_num_locks(); i++) {
+ lock_count[i] = 0;
+ (void) mutex_init(&lock_cs[i], USYNC_THREAD, NULL);
+ }
+
+ CRYPTO_set_id_callback((unsigned long (*)())thread_id);
+ CRYPTO_set_locking_callback((void (*)())locking_cb);
+ ssl_initialized = 1;
+ }
+ (void) mutex_unlock(&init_lock);
+
+ return (&openssl_plugin_table);
+}
+/*
+ * Convert an SSL DN to a KMF DN.
+ */
+static KMF_RETURN
+get_x509_dn(X509_NAME *sslDN, KMF_X509_NAME *kmfDN)
+{
+ KMF_DATA derdata;
+ KMF_RETURN rv = KMF_OK;
+ uchar_t *tmp;
+
+ /* Convert to raw DER format */
+ derdata.Length = i2d_X509_NAME(sslDN, NULL);
+ if ((tmp = derdata.Data = (uchar_t *)OPENSSL_malloc(derdata.Length))
+ == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+ (void) i2d_X509_NAME(sslDN, &tmp);
+
+ /* Decode to KMF format */
+ rv = DerDecodeName(&derdata, kmfDN);
+ if (rv != KMF_OK) {
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ }
+ OPENSSL_free(derdata.Data);
+
+ return (rv);
+}
+
+static int
+isdir(char *path)
+{
+ struct stat s;
+
+ if (stat(path, &s) == -1)
+ return (0);
+
+ return (s.st_mode & S_IFDIR);
+}
+
+static KMF_RETURN
+ssl_cert2KMFDATA(KMF_HANDLE *kmfh, X509 *x509cert, KMF_DATA *cert)
+{
+ KMF_RETURN rv = KMF_OK;
+ unsigned char *buf = NULL, *p;
+ int len;
+
+ /*
+ * Convert the X509 internal struct to DER encoded data
+ */
+ if ((len = i2d_X509(x509cert, NULL)) < 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ if ((buf = malloc(len)) == NULL) {
+ SET_SYS_ERROR(kmfh, errno);
+ rv = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * i2d_X509 will increment the buf pointer so that we need to
+ * save it.
+ */
+ p = buf;
+ if ((len = i2d_X509(x509cert, &p)) < 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ free(buf);
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ /* caller's responsibility to free it */
+ cert->Data = buf;
+ cert->Length = len;
+
+cleanup:
+ if (rv != KMF_OK) {
+ if (buf)
+ free(buf);
+ cert->Data = NULL;
+ cert->Length = 0;
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+check_cert(X509 *xcert, KMF_FINDCERT_PARAMS *params, boolean_t *match)
+{
+ KMF_RETURN rv = KMF_OK;
+ boolean_t findIssuer = FALSE;
+ boolean_t findSubject = FALSE;
+ boolean_t findSerial = FALSE;
+ KMF_X509_NAME issuerDN, subjectDN;
+ KMF_X509_NAME certIssuerDN, certSubjectDN;
+
+ *match = FALSE;
+ if (xcert == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ (void) memset(&issuerDN, 0, sizeof (KMF_X509_NAME));
+ (void) memset(&subjectDN, 0, sizeof (KMF_X509_NAME));
+ (void) memset(&certIssuerDN, 0, sizeof (KMF_X509_NAME));
+ (void) memset(&certSubjectDN, 0, sizeof (KMF_X509_NAME));
+
+ if (params->issuer != NULL && strlen(params->issuer)) {
+ rv = KMF_DNParser(params->issuer, &issuerDN);
+ if (rv != KMF_OK)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = get_x509_dn(xcert->cert_info->issuer, &certIssuerDN);
+ if (rv != KMF_OK) {
+ KMF_FreeDN(&issuerDN);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ findIssuer = TRUE;
+ }
+ if (params->subject != NULL && strlen(params->subject)) {
+ rv = KMF_DNParser(params->subject, &subjectDN);
+ if (rv != KMF_OK) {
+ rv = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ rv = get_x509_dn(xcert->cert_info->subject, &certSubjectDN);
+ if (rv != KMF_OK) {
+ rv = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+ findSubject = TRUE;
+ }
+ if (params->serial != NULL && params->serial->val != NULL)
+ findSerial = TRUE;
+
+ if (findSerial) {
+ BIGNUM *bn;
+
+ /* Comparing BIGNUMs is a pain! */
+ bn = ASN1_INTEGER_to_BN(xcert->cert_info->serialNumber, NULL);
+ if (bn != NULL) {
+ int bnlen = BN_num_bytes(bn);
+
+ if (bnlen == params->serial->len) {
+ uchar_t *a = malloc(bnlen);
+ if (a == NULL) {
+ rv = KMF_ERR_MEMORY;
+ BN_free(bn);
+ goto cleanup;
+ }
+ bnlen = BN_bn2bin(bn, a);
+ *match = !memcmp(a,
+ params->serial->val,
+ params->serial->len);
+ rv = KMF_OK;
+ free(a);
+ }
+ BN_free(bn);
+ if (!(*match))
+ goto cleanup;
+ } else {
+ rv = KMF_OK;
+ goto cleanup;
+ }
+ }
+ if (findIssuer) {
+ *match = !KMF_CompareRDNs(&issuerDN, &certIssuerDN);
+ if (!(*match)) {
+ rv = KMF_OK;
+ goto cleanup;
+ }
+ }
+ if (findSubject) {
+ *match = !KMF_CompareRDNs(&subjectDN, &certSubjectDN);
+ if (!(*match)) {
+ rv = KMF_OK;
+ goto cleanup;
+ }
+ }
+
+ *match = TRUE;
+cleanup:
+ if (findIssuer) {
+ KMF_FreeDN(&issuerDN);
+ KMF_FreeDN(&certIssuerDN);
+ }
+ if (findSubject) {
+ KMF_FreeDN(&subjectDN);
+ KMF_FreeDN(&certSubjectDN);
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+load_X509cert(KMF_HANDLE *kmfh,
+ KMF_FINDCERT_PARAMS *params,
+ char *pathname,
+ X509 **outcert)
+{
+ KMF_RETURN rv = KMF_OK;
+ X509 *xcert = NULL;
+ BIO *bcert = NULL;
+ boolean_t match = FALSE;
+ KMF_ENCODE_FORMAT format;
+
+ /*
+ * auto-detect the file format, regardless of what
+ * the 'format' parameters in the params say.
+ */
+ rv = KMF_GetFileFormat(pathname, &format);
+ if (rv != KMF_OK) {
+ if (rv == KMF_ERR_OPEN_FILE)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ return (rv);
+ }
+
+ /* Not ASN1(DER) format */
+ if ((bcert = BIO_new_file(pathname, "rb")) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ if (format == KMF_FORMAT_PEM)
+ xcert = PEM_read_bio_X509_AUX(bcert, NULL, NULL, NULL);
+ else if (format == KMF_FORMAT_ASN1)
+ xcert = d2i_X509_bio(bcert, NULL);
+ else if (format == KMF_FORMAT_PKCS12) {
+ PKCS12 *p12 = d2i_PKCS12_bio(bcert, NULL);
+ if (p12 != NULL) {
+ (void) PKCS12_parse(p12, NULL, NULL, &xcert, NULL);
+ PKCS12_free(p12);
+ p12 = NULL;
+ } else {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ }
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ if (check_cert(xcert, params, &match) != KMF_OK || match == FALSE) {
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ goto cleanup;
+ }
+
+ if (outcert != NULL) {
+ *outcert = xcert;
+ }
+
+cleanup:
+ if (bcert != NULL) (void) BIO_free(bcert);
+ if (rv != KMF_OK && xcert != NULL)
+ X509_free(xcert);
+
+ return (rv);
+}
+
+static KMF_RETURN
+kmf_load_cert(KMF_HANDLE *kmfh,
+ KMF_FINDCERT_PARAMS *params,
+ char *pathname,
+ KMF_DATA *cert)
+{
+ KMF_RETURN rv = KMF_OK;
+ X509 *x509cert = NULL;
+
+ rv = load_X509cert(kmfh, params, pathname, &x509cert);
+ if (rv == KMF_OK && x509cert != NULL && cert != NULL) {
+ rv = ssl_cert2KMFDATA(kmfh, x509cert, cert);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+ if (params->find_cert_validity == KMF_NONEXPIRED_CERTS) {
+ rv = KMF_CheckCertDate(kmfh, cert);
+ } else if (params->find_cert_validity == KMF_EXPIRED_CERTS) {
+ rv = KMF_CheckCertDate(kmfh, cert);
+ if (rv == KMF_OK) {
+ /*
+ * This is a valid cert so skip it.
+ */
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ }
+ if (rv == KMF_ERR_VALIDITY_PERIOD) {
+ /*
+ * We want to return success when we
+ * find an invalid cert.
+ */
+ rv = KMF_OK;
+ goto cleanup;
+ }
+ }
+ }
+cleanup:
+ if (x509cert != NULL)
+ X509_free(x509cert);
+
+ return (rv);
+}
+
+static EVP_PKEY *
+openssl_load_key(KMF_HANDLE_T handle, const char *file)
+{
+ BIO *keyfile = NULL;
+ EVP_PKEY *pkey = NULL;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ENCODE_FORMAT format;
+
+ if (file == NULL) {
+ return (NULL);
+ }
+
+ if (KMF_GetFileFormat((char *)file, &format) != KMF_OK)
+ return (NULL);
+
+ keyfile = BIO_new_file(file, "rb");
+ if (keyfile == NULL) {
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1)
+ pkey = d2i_PrivateKey_bio(keyfile, NULL);
+ else if (format == KMF_FORMAT_PEM)
+ pkey = PEM_read_bio_PrivateKey(keyfile, NULL, NULL, NULL);
+
+end:
+ if (pkey == NULL)
+ SET_ERROR(kmfh, ERR_get_error());
+
+ if (keyfile != NULL)
+ (void) BIO_free(keyfile);
+
+ return (pkey);
+}
+
+KMF_RETURN
+OpenSSL_FindCert(KMF_HANDLE_T handle,
+ KMF_FINDCERT_PARAMS *params,
+ KMF_X509_DER_CERT *kmf_cert,
+ uint32_t *num_certs)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_DATA certdata = {NULL, 0};
+ char *fullpath;
+
+ if (num_certs == NULL || params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ *num_certs = 0;
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.certfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(fullpath)) {
+ DIR *dirp;
+ struct dirent *dp;
+ int n = 0;
+
+ /* open all files in the directory and attempt to read them */
+ if ((dirp = opendir(fullpath)) == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ while ((dp = readdir(dirp)) != NULL) {
+ char *fname;
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+
+ fname = get_fullpath(fullpath,
+ (char *)&dp->d_name);
+
+ rv = kmf_load_cert(kmfh, params, fname,
+ &certdata);
+
+ if (rv != KMF_OK) {
+ free(fname);
+ KMF_FreeData(&certdata);
+ continue;
+ }
+
+ /* If load succeeds, add certdata to the list */
+ if (kmf_cert != NULL) {
+ kmf_cert[n].certificate.Data = certdata.Data;
+ kmf_cert[n].certificate.Length =
+ certdata.Length;
+
+ kmf_cert[n].kmf_private.keystore_type =
+ KMF_KEYSTORE_OPENSSL;
+ kmf_cert[n].kmf_private.flags =
+ KMF_FLAG_CERT_VALID;
+ kmf_cert[n].kmf_private.label = fname;
+ } else {
+ free(fname);
+ KMF_FreeData(&certdata);
+ }
+ n++;
+ }
+ (*num_certs) = n;
+ if (*num_certs == 0)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ if (*num_certs > 0)
+ rv = KMF_OK;
+exit:
+ (void) closedir(dirp);
+ } else {
+ /* Just try to load a single certificate */
+ rv = kmf_load_cert(kmfh, params, fullpath, &certdata);
+ if (rv != KMF_OK) {
+ free(fullpath);
+ KMF_FreeData(&certdata);
+ return (rv);
+ }
+
+ if (kmf_cert != NULL) {
+ kmf_cert->certificate.Data = certdata.Data;
+ kmf_cert->certificate.Length = certdata.Length;
+ kmf_cert->kmf_private.keystore_type =
+ KMF_KEYSTORE_OPENSSL;
+ kmf_cert->kmf_private.flags = KMF_FLAG_CERT_VALID;
+ kmf_cert->kmf_private.label = fullpath;
+ } else {
+ KMF_FreeData(&certdata);
+ }
+
+ *num_certs = 1;
+ }
+
+ if (kmf_cert == NULL || rv != KMF_OK)
+ free(fullpath);
+
+ return (rv);
+
+}
+
+void
+/*ARGSUSED*/
+OpenSSL_FreeKMFCert(KMF_HANDLE_T handle,
+ KMF_X509_DER_CERT *kmf_cert)
+{
+ if (kmf_cert != NULL) {
+ if (kmf_cert->certificate.Data != NULL) {
+ free(kmf_cert->certificate.Data);
+ kmf_cert->certificate.Data = NULL;
+ kmf_cert->certificate.Length = 0;
+ }
+ if (kmf_cert->kmf_private.label)
+ free(kmf_cert->kmf_private.label);
+ }
+}
+
+KMF_RETURN
+OpenSSL_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params,
+ KMF_DATA * pcert)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ X509 *xcert = NULL;
+ FILE *fp;
+ unsigned char *outbuf;
+ unsigned char *outbuf_p;
+ char *fullpath;
+ int outbuflen;
+ int len;
+ KMF_ENCODE_FORMAT format;
+
+ if (params == NULL || params->ks_opt_u.openssl_opts.certfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * check if the cert output format is supported by OPENSSL.
+ * however, since the keystore for OPENSSL is just a file, we have
+ * no way to store the format along with the file.
+ */
+ format = params->sslparms.format;
+ if (format != KMF_FORMAT_ASN1 && format != KMF_FORMAT_PEM)
+ return (KMF_ERR_BAD_CERT_FORMAT);
+
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.certfile);
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * When storing a certificate, you must specify a filename.
+ */
+ if (isdir(fullpath)) {
+ free(fullpath);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* copy cert data to outbuf */
+ outbuflen = pcert->Length;
+ outbuf = malloc(outbuflen);
+ if (outbuf == NULL) {
+ free(fullpath);
+ return (KMF_ERR_MEMORY);
+ }
+ (void) memcpy(outbuf, pcert->Data, pcert->Length);
+
+ if ((fp = fopen(fullpath, "w")) ==
+ NULL) {
+ SET_SYS_ERROR(kmfh, errno);
+ ret = KMF_ERR_INTERNAL;
+ goto out;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ len = fwrite(outbuf, 1, outbuflen, fp);
+ if (len != outbuflen) {
+ SET_SYS_ERROR(kmfh, errno);
+ ret = KMF_ERR_WRITE_FILE;
+ } else {
+ ret = KMF_OK;
+ }
+ goto out;
+ }
+
+ /*
+ * The output format is not KMF_FORMAT_ASN1, so we will
+ * Convert the cert data to OpenSSL internal X509 first.
+ */
+ outbuf_p = outbuf; /* use a temp pointer; required by openssl */
+ xcert = d2i_X509(NULL, (const uchar_t **)&outbuf_p, outbuflen);
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ if (format == KMF_FORMAT_PEM) {
+ /* Convert to the PEM format and write it out */
+ if (!PEM_write_X509(fp, xcert)) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ } else {
+ ret = KMF_OK;
+ }
+ goto out;
+ }
+
+out:
+ if (fullpath != NULL)
+ free(fullpath);
+
+ if (outbuf != NULL) {
+ free(outbuf);
+ }
+ if (fp != NULL) {
+ (void) fclose(fp);
+ }
+
+ if (xcert != NULL) {
+ X509_free(xcert);
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params)
+{
+ KMF_RETURN rv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ char *fullpath = NULL;
+ KMF_DATA certdata = {NULL, 0};
+
+ if (params == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.certfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(fullpath)) {
+ DIR *dirp;
+ struct dirent *dp;
+
+ /* open all files in the directory and attempt to read them */
+ if ((dirp = opendir(fullpath)) == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ while ((dp = readdir(dirp)) != NULL) {
+ if (strcmp(dp->d_name, ".") != 0 &&
+ strcmp(dp->d_name, "..") != 0) {
+ char *fname;
+
+ fname = get_fullpath(fullpath,
+ (char *)&dp->d_name);
+
+ if (fname == NULL) {
+ rv = KMF_ERR_MEMORY;
+ break;
+ }
+
+ rv = kmf_load_cert(kmfh, params, fname,
+ &certdata);
+
+ if (rv == KMF_ERR_CERT_NOT_FOUND) {
+ free(fname);
+ if (certdata.Data)
+ free(certdata.Data);
+ rv = KMF_OK;
+ continue;
+ } else if (rv != KMF_OK) {
+ free(fname);
+ break;
+ }
+
+ if (unlink(fname) != 0) {
+ SET_SYS_ERROR(kmfh, errno);
+ rv = KMF_ERR_INTERNAL;
+ free(fname);
+ break;
+ }
+ free(fname);
+ if (certdata.Data)
+ free(certdata.Data);
+ }
+ }
+ (void) closedir(dirp);
+ } else {
+ /* Just try to load a single certificate */
+ rv = kmf_load_cert(kmfh, params, fullpath, &certdata);
+ if (rv == KMF_OK) {
+ if (unlink(fullpath) != 0) {
+ SET_SYS_ERROR(kmfh, errno);
+ rv = KMF_ERR_INTERNAL;
+ }
+ }
+ }
+
+out:
+ if (fullpath != NULL)
+ free(fullpath);
+
+ if (certdata.Data)
+ free(certdata.Data);
+
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_DATA *keydata)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ int n;
+
+ if (key == NULL || keydata == NULL ||
+ key->keyp == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (key->keyalg == KMF_RSA) {
+ RSA *pubkey = EVP_PKEY_get1_RSA(key->keyp);
+
+ if (!(n = i2d_RSA_PUBKEY(pubkey, &keydata->Data))) {
+ SET_ERROR(kmfh, ERR_get_error());
+ return (KMF_ERR_ENCODING);
+ }
+ RSA_free(pubkey);
+ } else if (key->keyalg == KMF_DSA) {
+ DSA *pubkey = EVP_PKEY_get1_DSA(key->keyp);
+
+ if (!(n = i2d_DSA_PUBKEY(pubkey, &keydata->Data))) {
+ SET_ERROR(kmfh, ERR_get_error());
+ return (KMF_ERR_ENCODING);
+ }
+ DSA_free(pubkey);
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ keydata->Length = n;
+
+cleanup:
+ if (rv != KMF_OK) {
+ if (keydata->Data)
+ free(keydata->Data);
+ keydata->Data = NULL;
+ keydata->Length = 0;
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+ssl_write_private_key(KMF_HANDLE *kmfh, KMF_ENCODE_FORMAT format, BIO *out,
+ KMF_CREDENTIAL *cred, EVP_PKEY *pkey)
+{
+ int rv = 0;
+ RSA *rsa;
+ DSA *dsa;
+
+ switch (format) {
+ case KMF_FORMAT_ASN1:
+ if (pkey->type == EVP_PKEY_RSA) {
+ rsa = EVP_PKEY_get1_RSA(pkey);
+ rv = i2d_RSAPrivateKey_bio(out, rsa);
+ RSA_free(rsa);
+ } else if (pkey->type == EVP_PKEY_DSA) {
+ dsa = EVP_PKEY_get1_DSA(pkey);
+ rv = i2d_DSAPrivateKey_bio(out, dsa);
+ DSA_free(dsa);
+ }
+ if (rv == 1) {
+ rv = KMF_OK;
+ } else {
+ SET_ERROR(kmfh, rv);
+ }
+ break;
+ case KMF_FORMAT_PEM:
+ if (pkey->type == EVP_PKEY_RSA) {
+ rsa = EVP_PKEY_get1_RSA(pkey);
+ rv = PEM_write_bio_RSAPrivateKey(out,
+ rsa,
+ NULL /* encryption type */,
+ NULL, 0, NULL,
+ cred->cred);
+ RSA_free(rsa);
+ } else if (pkey->type == EVP_PKEY_DSA) {
+ dsa = EVP_PKEY_get1_DSA(pkey);
+ rv = PEM_write_bio_DSAPrivateKey(out,
+ dsa,
+ NULL /* encryption type */,
+ NULL, 0, NULL,
+ cred->cred);
+ DSA_free(dsa);
+ }
+
+ if (rv == 1) {
+ rv = KMF_OK;
+ } else {
+ SET_ERROR(kmfh, rv);
+ }
+ break;
+
+ default:
+ rv = KMF_ERR_BAD_PARAMETER;
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_CreateKeypair(KMF_HANDLE_T handle, KMF_CREATEKEYPAIR_PARAMS *params,
+ KMF_KEY_HANDLE *privkey, KMF_KEY_HANDLE *pubkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ int format;
+ uint32_t eValue = 0x010001;
+ RSA *sslPrivKey = NULL;
+ DSA *sslDSAKey = NULL;
+ EVP_PKEY *eprikey = NULL;
+ EVP_PKEY *epubkey = NULL;
+ BIO *out = NULL;
+ char *fullpath = NULL;
+
+ if (params == NULL || params->sslparms.keyfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.keyfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* If the requested file exists, return an error */
+ if (access(fullpath, F_OK) == 0) {
+ free(fullpath);
+ return (KMF_ERR_DUPLICATE_KEYFILE);
+ }
+
+ eprikey = EVP_PKEY_new();
+ if (eprikey == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ epubkey = EVP_PKEY_new();
+ if (epubkey == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ if (params->keytype == KMF_RSA) {
+ if (params->rsa_exponent.len > 0 &&
+ params->rsa_exponent.len <= sizeof (eValue) &&
+ params->rsa_exponent.val != NULL)
+ /*LINTED*/
+ eValue = *(uint32_t *)params->rsa_exponent.val;
+
+ sslPrivKey = RSA_generate_key(params->keylength, eValue,
+ NULL, NULL);
+ if (sslPrivKey == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ } else {
+ if (privkey != NULL &&
+ EVP_PKEY_set1_RSA(eprikey, sslPrivKey)) {
+ privkey->kstype = KMF_KEYSTORE_OPENSSL;
+ privkey->keyalg = KMF_RSA;
+ privkey->keyclass = KMF_ASYM_PRI;
+ privkey->israw = FALSE;
+ privkey->keylabel = (char *)strdup(fullpath);
+ privkey->keyp = (void *)eprikey;
+ }
+ /* OpenSSL derives the public key from the private */
+ if (pubkey != NULL &&
+ EVP_PKEY_set1_RSA(epubkey, sslPrivKey)) {
+ pubkey->kstype = KMF_KEYSTORE_OPENSSL;
+ pubkey->keyalg = KMF_RSA;
+ pubkey->israw = FALSE;
+ pubkey->keyclass = KMF_ASYM_PUB;
+ pubkey->keylabel = (char *)strdup(fullpath);
+ pubkey->keyp = (void *)epubkey;
+ }
+ }
+ } else if (params->keytype == KMF_DSA) {
+ sslDSAKey = DSA_new();
+ if (sslDSAKey == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ return (KMF_ERR_MEMORY);
+ }
+
+ if ((sslDSAKey->p = BN_bin2bn(P, sizeof (P), sslDSAKey->p)) ==
+ NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ if ((sslDSAKey->q = BN_bin2bn(Q, sizeof (Q), sslDSAKey->q)) ==
+ NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ if ((sslDSAKey->g = BN_bin2bn(G, sizeof (G), sslDSAKey->g)) ==
+ NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+
+ if (!DSA_generate_key(sslDSAKey)) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+
+ if (privkey != NULL) {
+ privkey->kstype = KMF_KEYSTORE_OPENSSL;
+ privkey->keyalg = KMF_DSA;
+ privkey->keyclass = KMF_ASYM_PRI;
+ privkey->israw = FALSE;
+ privkey->keylabel = (char *)strdup(fullpath);
+ if (EVP_PKEY_set1_DSA(eprikey, sslDSAKey)) {
+ privkey->keyp = (void *)eprikey;
+ } else {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ }
+ if (pubkey != NULL) {
+ DSA *dp = DSA_new();
+ /* Make a copy for the public key */
+ if (dp != NULL) {
+ if ((dp->p = BN_new()) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_MEMORY;
+ DSA_free(dp);
+ goto cleanup;
+ }
+ if ((dp->q = BN_new()) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_MEMORY;
+ BN_free(dp->p);
+ DSA_free(dp);
+ goto cleanup;
+ }
+ if ((dp->g = BN_new()) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_MEMORY;
+ BN_free(dp->q);
+ BN_free(dp->p);
+ DSA_free(dp);
+ goto cleanup;
+ }
+ if ((dp->pub_key = BN_new()) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_MEMORY;
+ BN_free(dp->q);
+ BN_free(dp->p);
+ BN_free(dp->g);
+ DSA_free(dp);
+ goto cleanup;
+ }
+ (void) BN_copy(dp->p, sslDSAKey->p);
+ (void) BN_copy(dp->q, sslDSAKey->q);
+ (void) BN_copy(dp->g, sslDSAKey->g);
+ (void) BN_copy(dp->pub_key, sslDSAKey->pub_key);
+
+ pubkey->kstype = KMF_KEYSTORE_OPENSSL;
+ pubkey->keyalg = KMF_DSA;
+ pubkey->keyclass = KMF_ASYM_PUB;
+ pubkey->israw = FALSE;
+ pubkey->keylabel = (char *)strdup(fullpath);
+
+ if (EVP_PKEY_set1_DSA(epubkey, sslDSAKey)) {
+ pubkey->keyp = (void *)epubkey;
+ } else {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ }
+ }
+ }
+
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+
+ /* Store the private key to the keyfile */
+ format = params->sslparms.format;
+ out = BIO_new_file(fullpath, "wb");
+ if (out == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+ rv = ssl_write_private_key(kmfh, format, out, &params->cred, eprikey);
+
+cleanup:
+ if (rv != KMF_OK) {
+ if (eprikey != NULL)
+ EVP_PKEY_free(eprikey);
+
+ if (epubkey != NULL)
+ EVP_PKEY_free(epubkey);
+
+ if (pubkey->keylabel) {
+ free(pubkey->keylabel);
+ pubkey->keylabel = NULL;
+ }
+
+ if (privkey->keylabel) {
+ free(privkey->keylabel);
+ privkey->keylabel = NULL;
+ }
+
+ pubkey->keyp = NULL;
+ privkey->keyp = NULL;
+ }
+
+ if (sslPrivKey)
+ RSA_free(sslPrivKey);
+
+ if (sslDSAKey)
+ DSA_free(sslDSAKey);
+
+
+ if (out != NULL)
+ (void) BIO_free(out);
+
+ if (fullpath)
+ free(fullpath);
+
+ /* Protect the file by making it read-only */
+ if (rv == KMF_OK) {
+ (void) chmod(fullpath, 0400);
+ }
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_OID *AlgOID, KMF_DATA *tobesigned, KMF_DATA *output)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ALGORITHM_INDEX AlgId;
+ EVP_MD_CTX ctx;
+ const EVP_MD *md;
+ if (key == NULL || AlgOID == NULL ||
+ tobesigned == NULL || output == NULL ||
+ tobesigned->Data == NULL ||
+ output->Data == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Map the OID to an OpenSSL algorithm */
+ AlgId = X509_AlgorithmOidToAlgId(AlgOID);
+ if (AlgId == KMF_ALGID_NONE)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (key->keyalg == KMF_RSA) {
+ EVP_PKEY *pkey = (EVP_PKEY *)key->keyp;
+ uchar_t *p;
+ uint32_t len;
+ if (AlgId == KMF_ALGID_MD5WithRSA)
+ md = EVP_md5();
+ else if (AlgId == KMF_ALGID_MD2WithRSA)
+ md = EVP_md2();
+ else if (AlgId == KMF_ALGID_SHA1WithRSA)
+ md = EVP_sha1();
+ else
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (md == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ return (KMF_ERR_MEMORY);
+ }
+
+ (void) EVP_MD_CTX_init(&ctx);
+ (void) EVP_SignInit_ex(&ctx, md, NULL);
+ (void) EVP_SignUpdate(&ctx, tobesigned->Data,
+ (uint32_t)tobesigned->Length);
+ len = (uint32_t)output->Length;
+ p = output->Data;
+ if (!EVP_SignFinal(&ctx, p, &len, pkey)) {
+ SET_ERROR(kmfh, ERR_get_error());
+ output->Length = 0;
+ }
+ output->Length = len;
+ (void) EVP_MD_CTX_cleanup(&ctx);
+ } else if (key->keyalg == KMF_DSA) {
+ DSA *dsa = EVP_PKEY_get1_DSA(key->keyp);
+
+ uchar_t hash[EVP_MAX_MD_SIZE];
+ uint32_t hashlen;
+ DSA_SIG *dsasig;
+
+ /*
+ * OpenSSL EVP_Sign operation automatically converts to
+ * ASN.1 output so we do the operations separately so we
+ * are assured of NOT getting ASN.1 output returned.
+ * KMF does not want ASN.1 encoded results because
+ * not all mechanisms return ASN.1 encodings (PKCS#11
+ * and NSS return raw signature data).
+ */
+ md = EVP_sha1();
+ EVP_MD_CTX_init(&ctx);
+ (void) EVP_DigestInit_ex(&ctx, md, NULL);
+ (void) EVP_DigestUpdate(&ctx, tobesigned->Data,
+ tobesigned->Length);
+ (void) EVP_DigestFinal_ex(&ctx, hash, &hashlen);
+ (void) EVP_MD_CTX_cleanup(&ctx);
+
+ dsasig = DSA_do_sign(hash, hashlen, dsa);
+ if (dsasig != NULL) {
+ int i;
+ output->Length = i = BN_bn2bin(dsasig->r, output->Data);
+ output->Length += BN_bn2bin(dsasig->s,
+ &output->Data[i]);
+ DSA_SIG_free(dsasig);
+ } else {
+ SET_ERROR(kmfh, ERR_get_error());
+ }
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+cleanup:
+ return (ret);
+}
+
+KMF_RETURN
+/*ARGSUSED*/
+OpenSSL_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params,
+ KMF_KEY_HANDLE *key, boolean_t destroy)
+{
+ KMF_RETURN rv = KMF_OK;
+ if (key == NULL || key->keyp == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (key->keyclass != KMF_ASYM_PUB &&
+ key->keyclass != KMF_ASYM_PRI &&
+ key->keyclass != KMF_SYMMETRIC)
+ return (KMF_ERR_BAD_KEY_CLASS);
+
+ if (key->keyclass == KMF_SYMMETRIC) {
+ KMF_FreeRawSymKey((KMF_RAW_SYM_KEY *)key->keyp);
+ key->keyp = NULL;
+ } else {
+ if (key->keyp != NULL) {
+ EVP_PKEY_free(key->keyp);
+ key->keyp = NULL;
+ }
+ }
+
+ if (key->keylabel != NULL) {
+ EVP_PKEY *pkey = NULL;
+ /* If the file exists, make sure it is a proper key. */
+ pkey = openssl_load_key(handle, key->keylabel);
+ if (pkey == NULL) {
+ free(key->keylabel);
+ key->keylabel = NULL;
+ return (KMF_ERR_KEY_NOT_FOUND);
+ }
+ EVP_PKEY_free(pkey);
+
+ if (destroy) {
+ if (unlink(key->keylabel) != 0) {
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ SET_SYS_ERROR(kmfh, errno);
+ rv = KMF_ERR_INTERNAL;
+ }
+ }
+ if (key->keylabel != NULL) {
+ free(key->keylabel);
+ key->keylabel = NULL;
+ }
+ }
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_ImportCRL(KMF_HANDLE_T handle, KMF_IMPORTCRL_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ X509_CRL *xcrl = NULL;
+ X509 *xcert = NULL;
+ EVP_PKEY *pkey;
+ KMF_ENCODE_FORMAT format;
+ BIO *in = NULL, *out = NULL;
+ int openssl_ret = 0;
+ char *outcrlfile = NULL;
+ KMF_ENCODE_FORMAT outformat;
+
+ if (params == NULL || params->sslparms.crlfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (params->sslparms.crl_check == B_TRUE &&
+ params->sslparms.certfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ outcrlfile = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.outcrlfile);
+
+ if (outcrlfile == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(outcrlfile)) {
+ free(outcrlfile);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_IsCRLFile(handle, params->sslparms.crlfile, &format);
+ if (ret != KMF_OK) {
+ free(outcrlfile);
+ return (ret);
+ }
+
+ in = BIO_new_file(params->sslparms.crlfile, "rb");
+ if (in == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ xcrl = d2i_X509_CRL_bio(in, NULL);
+ } else if (format == KMF_FORMAT_PEM) {
+ xcrl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
+ }
+
+ if (xcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto end;
+ }
+
+ /* If bypasscheck is specified, no need to verify. */
+ if (params->sslparms.crl_check == B_FALSE) {
+ goto output;
+ }
+
+ ret = KMF_IsCertFile(handle, params->sslparms.certfile, &format);
+ if (ret != KMF_OK)
+ goto end;
+
+ /* Read in the CA cert file and convert to X509 */
+ if (BIO_read_filename(in, params->sslparms.certfile) <= 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ xcert = d2i_X509_bio(in, NULL);
+ } else if (format == KMF_FORMAT_PEM) {
+ xcert = PEM_read_bio_X509(in, NULL, NULL, NULL);
+ } else {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ /* Now get the public key from the CA cert */
+ pkey = X509_get_pubkey(xcert);
+ if (!pkey) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CERTFILE;
+ goto end;
+ }
+
+ /* Verify the CRL with the CA's public key */
+ openssl_ret = X509_CRL_verify(xcrl, pkey);
+ EVP_PKEY_free(pkey);
+ if (openssl_ret > 0) {
+ ret = KMF_OK; /* verify succeed */
+ } else {
+ SET_ERROR(kmfh, openssl_ret);
+ ret = KMF_ERR_BAD_CRLFILE;
+ }
+
+output:
+ outformat = params->sslparms.format;
+
+ out = BIO_new_file(outcrlfile, "wb");
+ if (out == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (outformat == KMF_FORMAT_ASN1) {
+ openssl_ret = (int)i2d_X509_CRL_bio(out, xcrl);
+ } else if (outformat == KMF_FORMAT_PEM) {
+ openssl_ret = PEM_write_bio_X509_CRL(out, xcrl);
+ } else {
+ ret = KMF_ERR_BAD_PARAMETER;
+ goto end;
+ }
+
+ if (openssl_ret <= 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_WRITE_FILE;
+ } else {
+ ret = KMF_OK;
+ }
+
+end:
+ if (xcrl != NULL)
+ X509_CRL_free(xcrl);
+
+ if (xcert != NULL)
+ X509_free(xcert);
+
+ if (in != NULL)
+ (void) BIO_free(in);
+
+ if (out != NULL)
+ (void) BIO_free(out);
+
+ if (outcrlfile != NULL)
+ free(outcrlfile);
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_ListCRL(KMF_HANDLE_T handle, KMF_LISTCRL_PARAMS *params,
+ char **crldata)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ X509_CRL *x = NULL;
+ KMF_ENCODE_FORMAT format;
+ char *crlfile = NULL;
+ BIO *in = NULL;
+ BIO *mem = NULL;
+ long len;
+ char *memptr;
+ char *data = NULL;
+
+ if (params == NULL || params->sslparms.crlfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ crlfile = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.crlfile);
+
+ if (crlfile == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(crlfile)) {
+ free(crlfile);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_IsCRLFile(handle, crlfile, &format);
+ if (ret != KMF_OK) {
+ free(crlfile);
+ return (ret);
+ }
+
+ if (bio_err == NULL)
+ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
+
+ in = BIO_new_file(crlfile, "rb");
+ if (in == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ x = d2i_X509_CRL_bio(in, NULL);
+ } else if (format == KMF_FORMAT_PEM) {
+ x = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
+ }
+
+ if (x == NULL) { /* should not happen */
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ mem = BIO_new(BIO_s_mem());
+ if (mem == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ (void) X509_CRL_print(mem, x);
+ len = BIO_get_mem_data(mem, &memptr);
+ if (len <= 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ data = malloc(len + 1);
+ if (data == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ (void) memcpy(data, memptr, len);
+ data[len] = '\0';
+ *crldata = data;
+
+end:
+ if (x != NULL)
+ X509_CRL_free(x);
+
+ if (crlfile != NULL)
+ free(crlfile);
+
+ if (in != NULL)
+ (void) BIO_free(in);
+
+ if (mem != NULL)
+ (void) BIO_free(mem);
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_DeleteCRL(KMF_HANDLE_T handle, KMF_DELETECRL_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ENCODE_FORMAT format;
+ char *crlfile = NULL;
+ BIO *in = NULL;
+
+ if (params == NULL || params->sslparms.crlfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ crlfile = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.crlfile);
+
+ if (crlfile == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(crlfile)) {
+ ret = KMF_ERR_BAD_PARAMETER;
+ goto end;
+ }
+
+ ret = KMF_IsCRLFile(handle, crlfile, &format);
+ if (ret != KMF_OK)
+ goto end;
+
+ if (unlink(crlfile) != 0) {
+ SET_SYS_ERROR(kmfh, errno);
+ ret = KMF_ERR_INTERNAL;
+ goto end;
+ }
+
+end:
+ if (in != NULL)
+ (void) BIO_free(in);
+ if (crlfile != NULL)
+ free(crlfile);
+
+ return (ret);
+}
+
+
+KMF_RETURN
+OpenSSL_FindCertInCRL(KMF_HANDLE_T handle, KMF_FINDCERTINCRL_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ENCODE_FORMAT format;
+ BIO *in = NULL;
+ X509 *xcert = NULL;
+ X509_CRL *xcrl = NULL;
+ STACK_OF(X509_REVOKED) *revoke_stack = NULL;
+ X509_REVOKED *revoke;
+ int i;
+
+ if (params == NULL || params->sslparms.crlfile == NULL ||
+ params->sslparms.certfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_IsCRLFile(handle, params->sslparms.crlfile, &format);
+ if (ret != KMF_OK)
+ return (ret);
+
+ /* Read the CRL file and load it into a X509_CRL structure */
+ in = BIO_new_file(params->sslparms.crlfile, "rb");
+ if (in == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ xcrl = d2i_X509_CRL_bio(in, NULL);
+ } else if (format == KMF_FORMAT_PEM) {
+ xcrl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
+ }
+
+ if (xcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto end;
+ }
+ (void) BIO_free(in);
+
+ /* Read the Certificate file and load it into a X509 structure */
+ ret = KMF_IsCertFile(handle, params->sslparms.certfile, &format);
+ if (ret != KMF_OK)
+ goto end;
+
+ in = BIO_new_file(params->sslparms.certfile, "rb");
+ if (in == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ xcert = d2i_X509_bio(in, NULL);
+ } else if (format == KMF_FORMAT_PEM) {
+ xcert = PEM_read_bio_X509(in, NULL, NULL, NULL);
+ }
+
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CERTFILE;
+ goto end;
+ }
+
+ /* Check if the certificate and the CRL have same issuer */
+ if (X509_NAME_cmp(xcert->cert_info->issuer, xcrl->crl->issuer) != 0) {
+ ret = KMF_ERR_ISSUER;
+ goto end;
+ }
+
+ /* Check to see if the certificate serial number is revoked */
+ revoke_stack = X509_CRL_get_REVOKED(xcrl);
+ if (sk_X509_REVOKED_num(revoke_stack) <= 0) {
+ /* No revoked certificates in the CRL file */
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_EMPTY_CRL;
+ goto end;
+ }
+
+ for (i = 0; i < sk_X509_REVOKED_num(revoke_stack); i++) {
+ /*LINTED*/
+ revoke = sk_X509_REVOKED_value(revoke_stack, i);
+ if (ASN1_INTEGER_cmp(xcert->cert_info->serialNumber,
+ revoke->serialNumber) == 0) {
+ break;
+ }
+ }
+
+ if (i < sk_X509_REVOKED_num(revoke_stack)) {
+ ret = KMF_OK;
+ } else {
+ ret = KMF_ERR_NOT_REVOKED;
+ }
+
+end:
+ if (in != NULL)
+ (void) BIO_free(in);
+ if (xcrl != NULL)
+ X509_CRL_free(xcrl);
+ if (xcert != NULL)
+ X509_free(xcert);
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_GetErrorString(KMF_HANDLE_T handle, char **msgstr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ char str[256]; /* OpenSSL needs at least 120 byte buffer */
+
+ ERR_error_string_n(kmfh->lasterr.errcode, str, sizeof (str));
+ if (strlen(str)) {
+ *msgstr = (char *)strdup(str);
+ if ((*msgstr) == NULL)
+ ret = KMF_ERR_MEMORY;
+ } else {
+ *msgstr = NULL;
+ }
+
+ return (ret);
+}
+
+static int
+ext2NID(int kmfext)
+{
+ switch (kmfext) {
+ case KMF_X509_EXT_KEY_USAGE:
+ return (NID_key_usage);
+ case KMF_X509_EXT_PRIV_KEY_USAGE_PERIOD:
+ return (NID_private_key_usage_period);
+ case KMF_X509_EXT_CERT_POLICIES:
+ return (NID_certificate_policies);
+ case KMF_X509_EXT_SUBJ_ALTNAME:
+ return (NID_subject_alt_name);
+ case KMF_X509_EXT_ISSUER_ALTNAME:
+ return (NID_issuer_alt_name);
+ case KMF_X509_EXT_BASIC_CONSTRAINTS:
+ return (NID_basic_constraints);
+ case KMF_X509_EXT_EXT_KEY_USAGE:
+ return (NID_ext_key_usage);
+ case KMF_X509_EXT_AUTH_KEY_ID:
+ return (NID_authority_key_identifier);
+ case KMF_X509_EXT_CRL_DIST_POINTS:
+ return (NID_crl_distribution_points);
+ case KMF_X509_EXT_SUBJ_KEY_ID:
+ return (NID_subject_key_identifier);
+ case KMF_X509_EXT_POLICY_MAPPINGS:
+ return (OBJ_sn2nid("policyMappings"));
+ case KMF_X509_EXT_NAME_CONSTRAINTS:
+ return (OBJ_sn2nid("nameConstraints"));
+ case KMF_X509_EXT_POLICY_CONSTRAINTS:
+ return (OBJ_sn2nid("policyConstraints"));
+ case KMF_X509_EXT_INHIBIT_ANY_POLICY:
+ return (OBJ_sn2nid("inhibitAnyPolicy"));
+ case KMF_X509_EXT_FRESHEST_CRL:
+ return (OBJ_sn2nid("freshestCRL"));
+ default:
+ return (NID_undef);
+ }
+}
+
+KMF_RETURN
+OpenSSL_CertGetPrintable(KMF_HANDLE_T handle, const KMF_DATA *pcert,
+ KMF_PRINTABLE_ITEM flag, char *resultStr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ X509 *xcert = NULL;
+ unsigned char *outbuf = NULL;
+ unsigned char *outbuf_p;
+ char *tmpstr = NULL;
+ int j;
+ int ext_index, nid, len;
+ BIO *mem = NULL;
+ STACK *emlst = NULL;
+ X509_EXTENSION *ex;
+ X509_CINF *ci;
+
+ if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* copy cert data to outbuf */
+ outbuf = malloc(pcert->Length);
+ if (outbuf == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+ (void) memcpy(outbuf, pcert->Data, pcert->Length);
+
+ outbuf_p = outbuf; /* use a temp pointer; required by openssl */
+ xcert = d2i_X509(NULL, (const uchar_t **)&outbuf_p, pcert->Length);
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ mem = BIO_new(BIO_s_mem());
+ if (mem == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ switch (flag) {
+ case KMF_CERT_ISSUER:
+ (void) X509_NAME_print_ex(mem, X509_get_issuer_name(xcert), 0,
+ XN_FLAG_SEP_CPLUS_SPC);
+ len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ break;
+
+ case KMF_CERT_SUBJECT:
+ (void) X509_NAME_print_ex(mem, X509_get_subject_name(xcert), 0,
+ XN_FLAG_SEP_CPLUS_SPC);
+ len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ break;
+
+ case KMF_CERT_VERSION:
+ tmpstr = i2s_ASN1_INTEGER(NULL, xcert->cert_info->version);
+ (void) strncpy(resultStr, tmpstr, KMF_CERT_PRINTABLE_LEN);
+ OPENSSL_free(tmpstr);
+ len = strlen(resultStr);
+ break;
+
+ case KMF_CERT_SERIALNUM:
+ if (i2a_ASN1_INTEGER(mem, X509_get_serialNumber(xcert)) > 0) {
+ (void) strcpy(resultStr, "0x");
+ len = BIO_gets(mem, &resultStr[2],
+ KMF_CERT_PRINTABLE_LEN - 2);
+ }
+ break;
+
+ case KMF_CERT_NOTBEFORE:
+ (void) ASN1_TIME_print(mem, X509_get_notBefore(xcert));
+ len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ break;
+
+ case KMF_CERT_NOTAFTER:
+ (void) ASN1_TIME_print(mem, X509_get_notAfter(xcert));
+ len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ break;
+
+ case KMF_CERT_PUBKEY_DATA:
+ {
+ EVP_PKEY *pkey = X509_get_pubkey(xcert);
+ if (pkey == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ if (pkey->type == EVP_PKEY_RSA) {
+ (void) BIO_printf(mem,
+ "RSA Public Key: (%d bit)\n",
+ BN_num_bits(pkey->pkey.rsa->n));
+ (void) RSA_print(mem, pkey->pkey.rsa, 0);
+ } else if (pkey->type == EVP_PKEY_DSA) {
+ (void) BIO_printf(mem,
+ "%12sDSA Public Key:\n", "");
+ (void) DSA_print(mem, pkey->pkey.dsa, 0);
+ } else {
+ (void) BIO_printf(mem,
+ "%12sUnknown Public Key:\n", "");
+ }
+ (void) BIO_printf(mem, "\n");
+ EVP_PKEY_free(pkey);
+ }
+ len = BIO_read(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ break;
+ case KMF_CERT_SIGNATURE_ALG:
+ case KMF_CERT_PUBKEY_ALG:
+ if (flag == KMF_CERT_SIGNATURE_ALG) {
+ len = i2a_ASN1_OBJECT(mem,
+ xcert->sig_alg->algorithm);
+ } else {
+ len = i2a_ASN1_OBJECT(mem,
+ xcert->cert_info->key->algor->algorithm);
+ }
+
+ if (len > 0) {
+ len = BIO_read(mem, resultStr,
+ KMF_CERT_PRINTABLE_LEN);
+ }
+ break;
+
+ case KMF_CERT_EMAIL:
+ emlst = X509_get1_email(xcert);
+ for (j = 0; j < sk_num(emlst); j++)
+ (void) BIO_printf(mem, "%s\n", sk_value(emlst, j));
+
+ len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ X509_email_free(emlst);
+ break;
+ case KMF_X509_EXT_ISSUER_ALTNAME:
+ case KMF_X509_EXT_SUBJ_ALTNAME:
+ case KMF_X509_EXT_KEY_USAGE:
+ case KMF_X509_EXT_PRIV_KEY_USAGE_PERIOD:
+ case KMF_X509_EXT_CERT_POLICIES:
+ case KMF_X509_EXT_BASIC_CONSTRAINTS:
+ case KMF_X509_EXT_NAME_CONSTRAINTS:
+ case KMF_X509_EXT_POLICY_CONSTRAINTS:
+ case KMF_X509_EXT_EXT_KEY_USAGE:
+ case KMF_X509_EXT_INHIBIT_ANY_POLICY:
+ case KMF_X509_EXT_AUTH_KEY_ID:
+ case KMF_X509_EXT_SUBJ_KEY_ID:
+ case KMF_X509_EXT_POLICY_MAPPINGS:
+ case KMF_X509_EXT_CRL_DIST_POINTS:
+ case KMF_X509_EXT_FRESHEST_CRL:
+ nid = ext2NID(flag);
+ if (nid == NID_undef) {
+ ret = KMF_ERR_EXTENSION_NOT_FOUND;
+ goto out;
+ }
+ ci = xcert->cert_info;
+
+ ext_index = X509v3_get_ext_by_NID(ci->extensions, nid, -1);
+ if (ext_index == -1) {
+ SET_ERROR(kmfh, ERR_get_error());
+
+ ret = KMF_ERR_EXTENSION_NOT_FOUND;
+ goto out;
+ }
+ ex = X509v3_get_ext(ci->extensions, ext_index);
+
+ (void) i2a_ASN1_OBJECT(mem, X509_EXTENSION_get_object(ex));
+
+ if (BIO_printf(mem, ": %s\n",
+ X509_EXTENSION_get_critical(ex) ? "critical" : "") <=
+ 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+ if (!X509V3_EXT_print(mem, ex, X509V3_EXT_DUMP_UNKNOWN, 4)) {
+ (void) BIO_printf(mem, "%*s", 4, "");
+ (void) M_ASN1_OCTET_STRING_print(mem, ex->value);
+ }
+ if (BIO_write(mem, "\n", 1) <= 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+ len = BIO_read(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ }
+ if (len <= 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ }
+
+out:
+ if (outbuf != NULL) {
+ free(outbuf);
+ }
+
+ if (xcert != NULL) {
+ X509_free(xcert);
+ }
+
+ if (mem != NULL) {
+ (void) BIO_free(mem);
+ }
+
+ return (ret);
+}
+KMF_RETURN
+/*ARGSUSED*/
+OpenSSL_GetPrikeyByCert(KMF_HANDLE_T handle,
+ KMF_CRYPTOWITHCERT_PARAMS *params,
+ KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key,
+ KMF_KEY_ALG keytype)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_FINDKEY_PARAMS fkparms;
+ uint32_t numkeys = 0;
+
+ if (params == NULL && params->sslparms.keyfile == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * This is really just a FindKey operation, reuse the
+ * FindKey function.
+ */
+ (void *)memset(&fkparms, 0, sizeof (fkparms));
+ fkparms.kstype = KMF_KEYSTORE_OPENSSL;
+ fkparms.keyclass = KMF_ASYM_PRI;
+ fkparms.keytype = keytype;
+ fkparms.format = params->format;
+ fkparms.sslparms = params->sslparms;
+
+ rv = OpenSSL_FindKey(handle, &fkparms, key, &numkeys);
+
+ return (rv);
+}
+
+KMF_RETURN
+/*ARGSUSED*/
+OpenSSL_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_OID *AlgOID, KMF_DATA *ciphertext,
+ KMF_DATA *output)
+{
+ KMF_RETURN ret = KMF_OK;
+ RSA *rsa = NULL;
+ unsigned int in_len = 0, out_len = 0;
+ unsigned int total_decrypted = 0, modulus_len = 0;
+ uint8_t *in_data, *out_data;
+ int i, blocks;
+
+ if (key == NULL || AlgOID == NULL ||
+ ciphertext == NULL || output == NULL ||
+ ciphertext->Data == NULL ||
+ output->Data == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (key->keyalg == KMF_RSA) {
+ rsa = EVP_PKEY_get1_RSA((EVP_PKEY *)key->keyp);
+ modulus_len = RSA_size(rsa);
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ blocks = ciphertext->Length/modulus_len;
+ out_data = output->Data;
+ in_data = ciphertext->Data;
+ out_len = modulus_len - 11;
+ in_len = modulus_len;
+
+ for (i = 0; i < blocks; i++) {
+ out_len = RSA_private_decrypt(in_len,
+ in_data, out_data, rsa, RSA_PKCS1_PADDING);
+
+ if (out_len == 0) {
+ ret = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+
+ out_data += out_len;
+ total_decrypted += out_len;
+ in_data += in_len;
+ }
+
+ output->Length = total_decrypted;
+
+cleanup:
+ RSA_free(rsa);
+ if (ret != KMF_OK)
+ output->Length = 0;
+
+ return (ret);
+
+}
+
+/*
+ * This function will create a certid from issuer_cert and user_cert.
+ * The caller should use OCSP_CERTID_free(OCSP_CERTID *) to deallocate
+ * certid memory after use.
+ */
+static KMF_RETURN
+create_certid(KMF_HANDLE_T handle, const KMF_DATA *issuer_cert,
+ const KMF_DATA *user_cert, OCSP_CERTID **certid)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ X509 *issuer = NULL;
+ X509 *cert = NULL;
+ unsigned char *ptmp;
+
+ if (issuer_cert == NULL || user_cert == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* convert the DER-encoded issuer cert to an internal X509 */
+ ptmp = issuer_cert->Data;
+ issuer = d2i_X509(NULL, (const uchar_t **)&ptmp,
+ issuer_cert->Length);
+ if (issuer == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OCSP_BAD_ISSUER;
+ goto end;
+ }
+
+ /* convert the DER-encoded user cert to an internal X509 */
+ ptmp = user_cert->Data;
+ cert = d2i_X509(NULL, (const uchar_t **)&ptmp,
+ user_cert->Length);
+ if (cert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+
+ ret = KMF_ERR_OCSP_BAD_CERT;
+ goto end;
+ }
+
+ /* create a CERTID */
+ *certid = OCSP_cert_to_id(NULL, cert, issuer);
+ if (*certid == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OCSP_CERTID;
+ goto end;
+ }
+
+end:
+ if (issuer != NULL) {
+ X509_free(issuer);
+ }
+
+ if (cert != NULL) {
+ X509_free(cert);
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_CreateOCSPRequest(KMF_HANDLE_T handle, KMF_OCSPREQUEST_PARAMS *params,
+ char *reqfile)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ OCSP_CERTID *id = NULL;
+ OCSP_REQUEST *req = NULL;
+ BIO *derbio = NULL;
+
+ if (params->user_cert == NULL || params->issuer_cert == NULL ||
+ reqfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = create_certid(handle, params->issuer_cert, params->user_cert,
+ &id);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ /* Create an OCSP request */
+ req = OCSP_REQUEST_new();
+ if (req == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OCSP_CREATE_REQUEST;
+ goto end;
+ }
+
+ if (!OCSP_request_add0_id(req, id)) {
+ ret = KMF_ERR_OCSP_CREATE_REQUEST;
+ goto end;
+ }
+
+ /* Write the request to the output file with DER encoding */
+ derbio = BIO_new_file(reqfile, "wb");
+ if (!derbio) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+ if (i2d_OCSP_REQUEST_bio(derbio, req) <= 0) {
+ ret = KMF_ERR_ENCODING;
+ }
+
+end:
+ /*
+ * We don't need to free "id" explicitely, because OCSP_REQUEST_free()
+ * will deallocate certid's space also.
+ */
+ if (req != NULL) {
+ OCSP_REQUEST_free(req);
+ }
+
+ if (derbio != NULL) {
+ (void) BIO_free(derbio);
+ }
+
+ return (ret);
+}
+
+/* ocsp_find_signer_sk() is copied from openssl source */
+static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id)
+{
+ int i;
+ unsigned char tmphash[SHA_DIGEST_LENGTH], *keyhash;
+
+ /* Easy if lookup by name */
+ if (id->type == V_OCSP_RESPID_NAME)
+ return (X509_find_by_subject(certs, id->value.byName));
+
+ /* Lookup by key hash */
+
+ /* If key hash isn't SHA1 length then forget it */
+ if (id->value.byKey->length != SHA_DIGEST_LENGTH)
+ return (NULL);
+
+ keyhash = id->value.byKey->data;
+ /* Calculate hash of each key and compare */
+ for (i = 0; i < sk_X509_num(certs); i++) {
+ /*LINTED*/
+ X509 *x = sk_X509_value(certs, i);
+ (void) X509_pubkey_digest(x, EVP_sha1(), tmphash, NULL);
+ if (!memcmp(keyhash, tmphash, SHA_DIGEST_LENGTH))
+ return (x);
+ }
+ return (NULL);
+}
+
+/* ocsp_find_signer() is copied from openssl source */
+/*ARGSUSED*/
+static int
+ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
+ X509_STORE *st, unsigned long flags)
+{
+ X509 *signer;
+ OCSP_RESPID *rid = bs->tbsResponseData->responderId;
+ if ((signer = ocsp_find_signer_sk(certs, rid))) {
+ *psigner = signer;
+ return (2);
+ }
+ if (!(flags & OCSP_NOINTERN) &&
+ (signer = ocsp_find_signer_sk(bs->certs, rid))) {
+ *psigner = signer;
+ return (1);
+ }
+ /* Maybe lookup from store if by subject name */
+
+ *psigner = NULL;
+ return (0);
+}
+
+/*
+ * This function will verify the signature of a basic response, using
+ * the public key from the OCSP responder certificate.
+ */
+static KMF_RETURN
+check_response_signature(KMF_HANDLE_T handle, OCSP_BASICRESP *bs,
+ KMF_DATA *signer_cert, KMF_DATA *issuer_cert)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ STACK_OF(X509) *cert_stack = NULL;
+ X509 *signer = NULL;
+ X509 *issuer = NULL;
+ EVP_PKEY *skey = NULL;
+ unsigned char *ptmp;
+
+
+ if (bs == NULL || issuer_cert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * Find the certificate that signed the basic response.
+ *
+ * If signer_cert is not NULL, we will use that as the signer cert.
+ * Otherwise, we will check if the issuer cert is actually the signer.
+ * If we still do not find a signer, we will look for it from the
+ * certificate list came with the response file.
+ */
+ if (signer_cert != NULL) {
+ ptmp = signer_cert->Data;
+ signer = d2i_X509(NULL, (const uchar_t **)&ptmp,
+ signer_cert->Length);
+ if (signer == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OCSP_BAD_SIGNER;
+ goto end;
+ }
+ } else {
+ /*
+ * Convert the issuer cert into X509 and push it into a
+ * stack to be used by ocsp_find_signer().
+ */
+ ptmp = issuer_cert->Data;
+ issuer = d2i_X509(NULL, (const uchar_t **)&ptmp,
+ issuer_cert->Length);
+ if (issuer == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OCSP_BAD_ISSUER;
+ goto end;
+ }
+
+ if ((cert_stack = sk_X509_new_null()) == NULL) {
+ ret = KMF_ERR_INTERNAL;
+ goto end;
+ }
+
+ if (sk_X509_push(cert_stack, issuer) == NULL) {
+ ret = KMF_ERR_INTERNAL;
+ goto end;
+ }
+
+ ret = ocsp_find_signer(&signer, bs, cert_stack, NULL, 0);
+ if (!ret) {
+ /* can not find the signer */
+ ret = KMF_ERR_OCSP_BAD_SIGNER;
+ goto end;
+ }
+ }
+
+ /* Verify the signature of the response */
+ skey = X509_get_pubkey(signer);
+ if (skey == NULL) {
+ ret = KMF_ERR_OCSP_BAD_SIGNER;
+ goto end;
+ }
+
+ ret = OCSP_BASICRESP_verify(bs, skey, 0);
+ if (ret == 0) {
+ ret = KMF_ERR_OCSP_RESPONSE_SIGNATURE;
+ goto end;
+ }
+
+end:
+ if (issuer != NULL) {
+ X509_free(issuer);
+ }
+
+ if (signer != NULL) {
+ X509_free(signer);
+ }
+
+ if (skey != NULL) {
+ EVP_PKEY_free(skey);
+ }
+
+ if (cert_stack != NULL) {
+ sk_X509_free(cert_stack);
+ }
+
+ return (ret);
+}
+
+
+
+KMF_RETURN
+OpenSSL_GetOCSPStatusForCert(KMF_HANDLE_T handle,
+ KMF_OCSPRESPONSE_PARAMS_INPUT *params_in,
+ KMF_OCSPRESPONSE_PARAMS_OUTPUT *params_out)
+{
+ KMF_RETURN ret = KMF_OK;
+ BIO *derbio = NULL;
+ OCSP_RESPONSE *resp = NULL;
+ OCSP_BASICRESP *bs = NULL;
+ OCSP_CERTID *id = NULL;
+ OCSP_SINGLERESP *single = NULL;
+ ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+ int index, status, reason;
+
+ if (params_in == NULL || params_in->issuer_cert == NULL ||
+ params_in->user_cert == NULL || params_in->response == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (params_out == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* Read in the response */
+ derbio = BIO_new_mem_buf(params_in->response->Data,
+ params_in->response->Length);
+ if (!derbio) {
+ ret = KMF_ERR_MEMORY;
+ return (ret);
+ }
+
+ resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
+ if (resp == NULL) {
+ ret = KMF_ERR_OCSP_MALFORMED_RESPONSE;
+ goto end;
+ }
+
+ /* Check the response status */
+ status = OCSP_response_status(resp);
+ params_out->response_status = status;
+ if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ ret = KMF_ERR_OCSP_RESPONSE_STATUS;
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("Successfully checked the response file status.\n");
+#endif /* DEBUG */
+
+ /* Extract basic response */
+ bs = OCSP_response_get1_basic(resp);
+ if (bs == NULL) {
+ ret = KMF_ERR_OCSP_NO_BASIC_RESPONSE;
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("Successfully retrieved the basic response.\n");
+#endif /* DEBUG */
+
+ /* Check the basic response signature if required */
+ if (params_in->ignore_response_sign == B_FALSE) {
+ ret = check_response_signature(handle, bs,
+ params_in->signer_cert, params_in->issuer_cert);
+ if (ret != KMF_OK)
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("Successfully verified the response signature.\n");
+#endif /* DEBUG */
+
+ /* Create a certid for the certificate in question */
+ ret = create_certid(handle, params_in->issuer_cert,
+ params_in->user_cert, &id);
+ if (ret != KMF_OK) {
+ ret = KMF_ERR_OCSP_CERTID;
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("successfully created a certid for the cert.\n");
+#endif /* DEBUG */
+
+ /* Find the index of the single response for the certid */
+ index = OCSP_resp_find(bs, id, -1);
+ if (index < 0) {
+ /* cound not find this certificate in the response */
+ ret = KMF_ERR_OCSP_UNKNOWN_CERT;
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("Successfully found the single response index for the cert.\n");
+#endif /* DEBUG */
+
+ /* Retrieve the single response and get the cert status */
+ single = OCSP_resp_get0(bs, index);
+ status = OCSP_single_get0_status(single, &reason, &rev, &thisupd,
+ &nextupd);
+ if (status == V_OCSP_CERTSTATUS_GOOD) {
+ params_out->cert_status = OCSP_GOOD;
+ } else if (status == V_OCSP_CERTSTATUS_UNKNOWN) {
+ params_out->cert_status = OCSP_UNKNOWN;
+ } else { /* revoked */
+ params_out->cert_status = OCSP_REVOKED;
+ params_out->reason = reason;
+ }
+ ret = KMF_OK;
+
+ /* Verify the time */
+ if (!OCSP_check_validity(thisupd, nextupd, 300,
+ params_in->response_lifetime)) {
+ ret = KMF_ERR_OCSP_STATUS_TIME_INVALID;
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("Successfully verify the time.\n");
+#endif /* DEBUG */
+
+end:
+ if (derbio != NULL)
+ (void) BIO_free(derbio);
+
+ if (resp != NULL)
+ OCSP_RESPONSE_free(resp);
+
+ if (bs != NULL)
+ OCSP_BASICRESP_free(bs);
+
+ if (id != NULL)
+ OCSP_CERTID_free(id);
+
+ return (ret);
+}
+
+static KMF_RETURN
+fetch_key(KMF_HANDLE_T handle, char *path,
+ KMF_KEY_CLASS keyclass, KMF_KEY_HANDLE *key)
+{
+ KMF_RETURN rv = KMF_OK;
+ EVP_PKEY *pkey;
+ KMF_RAW_SYM_KEY *rkey = NULL;
+
+ /* Make sure the requested file actually exists. */
+ if (access(path, F_OK) != 0) {
+ return (KMF_ERR_KEY_NOT_FOUND);
+ }
+
+ if (keyclass == KMF_ASYM_PRI ||
+ keyclass == KMF_ASYM_PUB) {
+ pkey = openssl_load_key(handle, path);
+ if (pkey == NULL) {
+ return (KMF_ERR_KEY_NOT_FOUND);
+ }
+ if (key != NULL) {
+ if (pkey->type == EVP_PKEY_RSA)
+ key->keyalg = KMF_RSA;
+ else if (pkey->type == EVP_PKEY_DSA)
+ key->keyalg = KMF_DSA;
+
+ key->kstype = KMF_KEYSTORE_OPENSSL;
+ key->keyclass = keyclass;
+ key->keyp = (void *)pkey;
+ key->israw = FALSE;
+ key->keylabel = path;
+ } else {
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ }
+ } else if (keyclass == KMF_SYMMETRIC) {
+ KMF_ENCODE_FORMAT fmt;
+ /*
+ * If the file is a recognized format,
+ * then it is NOT a symmetric key.
+ */
+ rv = KMF_GetFileFormat(path, &fmt);
+ if (rv == KMF_OK || fmt != 0) {
+ return (KMF_ERR_KEY_NOT_FOUND);
+ } else if (rv == KMF_ERR_ENCODING) {
+ /*
+ * If we don't know the encoding,
+ * it is probably a symmetric key.
+ */
+ rv = KMF_OK;
+ }
+
+ if (key != NULL) {
+ KMF_DATA keyvalue;
+ rkey = malloc(sizeof (KMF_RAW_SYM_KEY));
+ if (rkey == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY));
+ rv = KMF_ReadInputFile(handle, path, &keyvalue);
+ if (rv != KMF_OK)
+ goto out;
+
+ rkey->keydata.len = keyvalue.Length;
+ rkey->keydata.val = keyvalue.Data;
+
+ key->kstype = KMF_KEYSTORE_OPENSSL;
+ key->keyclass = keyclass;
+ key->israw = TRUE;
+ key->keylabel = path;
+ key->keyp = (void *)rkey;
+ }
+ }
+out:
+ if (rv != KMF_OK) {
+ if (rkey != NULL) {
+ KMF_FreeRawSymKey(rkey);
+ }
+ if (pkey != NULL)
+ EVP_PKEY_free(pkey);
+
+ if (key != NULL) {
+ key->keyalg = KMF_KEYALG_NONE;
+ key->keyclass = KMF_KEYCLASS_NONE;
+ key->keyp = NULL;
+ }
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *params,
+ KMF_KEY_HANDLE *key, uint32_t *numkeys)
+{
+ KMF_RETURN rv = KMF_OK;
+ char *fullpath = NULL;
+
+ if (handle == NULL || params == NULL || numkeys == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (params->keyclass != KMF_ASYM_PUB &&
+ params->keyclass != KMF_ASYM_PRI &&
+ params->keyclass != KMF_SYMMETRIC)
+ return (KMF_ERR_BAD_KEY_CLASS);
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.keyfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ *numkeys = 0;
+
+ if (isdir(fullpath)) {
+ DIR *dirp;
+ struct dirent *dp;
+ int n = 0;
+
+ /* open all files in the directory and attempt to read them */
+ if ((dirp = opendir(fullpath)) == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ rewinddir(dirp);
+ while ((dp = readdir(dirp)) != NULL) {
+ if (strcmp(dp->d_name, ".") &&
+ strcmp(dp->d_name, "..")) {
+ char *fname;
+
+ fname = get_fullpath(fullpath,
+ (char *)&dp->d_name);
+
+ rv = fetch_key(handle, fname,
+ params->keyclass,
+ key ? &key[n] : NULL);
+
+ if (rv == KMF_OK)
+ n++;
+
+ if (rv != KMF_OK || key == NULL)
+ free(fname);
+ }
+ }
+ (void) closedir(dirp);
+ free(fullpath);
+ (*numkeys) = n;
+ } else {
+ rv = fetch_key(handle, fullpath, params->keyclass, key);
+ if (rv == KMF_OK)
+ (*numkeys) = 1;
+
+ if (rv != KMF_OK || key == NULL)
+ free(fullpath);
+ }
+
+ if ((*numkeys) == 0)
+ rv = KMF_ERR_KEY_NOT_FOUND;
+
+ return (rv);
+}
+
+#define HANDLE_PK12_ERROR { \
+ SET_ERROR(kmfh, ERR_get_error()); \
+ rv = KMF_ERR_ENCODING; \
+ goto out; \
+}
+
+static KMF_RETURN
+write_pkcs12(KMF_HANDLE *kmfh,
+ BIO *bio,
+ KMF_CREDENTIAL *cred,
+ EVP_PKEY *pkey,
+ X509 *sslcert)
+{
+ KMF_RETURN rv = KMF_OK;
+ STACK_OF(PKCS12_SAFEBAG) *bag_stack = NULL;
+ PKCS12_SAFEBAG *bag = NULL;
+ PKCS7 *cert_authsafe = NULL;
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
+ PKCS7 *key_authsafe = NULL;
+ STACK_OF(PKCS7) *authsafe_stack = NULL;
+ PKCS12 *p12_elem = NULL;
+ char *lab = NULL;
+ int lab_len = 0;
+ unsigned char keyid[EVP_MAX_MD_SIZE];
+ unsigned int keyidlen = 0;
+
+ /* Must have at least a cert OR a key */
+ if (sslcert == NULL && pkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(keyid, 0, sizeof (keyid));
+ /*
+ * Section 1:
+ *
+ * The first PKCS#12 container (safebag) will hold the certificates
+ * associated with this key. The result of this section is a
+ * PIN-encrypted PKCS#7 container (authsafe). If there are no
+ * certificates, there is no point in creating the "safebag" or the
+ * "authsafe" so we go to the next section.
+ */
+ if (sslcert != NULL && pkey != NULL) {
+ if (X509_check_private_key(sslcert, pkey)) {
+ (void) X509_digest(sslcert, EVP_sha1(), keyid,
+ &keyidlen);
+ } else {
+ /* The key doesn't match the cert */
+ HANDLE_PK12_ERROR
+ }
+ }
+
+ bag_stack = sk_PKCS12_SAFEBAG_new_null();
+ if (bag_stack == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (sslcert != NULL) {
+ /* Convert cert from X509 struct to PKCS#12 bag */
+ bag = PKCS12_x5092certbag(sslcert);
+ if (bag == NULL) {
+ HANDLE_PK12_ERROR
+ }
+
+ /* Add the key id to the certificate bag. */
+ if (keyidlen > 0 &&
+ !PKCS12_add_localkeyid(bag, keyid, keyidlen)) {
+ HANDLE_PK12_ERROR
+ }
+
+ /* Pile it on the bag_stack. */
+ if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) {
+ HANDLE_PK12_ERROR
+ }
+#if 0
+ /* No support for CA certs yet */
+ if (cacerts != NULL && ncacerts > 0) {
+ int i;
+ for (i = 0; i < ncacerts; i++) {
+ KMF_X509_DER_CERT *c = &cacerts[i];
+ X509 *ca = NULL;
+
+ uchar_t *p = (uchar_t *)c->certificate.Data;
+ ca = d2i_X509(NULL, &p,
+ c->certificate.Length);
+ if (ca == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ /* Convert CA cert to PKCS#12 bag. */
+ bag = PKCS12_x5092certbag(ca);
+ if (bag == NULL) {
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack,
+ PKCS12_SAFEBAG_free);
+ HANDLE_PK12_ERROR
+ }
+ /* Pile it onto the bag_stack. */
+ if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ }
+#endif
+ /* Turn bag_stack of certs into encrypted authsafe. */
+ cert_authsafe = PKCS12_pack_p7encdata(
+ NID_pbe_WithSHA1And40BitRC2_CBC,
+ cred->cred,
+ cred->credlen, NULL, 0,
+ PKCS12_DEFAULT_ITER,
+ bag_stack);
+
+ /* Clear away this bag_stack, we're done with it. */
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
+ bag_stack = NULL;
+
+ if (cert_authsafe == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ /*
+ * Section 2:
+ *
+ * The second PKCS#12 container (safebag) will hold the private key
+ * that goes with the certificates above. The results of this section
+ * is an unencrypted PKCS#7 container (authsafe). If there is no
+ * private key, there is no point in creating the "safebag" or the
+ * "authsafe" so we go to the next section.
+ */
+ if (pkey != NULL) {
+ p8 = EVP_PKEY2PKCS8(pkey);
+ if (p8 == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ /* Put the shrouded key into a PKCS#12 bag. */
+ bag = PKCS12_MAKE_SHKEYBAG(
+ NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
+ cred->cred, cred->credlen,
+ NULL, 0, PKCS12_DEFAULT_ITER, p8);
+
+ /* Clean up the PKCS#8 shrouded key, don't need it now. */
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ p8 = NULL;
+
+ if (bag == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ if (keyidlen &&
+ !PKCS12_add_localkeyid(bag, keyid, keyidlen)) {
+ HANDLE_PK12_ERROR
+ }
+ if (lab != NULL) {
+ if (!PKCS12_add_friendlyname(bag,
+ (char *)lab, lab_len)) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ /* Start a PKCS#12 safebag container for the private key. */
+ bag_stack = sk_PKCS12_SAFEBAG_new_null();
+ if (bag_stack == NULL) {
+ HANDLE_PK12_ERROR
+ }
+
+ /* Pile on the private key on the bag_stack. */
+ if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) {
+ HANDLE_PK12_ERROR
+ }
+ key_authsafe = PKCS12_pack_p7data(bag_stack);
+
+ /* Clear away this bag_stack, we're done with it. */
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
+ bag_stack = NULL;
+
+ if (key_authsafe == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ /*
+ * Section 3:
+ *
+ * This is where the two PKCS#7 containers, one for the certificates
+ * and one for the private key, are put together into a PKCS#12
+ * element. This final PKCS#12 element is written to the export file.
+ */
+
+ /* Start a PKCS#7 stack. */
+ authsafe_stack = sk_PKCS7_new_null();
+ if (authsafe_stack == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ if (key_authsafe != NULL) {
+ if (!sk_PKCS7_push(authsafe_stack, key_authsafe)) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ if (cert_authsafe != NULL) {
+ if (!sk_PKCS7_push(authsafe_stack, cert_authsafe)) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ p12_elem = PKCS12_init(NID_pkcs7_data);
+ if (p12_elem == NULL) {
+ sk_PKCS7_pop_free(authsafe_stack, PKCS7_free);
+ HANDLE_PK12_ERROR
+ }
+
+ /* Put the PKCS#7 stack into the PKCS#12 element. */
+ if (!PKCS12_pack_authsafes(p12_elem, authsafe_stack)) {
+ HANDLE_PK12_ERROR
+ }
+ /* Clear away the PKCS#7 stack, we're done with it. */
+ sk_PKCS7_pop_free(authsafe_stack, PKCS7_free);
+ authsafe_stack = NULL;
+
+ /* Set the integrity MAC on the PKCS#12 element. */
+ if (!PKCS12_set_mac(p12_elem, cred->cred, cred->credlen,
+ NULL, 0, PKCS12_DEFAULT_ITER, NULL)) {
+ HANDLE_PK12_ERROR
+ }
+
+ /* Write the PKCS#12 element to the export file. */
+ if (!i2d_PKCS12_bio(bio, p12_elem)) {
+ HANDLE_PK12_ERROR
+ }
+
+ PKCS12_free(p12_elem);
+out:
+ if (rv != KMF_OK) {
+ /* Clear away this bag_stack, we're done with it. */
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
+ sk_PKCS7_pop_free(authsafe_stack, PKCS7_free);
+ }
+ return (rv);
+}
+
+static EVP_PKEY *
+ImportRawRSAKey(KMF_RAW_RSA_KEY *key)
+{
+ RSA *rsa = NULL;
+ EVP_PKEY *newkey = NULL;
+
+ if ((rsa = RSA_new()) == NULL)
+ return (NULL);
+
+ if ((rsa->n = BN_bin2bn(key->mod.val, key->mod.len, rsa->n)) == NULL)
+ return (NULL);
+
+ if ((rsa->e = BN_bin2bn(key->pubexp.val, key->pubexp.len, rsa->e)) ==
+ NULL)
+ return (NULL);
+
+ if (key->priexp.val != NULL)
+ if ((rsa->d = BN_bin2bn(key->priexp.val, key->priexp.len,
+ rsa->d)) == NULL)
+ return (NULL);
+
+ if (key->prime1.val != NULL)
+ if ((rsa->p = BN_bin2bn(key->prime1.val, key->prime1.len,
+ rsa->p)) == NULL)
+ return (NULL);
+
+ if (key->prime2.val != NULL)
+ if ((rsa->q = BN_bin2bn(key->prime2.val, key->prime2.len,
+ rsa->q)) == NULL)
+ return (NULL);
+
+ if (key->exp1.val != NULL)
+ if ((rsa->dmp1 = BN_bin2bn(key->exp1.val, key->exp1.len,
+ rsa->dmp1)) == NULL)
+ return (NULL);
+
+ if (key->exp2.val != NULL)
+ if ((rsa->dmq1 = BN_bin2bn(key->exp2.val, key->exp2.len,
+ rsa->dmq1)) == NULL)
+ return (NULL);
+
+ if (key->coef.val != NULL)
+ if ((rsa->iqmp = BN_bin2bn(key->coef.val, key->coef.len,
+ rsa->iqmp)) == NULL)
+ return (NULL);
+
+ if ((newkey = EVP_PKEY_new()) == NULL)
+ return (NULL);
+
+ (void) EVP_PKEY_set1_RSA(newkey, rsa);
+
+ /* The original key must be freed once here or it leaks memory */
+ RSA_free(rsa);
+
+ return (newkey);
+}
+
+static EVP_PKEY *
+ImportRawDSAKey(KMF_RAW_DSA_KEY *key)
+{
+ DSA *dsa = NULL;
+ EVP_PKEY *newkey = NULL;
+
+ if ((dsa = DSA_new()) == NULL)
+ return (NULL);
+
+ if ((dsa->p = BN_bin2bn(key->prime.val, key->prime.len,
+ dsa->p)) == NULL)
+ return (NULL);
+
+ if ((dsa->q = BN_bin2bn(key->subprime.val, key->subprime.len,
+ dsa->q)) == NULL)
+ return (NULL);
+
+ if ((dsa->g = BN_bin2bn(key->base.val, key->base.len,
+ dsa->g)) == NULL)
+ return (NULL);
+
+ if ((dsa->priv_key = BN_bin2bn(key->value.val, key->value.len,
+ dsa->priv_key)) == NULL)
+ return (NULL);
+
+ if ((newkey = EVP_PKEY_new()) == NULL)
+ return (NULL);
+
+ (void) EVP_PKEY_set1_DSA(newkey, dsa);
+
+ /* The original key must be freed once here or it leaks memory */
+ DSA_free(dsa);
+ return (newkey);
+}
+
+static KMF_RETURN
+ExportPK12FromRawData(KMF_HANDLE_T handle,
+ KMF_CREDENTIAL *cred,
+ int numcerts, KMF_X509_DER_CERT *certlist,
+ int numkeys, KMF_KEY_HANDLE *keylist,
+ char *filename)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ BIO *bio = NULL;
+ X509 *xcert = NULL;
+ EVP_PKEY *pkey = NULL;
+ int i;
+
+ /*
+ * Open the output file.
+ */
+ if ((bio = BIO_new_file(filename, "wb")) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ if (numcerts > 0 && numkeys > 0) {
+ for (i = 0; rv == KMF_OK && i < numcerts; i++) {
+ KMF_RAW_KEY_DATA *key = NULL;
+ const uchar_t *p = certlist[i].certificate.Data;
+ long len = certlist[i].certificate.Length;
+
+ if (i < numkeys) {
+ key = (KMF_RAW_KEY_DATA *)keylist[i].keyp;
+
+ if (key->keytype == KMF_RSA) {
+ pkey = ImportRawRSAKey(
+ &key->rawdata.rsa);
+ } else if (key->keytype == KMF_DSA) {
+ pkey = ImportRawDSAKey(
+ &key->rawdata.dsa);
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ }
+ }
+
+ xcert = d2i_X509(NULL, &p, len);
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_ENCODING;
+ }
+ /* Stick the key and the cert into a PKCS#12 file */
+ rv = write_pkcs12(kmfh, bio, cred, pkey, xcert);
+ if (xcert)
+ X509_free(xcert);
+ if (pkey)
+ EVP_PKEY_free(pkey);
+ }
+ }
+
+cleanup:
+
+ if (bio != NULL)
+ (void) BIO_free_all(bio);
+
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_ExportP12(KMF_HANDLE_T handle,
+ KMF_EXPORTP12_PARAMS *params,
+ int numcerts, KMF_X509_DER_CERT *certlist,
+ int numkeys, KMF_KEY_HANDLE *keylist,
+ char *filename)
+{
+ KMF_RETURN rv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_FINDCERT_PARAMS fcargs;
+ BIO *bio = NULL;
+ X509 *xcert = NULL;
+ char *fullpath = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ /*
+ * First, find the certificate.
+ */
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * If the caller already sent the raw keys and certs,
+ * shortcut the search and just export that
+ * data.
+ *
+ * One *may* export a key OR a cert by itself.
+ */
+ if (certlist != NULL || keylist != NULL) {
+ rv = ExportPK12FromRawData(handle,
+ &params->p12cred,
+ numcerts, certlist,
+ numkeys, keylist,
+ filename);
+ return (rv);
+ }
+
+ if (params->sslparms.certfile != NULL) {
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.certfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(fullpath)) {
+ free(fullpath);
+ return (KMF_ERR_AMBIGUOUS_PATHNAME);
+ }
+
+ (void *)memset(&fcargs, 0, sizeof (fcargs));
+ fcargs.kstype = params->kstype;
+ fcargs.certLabel = params->certLabel;
+ fcargs.issuer = params->issuer;
+ fcargs.subject = params->subject;
+ fcargs.serial = params->serial;
+ fcargs.idstr = params->idstr;
+ fcargs.sslparms.dirpath = NULL;
+ fcargs.sslparms.certfile = fullpath;
+ fcargs.sslparms.format = params->sslparms.format;
+
+ rv = load_X509cert(kmfh, &fcargs, fullpath, &xcert);
+ if (rv != KMF_OK)
+ goto end;
+ }
+
+ /*
+ * Now find the private key.
+ */
+ if (params->sslparms.keyfile != NULL) {
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.keyfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(fullpath)) {
+ free(fullpath);
+ return (KMF_ERR_AMBIGUOUS_PATHNAME);
+ }
+
+ pkey = openssl_load_key(handle, fullpath);
+ if (pkey == NULL) {
+ rv = KMF_ERR_KEY_NOT_FOUND;
+ goto end;
+ }
+ }
+
+ /*
+ * Open the output file.
+ */
+ if ((bio = BIO_new_file(filename, "wb")) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ /* Stick the key and the cert into a PKCS#12 file */
+ rv = write_pkcs12(kmfh, bio, &params->p12cred,
+ pkey, xcert);
+
+end:
+ if (fullpath)
+ free(fullpath);
+ if (xcert)
+ X509_free(xcert);
+ if (pkey)
+ EVP_PKEY_free(pkey);
+ if (bio)
+ (void) BIO_free(bio);
+
+ return (rv);
+}
+
+/*
+ * Helper function to decrypt and parse PKCS#12 import file.
+ */
+static KMF_RETURN
+extract_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen,
+ EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca)
+/* ARGSUSED */
+{
+ PKCS12 *pk12, *pk12_tmp;
+ EVP_PKEY *temp_pkey = NULL;
+ X509 *temp_cert = NULL;
+ STACK_OF(X509) *temp_ca = NULL;
+
+ if ((pk12 = PKCS12_new()) == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ if ((pk12_tmp = d2i_PKCS12_bio(fbio, &pk12)) == NULL) {
+ /* This is ok; it seems to mean there is no more to read. */
+ if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_ASN1 &&
+ ERR_GET_REASON(ERR_peek_error()) == ASN1_R_HEADER_TOO_LONG)
+ goto end_extract_pkcs12;
+
+ PKCS12_free(pk12);
+ return (KMF_ERR_PKCS12_FORMAT);
+ }
+ pk12 = pk12_tmp;
+
+ if (PKCS12_parse(pk12, (char *)pin, &temp_pkey, &temp_cert,
+ &temp_ca) <= 0) {
+ PKCS12_free(pk12);
+ return (KMF_ERR_PKCS12_FORMAT);
+ }
+
+end_extract_pkcs12:
+
+ *priv_key = temp_pkey;
+ *cert = temp_cert;
+ *ca = temp_ca;
+
+ PKCS12_free(pk12);
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+sslBN2KMFBN(BIGNUM *from, KMF_BIGINT *to)
+{
+ KMF_RETURN rv = KMF_OK;
+ uint32_t sz;
+
+ sz = BN_num_bytes(from);
+ to->val = (uchar_t *)malloc(sz);
+ if (to->val == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if ((to->len = BN_bn2bin(from, to->val)) != sz) {
+ free(to->val);
+ to->val = NULL;
+ to->len = 0;
+ rv = KMF_ERR_MEMORY;
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+exportRawRSAKey(RSA *rsa, KMF_RAW_KEY_DATA *key)
+{
+ KMF_RETURN rv;
+ KMF_RAW_RSA_KEY *kmfkey = &key->rawdata.rsa;
+
+ (void) memset(kmfkey, 0, sizeof (KMF_RAW_RSA_KEY));
+ if ((rv = sslBN2KMFBN(rsa->n, &kmfkey->mod)) != KMF_OK)
+ goto cleanup;
+
+ if ((rv = sslBN2KMFBN(rsa->e, &kmfkey->pubexp)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->d != NULL)
+ if ((rv = sslBN2KMFBN(rsa->d, &kmfkey->priexp)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->p != NULL)
+ if ((rv = sslBN2KMFBN(rsa->p, &kmfkey->prime1)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->q != NULL)
+ if ((rv = sslBN2KMFBN(rsa->q, &kmfkey->prime2)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->dmp1 != NULL)
+ if ((rv = sslBN2KMFBN(rsa->dmp1, &kmfkey->exp1)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->dmq1 != NULL)
+ if ((rv = sslBN2KMFBN(rsa->dmq1, &kmfkey->exp2)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->iqmp != NULL)
+ if ((rv = sslBN2KMFBN(rsa->iqmp, &kmfkey->coef)) != KMF_OK)
+ goto cleanup;
+cleanup:
+ if (rv != KMF_OK)
+ KMF_FreeRawKey(key);
+ else
+ key->keytype = KMF_RSA;
+
+ /*
+ * Free the reference to this key, SSL will not actually free
+ * the memory until the refcount == 0, so this is safe.
+ */
+ RSA_free(rsa);
+
+ return (rv);
+}
+
+static KMF_RETURN
+exportRawDSAKey(DSA *dsa, KMF_RAW_KEY_DATA *key)
+{
+ KMF_RETURN rv;
+ KMF_RAW_DSA_KEY *kmfkey = &key->rawdata.dsa;
+
+ (void) memset(kmfkey, 0, sizeof (KMF_RAW_DSA_KEY));
+ if ((rv = sslBN2KMFBN(dsa->p, &kmfkey->prime)) != KMF_OK)
+ goto cleanup;
+
+ if ((rv = sslBN2KMFBN(dsa->q, &kmfkey->subprime)) != KMF_OK)
+ goto cleanup;
+
+ if ((rv = sslBN2KMFBN(dsa->g, &kmfkey->base)) != KMF_OK)
+ goto cleanup;
+
+ if ((rv = sslBN2KMFBN(dsa->priv_key, &kmfkey->value)) != KMF_OK)
+ goto cleanup;
+
+cleanup:
+ if (rv != KMF_OK)
+ KMF_FreeRawKey(key);
+ else
+ key->keytype = KMF_DSA;
+
+ /*
+ * Free the reference to this key, SSL will not actually free
+ * the memory until the refcount == 0, so this is safe.
+ */
+ DSA_free(dsa);
+
+ return (rv);
+}
+
+static KMF_RETURN
+add_cert_to_list(KMF_HANDLE *kmfh, X509 *sslcert,
+ KMF_DATA **certlist, int *ncerts)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_DATA *list = (*certlist);
+ KMF_DATA cert;
+ int n = (*ncerts);
+
+ if (list == NULL) {
+ list = (KMF_DATA *)malloc(sizeof (KMF_DATA));
+ } else {
+ list = (KMF_DATA *)realloc(list, sizeof (KMF_DATA) * (n + 1));
+ }
+
+ if (list == NULL)
+ return (KMF_ERR_MEMORY);
+
+ rv = ssl_cert2KMFDATA(kmfh, sslcert, &cert);
+ if (rv == KMF_OK) {
+ list[n] = cert;
+ (*ncerts) = n + 1;
+
+ *certlist = list;
+ } else {
+ free(list);
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+add_key_to_list(KMF_RAW_KEY_DATA **keylist,
+ KMF_RAW_KEY_DATA *newkey, int *nkeys)
+{
+ KMF_RAW_KEY_DATA *list = (*keylist);
+ int n = (*nkeys);
+
+ if (list == NULL) {
+ list = (KMF_RAW_KEY_DATA *)malloc(sizeof (KMF_RAW_KEY_DATA));
+ } else {
+ list = (KMF_RAW_KEY_DATA *)realloc(list,
+ sizeof (KMF_RAW_KEY_DATA) * (n + 1));
+ }
+
+ if (list == NULL)
+ return (KMF_ERR_MEMORY);
+
+ list[n] = *newkey;
+ (*nkeys) = n + 1;
+
+ *keylist = list;
+
+ return (KMF_OK);
+}
+
+
+static KMF_RETURN
+convertPK12Objects(
+ KMF_HANDLE *kmfh,
+ EVP_PKEY *sslkey, X509 *sslcert, STACK_OF(X509) *sslcacerts,
+ KMF_RAW_KEY_DATA **keylist, int *nkeys,
+ KMF_DATA **certlist, int *ncerts)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_RAW_KEY_DATA key;
+ int i;
+
+ if (sslkey != NULL) {
+ /* Convert SSL key to raw key */
+ switch (sslkey->type) {
+ case EVP_PKEY_RSA:
+ rv = exportRawRSAKey(EVP_PKEY_get1_RSA(sslkey),
+ &key);
+ if (rv != KMF_OK)
+ return (rv);
+
+ break;
+ case EVP_PKEY_DSA:
+ rv = exportRawDSAKey(EVP_PKEY_get1_DSA(sslkey),
+ &key);
+ if (rv != KMF_OK)
+ return (rv);
+
+ break;
+ default:
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ rv = add_key_to_list(keylist, &key, nkeys);
+ if (rv != KMF_OK)
+ return (rv);
+ }
+
+ /* Now add the certificate to the certlist */
+ if (sslcert != NULL) {
+ rv = add_cert_to_list(kmfh, sslcert, certlist, ncerts);
+ if (rv != KMF_OK)
+ return (rv);
+ }
+
+ /* Also add any included CA certs to the list */
+ for (i = 0; i != sk_X509_num(sslcacerts); i++) {
+ X509 *c;
+ /*
+ * sk_X509_value() is macro that embeds a cast to (X509 *).
+ * Here it translates into ((X509 *)sk_value((ca), (i))).
+ * Lint is complaining about the embedded casting, and
+ * to fix it, you need to fix openssl header files.
+ */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ c = sk_X509_value(sslcacerts, i);
+
+ /* Now add the ca cert to the certlist */
+ rv = add_cert_to_list(kmfh, c, certlist, ncerts);
+ if (rv != KMF_OK)
+ return (rv);
+ }
+ return (rv);
+}
+
+KMF_RETURN
+openssl_read_pkcs12(KMF_HANDLE *kmfh,
+ char *filename, KMF_CREDENTIAL *cred,
+ KMF_DATA **certlist, int *ncerts,
+ KMF_RAW_KEY_DATA **keylist, int *nkeys)
+{
+ KMF_RETURN rv = KMF_OK;
+ BIO *bio = NULL;
+ EVP_PKEY *privkey = NULL;
+ X509 *cert = NULL;
+ STACK_OF(X509) *cacerts = NULL;
+
+ bio = BIO_new_file(filename, "rb");
+ if (bio == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ *certlist = NULL;
+ *keylist = NULL;
+ *ncerts = 0;
+ *nkeys = 0;
+ while (rv == KMF_OK) {
+ rv = extract_pkcs12(bio,
+ (uchar_t *)cred->cred,
+ (uint32_t)cred->credlen,
+ &privkey, &cert, &cacerts);
+
+ /* Reached end of import file? */
+ if (rv == KMF_OK && privkey == NULL &&
+ cert == NULL && cacerts == NULL)
+ break;
+
+ if (rv == KMF_OK)
+ /* Convert keys and certs to exportable format */
+ rv = convertPK12Objects(kmfh, privkey, cert, cacerts,
+ keylist, nkeys, certlist, ncerts);
+
+ if (privkey)
+ EVP_PKEY_free(privkey);
+
+ if (cert)
+ X509_free(cert);
+
+ if (cacerts)
+ sk_X509_free(cacerts);
+ }
+end:
+ if (bio != NULL)
+ (void) BIO_free(bio);
+
+ if (privkey)
+ EVP_PKEY_free(privkey);
+
+ if (cert)
+ X509_free(cert);
+
+ if (cacerts)
+ sk_X509_free(cacerts);
+
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params,
+ KMF_RAW_KEY_DATA *key)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ char *fullpath;
+ EVP_PKEY *pkey = NULL;
+ BIO *bio = NULL;
+
+ if (key != NULL) {
+ if (key->keytype == KMF_RSA) {
+ pkey = ImportRawRSAKey(&key->rawdata.rsa);
+ } else if (key->keytype == KMF_DSA) {
+ pkey = ImportRawDSAKey(&key->rawdata.dsa);
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ }
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ }
+ if (rv != KMF_OK || pkey == NULL)
+ return (rv);
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.keyfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* If the requested file exists, return an error */
+ if (access(fullpath, F_OK) == 0) {
+ free(fullpath);
+ return (KMF_ERR_DUPLICATE_KEYFILE);
+ }
+
+ bio = BIO_new_file(fullpath, "wb");
+ if (bio == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ rv = ssl_write_private_key(kmfh,
+ params->sslparms.format,
+ bio, &params->cred, pkey);
+
+cleanup:
+ if (fullpath)
+ free(fullpath);
+
+ if (pkey)
+ EVP_PKEY_free(pkey);
+
+ if (bio)
+ (void) BIO_free(bio);
+
+ /* Protect the file by making it read-only */
+ if (rv == KMF_OK) {
+ (void) chmod(fullpath, 0400);
+ }
+ return (rv);
+}
+
+static KMF_RETURN
+create_deskey(DES_cblock **deskey)
+{
+ DES_cblock *key;
+
+ key = (DES_cblock *) malloc(sizeof (DES_cblock));
+ if (key == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ if (DES_random_key(key) == 0) {
+ free(key);
+ return (KMF_ERR_KEYGEN_FAILED);
+ }
+
+ *deskey = key;
+ return (KMF_OK);
+}
+
+#define KEYGEN_RETRY 3
+#define DES3_KEY_SIZE 24
+
+static KMF_RETURN
+create_des3key(unsigned char **des3key)
+{
+ KMF_RETURN ret = KMF_OK;
+ DES_cblock *deskey1 = NULL;
+ DES_cblock *deskey2 = NULL;
+ DES_cblock *deskey3 = NULL;
+ unsigned char *newkey = NULL;
+ int retry;
+
+ if ((newkey = malloc(DES3_KEY_SIZE)) == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ /* create the 1st DES key */
+ if ((ret = create_deskey(&deskey1)) != KMF_OK) {
+ goto out;
+ }
+
+ /*
+ * Create the 2nd DES key and make sure its value is different
+ * from the 1st DES key.
+ */
+ retry = 0;
+ do {
+ if (deskey2 != NULL) {
+ free(deskey2);
+ deskey2 = NULL;
+ }
+
+ if ((ret = create_deskey(&deskey2)) != KMF_OK) {
+ goto out;
+ }
+
+ if (memcmp((const void *) deskey1, (const void *) deskey2, 8)
+ == 0) {
+ ret = KMF_ERR_KEYGEN_FAILED;
+ retry++;
+ }
+ } while (ret == KMF_ERR_KEYGEN_FAILED && retry < KEYGEN_RETRY);
+
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+ /*
+ * Create the 3rd DES key and make sure its value is different
+ * from the 2nd DES key.
+ */
+ retry = 0;
+ do {
+ if (deskey3 != NULL) {
+ free(deskey3);
+ deskey3 = NULL;
+ }
+
+ if ((ret = create_deskey(&deskey3)) != KMF_OK) {
+ goto out;
+ }
+
+ if (memcmp((const void *)deskey2, (const void *)deskey3, 8)
+ == 0) {
+ ret = KMF_ERR_KEYGEN_FAILED;
+ retry++;
+ }
+ } while (ret == KMF_ERR_KEYGEN_FAILED && retry < KEYGEN_RETRY);
+
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+ /* Concatenate 3 DES keys into a DES3 key */
+ (void) memcpy((void *)newkey, (const void *)deskey1, 8);
+ (void) memcpy((void *)(newkey + 8), (const void *)deskey2, 8);
+ (void) memcpy((void *)(newkey + 16), (const void *)deskey3, 8);
+ *des3key = newkey;
+
+out:
+ if (deskey1 != NULL)
+ free(deskey1);
+
+ if (deskey2 != NULL)
+ free(deskey2);
+
+ if (deskey3 != NULL)
+ free(deskey3);
+
+ if (ret != KMF_OK && newkey != NULL)
+ free(newkey);
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_CreateSymKey(KMF_HANDLE_T handle, KMF_CREATESYMKEY_PARAMS *params,
+ KMF_KEY_HANDLE *symkey)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ char *fullpath = NULL;
+ KMF_RAW_SYM_KEY *rkey = NULL;
+ DES_cblock *deskey = NULL;
+ unsigned char *des3key = NULL;
+ unsigned char *random = NULL;
+ int fd = -1;
+
+ if (kmfh == NULL)
+ return (KMF_ERR_UNINITIALIZED);
+
+ if (params == NULL || params->sslparms.keyfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.keyfile);
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* If the requested file exists, return an error */
+ if (access(fullpath, F_OK) == 0) {
+ free(fullpath);
+ return (KMF_ERR_DUPLICATE_KEYFILE);
+ }
+
+ fd = open(fullpath, O_CREAT|O_TRUNC|O_RDWR, 0400);
+ if (fd == -1) {
+ ret = KMF_ERR_OPEN_FILE;
+ goto out;
+ }
+
+ rkey = malloc(sizeof (KMF_RAW_SYM_KEY));
+ if (rkey == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY));
+
+ if (params->keytype == KMF_DES) {
+ if ((ret = create_deskey(&deskey)) != KMF_OK) {
+ goto out;
+ }
+ rkey->keydata.val = (uchar_t *)deskey;
+ rkey->keydata.len = 8;
+
+ symkey->keyalg = KMF_DES;
+
+ } else if (params->keytype == KMF_DES3) {
+ if ((ret = create_des3key(&des3key)) != KMF_OK) {
+ goto out;
+ }
+ rkey->keydata.val = (uchar_t *)des3key;
+ rkey->keydata.len = DES3_KEY_SIZE;
+ symkey->keyalg = KMF_DES3;
+
+ } else if (params->keytype == KMF_AES || params->keytype == KMF_RC4) {
+ int bytes;
+
+ if (params->keylength % 8 != 0) {
+ ret = KMF_ERR_BAD_KEY_SIZE;
+ goto out;
+ }
+
+ if (params->keytype == KMF_AES) {
+ if (params->keylength != 128 &&
+ params->keylength != 192 &&
+ params->keylength != 256) {
+ ret = KMF_ERR_BAD_KEY_SIZE;
+ goto out;
+ }
+ }
+
+ bytes = params->keylength/8;
+ random = malloc(bytes);
+ if (random == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ if (RAND_bytes(random, bytes) != 1) {
+ ret = KMF_ERR_KEYGEN_FAILED;
+ goto out;
+ }
+
+ rkey->keydata.val = (uchar_t *)random;
+ rkey->keydata.len = bytes;
+ symkey->keyalg = params->keytype;
+
+ } else {
+ ret = KMF_ERR_BAD_KEY_TYPE;
+ goto out;
+ }
+
+ (void) write(fd, (const void *) rkey->keydata.val, rkey->keydata.len);
+
+ symkey->kstype = KMF_KEYSTORE_OPENSSL;
+ symkey->keyclass = KMF_SYMMETRIC;
+ symkey->keylabel = (char *)fullpath;
+ symkey->israw = TRUE;
+ symkey->keyp = rkey;
+
+out:
+ if (fd != -1)
+ (void) close(fd);
+
+ if (ret != KMF_OK && fullpath != NULL) {
+ free(fullpath);
+ }
+ if (ret != KMF_OK) {
+ KMF_FreeRawSymKey(rkey);
+ symkey->keyp = NULL;
+ symkey->keyalg = KMF_KEYALG_NONE;
+ }
+
+ return (ret);
+}
+
+
+KMF_RETURN
+OpenSSL_VerifyCRLFile(KMF_HANDLE_T handle, KMF_VERIFYCRL_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ BIO *bcrl = NULL;
+ X509_CRL *xcrl = NULL;
+ X509 *xcert = NULL;
+ EVP_PKEY *pkey;
+ int sslret;
+ KMF_ENCODE_FORMAT crl_format;
+ unsigned char *p;
+ long len;
+
+ if (params->crl_name == NULL || params->tacert == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_GetFileFormat(params->crl_name, &crl_format);
+ if (ret != KMF_OK)
+ return (ret);
+
+ bcrl = BIO_new_file(params->crl_name, "rb");
+ if (bcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ if (crl_format == KMF_FORMAT_ASN1) {
+ xcrl = d2i_X509_CRL_bio(bcrl, NULL);
+ } else if (crl_format == KMF_FORMAT_PEM) {
+ xcrl = PEM_read_bio_X509_CRL(bcrl, NULL, NULL, NULL);
+ } else {
+ ret = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ if (xcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto cleanup;
+ }
+
+ p = params->tacert->Data;
+ len = params->tacert->Length;
+ xcert = d2i_X509(NULL, (const uchar_t **)&p, len);
+
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CERTFILE;
+ goto cleanup;
+ }
+
+ /* Get issuer certificate public key */
+ pkey = X509_get_pubkey(xcert);
+ if (!pkey) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ /* Verify CRL signature */
+ sslret = X509_CRL_verify(xcrl, pkey);
+ EVP_PKEY_free(pkey);
+ if (sslret > 0) {
+ ret = KMF_OK;
+ } else {
+ SET_ERROR(kmfh, sslret);
+ ret = KMF_ERR_BAD_CRLFILE;
+ }
+
+cleanup:
+ if (bcrl != NULL)
+ (void) BIO_free(bcrl);
+
+ if (xcrl != NULL)
+ X509_CRL_free(xcrl);
+
+ if (xcert != NULL)
+ X509_free(xcert);
+
+ return (ret);
+
+}
+
+KMF_RETURN
+OpenSSL_CheckCRLDate(KMF_HANDLE_T handle,
+ KMF_CHECKCRLDATE_PARAMS *params)
+{
+
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ENCODE_FORMAT crl_format;
+ BIO *bcrl = NULL;
+ X509_CRL *xcrl = NULL;
+ int i;
+
+ if (params == NULL || params->crl_name == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_IsCRLFile(handle, params->crl_name, &crl_format);
+ if (ret != KMF_OK)
+ return (ret);
+
+ bcrl = BIO_new_file(params->crl_name, "rb");
+ if (bcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ if (crl_format == KMF_FORMAT_ASN1) {
+ xcrl = d2i_X509_CRL_bio(bcrl, NULL);
+ } else if (crl_format == KMF_FORMAT_PEM) {
+ xcrl = PEM_read_bio_X509_CRL(bcrl, NULL, NULL, NULL);
+ }
+
+ if (xcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto cleanup;
+ }
+
+ i = X509_cmp_time(X509_CRL_get_lastUpdate(xcrl), NULL);
+ if (i >= 0) {
+ ret = KMF_ERR_VALIDITY_PERIOD;
+ goto cleanup;
+ }
+
+ if (X509_CRL_get_nextUpdate(xcrl)) {
+ i = X509_cmp_time(X509_CRL_get_nextUpdate(xcrl), NULL);
+
+ if (i <= 0) {
+ ret = KMF_ERR_VALIDITY_PERIOD;
+ goto cleanup;
+ }
+ }
+
+ ret = KMF_OK;
+
+cleanup:
+ if (bcrl != NULL)
+ (void) BIO_free(bcrl);
+
+ if (xcrl != NULL)
+ X509_CRL_free(xcrl);
+
+ return (ret);
+}
+
+/*
+ * Check a file to see if it is a CRL file with PEM or DER format.
+ * If success, return its format in the "pformat" argument.
+ */
+KMF_RETURN
+OpenSSL_IsCRLFile(KMF_HANDLE_T handle, char *filename, int *pformat)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ BIO *bio = NULL;
+ X509_CRL *xcrl = NULL;
+
+ if (filename == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ bio = BIO_new_file(filename, "rb");
+ if (bio == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto out;
+ }
+
+ if ((xcrl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)) != NULL) {
+ *pformat = KMF_FORMAT_PEM;
+ goto out;
+ }
+ (void) BIO_free(bio);
+
+ /*
+ * Now try to read it as raw DER data.
+ */
+ bio = BIO_new_file(filename, "rb");
+ if (bio == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto out;
+ }
+
+ if ((xcrl = d2i_X509_CRL_bio(bio, NULL)) != NULL) {
+ *pformat = KMF_FORMAT_ASN1;
+ } else {
+ ret = KMF_ERR_BAD_CRLFILE;
+ }
+
+out:
+ if (bio != NULL)
+ (void) BIO_free(bio);
+
+ if (xcrl != NULL)
+ X509_CRL_free(xcrl);
+
+ return (ret);
+}
+
+/*
+ * Check a file to see if it is a certficate file with PEM or DER format.
+ * If success, return its format in the pformat argument.
+ */
+KMF_RETURN
+OpenSSL_IsCertFile(KMF_HANDLE_T handle, char *filename,
+ KMF_ENCODE_FORMAT *pformat)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ BIO *bio = NULL;
+ X509 *xcert = NULL;
+
+ if (filename == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_GetFileFormat(filename, pformat);
+ if (ret != KMF_OK)
+ return (ret);
+
+ bio = BIO_new_file(filename, "rb");
+ if (bio == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto out;
+ }
+
+ if ((*pformat) == KMF_FORMAT_PEM) {
+ if ((xcert = PEM_read_bio_X509(bio, NULL,
+ NULL, NULL)) == NULL) {
+ ret = KMF_ERR_BAD_CERTFILE;
+ }
+ } else if ((*pformat) == KMF_FORMAT_ASN1) {
+ if ((xcert = d2i_X509_bio(bio, NULL)) == NULL) {
+ ret = KMF_ERR_BAD_CERTFILE;
+ }
+ } else {
+ ret = KMF_ERR_BAD_CERTFILE;
+ }
+
+out:
+ if (bio != NULL)
+ (void) BIO_free(bio);
+
+ if (xcert != NULL)
+ X509_free(xcert);
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey,
+ KMF_RAW_SYM_KEY *rkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_DATA keyvalue;
+
+ if (kmfh == NULL)
+ return (KMF_ERR_UNINITIALIZED);
+
+ if (symkey == NULL || rkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ else if (symkey->keyclass != KMF_SYMMETRIC)
+ return (KMF_ERR_BAD_KEY_CLASS);
+
+ if (symkey->israw) {
+ KMF_RAW_SYM_KEY *rawkey = (KMF_RAW_SYM_KEY *)symkey->keyp;
+
+ if (rawkey == NULL ||
+ rawkey->keydata.val == NULL ||
+ rawkey->keydata.len == 0)
+ return (KMF_ERR_BAD_KEYHANDLE);
+
+ rkey->keydata.len = rawkey->keydata.len;
+ if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memcpy(rkey->keydata.val, rawkey->keydata.val,
+ rkey->keydata.len);
+ } else {
+ rv = KMF_ReadInputFile(handle, symkey->keylabel, &keyvalue);
+ if (rv != KMF_OK)
+ return (rv);
+ rkey->keydata.len = keyvalue.Length;
+ rkey->keydata.val = keyvalue.Data;
+ }
+
+ return (rv);
+}
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile
new file mode 100644
index 0000000000..443f78537a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: $(ROOTLIBS)
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile
new file mode 100644
index 0000000000..472ac90a9a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: $(ROOTLIBS)
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile
new file mode 100644
index 0000000000..e80bb3751a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile
@@ -0,0 +1,31 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../../Makefile.lib.64
+
+LDLIBS += $(OPENSSLLIBS64)
+install: $(ROOTLIBS64)
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile
new file mode 100644
index 0000000000..b65a323ef5
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile
@@ -0,0 +1,46 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS= $(MACH)
+
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+check := TARGET= check
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com
new file mode 100644
index 0000000000..f2a715de92
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com
@@ -0,0 +1,65 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Makefile for KMF Plugins
+#
+
+LIBRARY= kmf_pkcs11.a
+VERS= .1
+OBJECTS= pkcs11_spi.o
+
+include $(SRC)/lib/Makefile.lib
+
+LIBLINKS= $(DYNLIB:.so.1=.so)
+KMFINC= -I../../../include -I../../../ber_der/inc
+
+PKCS11LIBS= -lkmf -lkmfberder -lpkcs11 -lcryptoutil -lc
+
+SRCDIR= ../common
+INCDIR= ../../include
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT $(KMFINC) -I$(INCDIR) -I/usr/include/libxml2
+
+PICS= $(OBJECTS:%=pics/%)
+SONAME= $(PLUGIN)
+
+LDLIBS += $(PKCS11LIBS)
+
+ROOTLIBDIR= $(ROOT)/usr/lib/security
+ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64)
+
+.KEEP_STATE:
+
+LIBS = $(DYNLIB)
+
+all: $(LIBS) $(LINTLIB)
+
+lint: lintcheck
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile
new file mode 100644
index 0000000000..dfd8150806
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+install: $(ROOTLIBS64)
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers
new file mode 100644
index 0000000000..ee3b6bcb92
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers
@@ -0,0 +1,50 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate_1.1 {
+ global:
+ KMF_Plugin_Initialize;
+ KMFPK11_FindCert;
+ KMFPK11_FreeKMFCert;
+ KMFPK11_StoreCert;
+ KMFPK11_ImportCert;
+ KMFPK11_DeleteCert;
+ KMFPK11_CreateKeypair;
+ KMFPK11_FindKey;
+ KMFPK11_EncodePubKeyData;
+ KMFPK11_SignData;
+ KMFPK11_DeleteKey;
+ KMFPK11_GetErrorString;
+ KMFPK11_GetPrikeyByCert;
+ KMFPK11_DecryptData;
+ KMFPK11_StorePrivateKey;
+ KMFPK11_CreateSymKey;
+ KMFPK11_GetSymKeyValue;
+ KMFPK11_SetTokenPin;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c
new file mode 100644
index 0000000000..e548c64eb8
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c
@@ -0,0 +1,2945 @@
+/*
+ * 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
+ */
+/*
+ * PKCS11 token KMF Plugin
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h> /* debugging only */
+#include <errno.h>
+#include <values.h>
+
+#include <kmfapiP.h>
+#include <oidsalg.h>
+#include <ber_der.h>
+#include <algorithm.h>
+
+#include <cryptoutil.h>
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+
+#define SETATTR(t, n, atype, value, size) \
+ t[n].type = atype; \
+ t[n].pValue = (CK_BYTE *)value; \
+ t[n].ulValueLen = (CK_ULONG)size;
+
+#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; \
+ h->lasterr.errcode = c;
+
+typedef struct _objlist {
+ CK_OBJECT_HANDLE handle;
+ struct _objlist *next;
+} OBJLIST;
+
+static KMF_RETURN
+search_certs(KMF_HANDLE_T, char *, char *, char *, KMF_BIGINT *,
+ boolean_t, KMF_CERT_VALIDITY, OBJLIST **, uint32_t *);
+
+static KMF_RETURN
+keyObj2RawKey(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_KEY_DATA **);
+
+KMF_RETURN
+KMFPK11_ConfigureKeystore(KMF_HANDLE_T, KMF_CONFIG_PARAMS *);
+
+KMF_RETURN
+KMFPK11_FindCert(KMF_HANDLE_T,
+ KMF_FINDCERT_PARAMS *,
+ KMF_X509_DER_CERT *,
+ uint32_t *);
+
+void
+KMFPK11_FreeKMFCert(KMF_HANDLE_T,
+ KMF_X509_DER_CERT *kmf_cert);
+
+KMF_RETURN
+KMFPK11_StoreCert(KMF_HANDLE_T, KMF_STORECERT_PARAMS *, KMF_DATA *);
+
+KMF_RETURN
+KMFPK11_ImportCert(KMF_HANDLE_T, KMF_IMPORTCERT_PARAMS *);
+
+KMF_RETURN
+KMFPK11_DeleteCert(KMF_HANDLE_T, KMF_DELETECERT_PARAMS *);
+
+KMF_RETURN
+KMFPK11_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *,
+ KMF_KEY_HANDLE *, KMF_KEY_HANDLE *);
+
+KMF_RETURN
+KMFPK11_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *,
+ KMF_KEY_HANDLE *, boolean_t);
+
+KMF_RETURN
+KMFPK11_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *);
+
+KMF_RETURN
+KMFPK11_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+KMFPK11_GetErrorString(KMF_HANDLE_T, char **);
+
+KMF_RETURN
+KMFPK11_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *,
+ KMF_KEY_HANDLE *, KMF_KEY_ALG);
+
+KMF_RETURN
+KMFPK11_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+KMFPK11_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *,
+ KMF_KEY_HANDLE *, uint32_t *);
+
+KMF_RETURN
+KMFPK11_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *,
+ KMF_RAW_KEY_DATA *);
+
+KMF_RETURN
+KMFPK11_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *,
+ KMF_KEY_HANDLE *);
+
+KMF_RETURN
+KMFPK11_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *);
+
+KMF_RETURN
+KMFPK11_SetTokenPin(KMF_HANDLE_T, KMF_SETPIN_PARAMS *, KMF_CREDENTIAL *);
+
+static
+KMF_PLUGIN_FUNCLIST pk11token_plugin_table =
+{
+ 1, /* Version */
+ KMFPK11_ConfigureKeystore,
+ KMFPK11_FindCert,
+ KMFPK11_FreeKMFCert,
+ KMFPK11_StoreCert,
+ KMFPK11_ImportCert,
+ NULL, /* ImportCRL */
+ KMFPK11_DeleteCert,
+ NULL, /* DeleteCRL */
+ KMFPK11_CreateKeypair,
+ KMFPK11_FindKey,
+ KMFPK11_EncodePubKeyData,
+ KMFPK11_SignData,
+ KMFPK11_DeleteKey,
+ NULL, /* ListCRL */
+ NULL, /* FindCRL */
+ NULL, /* FindCertInCRL */
+ KMFPK11_GetErrorString,
+ KMFPK11_GetPrikeyByCert,
+ KMFPK11_DecryptData,
+ NULL, /* ExportP12 */
+ KMFPK11_StorePrivateKey,
+ KMFPK11_CreateSymKey,
+ KMFPK11_GetSymKeyValue,
+ KMFPK11_SetTokenPin,
+ NULL /* Finalize */
+};
+
+KMF_PLUGIN_FUNCLIST *
+KMF_Plugin_Initialize()
+{
+ return (&pk11token_plugin_table);
+}
+
+KMF_RETURN
+KMFPK11_ConfigureKeystore(KMF_HANDLE_T handle, KMF_CONFIG_PARAMS *params)
+{
+ KMF_RETURN rv = KMF_OK;
+
+ if (params == NULL || params->pkcs11config.label == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = KMF_SelectToken(handle, params->pkcs11config.label,
+ params->pkcs11config.readonly);
+
+ return (rv);
+}
+
+static KMF_RETURN
+pk11_authenticate(KMF_HANDLE_T handle,
+ KMF_CREDENTIAL *cred)
+{
+
+ CK_RV ck_rv = CKR_OK;
+ CK_SESSION_HANDLE hSession = (CK_SESSION_HANDLE)handle->pk11handle;
+
+ if (hSession == NULL)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (cred == NULL || cred->cred == NULL || cred->credlen == 0) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if ((ck_rv = C_Login(hSession, CKU_USER,
+ (uchar_t *)cred->cred, cred->credlen)) != CKR_OK) {
+ if (ck_rv != CKR_USER_ALREADY_LOGGED_IN) {
+ handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ handle->lasterr.errcode = ck_rv;
+ return (KMF_ERR_AUTH_FAILED);
+ }
+ }
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+PK11Cert2KMFCert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE hObj,
+ KMF_X509_DER_CERT *kmfcert)
+{
+ KMF_RETURN rv = 0;
+ CK_RV ckrv = CKR_OK;
+
+ CK_CERTIFICATE_TYPE cktype;
+ CK_OBJECT_CLASS class;
+ CK_BBOOL cktrusted, token;
+ CK_ULONG subject_len, value_len, issuer_len, serno_len, id_len;
+ CK_BYTE *subject = NULL, *value = NULL;
+ CK_BYTE *label = NULL;
+ CK_ULONG label_len = 0;
+ CK_ATTRIBUTE templ[10];
+
+ SETATTR(templ, 0, CKA_CLASS, &class, sizeof (class));
+
+ /* Is this a certificate object ? */
+ ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 1);
+ if (ckrv != CKR_OK || class != CKO_CERTIFICATE) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ SETATTR(templ, 0, CKA_CERTIFICATE_TYPE, &cktype, sizeof (cktype));
+ SETATTR(templ, 1, CKA_TOKEN, &token, sizeof (token));
+ SETATTR(templ, 2, CKA_TRUSTED, &cktrusted, sizeof (cktrusted));
+
+ ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 3);
+
+ if (ckrv != CKR_OK || cktype != CKC_X_509) {
+ SET_ERROR(kmfh, ckrv);
+ return (ckrv);
+ } else {
+ /* What attributes are available and how big are they? */
+ subject_len = issuer_len = serno_len = id_len = value_len =
+ label_len = 0;
+ SETATTR(templ, 0, CKA_SUBJECT, NULL, subject_len);
+ SETATTR(templ, 1, CKA_ISSUER, NULL, issuer_len);
+ SETATTR(templ, 2, CKA_SERIAL_NUMBER, NULL, serno_len);
+ SETATTR(templ, 3, CKA_ID, NULL, id_len);
+ SETATTR(templ, 4, CKA_VALUE, NULL, value_len);
+ SETATTR(templ, 5, CKA_LABEL, NULL, label_len);
+
+ /*
+ * Query the object with NULL values in the pValue spot
+ * so we know how much space to allocate for each field.
+ */
+ ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 6);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL); /* TODO - Error messages ? */
+ }
+
+ subject_len = templ[0].ulValueLen;
+ issuer_len = templ[1].ulValueLen;
+ serno_len = templ[2].ulValueLen;
+ id_len = templ[3].ulValueLen;
+ value_len = templ[4].ulValueLen;
+ label_len = templ[5].ulValueLen;
+
+ /*
+ * For PKCS#11 CKC_X_509 certificate objects,
+ * the following attributes must be defined.
+ * CKA_SUBJECT, CKA_ID, CKA_ISSUER, CKA_SERIAL_NUMBER,
+ * CKA_VALUE.
+ */
+ if (subject_len == 0 || issuer_len == 0 ||
+ serno_len == 0 || value_len == 0) {
+ return (KMF_ERR_INTERNAL);
+ }
+
+ /* Only fetch the value field if we are saving the data */
+ if (kmfcert != NULL) {
+ int i = 0;
+ value = malloc(value_len);
+ if (value == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto errout;
+ }
+
+ SETATTR(templ, i, CKA_VALUE, value, value_len);
+ i++;
+ if (label_len > 0) {
+ label = malloc(label_len + 1);
+ if (label == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto errout;
+ }
+ (void) memset(label, 0, label_len + 1);
+ SETATTR(templ, i, CKA_LABEL, label,
+ label_len);
+ i++;
+ }
+
+ /* re-query the object with room for the value attr */
+ ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj,
+ templ, i);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto errout;
+ }
+
+ kmfcert->certificate.Data = value;
+ kmfcert->certificate.Length = value_len;
+ kmfcert->kmf_private.flags |= KMF_FLAG_CERT_SIGNED;
+ kmfcert->kmf_private.keystore_type =
+ KMF_KEYSTORE_PK11TOKEN;
+ kmfcert->kmf_private.label = (char *)label;
+
+ rv = KMF_OK;
+ }
+ }
+
+errout:
+ if (rv != KMF_OK) {
+ if (subject)
+ free(subject);
+ if (value)
+ free(value);
+
+ if (kmfcert) {
+ kmfcert->certificate.Data = NULL;
+ kmfcert->certificate.Length = 0;
+ }
+ }
+ return (rv);
+}
+
+static void
+free_objlist(OBJLIST *head)
+{
+ OBJLIST *temp = head;
+
+ while (temp != NULL) {
+ head = head->next;
+ free(temp);
+ temp = head;
+ }
+}
+
+/*
+ * The caller should make sure that the templ->pValue is NULL since
+ * it will be overwritten below.
+ */
+static KMF_RETURN
+get_attr(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj,
+ CK_ATTRIBUTE *templ)
+{
+ CK_RV rv;
+
+ rv = C_GetAttributeValue(kmfh->pk11handle, obj, templ, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ if (templ->ulValueLen > 0) {
+ templ->pValue = malloc(templ->ulValueLen);
+ if (templ->pValue == NULL)
+ return (KMF_ERR_MEMORY);
+
+ rv = C_GetAttributeValue(kmfh->pk11handle, obj, templ, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+ }
+
+ return (KMF_OK);
+}
+
+/*
+ * Match a certificate with an issuer and/or subject name.
+ * This is tricky because we cannot reliably compare DER encodings
+ * because RDNs may have their AV-pairs in different orders even
+ * if the values are the same. You must compare individual
+ * AV pairs for the RDNs.
+ *
+ * RETURN: 0 for a match, non-zero for a non-match.
+ */
+static KMF_RETURN
+matchcert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj,
+ KMF_X509_NAME *issuer, KMF_X509_NAME *subject)
+{
+ KMF_RETURN rv = KMF_OK;
+ CK_ATTRIBUTE certattr;
+ KMF_DATA name;
+ KMF_X509_NAME dn;
+
+ if (issuer->numberOfRDNs > 0) {
+ certattr.type = CKA_ISSUER;
+ certattr.pValue = NULL;
+ certattr.ulValueLen = 0;
+
+ rv = get_attr(kmfh, obj, &certattr);
+
+ if (rv == KMF_OK) {
+ name.Data = certattr.pValue;
+ name.Length = certattr.ulValueLen;
+ rv = DerDecodeName(&name, &dn);
+ if (rv == KMF_OK) {
+ rv = KMF_CompareRDNs(issuer, &dn);
+ KMF_FreeDN(&dn);
+ }
+ free(certattr.pValue);
+ }
+
+ if (rv != KMF_OK)
+ return (rv);
+ }
+ if (subject->numberOfRDNs > 0) {
+ certattr.type = CKA_SUBJECT;
+ certattr.pValue = NULL;
+ certattr.ulValueLen = 0;
+
+ rv = get_attr(kmfh, obj, &certattr);
+
+ if (rv == KMF_OK) {
+ name.Data = certattr.pValue;
+ name.Length = certattr.ulValueLen;
+ rv = DerDecodeName(&name, &dn);
+ if (rv == KMF_OK) {
+ rv = KMF_CompareRDNs(subject, &dn);
+ KMF_FreeDN(&dn);
+ }
+ free(certattr.pValue);
+ }
+ }
+
+ return (rv);
+}
+
+/*
+ * delete "curr" node from the "newlist".
+ */
+static void
+pk11_delete_obj_from_list(OBJLIST **newlist,
+ OBJLIST **prev, OBJLIST **curr)
+{
+
+ if (*curr == *newlist) {
+ /* first node in the list */
+ *newlist = (*curr)->next;
+ *prev = (*curr)->next;
+ free(*curr);
+ *curr = *newlist;
+ } else {
+ (*prev)->next = (*curr)->next;
+ free(*curr);
+ *curr = (*prev)->next;
+ }
+}
+
+/*
+ * prepare_object_search
+ *
+ * Because this code is shared by the FindCert and
+ * DeleteCert functions, put it in a separate routine
+ * to save some work and make code easier to debug and
+ * read.
+ */
+static KMF_RETURN
+search_certs(KMF_HANDLE_T handle,
+ char *label, char *issuer, char *subject, KMF_BIGINT *serial,
+ boolean_t private, KMF_CERT_VALIDITY validity,
+ OBJLIST **objlist, uint32_t *numobj)
+{
+ KMF_RETURN rv = KMF_OK;
+ CK_RV ckrv = CKR_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_ATTRIBUTE templ[10];
+ CK_BBOOL true = TRUE;
+ CK_OBJECT_CLASS oclass = CKO_CERTIFICATE;
+ CK_CERTIFICATE_TYPE ctype = CKC_X_509;
+ KMF_X509_NAME subjectDN, issuerDN;
+ int i;
+ OBJLIST *newlist, *tail;
+ CK_ULONG num = 0;
+ uint32_t num_ok_certs = 0; /* number of non-expired or expired certs */
+
+ (void) memset(&templ, 0, 10 * sizeof (CK_ATTRIBUTE));
+ (void) memset(&issuerDN, 0, sizeof (KMF_X509_NAME));
+ (void) memset(&subjectDN, 0, sizeof (KMF_X509_NAME));
+ i = 0;
+ SETATTR(templ, i, CKA_TOKEN, &true, sizeof (true)); i++;
+ SETATTR(templ, i, CKA_CLASS, &oclass, sizeof (oclass)); i++;
+ SETATTR(templ, i, CKA_CERTIFICATE_TYPE, &ctype,
+ sizeof (ctype)); i++;
+
+ if (label != NULL && strlen(label)) {
+ SETATTR(templ, i, CKA_LABEL, label, strlen(label));
+ i++;
+ }
+ if (private) {
+ SETATTR(templ, i, CKA_PRIVATE, &true, sizeof (true)); i++;
+ }
+
+ if (issuer != NULL && strlen(issuer)) {
+ if ((rv = KMF_DNParser(issuer, &issuerDN)) != KMF_OK)
+ return (rv);
+ }
+ if (subject != NULL && strlen(subject)) {
+ if ((rv = KMF_DNParser(subject, &subjectDN)) != KMF_OK)
+ return (rv);
+ }
+
+ if (serial != NULL && serial->val != NULL && serial->len > 0) {
+ SETATTR(templ, i, CKA_SERIAL_NUMBER,
+ serial->val, serial->len);
+ i++;
+ }
+
+ (*numobj) = 0;
+ *objlist = NULL;
+ newlist = NULL;
+
+ ckrv = C_FindObjectsInit(kmfh->pk11handle, templ, i);
+ if (ckrv != CKR_OK)
+ goto cleanup;
+
+ tail = newlist = NULL;
+ while (ckrv == CKR_OK) {
+ CK_OBJECT_HANDLE tObj;
+ ckrv = C_FindObjects(kmfh->pk11handle, &tObj, 1, &num);
+ if (ckrv != CKR_OK || num == 0)
+ break;
+
+ /*
+ * 'matchcert' returns 0 if subject/issuer match
+ *
+ * If no match, move on to the next one
+ */
+ if (matchcert(kmfh, tObj, &issuerDN, &subjectDN))
+ continue;
+
+ if (newlist == NULL) {
+ newlist = malloc(sizeof (OBJLIST));
+ if (newlist == NULL) {
+ rv = KMF_ERR_MEMORY;
+ break;
+ }
+ newlist->handle = tObj;
+ newlist->next = NULL;
+ tail = newlist;
+ } else {
+ tail->next = malloc(sizeof (OBJLIST));
+ if (tail->next != NULL) {
+ tail = tail->next;
+ } else {
+ rv = KMF_ERR_MEMORY;
+ break;
+ }
+ tail->handle = tObj;
+ tail->next = NULL;
+ }
+ (*numobj)++;
+ }
+ ckrv = C_FindObjectsFinal(kmfh->pk11handle);
+
+cleanup:
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ if (newlist != NULL) {
+ free_objlist(newlist);
+ *numobj = 0;
+ newlist = NULL;
+ }
+ } else {
+ if (validity == KMF_ALL_CERTS) {
+ *objlist = newlist;
+ } else {
+ OBJLIST *node, *prev;
+ KMF_X509_DER_CERT tmp_kmf_cert;
+ uint32_t i = 0;
+
+ node = prev = newlist;
+ /*
+ * Now check to see if any found certificate is expired
+ * or valid.
+ */
+ while (node != NULL && i < (*numobj)) {
+ (void) memset(&tmp_kmf_cert, 0,
+ sizeof (KMF_X509_DER_CERT));
+ rv = PK11Cert2KMFCert(kmfh, node->handle,
+ &tmp_kmf_cert);
+ if (rv != KMF_OK) {
+ goto cleanup1;
+ }
+
+ rv = KMF_CheckCertDate(handle,
+ &tmp_kmf_cert.certificate);
+
+ if (validity == KMF_NONEXPIRED_CERTS) {
+ if (rv == KMF_OK) {
+ num_ok_certs++;
+ prev = node;
+ node = node->next;
+ } else if (rv ==
+ KMF_ERR_VALIDITY_PERIOD) {
+ /*
+ * expired - remove it from list
+ */
+ pk11_delete_obj_from_list(
+ &newlist, &prev, &node);
+ } else {
+ goto cleanup1;
+ }
+ }
+
+ if (validity == KMF_EXPIRED_CERTS) {
+ if (rv == KMF_ERR_VALIDITY_PERIOD) {
+ num_ok_certs++;
+ prev = node;
+ node = node->next;
+ rv = KMF_OK;
+ } else if (rv == KMF_OK) {
+ /*
+ * valid - remove it from list
+ */
+ pk11_delete_obj_from_list(
+ &newlist, &prev, &node);
+ } else {
+ goto cleanup1;
+ }
+ }
+ i++;
+ KMF_FreeKMFCert(handle, &tmp_kmf_cert);
+ }
+ *numobj = num_ok_certs;
+ *objlist = newlist;
+ }
+ }
+
+cleanup1:
+ if (rv != KMF_OK && newlist != NULL) {
+ free_objlist(newlist);
+ *numobj = 0;
+ *objlist = NULL;
+ }
+
+ if (issuer != NULL)
+ KMF_FreeDN(&issuerDN);
+
+ if (subject != NULL)
+ KMF_FreeDN(&subjectDN);
+
+ return (rv);
+}
+
+/*
+ * The caller may pass a NULL value for kmf_cert below and the function will
+ * just return the number of certs found (in num_certs).
+ */
+KMF_RETURN
+KMFPK11_FindCert(KMF_HANDLE_T handle, KMF_FINDCERT_PARAMS *params,
+ KMF_X509_DER_CERT *kmf_cert,
+ uint32_t *num_certs)
+{
+ KMF_RETURN rv = 0;
+ uint32_t want_certs;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ OBJLIST *objlist = NULL;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL || num_certs == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (*num_certs > 0)
+ want_certs = *num_certs;
+ else
+ want_certs = MAXINT; /* count them all */
+
+ *num_certs = 0;
+
+ rv = search_certs(handle,
+ params->certLabel, params->issuer,
+ params->subject, params->serial,
+ params->pkcs11parms.private,
+ params->find_cert_validity,
+ &objlist, num_certs);
+
+ if (rv == KMF_OK && objlist != NULL && kmf_cert != NULL) {
+ OBJLIST *node = objlist;
+ int i = 0;
+ while (node != NULL && i < want_certs) {
+ rv = PK11Cert2KMFCert(kmfh, node->handle,
+ &kmf_cert[i]);
+ i++;
+ node = node->next;
+ }
+ }
+
+ if (objlist != NULL)
+ free_objlist(objlist);
+
+ if (*num_certs == 0)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+
+ return (rv);
+}
+
+/*ARGSUSED*/
+void
+KMFPK11_FreeKMFCert(KMF_HANDLE_T handle,
+ KMF_X509_DER_CERT *kmf_cert)
+{
+ if (kmf_cert != NULL && kmf_cert->certificate.Data != NULL) {
+ free(kmf_cert->certificate.Data);
+ kmf_cert->certificate.Data = NULL;
+ kmf_cert->certificate.Length = 0;
+
+ if (kmf_cert->kmf_private.label != NULL) {
+ free(kmf_cert->kmf_private.label);
+ kmf_cert->kmf_private.label = NULL;
+ }
+ }
+}
+
+KMF_RETURN
+KMFPK11_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *pKey,
+ KMF_DATA *eData)
+{
+ KMF_RETURN ret = KMF_OK;
+ CK_RV rv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_OBJECT_CLASS ckObjClass = CKO_PUBLIC_KEY;
+ CK_KEY_TYPE ckKeyType;
+ KMF_DATA Modulus, Exponent, Prime, Subprime, Base, Value;
+ KMF_OID *Algorithm;
+ BerElement *asn1 = NULL;
+ BerValue *PubKeyParams = NULL, *EncodedKey = NULL;
+ KMF_X509_SPKI spki;
+
+ CK_ATTRIBUTE rsaTemplate[4];
+ CK_ATTRIBUTE dsaTemplate[6];
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (pKey == NULL || pKey->keyp == CK_INVALID_HANDLE)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&Modulus, 0, sizeof (Modulus));
+ (void) memset(&Exponent, 0, sizeof (Exponent));
+ (void) memset(&Prime, 0, sizeof (Prime));
+ (void) memset(&Subprime, 0, sizeof (Subprime));
+ (void) memset(&Base, 0, sizeof (Base));
+ (void) memset(&Value, 0, sizeof (Value));
+
+ SETATTR(rsaTemplate, 0, CKA_CLASS, &ckObjClass, sizeof (ckObjClass));
+ SETATTR(rsaTemplate, 1, CKA_KEY_TYPE, &ckKeyType, sizeof (ckKeyType));
+ SETATTR(rsaTemplate, 2, CKA_MODULUS, Modulus.Data, &Modulus.Length);
+ SETATTR(rsaTemplate, 3, CKA_PUBLIC_EXPONENT, Exponent.Data,
+ &Exponent.Length);
+
+ SETATTR(dsaTemplate, 0, CKA_CLASS, &ckObjClass, sizeof (ckObjClass));
+ SETATTR(dsaTemplate, 1, CKA_KEY_TYPE, &ckKeyType, sizeof (ckKeyType));
+ SETATTR(dsaTemplate, 2, CKA_PRIME, Prime.Data, &Prime.Length);
+ SETATTR(dsaTemplate, 3, CKA_SUBPRIME, Subprime.Data, &Subprime.Length);
+ SETATTR(dsaTemplate, 4, CKA_BASE, Base.Data, &Base.Length);
+ SETATTR(dsaTemplate, 5, CKA_VALUE, Value.Data, &Value.Length);
+
+ switch (pKey->keyalg) {
+ case KMF_RSA:
+ /* Get the length of the fields */
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pKey->keyp,
+ rsaTemplate, 4);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ Modulus.Length = rsaTemplate[2].ulValueLen;
+ Modulus.Data = malloc(Modulus.Length);
+ if (Modulus.Data == NULL)
+ return (KMF_ERR_MEMORY);
+
+ Exponent.Length = rsaTemplate[3].ulValueLen;
+ Exponent.Data = malloc(Exponent.Length);
+ if (Exponent.Data == NULL) {
+ free(Modulus.Data);
+ return (KMF_ERR_MEMORY);
+ }
+
+ SETATTR(rsaTemplate, 2, CKA_MODULUS, Modulus.Data,
+ Modulus.Length);
+ SETATTR(rsaTemplate, 3, CKA_PUBLIC_EXPONENT,
+ Exponent.Data, Exponent.Length);
+ /* Now get the values */
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pKey->keyp,
+ rsaTemplate, 4);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ free(Modulus.Data);
+ free(Exponent.Data);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * This is the KEY algorithm, not the
+ * signature algorithm.
+ */
+ Algorithm = X509_AlgIdToAlgorithmOid(KMF_ALGID_RSA);
+ if (Algorithm != NULL) {
+
+ /* Encode the RSA Key Data */
+ if ((asn1 = kmfder_alloc()) == NULL) {
+ free(Modulus.Data);
+ free(Exponent.Data);
+ return (KMF_ERR_MEMORY);
+ }
+ if (kmfber_printf(asn1, "{II}",
+ Modulus.Data, Modulus.Length,
+ Exponent.Data, Exponent.Length) == -1) {
+ kmfber_free(asn1, 1);
+ free(Modulus.Data);
+ free(Exponent.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ if (kmfber_flatten(asn1, &EncodedKey) == -1) {
+ kmfber_free(asn1, 1);
+ free(Modulus.Data);
+ free(Exponent.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ kmfber_free(asn1, 1);
+ }
+
+ free(Exponent.Data);
+ free(Modulus.Data);
+
+ break;
+ case KMF_DSA:
+ /* Get the length of the fields */
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pKey->keyp,
+ dsaTemplate, 6);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ Prime.Length = dsaTemplate[2].ulValueLen;
+ Prime.Data = malloc(Prime.Length);
+ if (Prime.Data == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ Subprime.Length = dsaTemplate[3].ulValueLen;
+ Subprime.Data = malloc(Subprime.Length);
+ if (Subprime.Data == NULL) {
+ free(Prime.Data);
+ return (KMF_ERR_MEMORY);
+ }
+
+ Base.Length = dsaTemplate[4].ulValueLen;
+ Base.Data = malloc(Base.Length);
+ if (Base.Data == NULL) {
+ free(Prime.Data);
+ free(Subprime.Data);
+ return (KMF_ERR_MEMORY);
+ }
+
+ Value.Length = dsaTemplate[5].ulValueLen;
+ Value.Data = malloc(Value.Length);
+ if (Value.Data == NULL) {
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+ return (KMF_ERR_MEMORY);
+ }
+ SETATTR(dsaTemplate, 2, CKA_PRIME, Prime.Data,
+ Prime.Length);
+ SETATTR(dsaTemplate, 3, CKA_SUBPRIME, Subprime.Data,
+ Subprime.Length);
+ SETATTR(dsaTemplate, 4, CKA_BASE, Base.Data,
+ Base.Length);
+ SETATTR(dsaTemplate, 5, CKA_VALUE, Value.Data,
+ Value.Length);
+
+ /* Now get the values */
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pKey->keyp,
+ dsaTemplate, 6);
+ if (rv != CKR_OK) {
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+ free(Value.Data);
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ /*
+ * This is the KEY algorithm, not the
+ * signature algorithm.
+ */
+ Algorithm =
+ X509_AlgIdToAlgorithmOid(KMF_ALGID_DSA);
+
+ /* Encode the DSA Algorithm Parameters */
+ if ((asn1 = kmfder_alloc()) == NULL) {
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+ free(Value.Data);
+ return (KMF_ERR_MEMORY);
+ }
+
+ if (kmfber_printf(asn1, "{III}",
+ Prime.Data, Prime.Length,
+ Subprime.Data, Subprime.Length,
+ Base.Data, Base.Length) == -1) {
+
+ kmfber_free(asn1, 1);
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+ free(Value.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ if (kmfber_flatten(asn1, &PubKeyParams) == -1) {
+ kmfber_free(asn1, 1);
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+ free(Value.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ kmfber_free(asn1, 1);
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+
+ /* Encode the DSA Key Value */
+ if ((asn1 = kmfder_alloc()) == NULL) {
+ free(Value.Data);
+ return (KMF_ERR_MEMORY);
+ }
+
+ if (kmfber_printf(asn1, "I",
+ Value.Data, Value.Length) == -1) {
+ kmfber_free(asn1, 1);
+ free(Value.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ if (kmfber_flatten(asn1, &EncodedKey) == -1) {
+ kmfber_free(asn1, 1);
+ free(Value.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ kmfber_free(asn1, 1);
+ free(Value.Data);
+ break;
+ default:
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* Now, build an SPKI structure for the final encoding step */
+ spki.algorithm.algorithm = *Algorithm;
+ if (PubKeyParams != NULL) {
+ spki.algorithm.parameters.Data =
+ (uchar_t *)PubKeyParams->bv_val;
+ spki.algorithm.parameters.Length = PubKeyParams->bv_len;
+ } else {
+ spki.algorithm.parameters.Data = NULL;
+ spki.algorithm.parameters.Length = 0;
+ }
+
+ if (EncodedKey != NULL) {
+ spki.subjectPublicKey.Data = (uchar_t *)EncodedKey->bv_val;
+ spki.subjectPublicKey.Length = EncodedKey->bv_len;
+ } else {
+ spki.subjectPublicKey.Data = NULL;
+ spki.subjectPublicKey.Length = 0;
+ }
+
+ /* Finally, encode the entire SPKI record */
+ ret = DerEncodeSPKI(&spki, eData);
+
+cleanup:
+ if (EncodedKey) {
+ free(EncodedKey->bv_val);
+ free(EncodedKey);
+ }
+
+ if (PubKeyParams) {
+ free(PubKeyParams->bv_val);
+ free(PubKeyParams);
+ }
+
+ return (ret);
+}
+
+
+static KMF_RETURN
+CreateCertObject(KMF_HANDLE_T handle, char *label, KMF_DATA *pcert)
+{
+ KMF_RETURN rv = 0;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ KMF_X509_CERTIFICATE *signed_cert_ptr = NULL;
+ KMF_DATA data;
+ KMF_DATA Id;
+
+ CK_RV ckrv;
+ CK_ULONG subject_len, issuer_len, serno_len;
+ CK_BYTE *subject, *issuer, *serial;
+ CK_BBOOL true = TRUE;
+ CK_CERTIFICATE_TYPE certtype = CKC_X_509;
+ CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
+ CK_ATTRIBUTE x509templ[11];
+ CK_OBJECT_HANDLE hCert = NULL;
+ int i;
+
+ if (!kmfh)
+ return (KMF_ERR_INTERNAL); /* should not happen */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_INTERNAL); /* should not happen */
+
+ if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0)
+ return (KMF_ERR_INTERNAL); /* should not happen */
+
+ /*
+ * The data *must* be a DER encoded X.509 certificate.
+ * Convert it to a CSSM cert and then parse the fields so
+ * the PKCS#11 attributes can be filled in correctly.
+ */
+ rv = DerDecodeSignedCertificate((const KMF_DATA *)pcert,
+ &signed_cert_ptr);
+ if (rv != KMF_OK) {
+ return (KMF_ERR_ENCODING);
+ }
+
+ /*
+ * Encode fields into PKCS#11 attributes.
+ */
+
+ /* Get the subject name */
+ rv = DerEncodeName(&signed_cert_ptr->certificate.subject, &data);
+ if (rv == KMF_OK) {
+ subject = data.Data;
+ subject_len = data.Length;
+ } else {
+ rv = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ /* Encode the issuer */
+ rv = DerEncodeName(&signed_cert_ptr->certificate.issuer, &data);
+ if (rv == KMF_OK) {
+ issuer = data.Data;
+ issuer_len = data.Length;
+ } else {
+ rv = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ /* Encode serial number */
+ if (signed_cert_ptr->certificate.serialNumber.len > 0 &&
+ signed_cert_ptr->certificate.serialNumber.val != NULL) {
+ serial = signed_cert_ptr->certificate.serialNumber.val;
+ serno_len = signed_cert_ptr->certificate.serialNumber.len;
+ } else {
+ rv = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ /* Generate an ID from the SPKI data */
+ rv = GetIDFromSPKI(&signed_cert_ptr->certificate.subjectPublicKeyInfo,
+ &Id);
+
+ if (rv != KMF_OK) {
+ SET_ERROR(kmfh, rv);
+ goto cleanup;
+ }
+
+ i = 0;
+ SETATTR(x509templ, i, CKA_CLASS, &certClass,
+ sizeof (certClass)); i++;
+ SETATTR(x509templ, i, CKA_CERTIFICATE_TYPE, &certtype,
+ sizeof (certtype)); i++;
+ SETATTR(x509templ, i, CKA_TOKEN, &true, sizeof (true)); i++;
+ SETATTR(x509templ, i, CKA_SUBJECT, subject, subject_len); i++;
+ SETATTR(x509templ, i, CKA_ISSUER, issuer, issuer_len); i++;
+ SETATTR(x509templ, i, CKA_SERIAL_NUMBER, serial, serno_len); i++;
+ SETATTR(x509templ, i, CKA_VALUE, pcert->Data, pcert->Length); i++;
+ SETATTR(x509templ, i, CKA_ID, Id.Data, Id.Length); i++;
+ if (label != NULL && strlen(label)) {
+ SETATTR(x509templ, i, CKA_LABEL, label, strlen(label));
+ i++;
+ }
+
+ /*
+ * The cert object handle is actually "leaked" here. If the app
+ * really wants to clean up the data space, it will have to call
+ * KMF_DeleteCert and specify the softtoken keystore.
+ */
+ ckrv = C_CreateObject(kmfh->pk11handle, x509templ, i, &hCert);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ rv = KMF_ERR_INTERNAL;
+ }
+ free(subject);
+ free(issuer);
+
+cleanup:
+ if (Id.Data != NULL)
+ free(Id.Data);
+
+ if (signed_cert_ptr) {
+ KMF_FreeSignedCert(signed_cert_ptr);
+ free(signed_cert_ptr);
+ }
+ return (rv);
+}
+
+
+KMF_RETURN
+KMFPK11_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params,
+ KMF_DATA *pcert)
+{
+ KMF_RETURN rv = 0;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = CreateCertObject(handle, params->certLabel, pcert);
+ return (rv);
+}
+
+
+
+KMF_RETURN
+KMFPK11_ImportCert(KMF_HANDLE_T handle, KMF_IMPORTCERT_PARAMS *params)
+{
+ KMF_RETURN rv = 0;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ENCODE_FORMAT format;
+ KMF_DATA cert1 = { NULL, 0};
+ KMF_DATA cert2 = { NULL, 0};
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL || params->certfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * Check if the input cert file is a valid certificate and
+ * auto-detect the file format of it.
+ */
+ rv = KMF_IsCertFile(handle, params->certfile, &format);
+ if (rv != KMF_OK)
+ return (rv);
+
+ /* Read in the CERT file */
+ rv = KMF_ReadInputFile(handle, params->certfile, &cert1);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /*
+ * If the input certificate is in PEM format, we need to convert
+ * it to DER first.
+ */
+ if (format == KMF_FORMAT_PEM) {
+ int derlen;
+ rv = KMF_Pem2Der(cert1.Data, cert1.Length,
+ &cert2.Data, &derlen);
+ if (rv != KMF_OK) {
+ goto out;
+ }
+ cert2.Length = (size_t)derlen;
+ }
+
+ rv = CreateCertObject(handle, params->certLabel,
+ format == KMF_FORMAT_ASN1 ? &cert1 : &cert2);
+
+out:
+ if (cert1.Data != NULL) {
+ free(cert1.Data);
+ }
+
+ if (cert2.Data != NULL) {
+ free(cert2.Data);
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params)
+{
+ KMF_RETURN rv = 0;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ OBJLIST *objlist;
+ uint32_t numObjects = 0;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * Use the same search routine as is used for the FindCert
+ * operation.
+ */
+ objlist = NULL;
+ rv = search_certs(handle,
+ params->certLabel, params->issuer,
+ params->subject, params->serial,
+ params->pkcs11parms.private,
+ params->find_cert_validity,
+ &objlist, &numObjects);
+
+ if (rv == KMF_OK && objlist != NULL) {
+ OBJLIST *node = objlist;
+
+ while (node != NULL) {
+ CK_RV ckrv;
+ ckrv = C_DestroyObject(kmfh->pk11handle,
+ node->handle);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ break;
+ }
+ node = node->next;
+ }
+ free_objlist(objlist);
+ }
+
+ if (rv == KMF_OK && numObjects == 0)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+
+out:
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_CreateKeypair(KMF_HANDLE_T handle, KMF_CREATEKEYPAIR_PARAMS *params,
+ KMF_KEY_HANDLE *privkey, KMF_KEY_HANDLE *pubkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ CK_RV ckrv = 0;
+ CK_OBJECT_HANDLE pubKey = CK_INVALID_HANDLE;
+ CK_OBJECT_HANDLE priKey = CK_INVALID_HANDLE;
+ CK_SESSION_HANDLE hSession = kmfh->pk11handle;
+
+ static CK_OBJECT_CLASS priClass = CKO_PRIVATE_KEY;
+ static CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
+
+ static CK_ULONG rsaKeyType = CKK_RSA;
+ static CK_ULONG modulusBits = 1024;
+ static CK_BYTE PubExpo[3] = {0x01, 0x00, 0x01};
+ static CK_BBOOL true = TRUE;
+ static CK_BBOOL ontoken = TRUE;
+ static CK_BBOOL false = FALSE;
+ static CK_ULONG dsaKeyType = CKK_DSA;
+
+ CK_ATTRIBUTE rsaPubKeyTemplate[8];
+ CK_ATTRIBUTE rsaPriKeyTemplate[6];
+
+ static CK_BYTE ckDsaPrime[128] = {
+ 0xb2, 0x6b, 0xc3, 0xfb, 0xe3, 0x26, 0xf4, 0xc2,
+ 0xcf, 0xdd, 0xf9, 0xae, 0x3e, 0x39, 0x7f, 0x9c,
+ 0xa7, 0x73, 0xc3, 0x00, 0xa3, 0x50, 0x67, 0xc3,
+ 0xab, 0x49, 0x2c, 0xea, 0x59, 0x10, 0xa4, 0xbc,
+ 0x09, 0x94, 0xa9, 0x05, 0x3b, 0x0d, 0x35, 0x3c,
+ 0x55, 0x52, 0x47, 0xf0, 0xe3, 0x72, 0x5b, 0xe8,
+ 0x72, 0xa0, 0x71, 0x1c, 0x23, 0x4f, 0x6d, 0xe8,
+ 0xac, 0xe5, 0x21, 0x1b, 0xc0, 0xd8, 0x42, 0xd3,
+ 0x87, 0xae, 0x83, 0x5e, 0x52, 0x7e, 0x46, 0x09,
+ 0xb5, 0xc7, 0x3d, 0xd6, 0x00, 0xf5, 0xf2, 0x9c,
+ 0x84, 0x30, 0x81, 0x7e, 0x7b, 0x30, 0x5b, 0xd5,
+ 0xab, 0xd0, 0x2f, 0x21, 0xb3, 0xd8, 0xed, 0xdb,
+ 0x97, 0x77, 0xe4, 0x7e, 0x6c, 0xcc, 0xb9, 0x6b,
+ 0xdd, 0xaa, 0x96, 0x04, 0xe7, 0xd4, 0x55, 0x11,
+ 0x53, 0xab, 0xba, 0x95, 0x9a, 0xa2, 0x8c, 0x27,
+ 0xd9, 0xcf, 0xad, 0xf3, 0xcf, 0x3a, 0x0c, 0x4b};
+
+ static CK_BYTE ckDsaSubPrime[20] = {
+ 0xa4, 0x5f, 0x2a, 0x27, 0x09, 0x49, 0xb6, 0xfe,
+ 0x73, 0xeb, 0x95, 0x7d, 0x00, 0xf3, 0x42, 0xfc,
+ 0x78, 0x47, 0xb0, 0xd5};
+
+ static CK_BYTE ckDsaBase[128] = {
+ 0x5c, 0x57, 0x16, 0x49, 0xef, 0xc8, 0xfb, 0x4b,
+ 0xee, 0x07, 0x45, 0x3b, 0x6a, 0x1d, 0xf3, 0xe5,
+ 0xeb, 0xee, 0xad, 0x11, 0x13, 0xe3, 0x52, 0xe3,
+ 0x0d, 0xc0, 0x21, 0x25, 0xfa, 0xf0, 0x93, 0x1c,
+ 0x53, 0x4d, 0xdc, 0x0d, 0x76, 0xd2, 0xfe, 0xc2,
+ 0xd7, 0x72, 0x64, 0x69, 0x53, 0x3d, 0x33, 0xbd,
+ 0xe1, 0x34, 0xf2, 0x5a, 0x67, 0x83, 0xe0, 0xd3,
+ 0x1c, 0xd6, 0x41, 0x4d, 0x16, 0xe8, 0x6c, 0x5a,
+ 0x07, 0x95, 0x21, 0x9a, 0xa3, 0xc4, 0xb9, 0x05,
+ 0x9d, 0x11, 0xcb, 0xc8, 0xc4, 0x9d, 0x00, 0x1a,
+ 0xf4, 0x85, 0x2a, 0xa9, 0x20, 0x3c, 0xba, 0x67,
+ 0xe5, 0xed, 0x31, 0xb2, 0x11, 0xfb, 0x1f, 0x73,
+ 0xec, 0x61, 0x29, 0xad, 0xc7, 0x68, 0xb2, 0x3f,
+ 0x38, 0xea, 0xd9, 0x87, 0x83, 0x9e, 0x7e, 0x19,
+ 0x18, 0xdd, 0xc2, 0xc3, 0x5b, 0x16, 0x6d, 0xce,
+ 0xcf, 0x88, 0x91, 0x07, 0xe0, 0x2b, 0xa8, 0x54 };
+
+ static CK_ATTRIBUTE ckDsaPubKeyTemplate[] = {
+ { CKA_CLASS, &pubClass, sizeof (pubClass) },
+ { CKA_KEY_TYPE, &dsaKeyType, sizeof (dsaKeyType) },
+ { CKA_TOKEN, &ontoken, sizeof (ontoken)},
+ { CKA_PRIVATE, &false, sizeof (false)},
+ { CKA_PRIME, &ckDsaPrime, sizeof (ckDsaPrime) },
+ { CKA_SUBPRIME, &ckDsaSubPrime, sizeof (ckDsaSubPrime)},
+ { CKA_BASE, &ckDsaBase, sizeof (ckDsaBase) },
+ { CKA_VERIFY, &true, sizeof (true) },
+};
+
+#define NUMBER_DSA_PUB_TEMPLATES (sizeof (ckDsaPubKeyTemplate) / \
+ sizeof (CK_ATTRIBUTE))
+#define MAX_DSA_PUB_TEMPLATES (sizeof (ckDsaPubKeyTemplate) / \
+ sizeof (CK_ATTRIBUTE))
+
+ static CK_ATTRIBUTE ckDsaPriKeyTemplate[] = {
+ {CKA_CLASS, &priClass, sizeof (priClass)},
+ {CKA_KEY_TYPE, &dsaKeyType, sizeof (dsaKeyType)},
+ {CKA_TOKEN, &ontoken, sizeof (ontoken)},
+ {CKA_PRIVATE, &true, sizeof (true)},
+ {CKA_SIGN, &true, sizeof (true)},
+ };
+
+ CK_ATTRIBUTE labelattr[1];
+ CK_ATTRIBUTE idattr[1];
+ char IDHashData[SHA1_HASH_LENGTH];
+ KMF_DATA IDInput, IDOutput;
+
+#define NUMBER_DSA_PRI_TEMPLATES (sizeof (ckDsaPriKeyTemplate) / \
+ sizeof (CK_ATTRIBUTE))
+#define MAX_DSA_PRI_TEMPLATES (sizeof (ckDsaPriKeyTemplate) / \
+ sizeof (CK_ATTRIBUTE))
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = pk11_authenticate(handle, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ if (params->keytype == KMF_RSA) {
+ CK_MECHANISM keyGenMech = {CKM_RSA_PKCS_KEY_PAIR_GEN,
+ NULL, 0};
+ CK_BYTE *modulus;
+ CK_ULONG modulusLength;
+ CK_ATTRIBUTE modattr[1];
+
+ SETATTR(rsaPubKeyTemplate, 0, CKA_CLASS,
+ &pubClass, sizeof (pubClass));
+ SETATTR(rsaPubKeyTemplate, 1, CKA_KEY_TYPE,
+ &rsaKeyType, sizeof (rsaKeyType));
+ SETATTR(rsaPubKeyTemplate, 2, CKA_TOKEN,
+ &false, sizeof (false));
+ SETATTR(rsaPubKeyTemplate, 3, CKA_PRIVATE,
+ &false, sizeof (false));
+ SETATTR(rsaPubKeyTemplate, 4, CKA_MODULUS_BITS,
+ &modulusBits, sizeof (modulusBits));
+ if (params->rsa_exponent.len > 0 &&
+ params->rsa_exponent.val != NULL) {
+ SETATTR(rsaPubKeyTemplate, 5,
+ CKA_PUBLIC_EXPONENT,
+ params->rsa_exponent.val,
+ params->rsa_exponent.len);
+ } else {
+ SETATTR(rsaPubKeyTemplate, 5,
+ CKA_PUBLIC_EXPONENT, &PubExpo,
+ sizeof (PubExpo));
+ }
+ SETATTR(rsaPubKeyTemplate, 6, CKA_ENCRYPT,
+ &true, sizeof (true));
+ SETATTR(rsaPubKeyTemplate, 7, CKA_VERIFY,
+ &true, sizeof (true));
+
+ SETATTR(rsaPriKeyTemplate, 0, CKA_CLASS, &priClass,
+ sizeof (priClass));
+ SETATTR(rsaPriKeyTemplate, 1, CKA_KEY_TYPE, &rsaKeyType,
+ sizeof (rsaKeyType));
+ SETATTR(rsaPriKeyTemplate, 2, CKA_TOKEN, &ontoken,
+ sizeof (ontoken));
+ SETATTR(rsaPriKeyTemplate, 3, CKA_PRIVATE, &true,
+ sizeof (true));
+ SETATTR(rsaPriKeyTemplate, 4, CKA_DECRYPT, &true,
+ sizeof (true));
+ SETATTR(rsaPriKeyTemplate, 5, CKA_SIGN, &true,
+ sizeof (true));
+
+ SETATTR(modattr, 0, CKA_MODULUS, NULL, &modulusLength);
+
+ modulusBits = params->keylength;
+
+ pubKey = CK_INVALID_HANDLE;
+ priKey = CK_INVALID_HANDLE;
+ ckrv = C_GenerateKeyPair(hSession, &keyGenMech,
+ rsaPubKeyTemplate,
+ (sizeof (rsaPubKeyTemplate)/sizeof (CK_ATTRIBUTE)),
+ rsaPriKeyTemplate,
+ (sizeof (rsaPriKeyTemplate)/sizeof (CK_ATTRIBUTE)),
+ &pubKey, &priKey);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_KEYGEN_FAILED);
+ }
+
+ if (privkey != NULL) {
+ privkey->kstype = KMF_KEYSTORE_PK11TOKEN;
+ privkey->keyalg = KMF_RSA;
+ privkey->keyclass = KMF_ASYM_PRI;
+ privkey->keyp = (void *)priKey;
+ }
+ if (pubkey != NULL) {
+ pubkey->kstype = KMF_KEYSTORE_PK11TOKEN;
+ pubkey->keyalg = KMF_RSA;
+ pubkey->keyclass = KMF_ASYM_PUB;
+ pubkey->keyp = (void *)pubKey;
+ }
+
+ /* Get the Modulus field to use as input for creating the ID */
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pubKey,
+ modattr, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ modulusLength = modattr[0].ulValueLen;
+ modulus = malloc(modulusLength);
+ if (modulus == NULL)
+ return (KMF_ERR_MEMORY);
+
+ modattr[0].pValue = modulus;
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pubKey,
+ modattr, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ free(modulus);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ IDInput.Data = modulus;
+ IDInput.Length = modulusLength;
+
+ } else if (params->keytype == KMF_DSA) {
+ CK_MECHANISM keyGenMech = {CKM_DSA_KEY_PAIR_GEN, NULL, 0};
+ CK_BYTE *keyvalue;
+ CK_ULONG valueLen;
+ CK_ATTRIBUTE valattr[1];
+
+ SETATTR(ckDsaPriKeyTemplate, 2, CKA_TOKEN,
+ &ontoken, sizeof (ontoken));
+ SETATTR(valattr, 0, CKA_VALUE, NULL, &valueLen);
+
+ ckrv = C_GenerateKeyPair(hSession, &keyGenMech,
+ ckDsaPubKeyTemplate,
+ (sizeof (ckDsaPubKeyTemplate)/sizeof (CK_ATTRIBUTE)),
+ ckDsaPriKeyTemplate,
+ (sizeof (ckDsaPriKeyTemplate)/sizeof (CK_ATTRIBUTE)),
+ &pubKey, &priKey);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_KEYGEN_FAILED);
+ }
+
+ if (privkey != NULL) {
+ privkey->kstype = KMF_KEYSTORE_PK11TOKEN;
+ privkey->keyalg = KMF_DSA;
+ privkey->keyclass = KMF_ASYM_PRI;
+ privkey->keyp = (void *)priKey;
+ }
+ if (pubkey != NULL) {
+ pubkey->kstype = KMF_KEYSTORE_PK11TOKEN;
+ pubkey->keyalg = KMF_DSA;
+ pubkey->keyclass = KMF_ASYM_PUB;
+ pubkey->keyp = (void *)pubKey;
+ }
+ /* Get the Public Value to use as input for creating the ID */
+ rv = C_GetAttributeValue(hSession,
+ (CK_OBJECT_HANDLE)pubKey,
+ valattr, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ valueLen = valattr[0].ulValueLen;
+ keyvalue = malloc(valueLen);
+ if (keyvalue == NULL)
+ return (KMF_ERR_MEMORY);
+
+ valattr[0].pValue = keyvalue;
+ rv = C_GetAttributeValue(hSession,
+ (CK_OBJECT_HANDLE)pubKey,
+ valattr, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ free(keyvalue);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ IDInput.Data = keyvalue;
+ IDInput.Length = valueLen;
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (params->keylabel != NULL &&
+ strlen(params->keylabel)) {
+
+ SETATTR(labelattr, 0, CKA_LABEL, params->keylabel,
+ strlen(params->keylabel));
+
+ /* Set the CKA_LABEL if one was indicated */
+ if ((ckrv = C_SetAttributeValue(hSession, pubKey,
+ labelattr, 1)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+ if (pubkey != NULL) {
+ pubkey->keylabel =
+ (char *)strdup(params->keylabel);
+ if (pubkey->keylabel == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ }
+ if ((ckrv = C_SetAttributeValue(hSession, priKey,
+ labelattr, 1)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+ if (privkey != NULL) {
+ privkey->keylabel =
+ (char *)strdup(params->keylabel);
+ if (privkey->keylabel == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ }
+ }
+
+ /* Now, assign a CKA_ID value so it can be searched */
+ /* ID_Input was assigned above in the RSA or DSA keygen section */
+ IDOutput.Data = (uchar_t *)IDHashData;
+ IDOutput.Length = sizeof (IDHashData);
+
+ rv = DigestData(hSession, &IDInput, &IDOutput);
+ free(IDInput.Data);
+
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ goto cleanup;
+ }
+ SETATTR(idattr, 0, CKA_ID, IDOutput.Data, IDOutput.Length);
+ if ((ckrv = C_SetAttributeValue(hSession, pubKey,
+ idattr, 1)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+ if ((ckrv = C_SetAttributeValue(hSession, priKey,
+ idattr, 1)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+
+cleanup:
+ if (rv != KMF_OK) {
+ if (pubKey != CK_INVALID_HANDLE)
+ (void) C_DestroyObject(hSession, pubKey);
+ if (priKey != CK_INVALID_HANDLE)
+ (void) C_DestroyObject(hSession, priKey);
+ if (privkey) {
+ privkey->keyp = NULL;
+ if (privkey->keylabel)
+ free(privkey->keylabel);
+ }
+ if (pubkey) {
+ pubkey->keyp = NULL;
+ if (pubkey->keylabel)
+ free(pubkey->keylabel);
+ }
+ }
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params,
+ KMF_KEY_HANDLE *key, boolean_t destroy)
+{
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_RV ckrv = CKR_OK;
+ KMF_RETURN rv = KMF_OK;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (key == NULL || key->keyp == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (key->keyclass != KMF_ASYM_PUB &&
+ key->keyclass != KMF_ASYM_PRI &&
+ key->keyclass != KMF_SYMMETRIC)
+ return (KMF_ERR_BAD_KEY_CLASS);
+
+ if (destroy) {
+ rv = pk11_authenticate(handle, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+ }
+
+ if (!key->israw && destroy)
+ ckrv = C_DestroyObject(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)key->keyp);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ /* Report authentication failures to the caller */
+ if (ckrv == CKR_PIN_EXPIRED ||
+ ckrv == CKR_SESSION_READ_ONLY)
+ rv = KMF_ERR_AUTH_FAILED;
+ else
+ rv = KMF_ERR_INTERNAL;
+ }
+ return (rv);
+
+}
+
+KMF_RETURN
+KMFPK11_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *keyp,
+ KMF_OID *algOID,
+ KMF_DATA *tobesigned,
+ KMF_DATA *output)
+{
+ CK_RV ckrv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_SESSION_HANDLE hSession = kmfh->pk11handle;
+ CK_MECHANISM mechanism;
+ PKCS_ALGORITHM_MAP *pAlgMap;
+ KMF_ALGORITHM_INDEX AlgId;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (keyp == NULL || algOID == NULL ||
+ tobesigned == NULL || output == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* These functions are available to the plugin from libkmf */
+ AlgId = X509_AlgorithmOidToAlgId(algOID);
+ if (AlgId == KMF_ALGID_NONE)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Map the Algorithm OID to a PKCS#11 mechanism */
+ pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE,
+ AlgId, PKCS_GetDefaultSignatureMode(AlgId));
+
+ if (pAlgMap == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ mechanism.mechanism = pAlgMap->pkcs_mechanism;
+ mechanism.pParameter = NULL;
+ mechanism.ulParameterLen = 0;
+
+ ckrv = C_SignInit(hSession, &mechanism, (CK_OBJECT_HANDLE)keyp->keyp);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ ckrv = C_Sign(hSession,
+ tobesigned->Data, tobesigned->Length,
+ output->Data, (CK_ULONG *)&output->Length);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ return (KMF_OK);
+}
+
+KMF_RETURN
+KMFPK11_GetErrorString(KMF_HANDLE_T handle, char **msgstr)
+{
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ *msgstr = NULL;
+ if (kmfh->lasterr.errcode != 0) {
+ char *e = pkcs11_strerror(kmfh->lasterr.errcode);
+ if (e == NULL || (*msgstr = (char *)strdup(e)) == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+ }
+
+ return (KMF_OK);
+}
+
+static CK_RV
+getObjectKeytype(KMF_HANDLE_T handle, CK_OBJECT_HANDLE obj,
+ CK_ULONG *keytype)
+{
+ CK_RV rv = CKR_OK;
+ CK_ATTRIBUTE templ;
+ CK_ULONG len = sizeof (CK_ULONG);
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ templ.type = CKA_KEY_TYPE;
+ templ.pValue = keytype;
+ templ.ulValueLen = len;
+
+ rv = C_GetAttributeValue(kmfh->pk11handle, obj, &templ, 1);
+
+ return (rv);
+
+}
+static CK_RV
+getObjectLabel(KMF_HANDLE_T handle, CK_OBJECT_HANDLE obj,
+ char **outlabel)
+{
+ CK_RV rv = CKR_OK;
+ CK_ATTRIBUTE templ;
+ char Label[BUFSIZ];
+ CK_ULONG len = sizeof (Label);
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ (void) memset(Label, 0, len);
+ templ.type = CKA_LABEL;
+ templ.pValue = Label;
+ templ.ulValueLen = len;
+
+ rv = C_GetAttributeValue(kmfh->pk11handle, obj, &templ, 1);
+ if (rv == CKR_OK) {
+ *outlabel = (char *)strdup(Label);
+ } else {
+ *outlabel = NULL;
+ }
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_GetPrikeyByCert(KMF_HANDLE_T handle,
+ KMF_CRYPTOWITHCERT_PARAMS *params,
+ KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key,
+ KMF_KEY_ALG keytype)
+{
+ KMF_X509_SPKI *pubkey;
+ KMF_X509_CERTIFICATE *SignerCert = NULL;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_RETURN rv = KMF_OK;
+ CK_RV ckrv = CKR_OK;
+ CK_ATTRIBUTE templ[4];
+ CK_OBJECT_HANDLE pri_obj = CK_INVALID_HANDLE;
+ CK_ULONG obj_count;
+ CK_OBJECT_CLASS certClass = CKO_PRIVATE_KEY;
+ CK_BBOOL true = TRUE;
+ KMF_DATA Id = { NULL, 0 };
+
+ /* Decode the signer cert so we can get the SPKI data */
+ if ((rv = DerDecodeSignedCertificate(SignerCertData,
+ &SignerCert)) != KMF_OK)
+ return (rv);
+
+ /* Get the public key info from the signer certificate */
+ pubkey = &SignerCert->certificate.subjectPublicKeyInfo;
+
+ /* Generate an ID from the SPKI data */
+ rv = GetIDFromSPKI(pubkey, &Id);
+
+ if (rv != KMF_OK) {
+ SET_ERROR(kmfh, rv);
+ goto errout;
+ }
+
+ SETATTR(templ, 0, CKA_CLASS, &certClass, sizeof (certClass));
+ SETATTR(templ, 1, CKA_TOKEN, &true, sizeof (true));
+ SETATTR(templ, 2, CKA_PRIVATE, &true, sizeof (true));
+ SETATTR(templ, 3, CKA_ID, Id.Data, Id.Length);
+
+ rv = pk11_authenticate(handle, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ if ((ckrv = C_FindObjectsInit(kmfh->pk11handle, templ, 4)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto errout;
+ }
+
+ if ((rv = C_FindObjects(kmfh->pk11handle, &pri_obj, 1,
+ &obj_count)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto errout;
+ }
+
+ if (obj_count == 0) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto errout;
+ }
+
+ key->kstype = KMF_KEYSTORE_PK11TOKEN;
+ key->keyclass = KMF_ASYM_PRI;
+ key->keyalg = keytype;
+ key->keyp = (void *)pri_obj;
+
+ (void) C_FindObjectsFinal(kmfh->pk11handle);
+
+ ckrv = getObjectLabel(handle, (CK_OBJECT_HANDLE)key->keyp,
+ &key->keylabel);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(handle, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ } else {
+ rv = KMF_OK;
+ }
+
+ if (rv == KMF_OK && params->format == KMF_FORMAT_RAWKEY) {
+ KMF_RAW_KEY_DATA *rkey = NULL;
+ rv = keyObj2RawKey(handle, key, &rkey);
+ if (rv == KMF_OK) {
+ key->keyp = rkey;
+ key->israw = TRUE;
+ }
+ }
+
+errout:
+ if (Id.Data != NULL)
+ free(Id.Data);
+
+ if (SignerCert != NULL) {
+ KMF_FreeSignedCert(SignerCert);
+ free(SignerCert);
+ }
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_OID *algOID, KMF_DATA *ciphertext,
+ KMF_DATA *output)
+{
+ CK_RV ckrv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_SESSION_HANDLE hSession = kmfh->pk11handle;
+ CK_MECHANISM mechanism;
+ PKCS_ALGORITHM_MAP *pAlgMap;
+ KMF_ALGORITHM_INDEX AlgId;
+ CK_ULONG out_len = 0, block_len = 0, total_decrypted = 0;
+ uint8_t *in_data, *out_data;
+ int i, blocks;
+ CK_ATTRIBUTE ckTemplate[1];
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (key == NULL || algOID == NULL ||
+ ciphertext == NULL || output == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ AlgId = X509_AlgorithmOidToAlgId(algOID);
+ if (AlgId == KMF_ALGID_NONE)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Map the Algorithm ID to a PKCS#11 mechanism */
+ pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE,
+ AlgId, PKCS_GetDefaultSignatureMode(AlgId));
+
+ if (pAlgMap == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ mechanism.mechanism = pAlgMap->pkcs_mechanism;
+ mechanism.pParameter = NULL;
+ mechanism.ulParameterLen = 0;
+
+ SETATTR(ckTemplate, 0, CKA_MODULUS, (CK_BYTE *)NULL,
+ sizeof (CK_ULONG));
+
+ /* Get the modulus length */
+ ckrv = C_GetAttributeValue(hSession,
+ (CK_OBJECT_HANDLE)key->keyp, ckTemplate, 1);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ block_len = ckTemplate[0].ulValueLen;
+
+ /* Compute the number of times to do single-part decryption */
+ blocks = ciphertext->Length/block_len;
+
+ out_data = output->Data;
+ in_data = ciphertext->Data;
+ out_len = block_len - 11;
+
+ for (i = 0; i < blocks; i++) {
+ ckrv = C_DecryptInit(hSession, &mechanism,
+ (CK_OBJECT_HANDLE)key->keyp);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ ckrv = C_Decrypt(hSession, in_data, block_len,
+ out_data, (CK_ULONG *)&out_len);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ out_data += out_len;
+ total_decrypted += out_len;
+ in_data += block_len;
+
+ }
+
+ output->Length = total_decrypted;
+ return (KMF_OK);
+}
+
+static void
+attr2bigint(CK_ATTRIBUTE_PTR attr, KMF_BIGINT *big)
+{
+ big->val = attr->pValue;
+ big->len = attr->ulValueLen;
+}
+
+
+static KMF_RETURN
+get_raw_rsa(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_RSA_KEY *rawrsa)
+{
+ KMF_RETURN rv = KMF_OK;
+ CK_SESSION_HANDLE sess = kmfh->pk11handle;
+ CK_ATTRIBUTE rsa_pri_attrs[8] = {
+ { CKA_MODULUS, NULL, 0 },
+ { CKA_PUBLIC_EXPONENT, NULL, 0 },
+ { CKA_PRIVATE_EXPONENT, NULL, 0 }, /* optional */
+ { CKA_PRIME_1, NULL, 0 }, /* | */
+ { CKA_PRIME_2, NULL, 0 }, /* | */
+ { CKA_EXPONENT_1, NULL, 0 }, /* | */
+ { CKA_EXPONENT_2, NULL, 0 }, /* | */
+ { CKA_COEFFICIENT, NULL, 0 } /* V */
+ };
+ CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
+ int i;
+
+ if ((rv = C_GetAttributeValue(sess, obj,
+ rsa_pri_attrs, count)) != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ /* Allocate memory for each attribute. */
+ for (i = 0; i < count; i++) {
+ if (rsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ rsa_pri_attrs[i].ulValueLen == 0) {
+ rsa_pri_attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((rsa_pri_attrs[i].pValue =
+ malloc(rsa_pri_attrs[i].ulValueLen)) == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto end;
+ }
+ }
+ /* Now that we have space, really get the attributes */
+ if ((rv = C_GetAttributeValue(sess, obj,
+ rsa_pri_attrs, count)) != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ rv = KMF_ERR_INTERNAL;
+ goto end;
+ }
+ i = 0;
+ attr2bigint(&(rsa_pri_attrs[i++]), &rawrsa->mod);
+ attr2bigint(&(rsa_pri_attrs[i++]), &rawrsa->pubexp);
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->priexp);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->prime1);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->prime2);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->exp1);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->exp2);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->coef);
+ i++;
+
+end:
+ if (rv != KMF_OK) {
+ for (i = 0; i < count; i++) {
+ if (rsa_pri_attrs[i].pValue != NULL)
+ free(rsa_pri_attrs[i].pValue);
+ }
+ (void) memset(rawrsa, 0, sizeof (KMF_RAW_RSA_KEY));
+ }
+ return (rv);
+}
+
+static KMF_RETURN
+get_raw_dsa(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_DSA_KEY *rawdsa)
+{
+ KMF_RETURN rv = KMF_OK;
+ CK_SESSION_HANDLE sess = kmfh->pk11handle;
+ CK_ATTRIBUTE dsa_pri_attrs[8] = {
+ { CKA_PRIME, NULL, 0 },
+ { CKA_SUBPRIME, NULL, 0 },
+ { CKA_BASE, NULL, 0 },
+ { CKA_VALUE, NULL, 0 }
+ };
+ CK_ULONG count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
+ int i;
+
+ if ((rv = C_GetAttributeValue(sess, obj,
+ dsa_pri_attrs, count)) != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ /* Allocate memory for each attribute. */
+ for (i = 0; i < count; i++) {
+ if (dsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ dsa_pri_attrs[i].ulValueLen == 0) {
+ dsa_pri_attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((dsa_pri_attrs[i].pValue =
+ malloc(dsa_pri_attrs[i].ulValueLen)) == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto end;
+ }
+ }
+ if ((rv = C_GetAttributeValue(sess, obj,
+ dsa_pri_attrs, count)) != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ rv = KMF_ERR_INTERNAL;
+ goto end;
+ }
+
+ /* Fill in all the temp variables. They are all required. */
+ i = 0;
+ attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->prime);
+ attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->subprime);
+ attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->base);
+ attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->value);
+
+end:
+ if (rv != KMF_OK) {
+ for (i = 0; i < count; i++) {
+ if (dsa_pri_attrs[i].pValue != NULL)
+ free(dsa_pri_attrs[i].pValue);
+ }
+ (void) memset(rawdsa, 0, sizeof (KMF_RAW_DSA_KEY));
+ }
+ return (rv);
+}
+
+static KMF_RETURN
+get_raw_sym(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_SYM_KEY *rawsym)
+{
+ KMF_RETURN rv = KMF_OK;
+ CK_RV ckrv;
+ CK_SESSION_HANDLE sess = kmfh->pk11handle;
+ CK_ATTRIBUTE sym_attr[1];
+ CK_ULONG value_len = 0;
+
+ /* find the key length first */
+ sym_attr[0].type = CKA_VALUE;
+ sym_attr[0].pValue = NULL;
+ sym_attr[0].ulValueLen = value_len;
+ if ((ckrv = C_GetAttributeValue(sess, obj, sym_attr, 1)) != CKR_OK) {
+ /*
+ * Don't return error if the key is sensitive, just
+ * don't return any raw data. Operations like "list"
+ * need to succeed even if the raw data is not
+ * available.
+ */
+ if (ckrv == CKR_ATTRIBUTE_SENSITIVE) {
+ rawsym->keydata.val = NULL;
+ rawsym->keydata.len = 0;
+ return (CKR_OK);
+ }
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ /* Allocate memory for pValue */
+ sym_attr[0].pValue = malloc(sym_attr[0].ulValueLen);
+ if (sym_attr[0].pValue == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ /* get the key data */
+ if ((rv = C_GetAttributeValue(sess, obj, sym_attr, 1)) != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ free(sym_attr[0].pValue);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ rawsym->keydata.val = sym_attr[0].pValue;
+ rawsym->keydata.len = sym_attr[0].ulValueLen;
+ return (rv);
+}
+
+static KMF_RETURN
+keyObj2RawKey(KMF_HANDLE_T handle, KMF_KEY_HANDLE *inkey,
+ KMF_RAW_KEY_DATA **outkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_RAW_KEY_DATA *rkey;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ rkey = malloc(sizeof (KMF_RAW_KEY_DATA));
+ if (rkey == NULL)
+ return (KMF_ERR_MEMORY);
+
+ (void) memset(rkey, 0, sizeof (KMF_RAW_KEY_DATA));
+
+ rkey->keytype = inkey->keyalg;
+
+ if (inkey->keyalg == KMF_RSA) {
+ rv = get_raw_rsa(kmfh, (CK_OBJECT_HANDLE)inkey->keyp,
+ &rkey->rawdata.rsa);
+ } else if (inkey->keyalg == KMF_DSA) {
+ rv = get_raw_dsa(kmfh, (CK_OBJECT_HANDLE)inkey->keyp,
+ &rkey->rawdata.dsa);
+ } else if (inkey->keyalg == KMF_AES ||
+ inkey->keyalg == KMF_RC4 ||
+ inkey->keyalg == KMF_DES ||
+ inkey->keyalg == KMF_DES3) {
+ rv = get_raw_sym(kmfh, (CK_OBJECT_HANDLE)inkey->keyp,
+ &rkey->rawdata.sym);
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ }
+
+ if (rv == KMF_OK) {
+ *outkey = rkey;
+ } else if (rkey != NULL) {
+ free(rkey);
+ *outkey = NULL;
+ }
+
+ return (rv);
+}
+
+
+static KMF_RETURN
+kmf2pk11keytype(KMF_KEY_ALG keyalg, CK_KEY_TYPE *type)
+{
+ switch (keyalg) {
+ case KMF_RSA:
+ *type = CKK_RSA;
+ break;
+ case KMF_DSA:
+ *type = CKK_DSA;
+ break;
+ case KMF_AES:
+ *type = CKK_AES;
+ break;
+ case KMF_RC4:
+ *type = CKK_RC4;
+ break;
+ case KMF_DES:
+ *type = CKK_DES;
+ break;
+ case KMF_DES3:
+ *type = CKK_DES3;
+ break;
+ default:
+ return (KMF_ERR_BAD_KEY_TYPE);
+ }
+
+ return (KMF_OK);
+}
+
+static int
+IDStringToData(char *idstr, KMF_DATA *iddata)
+{
+ int len, i;
+ char *iddup, *byte;
+ uint_t lvalue;
+
+ if (idstr == NULL || !strlen(idstr))
+ return (-1);
+
+ iddup = (char *)strdup(idstr);
+ if (iddup == NULL)
+ return (KMF_ERR_MEMORY);
+
+ len = strlen(iddup) / 3 + 1;
+ iddata->Data = malloc(len);
+ if (iddata->Data == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(iddata->Data, 0, len);
+ iddata->Length = len;
+
+ byte = strtok(iddup, ":");
+ if (byte == NULL) {
+ free(iddup);
+ free(iddata->Data);
+ iddata->Data = NULL;
+ iddata->Length = 0;
+ return (-1);
+ }
+
+ i = 0;
+ do {
+ (void) sscanf(byte, "%x", &lvalue);
+ iddata->Data[i++] = (uchar_t)(lvalue & 0x000000FF);
+ byte = strtok(NULL, ":");
+ } while (byte != NULL && i < len);
+
+ iddata->Length = i;
+ free(iddup);
+ return (0);
+}
+
+KMF_RETURN
+KMFPK11_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms,
+ KMF_KEY_HANDLE *keys, uint32_t *numkeys)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ uint32_t want_keys, i;
+ CK_RV ckrv;
+ CK_ATTRIBUTE pTmpl[10];
+ CK_OBJECT_CLASS class;
+ CK_BBOOL true = TRUE;
+ CK_BBOOL false = FALSE;
+ CK_ULONG alg;
+ CK_BBOOL is_token;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (parms == NULL || numkeys == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (numkeys != NULL && *numkeys > 0)
+ want_keys = *numkeys;
+ else
+ want_keys = MAXINT; /* count them all */
+
+ if (parms->keyclass == KMF_ASYM_PUB) {
+ class = CKO_PUBLIC_KEY;
+ is_token = false;
+ } else if (parms->keyclass == KMF_ASYM_PRI) {
+ class = CKO_PRIVATE_KEY;
+ is_token = true;
+ } else if (parms->keyclass == KMF_SYMMETRIC) {
+ class = CKO_SECRET_KEY;
+ is_token = true;
+ } else {
+ return (KMF_ERR_BAD_KEY_CLASS);
+ }
+
+ i = 0;
+ pTmpl[i].type = CKA_TOKEN;
+ pTmpl[i].pValue = &is_token;
+ pTmpl[i].ulValueLen = sizeof (CK_BBOOL);
+ i++;
+
+ pTmpl[i].type = CKA_CLASS;
+ pTmpl[i].pValue = &class;
+ pTmpl[i].ulValueLen = sizeof (class);
+ i++;
+
+ if (parms->findLabel != NULL && strlen(parms->findLabel)) {
+ pTmpl[i].type = CKA_LABEL;
+ pTmpl[i].pValue = parms->findLabel;
+ pTmpl[i].ulValueLen = strlen(parms->findLabel);
+ i++;
+ }
+
+ if (parms->keytype != 0) {
+ rv = kmf2pk11keytype(parms->keytype, &alg);
+ if (rv != KMF_OK) {
+ return (KMF_ERR_BAD_KEY_TYPE);
+ }
+ pTmpl[i].type = CKA_KEY_TYPE;
+ pTmpl[i].pValue = &alg;
+ pTmpl[i].ulValueLen = sizeof (alg);
+ i++;
+ }
+
+ if (parms->idstr != NULL) {
+ KMF_DATA iddata = { NULL, 0 };
+
+ /*
+ * ID String parameter is assumed to be of form:
+ * XX:XX:XX:XX:XX ... :XX
+ * where XX is a hex number.
+ *
+ * We must convert this back to binary in order to
+ * use it in a search.
+ */
+ rv = IDStringToData(parms->idstr, &iddata);
+ if (rv == KMF_OK) {
+ pTmpl[i].type = CKA_ID;
+ pTmpl[i].pValue = iddata.Data;
+ pTmpl[i].ulValueLen = iddata.Length;
+ i++;
+ } else {
+ return (rv);
+ }
+ }
+
+ if (parms->pkcs11parms.private) {
+ pTmpl[i].type = CKA_PRIVATE;
+ pTmpl[i].pValue = &true;
+ pTmpl[i].ulValueLen = sizeof (true);
+ i++;
+ }
+
+ if (is_token) {
+ rv = pk11_authenticate(handle, &parms->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+ }
+
+ ckrv = C_FindObjectsInit(kmfh->pk11handle, pTmpl, i);
+ if (ckrv == CKR_OK) {
+ CK_ULONG obj_count, n = 0;
+ while (ckrv == CKR_OK && n < want_keys) {
+ CK_OBJECT_HANDLE hObj;
+
+ ckrv = C_FindObjects(kmfh->pk11handle, &hObj,
+ 1, &obj_count);
+ if (ckrv == CKR_OK && obj_count == 1) {
+ if (keys != NULL) {
+ CK_ULONG keytype;
+ keys[n].kstype = KMF_KEYSTORE_PK11TOKEN;
+ keys[n].keyclass = parms->keyclass;
+ keys[n].israw = FALSE;
+ keys[n].keyp = (void *)hObj;
+
+ ckrv = getObjectKeytype(handle,
+ (CK_OBJECT_HANDLE)keys[n].keyp,
+ &keytype);
+ if (ckrv != CKR_OK)
+ goto end;
+
+ ckrv = getObjectLabel(handle,
+ (CK_OBJECT_HANDLE)keys[n].keyp,
+ &(keys[n].keylabel));
+ if (ckrv != CKR_OK)
+ goto end;
+
+ if (keytype == CKK_RSA)
+ keys[n].keyalg = KMF_RSA;
+ else if (keytype == CKK_DSA)
+ keys[n].keyalg = KMF_DSA;
+ else if (keytype == CKK_AES)
+ keys[n].keyalg = KMF_AES;
+ else if (keytype == CKK_RC4)
+ keys[n].keyalg = KMF_RC4;
+ else if (keytype == CKK_DES)
+ keys[n].keyalg = KMF_DES;
+ else if (keytype == CKK_DES3)
+ keys[n].keyalg = KMF_DES3;
+
+ }
+ n++;
+ } else {
+ break;
+ }
+ }
+ ckrv = C_FindObjectsFinal(kmfh->pk11handle);
+
+ /* "numkeys" indicates the number that were actually found */
+ *numkeys = n;
+ }
+ if (ckrv == KMF_OK && keys != NULL && (*numkeys) > 0 &&
+ parms->format == KMF_FORMAT_RAWKEY) {
+ /* Convert keys to "rawkey" format */
+ for (i = 0; i < (*numkeys); i++) {
+ KMF_RAW_KEY_DATA *rkey = NULL;
+ rv = keyObj2RawKey(handle, &keys[i], &rkey);
+ if (rv == KMF_OK) {
+ keys[i].keyp = rkey;
+ keys[i].israw = TRUE;
+ } else {
+ break;
+ }
+ }
+ }
+end:
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ /* Report authentication failures to the caller */
+ if (ckrv == CKR_USER_NOT_LOGGED_IN ||
+ ckrv == CKR_PIN_INCORRECT ||
+ ckrv == CKR_PIN_INVALID ||
+ ckrv == CKR_PIN_EXPIRED ||
+ ckrv == CKR_PIN_LOCKED ||
+ ckrv == CKR_SESSION_READ_ONLY)
+ rv = KMF_ERR_AUTH_FAILED;
+ else
+ rv = KMF_ERR_INTERNAL;
+ } else if ((*numkeys) == 0) {
+ rv = KMF_ERR_KEY_NOT_FOUND;
+ }
+
+ return (rv);
+}
+
+static char *
+convertDate(char *fulldate)
+{
+ struct tm tms;
+ char newtime[9];
+
+ (void) strptime(fulldate, "%b %d %T %Y %Z", &tms);
+
+ if (tms.tm_year < 69)
+ tms.tm_year += 100;
+
+ (void) strftime(newtime, sizeof (newtime), "m%d", &tms);
+
+ newtime[8] = 0;
+
+ /* memory returned must be freed by the caller */
+ return ((char *)strdup(newtime));
+}
+
+KMF_RETURN
+KMFPK11_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params,
+ KMF_RAW_KEY_DATA *rawkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ int i;
+ CK_RV ckrv = CKR_OK;
+ CK_ATTRIBUTE templ[32];
+ CK_OBJECT_HANDLE keyobj;
+ CK_KEY_TYPE keytype;
+ CK_OBJECT_CLASS oClass = CKO_PRIVATE_KEY;
+ CK_BBOOL cktrue = TRUE;
+ CK_DATE startdate, enddate;
+ KMF_DATA id = {NULL, 0};
+ KMF_DATA subject = {NULL, 0};
+ KMF_X509EXT_KEY_USAGE kuext;
+ KMF_X509_CERTIFICATE *x509 = NULL;
+ CK_BBOOL kufound;
+ char *notbefore = NULL, *start = NULL;
+ char *notafter = NULL, *end = NULL;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL || params->certificate == NULL ||
+ rawkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (rawkey->keytype == KMF_RSA)
+ keytype = CKK_RSA;
+ else if (rawkey->keytype == KMF_DSA)
+ keytype = CKK_DSA;
+ else
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = pk11_authenticate(handle, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ id.Data = NULL;
+ id.Length = 0;
+ rv = KMF_GetCertIDData(params->certificate, &id);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+
+ rv = DerDecodeSignedCertificate(
+ (const KMF_DATA *)params->certificate, &x509);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+
+ rv = DerEncodeName(&x509->certificate.subject, &subject);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+
+ rv = KMF_GetCertStartDateString(handle, params->certificate,
+ &notbefore);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+ start = convertDate(notbefore);
+
+ rv = KMF_GetCertEndDateString(handle, params->certificate,
+ &notafter);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+ end = convertDate(notafter);
+
+ if ((rv = KMF_GetCertKeyUsageExt(params->certificate, &kuext))
+ != KMF_OK && rv != KMF_ERR_EXTENSION_NOT_FOUND)
+ goto cleanup;
+
+ kufound = (rv == KMF_OK);
+ rv = KMF_OK; /* reset if we got KMF_ERR_EXTENSION_NOT_FOUND above */
+
+ i = 0;
+ SETATTR(templ, i, CKA_CLASS, &oClass, sizeof (CK_OBJECT_CLASS)); i++;
+ SETATTR(templ, i, CKA_KEY_TYPE, &keytype, sizeof (keytype)); i++;
+ SETATTR(templ, i, CKA_TOKEN, &cktrue, sizeof (cktrue)); i++;
+ SETATTR(templ, i, CKA_PRIVATE, &cktrue, sizeof (cktrue)); i++;
+ SETATTR(templ, i, CKA_SUBJECT, subject.Data, subject.Length); i++;
+
+ /*
+ * Only set the KeyUsage stuff if the KU extension was present.
+ */
+ if (kufound) {
+ CK_BBOOL condition;
+
+ condition = (kuext.KeyUsageBits & KMF_keyEncipherment) ?
+ B_TRUE : B_FALSE;
+ SETATTR(templ, i, CKA_UNWRAP, &condition,
+ sizeof (CK_BBOOL)); i++;
+ condition = (kuext.KeyUsageBits & KMF_dataEncipherment) ?
+ B_TRUE : B_FALSE;
+ SETATTR(templ, i, CKA_DECRYPT, &condition,
+ sizeof (CK_BBOOL)); i++;
+ condition = (kuext.KeyUsageBits & KMF_digitalSignature) ?
+ B_TRUE : B_FALSE;
+ SETATTR(templ, i, CKA_SIGN, &condition,
+ sizeof (CK_BBOOL)); i++;
+ condition = (kuext.KeyUsageBits & KMF_digitalSignature) ?
+ B_TRUE : B_FALSE;
+ SETATTR(templ, i, CKA_SIGN_RECOVER, &condition,
+ sizeof (CK_BBOOL)); i++;
+ }
+ if (params->label != NULL) {
+ SETATTR(templ, i, CKA_LABEL, params->label,
+ strlen(params->label));
+ i++;
+ }
+ if (id.Data != NULL &&
+ id.Data != NULL && id.Length > 0) {
+ SETATTR(templ, i, CKA_ID, id.Data, id.Length);
+ i++;
+ }
+ if (start != NULL) {
+ /*
+ * This make some potentially dangerous assumptions:
+ * 1. that the startdate in the parameter block is
+ * properly formatted as YYYYMMDD
+ * 2. That the CK_DATE structure is always the same.
+ */
+ (void) memcpy(&startdate, start, sizeof (CK_DATE));
+ SETATTR(templ, i, CKA_START_DATE, &startdate,
+ sizeof (startdate));
+ i++;
+ }
+ if (end != NULL) {
+ (void) memcpy(&enddate, end, sizeof (CK_DATE));
+ SETATTR(templ, i, CKA_END_DATE, &enddate, sizeof (enddate));
+ i++;
+ }
+ if (keytype == CKK_RSA) {
+ SETATTR(templ, i, CKA_MODULUS,
+ rawkey->rawdata.rsa.mod.val,
+ rawkey->rawdata.rsa.mod.len);
+ i++;
+ SETATTR(templ, i, CKA_PUBLIC_EXPONENT,
+ rawkey->rawdata.rsa.pubexp.val,
+ rawkey->rawdata.rsa.pubexp.len);
+ i++;
+ if (rawkey->rawdata.rsa.priexp.val != NULL) {
+ SETATTR(templ, i, CKA_PRIVATE_EXPONENT,
+ rawkey->rawdata.rsa.priexp.val,
+ rawkey->rawdata.rsa.priexp.len);
+ i++;
+ }
+ if (rawkey->rawdata.rsa.prime1.val != NULL) {
+ SETATTR(templ, i, CKA_PRIME_1,
+ rawkey->rawdata.rsa.prime1.val,
+ rawkey->rawdata.rsa.prime1.len);
+ i++;
+ }
+ if (rawkey->rawdata.rsa.prime2.val != NULL) {
+ SETATTR(templ, i, CKA_PRIME_2,
+ rawkey->rawdata.rsa.prime2.val,
+ rawkey->rawdata.rsa.prime2.len);
+ i++;
+ }
+ if (rawkey->rawdata.rsa.exp1.val != NULL) {
+ SETATTR(templ, i, CKA_EXPONENT_1,
+ rawkey->rawdata.rsa.exp1.val,
+ rawkey->rawdata.rsa.exp1.len);
+ i++;
+ }
+ if (rawkey->rawdata.rsa.exp2.val != NULL) {
+ SETATTR(templ, i, CKA_EXPONENT_2,
+ rawkey->rawdata.rsa.exp2.val,
+ rawkey->rawdata.rsa.exp2.len);
+ i++;
+ }
+ if (rawkey->rawdata.rsa.coef.val != NULL) {
+ SETATTR(templ, i, CKA_COEFFICIENT,
+ rawkey->rawdata.rsa.coef.val,
+ rawkey->rawdata.rsa.coef.len);
+ i++;
+ }
+ } else {
+ SETATTR(templ, i, CKA_PRIME,
+ rawkey->rawdata.dsa.prime.val,
+ rawkey->rawdata.dsa.prime.len);
+ i++;
+ SETATTR(templ, i, CKA_SUBPRIME,
+ rawkey->rawdata.dsa.subprime.val,
+ rawkey->rawdata.dsa.subprime.len);
+ i++;
+ SETATTR(templ, i, CKA_BASE,
+ rawkey->rawdata.dsa.base.val,
+ rawkey->rawdata.dsa.base.len);
+ i++;
+ SETATTR(templ, i, CKA_VALUE,
+ rawkey->rawdata.dsa.value.val,
+ rawkey->rawdata.dsa.value.len);
+ i++;
+ }
+
+ ckrv = C_CreateObject(kmfh->pk11handle, templ, i, &keyobj);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+
+ /* Report authentication failures to the caller */
+ if (ckrv == CKR_USER_NOT_LOGGED_IN ||
+ ckrv == CKR_PIN_INCORRECT ||
+ ckrv == CKR_PIN_INVALID ||
+ ckrv == CKR_PIN_EXPIRED ||
+ ckrv == CKR_PIN_LOCKED ||
+ ckrv == CKR_SESSION_READ_ONLY)
+ rv = KMF_ERR_AUTH_FAILED;
+ else
+ rv = KMF_ERR_INTERNAL;
+ }
+cleanup:
+ KMF_FreeData(&id);
+ KMF_FreeData(&subject);
+ KMF_FreeSignedCert(x509);
+ free(x509);
+
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_CreateSymKey(KMF_HANDLE_T handle, KMF_CREATESYMKEY_PARAMS *params,
+ KMF_KEY_HANDLE *symkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_RV ckrv;
+ CK_SESSION_HANDLE hSession = kmfh->pk11handle;
+ CK_OBJECT_HANDLE keyhandle;
+ CK_MECHANISM keyGenMech;
+ CK_OBJECT_CLASS class = CKO_SECRET_KEY;
+ CK_ULONG secKeyType;
+ CK_ULONG secKeyLen; /* for RC4 and AES */
+ CK_BBOOL true = TRUE;
+ CK_BBOOL false = FALSE;
+ CK_ATTRIBUTE templ[15];
+ int i;
+
+ if (kmfh == NULL)
+ return (KMF_ERR_UNINITIALIZED);
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ keyGenMech.pParameter = NULL_PTR;
+ keyGenMech.ulParameterLen = 0;
+ switch (params->keytype) {
+ case KMF_AES:
+ keyGenMech.mechanism = CKM_AES_KEY_GEN;
+ secKeyType = CKK_AES;
+ break;
+ case KMF_RC4:
+ keyGenMech.mechanism = CKM_RC4_KEY_GEN;
+ secKeyType = CKK_RC4;
+ break;
+ case KMF_DES:
+ keyGenMech.mechanism = CKM_DES_KEY_GEN;
+ secKeyType = CKK_DES;
+ break;
+ case KMF_DES3:
+ keyGenMech.mechanism = CKM_DES3_KEY_GEN;
+ secKeyType = CKK_DES3;
+ break;
+ default:
+ return (KMF_ERR_BAD_KEY_TYPE);
+ }
+
+ i = 0;
+ SETATTR(templ, i, CKA_CLASS, &class, sizeof (class));
+ i++;
+ SETATTR(templ, i, CKA_KEY_TYPE, &secKeyType, sizeof (secKeyType));
+ i++;
+
+ if (params->keytype == KMF_AES || params->keytype == KMF_RC4) {
+ if ((params->keylength % 8) != 0) {
+ return (KMF_ERR_BAD_KEY_SIZE);
+ }
+ secKeyLen = params->keylength/8; /* in bytes for RC4/AES */
+ SETATTR(templ, i, CKA_VALUE_LEN, &secKeyLen,
+ sizeof (secKeyLen));
+ i++;
+ }
+
+ if (params->keylabel != NULL) {
+ SETATTR(templ, i, CKA_LABEL, params->keylabel,
+ strlen(params->keylabel));
+ i++;
+ }
+
+ if (params->pkcs11parms.sensitive == B_TRUE) {
+ SETATTR(templ, i, CKA_SENSITIVE, &true, sizeof (true));
+ } else {
+ SETATTR(templ, i, CKA_SENSITIVE, &false, sizeof (false));
+ }
+ i++;
+
+ if (params->pkcs11parms.not_extractable == B_TRUE) {
+ SETATTR(templ, i, CKA_EXTRACTABLE, &false, sizeof (false));
+ } else {
+ SETATTR(templ, i, CKA_EXTRACTABLE, &true, sizeof (true));
+ }
+ i++;
+
+ SETATTR(templ, i, CKA_TOKEN, &true, sizeof (true));
+ i++;
+ SETATTR(templ, i, CKA_PRIVATE, &true, sizeof (true));
+ i++;
+ SETATTR(templ, i, CKA_ENCRYPT, &true, sizeof (true));
+ i++;
+ SETATTR(templ, i, CKA_DECRYPT, &true, sizeof (true));
+ i++;
+ SETATTR(templ, i, CKA_SIGN, &true, sizeof (true));
+ i++;
+ SETATTR(templ, i, CKA_VERIFY, &true, sizeof (true));
+ i++;
+
+ rv = pk11_authenticate(handle, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ ckrv = C_GenerateKey(hSession, &keyGenMech, templ, i, &keyhandle);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto out;
+ }
+
+ symkey->kstype = KMF_KEYSTORE_PK11TOKEN;
+ symkey->keyalg = params->keytype;
+ symkey->keyclass = KMF_SYMMETRIC;
+ symkey->israw = FALSE;
+ symkey->keyp = (void *)keyhandle;
+
+out:
+ return (rv);
+}
+
+
+KMF_RETURN
+KMFPK11_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey,
+ KMF_RAW_SYM_KEY *rkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ if (kmfh == NULL)
+ return (KMF_ERR_UNINITIALIZED);
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (symkey == NULL || rkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ else if (symkey->keyclass != KMF_SYMMETRIC)
+ return (KMF_ERR_BAD_KEY_CLASS);
+
+ if (symkey->israw) {
+ KMF_RAW_KEY_DATA *rawkey = (KMF_RAW_KEY_DATA *)symkey->keyp;
+
+ if (rawkey == NULL ||
+ rawkey->rawdata.sym.keydata.val == NULL ||
+ rawkey->rawdata.sym.keydata.len == 0)
+ return (KMF_ERR_BAD_KEYHANDLE);
+
+ rkey->keydata.len = rawkey->rawdata.sym.keydata.len;
+ if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memcpy(rkey->keydata.val,
+ rawkey->rawdata.sym.keydata.val, rkey->keydata.len);
+ } else {
+ rv = get_raw_sym(kmfh, (CK_OBJECT_HANDLE)symkey->keyp, rkey);
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_SetTokenPin(KMF_HANDLE_T handle, KMF_SETPIN_PARAMS *params,
+ KMF_CREDENTIAL *newpin)
+{
+ KMF_RETURN ret = KMF_OK;
+ CK_RV rv = CKR_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_SESSION_HANDLE session = NULL;
+
+ if (handle == NULL || params == NULL || newpin == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = C_OpenSession(params->pkcs11parms.slot,
+ CKF_SERIAL_SESSION | CKF_RW_SESSION,
+ NULL, NULL, &session);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ ret = KMF_ERR_UNINITIALIZED;
+ goto end;
+ }
+
+ rv = C_SetPIN(session,
+ (CK_BYTE *)params->cred.cred, params->cred.credlen,
+ (CK_BYTE *)newpin->cred, newpin->credlen);
+
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ if (rv == CKR_PIN_INCORRECT ||
+ rv == CKR_PIN_INVALID ||
+ rv == CKR_PIN_EXPIRED ||
+ rv == CKR_PIN_LOCKED)
+ ret = KMF_ERR_AUTH_FAILED;
+ else
+ ret = KMF_ERR_INTERNAL;
+ }
+end:
+ if (session != NULL)
+ (void) C_CloseSession(session);
+ return (ret);
+}
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile
new file mode 100644
index 0000000000..443f78537a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: $(ROOTLIBS)
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile
new file mode 100644
index 0000000000..472ac90a9a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: $(ROOTLIBS)
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile
new file mode 100644
index 0000000000..0dd91e1065
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../../Makefile.lib.64
+
+install: $(ROOTLIBS64)
diff --git a/usr/src/lib/libsecdb/exec_attr.txt b/usr/src/lib/libsecdb/exec_attr.txt
index 020c2ab0c6..5883a81cd7 100644
--- a/usr/src/lib/libsecdb/exec_attr.txt
+++ b/usr/src/lib/libsecdb/exec_attr.txt
@@ -41,6 +41,7 @@ Contract Observer:solaris:cmd:::/usr/bin/ctwatch:\
privs=contract_event,contract_observer
Cron Management:suser:cmd:::/usr/bin/crontab:euid=0
Crypto Management:suser:cmd:::/usr/sbin/cryptoadm:euid=0
+Crypto Management:suser:cmd:::/usr/bin/kfmcfg:euid=0
Crypto Management:suser:cmd:::/usr/sfw/bin/openssl:euid=0
Crypto Management:suser:cmd:::/usr/sfw/bin/CA.pl:euid=0
DHCP Management:suser:cmd:::/usr/lib/inet/dhcp/svcadm/dhcpconfig:uid=0
diff --git a/usr/src/pkgdefs/SUNWarc/prototype_com b/usr/src/pkgdefs/SUNWarc/prototype_com
index 7272645f33..bc4f649b6b 100644
--- a/usr/src/pkgdefs/SUNWarc/prototype_com
+++ b/usr/src/pkgdefs/SUNWarc/prototype_com
@@ -122,6 +122,8 @@ f none usr/lib/llib-lipmp 644 root bin
f none usr/lib/llib-lipmp.ln 644 root bin
f none usr/lib/llib-lipp 644 root bin
f none usr/lib/llib-lipp.ln 644 root bin
+f none usr/lib/llib-lkmf.ln 644 root bin
+f none usr/lib/llib-lkmfberder.ln 644 root bin
s none usr/lib/llib-lkstat=../../lib/llib-lkstat
s none usr/lib/llib-lkstat.ln=../../lib/llib-lkstat.ln
f none usr/lib/llib-lkvm 644 root bin
diff --git a/usr/src/pkgdefs/SUNWarc/prototype_i386 b/usr/src/pkgdefs/SUNWarc/prototype_i386
index 8099c626ab..627f850a9d 100644
--- a/usr/src/pkgdefs/SUNWarc/prototype_i386
+++ b/usr/src/pkgdefs/SUNWarc/prototype_i386
@@ -91,6 +91,8 @@ s none usr/lib/amd64/llib-lgen.ln=../../../lib/amd64/llib-lgen.ln
f none usr/lib/amd64/llib-lgss.ln 644 root bin
s none usr/lib/amd64/llib-lintl.ln=../../../lib/amd64/llib-lintl.ln
f none usr/lib/amd64/llib-lipp.ln 644 root bin
+f none usr/lib/amd64/llib-lkmf.ln 644 root bin
+f none usr/lib/amd64/llib-lkmfberder.ln 644 root bin
s none usr/lib/amd64/llib-lkstat.ln=../../../lib/amd64/llib-lkstat.ln
f none usr/lib/amd64/llib-lkvm.ln 644 root bin
f none usr/lib/amd64/llib-lldap.ln 644 root bin
diff --git a/usr/src/pkgdefs/SUNWarc/prototype_sparc b/usr/src/pkgdefs/SUNWarc/prototype_sparc
index 37f008e017..5c4fc485f4 100644
--- a/usr/src/pkgdefs/SUNWarc/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc
@@ -87,6 +87,8 @@ s none usr/lib/sparcv9/llib-lgen.ln=../../../lib/sparcv9/llib-lgen.ln
f none usr/lib/sparcv9/llib-lgss.ln 644 root bin
s none usr/lib/sparcv9/llib-lintl.ln=../../../lib/sparcv9/llib-lintl.ln
f none usr/lib/sparcv9/llib-lipp.ln 644 root bin
+f none usr/lib/sparcv9/llib-lkmf.ln 644 root bin
+f none usr/lib/sparcv9/llib-lkmfberder.ln 644 root bin
s none usr/lib/sparcv9/llib-lkstat.ln=../../../lib/sparcv9/llib-lkstat.ln
f none usr/lib/sparcv9/llib-lkvm.ln 644 root bin
f none usr/lib/sparcv9/llib-lldap.ln 644 root bin
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_com b/usr/src/pkgdefs/SUNWcsl/prototype_com
index a8e9305623..5e557a0004 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_com
@@ -146,6 +146,10 @@ f none usr/lib/libipp.so.1 755 root bin
f none usr/lib/libipsecutil.so.1 755 root bin
s none usr/lib/libkstat.so=../../lib/libkstat.so.1
s none usr/lib/libkstat.so.1=../../lib/libkstat.so.1
+f none usr/lib/libkmf.so.1 755 root bin
+s none usr/lib/libkmf.so=./libkmf.so.1
+f none usr/lib/libkmfberder.so.1 755 root bin
+s none usr/lib/libkmfberder.so=./libkmfberder.so.1
s none usr/lib/libkvm.so=./libkvm.so.1
f none usr/lib/libkvm.so.1 755 root bin
s none usr/lib/libl.so=./libl.so.1
@@ -294,6 +298,9 @@ f none usr/lib/security/crypt_bsdbf.so.1 755 root bin
s none usr/lib/security/crypt_bsdbf.so=./crypt_bsdbf.so.1
f none usr/lib/security/crypt_sunmd5.so.1 755 root bin
s none usr/lib/security/crypt_sunmd5.so=./crypt_sunmd5.so.1
+f none usr/lib/security/kmf_nss.so.1 755 root bin
+f none usr/lib/security/kmf_openssl.so.1 755 root bin
+f none usr/lib/security/kmf_pkcs11.so.1 755 root bin
f none usr/lib/security/pam_ldap.so.1 755 root bin
s none usr/lib/security/pam_ldap.so=./pam_ldap.so.1
f none usr/lib/security/pam_allow.so.1 755 root bin
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_i386 b/usr/src/pkgdefs/SUNWcsl/prototype_i386
index 21dc389597..4c65a8fd58 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_i386
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386
@@ -94,6 +94,9 @@ f none usr/lib/security/amd64/crypt_bsdbf.so.1 755 root bin
s none usr/lib/security/amd64/crypt_bsdbf.so=./crypt_bsdbf.so.1
f none usr/lib/security/amd64/crypt_sunmd5.so.1 755 root bin
s none usr/lib/security/amd64/crypt_sunmd5.so=./crypt_sunmd5.so.1
+f none usr/lib/security/amd64/kmf_nss.so.1 755 root bin
+f none usr/lib/security/amd64/kmf_openssl.so.1 755 root bin
+f none usr/lib/security/amd64/kmf_pkcs11.so.1 755 root bin
f none usr/lib/security/amd64/pam_ldap.so.1 755 root bin
s none usr/lib/security/amd64/pam_ldap.so=./pam_ldap.so.1
f none usr/lib/security/amd64/pam_allow.so.1 755 root bin
@@ -165,6 +168,10 @@ s none usr/lib/amd64/libgen.so=../../../lib/amd64/libgen.so.1
s none usr/lib/amd64/libinetutil.so.1=../../../lib/amd64/libinetutil.so.1
f none usr/lib/amd64/libipp.so.1 755 root bin
s none usr/lib/amd64/libipp.so=libipp.so.1
+f none usr/lib/amd64/libkmf.so.1 755 root bin
+s none usr/lib/amd64/libkmf.so=libkmf.so.1
+f none usr/lib/amd64/libkmfberder.so.1 755 root bin
+s none usr/lib/amd64/libkmfberder.so=libkmfberder.so.1
f none usr/lib/amd64/libldap.so.4 755 root bin
f none usr/lib/amd64/libldap.so.5 755 root bin
s none usr/lib/amd64/libldap.so=libldap.so.5
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_sparc b/usr/src/pkgdefs/SUNWcsl/prototype_sparc
index f83c4c616e..1bcdad558d 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc
@@ -87,6 +87,9 @@ f none usr/lib/security/sparcv9/crypt_bsdbf.so.1 755 root bin
s none usr/lib/security/sparcv9/crypt_bsdbf.so=./crypt_bsdbf.so.1
f none usr/lib/security/sparcv9/crypt_sunmd5.so.1 755 root bin
s none usr/lib/security/sparcv9/crypt_sunmd5.so=./crypt_sunmd5.so.1
+f none usr/lib/security/sparcv9/kmf_nss.so.1 755 root bin
+f none usr/lib/security/sparcv9/kmf_openssl.so.1 755 root bin
+f none usr/lib/security/sparcv9/kmf_pkcs11.so.1 755 root bin
f none usr/lib/security/sparcv9/pam_ldap.so.1 755 root bin
s none usr/lib/security/sparcv9/pam_ldap.so=./pam_ldap.so.1
f none usr/lib/security/sparcv9/pam_allow.so.1 755 root bin
@@ -158,6 +161,10 @@ s none usr/lib/sparcv9/libgen.so=../../../lib/sparcv9/libgen.so.1
s none usr/lib/sparcv9/libinetutil.so.1=../../../lib/sparcv9/libinetutil.so.1
f none usr/lib/sparcv9/libipp.so.1 755 root bin
s none usr/lib/sparcv9/libipp.so=libipp.so.1
+f none usr/lib/sparcv9/libkmf.so.1 755 root bin
+s none usr/lib/sparcv9/libkmf.so=libkmf.so.1
+f none usr/lib/sparcv9/libkmfberder.so.1 755 root bin
+s none usr/lib/sparcv9/libkmfberder.so=libkmfberder.so.1
f none usr/lib/sparcv9/libldap.so.4 755 root bin
f none usr/lib/sparcv9/libldap.so.5 755 root bin
s none usr/lib/sparcv9/libldap.so=libldap.so.5
diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com
index be5acf70a4..00aab420fd 100644
--- a/usr/src/pkgdefs/SUNWcsr/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsr/prototype_com
@@ -275,6 +275,7 @@ f none etc/security/dev/fd0 400 root bin
f none etc/security/dev/sr0 400 root bin
f none etc/security/dev/st0 400 root bin
f none etc/security/dev/st1 400 root bin
+f none etc/security/kmfpolicy.xml 644 root bin
d none etc/security/lib 755 root sys
f none etc/security/lib/audio_clean 555 root sys
f none etc/security/lib/fd_clean 555 root sys
diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com
index 65a9eac914..00f5b80e1c 100644
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com
@@ -163,6 +163,7 @@ f none usr/bin/kbd 555 root bin
f none usr/bin/keylogin 555 root bin
f none usr/bin/keylogout 555 root bin
l none usr/bin/kill=../../usr/bin/alias
+f none usr/bin/kmfcfg 555 root bin
f none usr/bin/ksh 555 root bin
f none usr/bin/line 555 root bin
f none usr/bin/listdgrp 555 root bin
@@ -975,6 +976,7 @@ f none usr/share/lib/unittab 444 root bin
d none usr/share/lib/xml 755 root sys
d none usr/share/lib/xml/dtd 755 root sys
f none usr/share/lib/xml/dtd/adt_record.dtd.1 444 root bin
+f none usr/share/lib/xml/dtd/kmfpolicy.dtd 444 root bin
f none usr/share/lib/xml/dtd/service_bundle.dtd.1 0444 root sys
d none usr/share/lib/xml/style 755 root sys
f none usr/share/lib/xml/style/adt_record.xsl.1 444 root bin
diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com
index 7306f102cd..20f6f0e581 100644
--- a/usr/src/pkgdefs/SUNWhea/prototype_com
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com
@@ -174,6 +174,8 @@ f none usr/include/kerberosv5/com_err.h 644 root bin
f none usr/include/kerberosv5/krb5.h 644 root bin
f none usr/include/kerberosv5/mit_copyright.h 644 root bin
f none usr/include/kerberosv5/mit-sipb-copyright.h 644 root bin
+f none usr/include/kmfapi.h 644 root bin
+f none usr/include/kmftypes.h 644 root bin
f none usr/include/kstat.h 644 root bin
f none usr/include/kvm.h 644 root bin
f none usr/include/lber.h 644 root bin