view usr/src/lib/libkmf/libkmf/common/generalop.c @ 5051:cbbb7c8b40a9

PSARC 2007/426 KMFAPI Interface Taxonomy Change PSARC 2007/465 pktool symmetric key enhancements 6546405 KMF Interfaces need to be extensible 6547894 pktool should be more detailed 6590232 pktool should import and export generic keys
author wyllys
date Fri, 14 Sep 2007 12:13:39 -0700
parents ff19cef282d8
children 4856fb4fc3d6
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 *
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <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"},
	{KMF_ERR_SENSITIVE_KEY,		"KMF_ERR_SENSITIVE_KEY"},
	{KMF_ERR_UNEXTRACTABLE_KEY,	"KMF_ERR_UNEXTRACTABLE_KEY"},
	{KMF_ERR_KEY_MISMATCH,		"KMF_ERR_KEY_MISMATCH"}
};

typedef struct {
	KMF_KEYSTORE_TYPE	kstype;
	char			*path;
	boolean_t		critical;
} KMF_PLUGIN_ITEM;

KMF_PLUGIN_ITEM plugin_list[] = {
	{KMF_KEYSTORE_OPENSSL,	KMF_PLUGIN_PATH "kmf_openssl.so.1",  TRUE},
	{KMF_KEYSTORE_PK11TOKEN, KMF_PLUGIN_PATH "kmf_pkcs11.so.1",  TRUE},
	{KMF_KEYSTORE_NSS,	KMF_PLUGIN_PATH "kmf_nss.so.1",  FALSE}
};



static void free_extensions(KMF_X509_EXTENSIONS *extns);

KMF_RETURN
init_pk11()
{
	(void) mutex_lock(&init_lock);
	if (!pkcs11_initialized) {
		CK_RV rv = C_Initialize(NULL);
		if ((rv != CKR_OK) &&
		    (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
			(void) mutex_unlock(&init_lock);
			return (KMF_ERR_UNINITIALIZED);
		} else {
			pkcs11_initialized = 1;
		}
	}
	(void) mutex_unlock(&init_lock);
	return (KMF_OK);
}

/*
 * 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_free_policy_record(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;
	int i, numitems;

	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;

	/* Initialize the handle with the policy */
	ret = kmf_set_policy((void *)handle,
	    policyfile == NULL ? KMF_DEFAULT_POLICY_FILE : policyfile,
	    policyname == NULL ? KMF_DEFAULT_POLICY_NAME : policyname);
	if (ret != KMF_OK)
		goto errout;

	numitems = sizeof (plugin_list)/sizeof (KMF_PLUGIN_ITEM);
	for (i = 0; i < numitems; i++) {
		ret = InitializePlugin(plugin_list[i].kstype,
		    plugin_list[i].path, &pluginrec);
		if (ret != KMF_OK) {
			cryptoerror(
			    plugin_list[i].critical ? LOG_WARNING : LOG_DEBUG,
			    "KMF was unable to load %s plugin module %s\n",
			    plugin_list[i].critical ? "critical" : "optional",
			    plugin_list[i].path);

			if (plugin_list[i].critical == FALSE)
				ret = KMF_OK;
			else
				goto errout;
		}
		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_configure_keystore(KMF_HANDLE_T handle,
	int	num_args,
	KMF_ATTRIBUTE	*attrlist)
{
	KMF_RETURN ret = KMF_OK;
	KMF_PLUGIN *plugin;
	KMF_KEYSTORE_TYPE kstype;
	uint32_t len;

	KMF_ATTRIBUTE_TESTER required_attrs[] = {
		{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
	};

	int num_req_attrs = sizeof (required_attrs) /
	    sizeof (KMF_ATTRIBUTE_TESTER);

	if (handle == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	CLEAR_ERROR(handle, ret);

	ret = test_attributes(num_req_attrs, required_attrs,
	    0, NULL, num_args, attrlist);

	if (ret != KMF_OK)
		return (ret);

	len = sizeof (kstype);
	ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, num_args,
	    &kstype, &len);
	if (ret != KMF_OK)
		return (ret);

	plugin = FindPlugin(handle, kstype);
	if (plugin != NULL && plugin->funclist->ConfigureKeystore != NULL) {
		return (plugin->funclist->ConfigureKeystore(handle, num_args,
		    attrlist));
	} 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_get_kmf_error_str(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++)
		/* empty body */
		;

	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_get_plugin_error_str(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);
}


#define	SET_SYS_ERROR(h, c) if (h) {\
	h->lasterr.kstype = -1;\
	h->lasterr.errcode = c;\
}

KMF_RETURN
kmf_read_input_file(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;

	if (handle) {
		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_der_to_pem
 *
 * 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_der_to_pem(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_pem_to_der
 *
 * 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_pem_to_der(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_oid_to_string(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);
}

static boolean_t
check_for_pem(uchar_t *buf, KMF_ENCODE_FORMAT *fmt)
{
	char *p;

	if (buf == NULL)
		return (FALSE);

	if (memcmp(buf, "Bag Attr", 8) == 0) {
		*fmt = KMF_FORMAT_PEM_KEYPAIR;
		return (TRUE);
	}

	/* Look for "-----BEGIN" right after a newline */
	p = strtok((char *)buf, "\n");
	while (p != NULL) {
		if (strstr(p, "-----BEGIN") != NULL) {
			*fmt = KMF_FORMAT_PEM;
			return (TRUE);
		}
		p = strtok(NULL, "\n");
	}
	return (FALSE);
}


static unsigned char pkcs12_version[3] = {0x02, 0x01, 0x03};
static unsigned char pkcs12_oid[11] =
{0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01};

/*
 * This function takes a BER encoded string as input and checks the version
 * and the oid in the the top-level ASN.1 structure to see if it complies to
 * the PKCS#12 Syntax.
 */
static boolean_t
check_for_pkcs12(uchar_t *buf, int buf_len)
{
	int index = 0;
	int length_octets;

	if (buf == NULL || buf_len <= 0)
		return (FALSE);

	/*
	 * The top level structure for a PKCS12 string:
	 *
	 * PFX ::= SEQUENCE {
	 *	version		INTEGER {v3(3)}(v3,...)
	 *	authSafe	ContentInfo
	 *	macData		MacData OPTIONAL
	 * }
	 *
	 * ContentInfo
	 *	FROM PKCS-7 {iso(1) member-body(2) us(840) rsadsi(113549)
	 *		pkcs(1) pkcs-7(7) modules(0) pkcs-7(1)}
	 *
	 * Therefore, the BER/DER dump of a PKCS#12 file for the first 2
	 * sequences up to the oid part is as following:
	 *
	 *	SEQUENCE {
	 *	    INTEGER 3
	 *	    SEQUENCE {
	 *		OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
	 */

	/*
	 * Check the first sequence and calculate the number of bytes used
	 * to store the length.
	 */
	if (buf[index++] != 0x30)
		return (FALSE);

	if (buf[index] & 0x80) {
		length_octets = buf[index++] & 0x0F;  /* long form */
	} else {
		length_octets = 1; /* short form */
	}

	index += length_octets;
	if (index  >= buf_len)
		return (FALSE);

	/* Skip the length octets and check the pkcs12 version */
	if (memcmp(buf + index, pkcs12_version, sizeof (pkcs12_version)) != 0)
		return (FALSE);

	index += sizeof (pkcs12_version);
	if (index  >= buf_len)
		return (FALSE);

	/*
	 * Check the 2nd sequence and calculate the number of bytes used
	 * to store the length.
	 */
	if ((buf[index++] & 0xFF) != 0x30)
		return (FALSE);

	if (buf[index] & 0x80) {
		length_octets = buf[index++] & 0x0F;
	} else {
		length_octets = 1;
	}

	index += length_octets;
	if (index + sizeof (pkcs12_oid) >= buf_len)
		return (FALSE);

	/* Skip the length octets and check the oid */
	if (memcmp(buf + index, pkcs12_oid, sizeof (pkcs12_oid)) != 0)
		return (FALSE);
	else
		return (TRUE);
}

KMF_RETURN
kmf_get_file_format(char *filename, KMF_ENCODE_FORMAT *fmt)
{
	KMF_RETURN ret = KMF_OK;
	KMF_DATA filebuf = {NULL, 0};
	uchar_t *buf;

	if (filename == NULL || !strlen(filename) || fmt == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	*fmt = 0;
	ret = kmf_read_input_file(NULL, filename, &filebuf);
	if (ret != KMF_OK)
		return (ret);

	if (filebuf.Length < 8) {
		ret = KMF_ERR_ENCODING; /* too small */
		goto end;
	}

	buf = filebuf.Data;
	if (check_for_pkcs12(buf, filebuf.Length) == TRUE) {
		*fmt = KMF_FORMAT_PKCS12;
	} else if (buf[0] == 0x30 && (buf[1] & 0x80)) {
		/* It is most likely a generic ASN.1 encoded file */
		*fmt = KMF_FORMAT_ASN1;
	} else if (check_for_pem(buf, fmt) == TRUE) {
		goto end;
	} else {
		/* Cannot determine this file format */
		*fmt = 0;
		ret = KMF_ERR_ENCODING;
	}

end:
	kmf_free_data(&filebuf);
	return (ret);
}

KMF_RETURN
kmf_hexstr_to_bytes(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++)
		/* empty body */
		;
	/*
	 * 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_free_dn(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_free_data(&av->type);
				kmf_free_data(&av->value);
			}
			free(newrdn->AttributeTypeAndValue);
			newrdn->numberOfPairs = 0;
			newrdn->AttributeTypeAndValue = NULL;
		}
		free(name->RelativeDistinguishedName);
		name->numberOfRDNs = 0;
		name->RelativeDistinguishedName = NULL;
	}
}

void
kmf_free_kmf_cert(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_free_data(KMF_DATA *datablock)
{
	if (datablock != NULL && datablock->Data != NULL) {
		free(datablock->Data);
		datablock->Data = NULL;
		datablock->Length = 0;
	}
}

void
kmf_free_algoid(KMF_X509_ALGORITHM_IDENTIFIER *algoid)
{
	if (algoid == NULL)
		return;
	kmf_free_data(&algoid->algorithm);
	kmf_free_data(&algoid->parameters);
}

void
kmf_free_extn(KMF_X509_EXTENSION *exptr)
{
	if (exptr == NULL)
		return;

	kmf_free_data((KMF_DATA *)&exptr->extnId);
	kmf_free_data(&exptr->BERvalue);

	if (exptr->value.tagAndValue) {
		kmf_free_data(&exptr->value.tagAndValue->value);
		free(exptr->value.tagAndValue);
	}
}

void
kmf_free_tbs_csr(KMF_TBS_CSR *tbscsr)
{
	if (tbscsr) {
		kmf_free_data(&tbscsr->version);

		kmf_free_dn(&tbscsr->subject);

		kmf_free_algoid(&tbscsr->subjectPublicKeyInfo.algorithm);
		kmf_free_data(&tbscsr->subjectPublicKeyInfo.subjectPublicKey);

		free_extensions(&tbscsr->extensions);
	}
}

void
kmf_free_signed_csr(KMF_CSR_DATA *csr)
{
	if (csr) {
		kmf_free_tbs_csr(&csr->csr);

		kmf_free_algoid(&csr->signature.algorithmIdentifier);
		kmf_free_data(&csr->signature.encrypted);
	}
}

static void
free_validity(KMF_X509_VALIDITY *validity)
{
	if (validity == NULL)
		return;
	kmf_free_data(&validity->notBefore.time);
	kmf_free_data(&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_free_extn(exptr);
		}
		free(extns->extensions);
		extns->numberOfExtensions = 0;
		extns->extensions = NULL;
	}
}

void
kmf_free_tbs_cert(KMF_X509_TBS_CERT *tbscert)
{
	if (tbscert) {
		kmf_free_data(&tbscert->version);
		kmf_free_bigint(&tbscert->serialNumber);
		kmf_free_algoid(&tbscert->signature);

		kmf_free_dn(&tbscert->issuer);
		kmf_free_dn(&tbscert->subject);

		free_validity(&tbscert->validity);

		kmf_free_data(&tbscert->issuerUniqueIdentifier);
		kmf_free_data(&tbscert->subjectUniqueIdentifier);

		kmf_free_algoid(&tbscert->subjectPublicKeyInfo.algorithm);
		kmf_free_data(&tbscert->subjectPublicKeyInfo.subjectPublicKey);

		free_extensions(&tbscert->extensions);

		kmf_free_data(&tbscert->issuerUniqueIdentifier);
		kmf_free_data(&tbscert->subjectUniqueIdentifier);
	}
}

void
kmf_free_signed_cert(KMF_X509_CERTIFICATE *certptr)
{
	if (!certptr)
		return;

	kmf_free_tbs_cert(&certptr->certificate);

	kmf_free_algoid(&certptr->signature.algorithmIdentifier);
	kmf_free_data(&certptr->signature.encrypted);
}

void
kmf_free_str(char *pstr)
{
	if (pstr != NULL)
		free(pstr);
}

void
free_keyidlist(KMF_OID *oidlist, int len)
{
	int i;
	for (i = 0; i < len; i++) {
		kmf_free_data((KMF_DATA *)&oidlist[i]);
	}
	free(oidlist);
}

void
kmf_free_eku(KMF_X509EXT_EKU *eptr)
{
	if (eptr && eptr->nEKUs > 0 && eptr->keyPurposeIdList != NULL)
		free_keyidlist(eptr->keyPurposeIdList, eptr->nEKUs);
}

void
kmf_free_spki(KMF_X509_SPKI *spki)
{
	if (spki != NULL) {
		kmf_free_algoid(&spki->algorithm);
		kmf_free_data(&spki->subjectPublicKey);
	}
}

void
kmf_free_kmf_key(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key)
{
	KMF_PLUGIN *plugin;
	KMF_RETURN ret;
	KMF_ATTRIBUTE attlist[2]; /* only 2 attributes for DeleteKey op */
	int i = 0;
	boolean_t token_destroy = B_FALSE;

	if (key == NULL)
		return;

	CLEAR_ERROR(handle, ret);
	if (ret != KMF_OK)
		return;

	kmf_set_attr_at_index(attlist, i,
	    KMF_KEY_HANDLE_ATTR, key, sizeof (KMF_KEY_HANDLE));
	i++;

	kmf_set_attr_at_index(attlist, i,
	    KMF_DESTROY_BOOL_ATTR, &token_destroy, sizeof (boolean_t));
	i++;

	plugin = FindPlugin(handle, key->kstype);
	if (plugin != NULL && plugin->funclist->DeleteKey != NULL) {
		(void) plugin->funclist->DeleteKey(handle, i, attlist);
	}

	if (key->keylabel)
		free(key->keylabel);

	if (key->israw) {
		kmf_free_raw_key(key->keyp);
		free(key->keyp);
	}

	(void) memset(key, 0, sizeof (KMF_KEY_HANDLE));
}

void
kmf_free_bigint(KMF_BIGINT *big)
{
	if (big != NULL && big->val != NULL) {
		/* Clear it out before returning it to the pool */
		(void) memset(big->val, 0x00, big->len);
		free(big->val);
		big->val = NULL;
		big->len = 0;
	}
}

static void
free_raw_rsa(KMF_RAW_RSA_KEY *key)
{
	if (key == NULL)
		return;
	kmf_free_bigint(&key->mod);
	kmf_free_bigint(&key->pubexp);
	kmf_free_bigint(&key->priexp);
	kmf_free_bigint(&key->prime1);
	kmf_free_bigint(&key->prime2);
	kmf_free_bigint(&key->exp1);
	kmf_free_bigint(&key->exp2);
	kmf_free_bigint(&key->coef);
}

static void
free_raw_dsa(KMF_RAW_DSA_KEY *key)
{
	if (key == NULL)
		return;
	kmf_free_bigint(&key->prime);
	kmf_free_bigint(&key->subprime);
	kmf_free_bigint(&key->base);
	kmf_free_bigint(&key->value);
}

static void
free_raw_sym(KMF_RAW_SYM_KEY *key)
{
	if (key == NULL)
		return;
	kmf_free_bigint(&key->keydata);
}

void
kmf_free_raw_key(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_free_raw_sym_key(KMF_RAW_SYM_KEY *key)
{
	if (key == NULL)
		return;
	kmf_free_bigint(&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_free_data(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_free_data(&(dp->reasons));
	/* Need not to free crl_issuer space at phase 1 */
}

/*
 * This function frees space for a KMF_X509EXT_CRLDISTPOINTS internally.
 */
void
kmf_free_crl_dist_pts(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_create_ocsp_request(KMF_HANDLE_T handle,
	int	num_args,
	KMF_ATTRIBUTE	*attrlist)
{
	KMF_RETURN ret = KMF_OK;
	KMF_PLUGIN *plugin;
	KMF_RETURN (*createReqFn)(void *, int num_args,
	    KMF_ATTRIBUTE *attrlist);

	KMF_ATTRIBUTE_TESTER required_attrs[] = {
		{KMF_OCSP_REQUEST_FILENAME_ATTR, FALSE, 1, 0},
		{KMF_USER_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
			sizeof (KMF_DATA)},
		{KMF_ISSUER_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
			sizeof (KMF_DATA)},
	};

	int num_req_attrs = sizeof (required_attrs) /
	    sizeof (KMF_ATTRIBUTE_TESTER);

	if (handle == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	CLEAR_ERROR(handle, ret);

	ret = test_attributes(num_req_attrs, required_attrs,
	    0, NULL, num_args, attrlist);

	if (ret != KMF_OK)
		return (ret);

	/*
	 * 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, num_args, attrlist));

}

KMF_RETURN
kmf_get_ocsp_status_for_cert(KMF_HANDLE_T handle,
	int	num_args,
	KMF_ATTRIBUTE	*attrlist)
{
	KMF_RETURN ret = KMF_OK;
	KMF_PLUGIN *plugin;
	KMF_RETURN (*getCertStatusFn)(void *, int num_args,
	    KMF_ATTRIBUTE *attrlist);

	KMF_ATTRIBUTE_TESTER required_attrs[] = {
		{KMF_USER_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
			sizeof (KMF_DATA)},
		{KMF_ISSUER_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
			sizeof (KMF_DATA)},
		{KMF_OCSP_RESPONSE_DATA_ATTR, FALSE, sizeof (KMF_DATA),
			sizeof (KMF_DATA)},
		{KMF_OCSP_RESPONSE_STATUS_ATTR, FALSE, sizeof (int),
			sizeof (uint32_t)},
		{KMF_OCSP_RESPONSE_REASON_ATTR, FALSE, sizeof (int),
			sizeof (uint32_t)},
		{KMF_OCSP_RESPONSE_CERT_STATUS_ATTR, FALSE, sizeof (int),
			sizeof (uint32_t)},
	};

	int num_req_attrs = sizeof (required_attrs) /
	    sizeof (KMF_ATTRIBUTE_TESTER);

	if (handle == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	CLEAR_ERROR(handle, ret);

	ret = test_attributes(num_req_attrs, required_attrs,
	    0, NULL, num_args, attrlist);

	if (ret != KMF_OK)
		return (ret);

	/*
	 * 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, num_args, attrlist));

}

KMF_RETURN
kmf_string_to_oid(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_string_to_oid(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_dn_parser(namedata, &dnname);
			if (ret == KMF_OK) {
				ret = DerEncodeName(&dnname, encodedname);
			}
			(void) kmf_free_dn(&dnname);
			tagval = (0xA0 | nametype);
			break;
		default:
			/* unsupported */
			return (KMF_ERR_BAD_PARAMETER);

	}
	if (ret != KMF_OK) {
		kmf_free_data(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_free_data(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_free_data(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_set_altname(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_free_data(&dername);
	if (ret != KMF_OK)
		kmf_free_data(&subjAltName.extnId);
	if (asn1 != NULL)
		kmfber_free(asn1, 1);
	return (ret);
}

/*
 * Search a list of attributes for one that matches the given type.
 * Return a pointer into the attribute list.  This does not
 * return a copy of the value, it returns a reference into the
 * given list.
 */
int
kmf_find_attr(KMF_ATTR_TYPE type, KMF_ATTRIBUTE *attlist, int numattrs)
{
	int i;
	for (i = 0; i < numattrs; i++) {
		if (attlist[i].type == type)
			return (i);
	}
	return (-1);
}

/*
 * Verify that a given attribute is consistent with the
 * "test" attribute.
 */
static KMF_RETURN
verify_attribute(KMF_ATTRIBUTE *givenattr,
	KMF_ATTRIBUTE_TESTER *testattr)
{
	/* A NULL pValue was found where one is required */
	if (testattr->null_value_ok == FALSE &&
	    givenattr->pValue == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	/* If the given valueLen is too small, return error */
	if (givenattr->pValue != NULL &&
	    testattr->minlen > 0 &&
	    (givenattr->valueLen < testattr->minlen))
		return (KMF_ERR_BAD_PARAMETER);

	/* If the given valueLen is too big, return error */
	if (givenattr->pValue != NULL &&
	    testattr->maxlen > 0 &&
	    (givenattr->valueLen > testattr->maxlen))
		return (KMF_ERR_BAD_PARAMETER);

	return (KMF_OK);
}

/*
 * Given a set of required attribute tests and optional
 * attributes, make sure that the actual attributes
 * being tested (attrlist below) are allowed and are
 * properly specified.
 */
KMF_RETURN
test_attributes(int reqnum, KMF_ATTRIBUTE_TESTER *reqattrs,
	int optnum, KMF_ATTRIBUTE_TESTER *optattrs,
	int numattrs, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN ret = KMF_OK;
	int i, idx;

	/*
	 * If the caller didn't supply enough attributes,
	 * return an error.
	 */
	if (numattrs < reqnum || attrlist == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	/*
	 * Make sure all required attrs are present and
	 * correct.
	 */
	for (i = 0; i < reqnum && ret == KMF_OK; i++) {
		idx = kmf_find_attr(reqattrs[i].type, attrlist, numattrs);
		/* If a required attr is not found, return error */
		if (idx == -1) {
			return (KMF_ERR_BAD_PARAMETER);
		}

		ret = verify_attribute(&attrlist[idx], &reqattrs[i]);
	}
	/*
	 * Now test the optional parameters.
	 */
	for (i = 0; i < optnum && ret == KMF_OK; i++) {
		idx = kmf_find_attr(optattrs[i].type, attrlist, numattrs);
		/* If a optional attr is not found, continue. */
		if (idx == -1) {
			continue;
		}

		ret = verify_attribute(&attrlist[idx], &optattrs[i]);
	}

	return (ret);
}

/*
 * Given an already allocated attribute list, insert
 * the given attribute information at a specific index
 * in the list.
 */
void
kmf_set_attr_at_index(KMF_ATTRIBUTE *attlist, int index,
	KMF_ATTR_TYPE type,  void *pValue, uint32_t len)
{
	if (attlist == NULL)
		return;

	attlist[index].type = type;
	attlist[index].pValue = pValue;
	attlist[index].valueLen = len;
}

/*
 * Find an attribute matching a particular type and set
 * the pValue and length fields to the given values.
 */
KMF_RETURN
kmf_set_attr(KMF_ATTRIBUTE *attlist, int numattr,
	KMF_ATTR_TYPE type,  void *pValue, uint32_t len)
{
	int idx;
	if (attlist == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	idx = kmf_find_attr(type, attlist, numattr);
	if (idx == -1)
		return (KMF_ERR_ATTR_NOT_FOUND);

	attlist[idx].type = type;
	/* Assumes the attribute pValue can hold the result */
	if (attlist[idx].pValue != NULL) {
		if (attlist[idx].valueLen >= len)
			(void) memcpy(attlist[idx].pValue, pValue, len);
		else
			return (KMF_ERR_BUFFER_SIZE);
	}
	attlist[idx].valueLen = len;
	return (KMF_OK);
}

/*
 * Find a particular attribute in a list and return
 * a pointer to its value.
 */
void *
kmf_get_attr_ptr(KMF_ATTR_TYPE type, KMF_ATTRIBUTE *attlist,
	int numattrs)
{
	int i;

	i = kmf_find_attr(type, attlist, numattrs);
	if (i == -1)
		return (NULL);

	return (attlist[i].pValue);
}

/*
 * Find a particular attribute in a list and return
 * the value and length values.  Value and length
 * may be NULL if the caller doesn't want their values
 * to be filled in.
 */
KMF_RETURN
kmf_get_attr(KMF_ATTR_TYPE type, KMF_ATTRIBUTE *attlist,
	int numattrs, void *outValue, uint32_t *outlen)
{
	int i;
	uint32_t len = 0;
	uint32_t *lenptr = outlen;

	if (lenptr == NULL)
		lenptr = &len;

	i = kmf_find_attr(type, attlist, numattrs);
	if (i == -1)
		return (KMF_ERR_ATTR_NOT_FOUND);

	/* This assumes that the ptr passed in is pre-allocated space */
	if (attlist[i].pValue != NULL && outValue != NULL) {
		/*
		 * If the caller did not specify a length,
		 * assume "outValue" is big enough.
		 */
		if (outlen != NULL) {
			if (*outlen >= attlist[i].valueLen)
				(void) memcpy(outValue, attlist[i].pValue,
				    attlist[i].valueLen);
			else
				return (KMF_ERR_BUFFER_SIZE);
		} else {
			(void) memcpy(outValue, attlist[i].pValue,
			    attlist[i].valueLen);
		}
	}

	if (outlen != NULL)
		*outlen = attlist[i].valueLen;
	return (KMF_OK);
}

/*
 * Utility routine to find a string type attribute, allocate it
 * and return the value to the caller.  This simplifies the
 * operation by doing both "kmf_get_attr" calls and avoids
 * duplicating this block of code in lots of places.
 */
KMF_RETURN
kmf_get_string_attr(KMF_ATTR_TYPE type, KMF_ATTRIBUTE *attrlist,
	int numattrs, char **outstr)
{
	KMF_RETURN rv;
	uint32_t len;

	if (outstr == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	if ((rv = kmf_get_attr(type, attrlist, numattrs, NULL, &len)) ==
	    KMF_OK) {
		*outstr = malloc(len + 1);
		if ((*outstr) == NULL)
			return (KMF_ERR_MEMORY);
		(void) memset((*outstr), 0, len + 1);
		rv = kmf_get_attr(type, attrlist, numattrs, (*outstr), &len);
		if (rv != KMF_OK) {
			free(*outstr);
			*outstr = NULL;
		}
	}

	return (rv);
}

/*
 * This API is used by elfsign. We must keep it in old API form.
 */
KMF_RETURN
KMF_ConfigureKeystore(KMF_HANDLE_T handle, KMF_CONFIG_PARAMS *params)
{

	KMF_ATTRIBUTE attlist[32];
	int i = 0;

	if (params == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	kmf_set_attr_at_index(attlist, i,
	    KMF_KEYSTORE_TYPE_ATTR, &params->kstype, sizeof (params->kstype));
	i++;

	if (params->kstype == KMF_KEYSTORE_NSS) {
		if (params->nssconfig.configdir != NULL) {
			kmf_set_attr_at_index(attlist, i,
			    KMF_DIRPATH_ATTR,
			    params->nssconfig.configdir,
			    strlen(params->nssconfig.configdir));
			i++;
		}
		if (params->nssconfig.certPrefix != NULL) {
			kmf_set_attr_at_index(attlist, i,
			    KMF_CERTPREFIX_ATTR,
			    params->nssconfig.certPrefix,
			    strlen(params->nssconfig.certPrefix));
			i++;
		}
		if (params->nssconfig.keyPrefix != NULL) {
			kmf_set_attr_at_index(attlist, i,
			    KMF_KEYPREFIX_ATTR,
			    params->nssconfig.keyPrefix,
			    strlen(params->nssconfig.keyPrefix));
			i++;
		}
		if (params->nssconfig.secModName != NULL) {
			kmf_set_attr_at_index(attlist, i,
			    KMF_SECMODNAME_ATTR,
			    params->nssconfig.secModName,
			    strlen(params->nssconfig.secModName));
			i++;
		}
	} else if (params->kstype == KMF_KEYSTORE_PK11TOKEN) {
		if (params->pkcs11config.label != NULL) {
			kmf_set_attr_at_index(attlist, i,
			    KMF_TOKEN_LABEL_ATTR,
			    params->pkcs11config.label,
			    strlen(params->pkcs11config.label));
			i++;
		}
		kmf_set_attr_at_index(attlist, i,
		    KMF_READONLY_ATTR,
		    &params->pkcs11config.readonly,
		    sizeof (params->pkcs11config.readonly));
		i++;
	}

	return (kmf_configure_keystore(handle, i, attlist));
}

/*
 * This API is used by elfsign. We must keep it in old API form.
 */
KMF_RETURN
KMF_Initialize(KMF_HANDLE_T *outhandle, char *policyfile, char *policyname)
{
	return (kmf_initialize(outhandle, policyfile, policyname));
}

/*
 * This API is used by elfsign. We must keep it in old API form.
 */
KMF_RETURN
KMF_Finalize(KMF_HANDLE_T handle)
{
	return (kmf_finalize(handle));
}

/*
 * This API is used by elfsign. We must keep it in old API form.
 */
KMF_RETURN
KMF_GetKMFErrorString(KMF_RETURN errcode, char **errmsg)
{
	return (kmf_get_kmf_error_str(errcode, errmsg));
}

/*
 * This API is used by elfsign. We must keep it in old API form.
 */
KMF_RETURN
KMF_ReadInputFile(KMF_HANDLE_T handle, char *filename,  KMF_DATA *pdata)
{
	return (kmf_read_input_file(handle, filename, pdata));
}


/*
 * This API is used by elfsign. We must keep it in old API form.
 */
void
KMF_FreeKMFCert(KMF_HANDLE_T handle, KMF_X509_DER_CERT *kmf_cert)
{
	kmf_free_kmf_cert(handle, kmf_cert);
}

/*
 * This API is used by elfsign. We must keep it in old API form.
 */
void
KMF_FreeData(KMF_DATA *datablock)
{
	kmf_free_data(datablock);
}

/*
 * This API is used by elfsign. We must keep it in old API form.
 */
void
KMF_FreeKMFKey(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key)
{
	kmf_free_kmf_key(handle, key);
}

/*
 * This API is used by elfsign. We must keep it in old API form.
 */
void
KMF_FreeSignedCSR(KMF_CSR_DATA *csr)
{
	kmf_free_signed_csr(csr);
}