summaryrefslogtreecommitdiff
path: root/usr/src/lib/libkmf
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libkmf')
-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-lkmfberder31
-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-lkmf31
-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
70 files changed, 32205 insertions, 0 deletions
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/lib/libkmf/ber_der/common/llib-lkmfberder b/usr/src/lib/libkmf/ber_der/common/llib-lkmfberder
new file mode 100644
index 0000000000..44d4dec3b5
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/common/llib-lkmfberder
@@ -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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#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/lib/libkmf/libkmf/common/llib-lkmf b/usr/src/lib/libkmf/libkmf/common/llib-lkmf
new file mode 100644
index 0000000000..114e823e4d
--- /dev/null
+++ b/usr/src/lib/libkmf/libkmf/common/llib-lkmf
@@ -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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* 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)