view usr/src/cmd/cmd-crypto/pktool/list.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 ae098b2a8faa
children b0f2e9abb0f4
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"

/*
 * This file implements the token object list operation for this tool.
 * It loads the PKCS#11 modules, finds the object to list, lists it,
 * and cleans up.  User must be logged into the token to list private
 * objects.
 */

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <cryptoutil.h>
#include <security/cryptoki.h>
#include "common.h"

#include <kmfapi.h>

static void
pk_show_certs(KMF_HANDLE_T kmfhandle, KMF_X509_DER_CERT *certs, int num_certs)
{
	int i;
	char *subject, *issuer, *serial, *id, *altname;
	char *start, *end, *keyusage, *extkeyusage;

	for (i = 0; i < num_certs; i++) {
		subject = NULL;
		issuer = NULL;
		serial = NULL;
		id = NULL;
		altname = NULL;
		start = end = NULL;
		keyusage = extkeyusage = NULL;

		(void) fprintf(stdout,
		    gettext("%d. (X.509 certificate)\n"), i + 1);
		if (certs[i].kmf_private.label != NULL)
			(void) fprintf(stdout, gettext("\t%s: %s\n"),
			    (certs[i].kmf_private.keystore_type ==
			    KMF_KEYSTORE_OPENSSL ?  "Filename" : "Label"),
			    certs[i].kmf_private.label);
		if (kmf_get_cert_id_str(&certs[i].certificate,
		    &id) == KMF_OK)
			(void) fprintf(stdout, gettext("\tID: %s\n"), id);
		if (kmf_get_cert_subject_str(kmfhandle,
		    &certs[i].certificate, &subject) == KMF_OK)
			(void) fprintf(stdout, gettext("\tSubject: %s\n"),
			    subject);
		if (kmf_get_cert_issuer_str(kmfhandle,
		    &certs[i].certificate, &issuer) == KMF_OK)
			(void) fprintf(stdout, gettext("\tIssuer: %s\n"),
			    issuer);
		if (kmf_get_cert_start_date_str(kmfhandle,
		    &certs[i].certificate, &start) == KMF_OK)
			(void) fprintf(stdout, gettext("\tNot Before: %s\n"),
			    start);
		if (kmf_get_cert_end_date_str(kmfhandle,
		    &certs[i].certificate, &end) == KMF_OK)
			(void) fprintf(stdout, gettext("\tNot After: %s\n"),
			    end);
		if (kmf_get_cert_serial_str(kmfhandle,
		    &certs[i].certificate, &serial) == KMF_OK)
			(void) fprintf(stdout, gettext("\tSerial: %s\n"),
			    serial);
		if (kmf_get_cert_extn_str(kmfhandle,
		    &certs[i].certificate, KMF_X509_EXT_SUBJ_ALTNAME,
		    &altname) == KMF_OK)  {
			(void) fprintf(stdout, gettext("\t%s\n"),
			    altname);
		}
		if (kmf_get_cert_extn_str(kmfhandle,
		    &certs[i].certificate, KMF_X509_EXT_KEY_USAGE,
		    &keyusage) == KMF_OK)  {
			(void) fprintf(stdout, gettext("\t%s\n"),
			    keyusage);
		}
		if (kmf_get_cert_extn_str(kmfhandle,
		    &certs[i].certificate, KMF_X509_EXT_EXT_KEY_USAGE,
		    &extkeyusage) == KMF_OK)  {
			(void) fprintf(stdout, gettext("\t%s\n"),
			    extkeyusage);
		}
		kmf_free_str(subject);
		kmf_free_str(issuer);
		kmf_free_str(serial);
		kmf_free_str(id);
		kmf_free_str(altname);
		kmf_free_str(keyusage);
		kmf_free_str(extkeyusage);
		kmf_free_str(start);
		kmf_free_str(end);
		(void) fprintf(stdout, "\n");
	}
}

static char *
describeKey(KMF_KEY_HANDLE *key)
{
	if (key->keyclass == KMF_ASYM_PUB) {
		if (key->keyalg == KMF_RSA)
			return (gettext("RSA public key"));
		if (key->keyalg == KMF_DSA)
			return (gettext("DSA public key"));
	}
	if (key->keyclass == KMF_ASYM_PRI) {
		if (key->keyalg == KMF_RSA)
			return ("RSA private key");
		if (key->keyalg == KMF_DSA)
			return ("DSA private key");
	}
	if (key->keyclass == KMF_SYMMETRIC) {
		switch (key->keyalg) {
			case KMF_AES:
				return (gettext("AES"));
				break;
			case KMF_RC4:
				return (gettext("ARCFOUR"));
				break;
			case KMF_DES:
				return (gettext("DES"));
				break;
			case KMF_DES3:
				return (gettext("Triple-DES"));
				break;
			default:
				return (gettext("symmetric"));
				break;
		}
	}

	return (gettext("unrecognized key object"));

}


static void
pk_show_keys(void *handle, KMF_KEY_HANDLE *keys, int numkeys)
{
	int i;

	for (i = 0; i < numkeys; i++) {
		(void) fprintf(stdout, gettext("Key #%d - %s:  %s"),
		    i+1, describeKey(&keys[i]),
		    keys[i].keylabel ? keys[i].keylabel :
		    gettext("No label"));

		if (keys[i].keyclass == KMF_SYMMETRIC) {
			KMF_RETURN rv;
			KMF_RAW_SYM_KEY rkey;

			(void) memset(&rkey, 0, sizeof (rkey));
			rv = kmf_get_sym_key_value(handle, &keys[i],
			    &rkey);
			if (rv == KMF_OK) {
				(void) fprintf(stdout, " (%d bits)",
				    rkey.keydata.len * 8);
				kmf_free_bigint(&rkey.keydata);
			} else if (keys[i].kstype == KMF_KEYSTORE_PK11TOKEN) {
				if (rv == KMF_ERR_SENSITIVE_KEY) {
					(void) fprintf(stdout, " (sensitive)");
				} else if (rv == KMF_ERR_UNEXTRACTABLE_KEY) {
					(void) fprintf(stdout,
					    " (non-extractable)");
				} else {
					char *err = NULL;
					if (kmf_get_kmf_error_str(rv, &err) ==
					    KMF_OK)
						(void) fprintf(stdout,
						    " (error: %s)", err);
					if (err != NULL)
						free(err);
				}
			}
		}
		(void) fprintf(stdout, "\n");
	}
}

/*
 * Generic routine used by all "list cert" operations to find
 * all matching certificates.
 */
static KMF_RETURN
pk_find_certs(KMF_HANDLE_T kmfhandle, KMF_ATTRIBUTE *attrlist, int numattr)
{
	KMF_RETURN rv = KMF_OK;
	KMF_X509_DER_CERT *certlist = NULL;
	uint32_t numcerts = 0;
	KMF_KEYSTORE_TYPE kstype;

	rv = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
	    &kstype, NULL);
	if (rv != KMF_OK)
		return (rv);

	kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR,
	    &numcerts, sizeof (uint32_t));
	numattr++;

	rv = kmf_find_cert(kmfhandle, numattr, attrlist);
	if (rv == KMF_OK && numcerts > 0) {
		(void) printf(gettext("Found %d certificates.\n"),
		    numcerts);
		certlist = (KMF_X509_DER_CERT *)malloc(numcerts *
		    sizeof (KMF_X509_DER_CERT));
		if (certlist == NULL)
			return (KMF_ERR_MEMORY);
		(void) memset(certlist, 0, numcerts *
		    sizeof (KMF_X509_DER_CERT));

		kmf_set_attr_at_index(attrlist, numattr,
		    KMF_X509_DER_CERT_ATTR, certlist,
		    sizeof (KMF_X509_DER_CERT));
		numattr++;

		rv = kmf_find_cert(kmfhandle, numattr, attrlist);
		if (rv == KMF_OK) {
			int i;
			(void) pk_show_certs(kmfhandle, certlist,
			    numcerts);
			for (i = 0; i < numcerts; i++)
				kmf_free_kmf_cert(kmfhandle, &certlist[i]);
		}
		free(certlist);
	}
	if (rv == KMF_ERR_CERT_NOT_FOUND &&
	    kstype != KMF_KEYSTORE_OPENSSL)
		rv = KMF_OK;

	return (rv);
}

static KMF_RETURN
pk_list_keys(void *handle, KMF_ATTRIBUTE *attrlist, int numattr)
{
	KMF_RETURN rv;
	KMF_KEY_HANDLE *keys;
	uint32_t numkeys = 0;
	KMF_KEYSTORE_TYPE kstype;

	rv = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
	    &kstype, NULL);
	if (rv != KMF_OK)
		return (rv);

	kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR,
	    &numkeys, sizeof (uint32_t));
	numattr++;

	rv = kmf_find_key(handle, numattr, attrlist);
	if (rv == KMF_OK && numkeys > 0) {
		int i;
		(void) printf(gettext("Found %d keys.\n"), numkeys);
		keys = (KMF_KEY_HANDLE *)malloc(numkeys *
		    sizeof (KMF_KEY_HANDLE));
		if (keys == NULL)
			return (KMF_ERR_MEMORY);
		(void) memset(keys, 0, numkeys *
		    sizeof (KMF_KEY_HANDLE));

		kmf_set_attr_at_index(attrlist, numattr,
		    KMF_KEY_HANDLE_ATTR,
		    keys, sizeof (KMF_KEY_HANDLE));
		numattr++;

		rv = kmf_find_key(handle, numattr, attrlist);
		if (rv == KMF_OK)
			pk_show_keys(handle, keys, numkeys);
		for (i = 0; i < numkeys; i++)
			kmf_free_kmf_key(handle, &keys[i]);
		free(keys);
	}
	if (rv == KMF_ERR_KEY_NOT_FOUND &&
	    kstype != KMF_KEYSTORE_OPENSSL)
		rv = KMF_OK;
	return (rv);
}

static KMF_RETURN
list_pk11_objects(KMF_HANDLE_T kmfhandle, char *token, int oclass,
	char *objlabel, KMF_BIGINT *serial, char *issuer, char *subject,
	char *dir, char *filename, KMF_CREDENTIAL *tokencred,
	KMF_CERT_VALIDITY find_criteria_flag)
{
	KMF_RETURN rv;
	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
	int numattr = 0;
	KMF_ATTRIBUTE attrlist[16];
	boolean_t token_bool = B_TRUE;
	boolean_t private = B_FALSE;
	KMF_KEY_CLASS keyclass;
	KMF_ENCODE_FORMAT format;

	/*
	 * Symmetric keys and RSA/DSA private keys are always
	 * created with the "CKA_PRIVATE" field == TRUE, so
	 * make sure we search for them with it also set.
	 */
	if (oclass & (PK_SYMKEY_OBJ | PK_PRIKEY_OBJ))
		oclass |= PK_PRIVATE_OBJ;

	rv = select_token(kmfhandle, token,
	    !(oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)));

	if (rv != KMF_OK) {
		return (rv);
	}

	if (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ)) {
		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
		    &kstype, sizeof (kstype));
		numattr++;

		if (objlabel != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_KEYLABEL_ATTR, objlabel,
			    strlen(objlabel));
			numattr++;
		}

		private = ((oclass & PK_PRIVATE_OBJ) > 0);

		kmf_set_attr_at_index(attrlist, numattr,
		    KMF_PRIVATE_BOOL_ATTR, &private,
		    sizeof (private));
		numattr++;

		kmf_set_attr_at_index(attrlist, numattr,
		    KMF_TOKEN_BOOL_ATTR, &token_bool,
		    sizeof (token_bool));
		numattr++;

		if (oclass & PK_PRIKEY_OBJ) {
			int num = numattr;

			keyclass = KMF_ASYM_PRI;
			kmf_set_attr_at_index(attrlist, num,
			    KMF_KEYCLASS_ATTR, &keyclass,
			    sizeof (keyclass));
			num++;

			if (tokencred != NULL &&
			    tokencred->credlen > 0) {
				kmf_set_attr_at_index(attrlist, num,
				    KMF_CREDENTIAL_ATTR, tokencred,
				    sizeof (KMF_CREDENTIAL));
				num++;
			}

			/* list asymmetric private keys */
			rv = pk_list_keys(kmfhandle, attrlist, num);
		}

		if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) {
			int num = numattr;

			keyclass = KMF_SYMMETRIC;
			kmf_set_attr_at_index(attrlist, num,
			    KMF_KEYCLASS_ATTR, &keyclass,
			    sizeof (keyclass));
			num++;

			if (tokencred != NULL &&
			    tokencred->credlen > 0) {
				kmf_set_attr_at_index(attrlist, num,
				    KMF_CREDENTIAL_ATTR, tokencred,
				    sizeof (KMF_CREDENTIAL));
				num++;
			}

			format = KMF_FORMAT_RAWKEY;
			kmf_set_attr_at_index(attrlist, num,
			    KMF_ENCODE_FORMAT_ATTR, &format,
			    sizeof (format));
			num++;

			/* list symmetric keys */
			rv = pk_list_keys(kmfhandle, attrlist, num);
		}

		if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) {
			int num = numattr;

			keyclass = KMF_ASYM_PUB;
			kmf_set_attr_at_index(attrlist, num,
			    KMF_KEYCLASS_ATTR, &keyclass,
			    sizeof (keyclass));
			num++;

			/* list asymmetric public keys (if any) */
			rv = pk_list_keys(kmfhandle, attrlist, num);
		}

		if (rv != KMF_OK)
			return (rv);
	}

	numattr = 0;
	if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) {
		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
		    &kstype, sizeof (kstype));
		numattr++;

		if (objlabel != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_CERT_LABEL_ATTR, objlabel,
			    strlen(objlabel));
			numattr++;
		}

		if (issuer != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_ISSUER_NAME_ATTR, issuer,
			    strlen(issuer));
			numattr++;
		}

		if (subject != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_SUBJECT_NAME_ATTR, subject,
			    strlen(subject));
			numattr++;
		}

		if (serial != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_BIGINT_ATTR, serial,
			    sizeof (KMF_BIGINT));
			numattr++;
		}

		kmf_set_attr_at_index(attrlist, numattr,
		    KMF_PRIVATE_BOOL_ATTR, &private,
		    sizeof (private));
		numattr++;

		kmf_set_attr_at_index(attrlist, numattr,
		    KMF_CERT_VALIDITY_ATTR, &find_criteria_flag,
		    sizeof (KMF_CERT_VALIDITY));
		numattr++;

		rv = pk_find_certs(kmfhandle, attrlist, numattr);
		if (rv != KMF_OK)
			return (rv);
	}

	numattr = 0;
	kstype = KMF_KEYSTORE_OPENSSL; /* CRL is file-based */
	if (oclass & PK_CRL_OBJ) {
		char *crldata = NULL;

		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
		    &kstype, sizeof (kstype));
		numattr++;

		if (dir != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_DIRPATH_ATTR, dir, strlen(dir));
			numattr++;
		}
		if (filename != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_CRL_FILENAME_ATTR,
			    filename, strlen(filename));
			numattr++;
		}
		kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_DATA_ATTR,
		    &crldata, sizeof (char *));
		numattr++;

		rv = kmf_list_crl(kmfhandle, numattr, attrlist);
		if (rv == KMF_OK && crldata != NULL) {
			(void) printf("%s\n", crldata);
			free(crldata);
		}
	}

	return (rv);
}

static int
list_file_objects(KMF_HANDLE_T kmfhandle, int oclass,
	char *dir, char *filename, KMF_BIGINT *serial,
	char *issuer, char *subject,
	KMF_CERT_VALIDITY find_criteria_flag)
{
	int rv;
	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL;
	int numattr = 0;
	KMF_ATTRIBUTE attrlist[16];
	KMF_KEY_CLASS keyclass;
	KMF_ENCODE_FORMAT format;
	char *defaultdir = ".";

	if (oclass & PK_KEY_OBJ) {
		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
		    &kstype, sizeof (kstype));
		numattr++;

		if (dir == NULL && filename == NULL)
			dir = defaultdir;

		if (dir != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_DIRPATH_ATTR, dir,
			    strlen(dir));
			numattr++;
		}

		if (filename != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_KEY_FILENAME_ATTR, filename,
			    strlen(filename));
			numattr++;
		}

		if (oclass & PK_PRIKEY_OBJ) {
			int num = numattr;

			keyclass = KMF_ASYM_PRI;
			kmf_set_attr_at_index(attrlist, num,
			    KMF_KEYCLASS_ATTR, &keyclass,
			    sizeof (keyclass));
			num++;

			/* list asymmetric private keys */
			rv = pk_list_keys(kmfhandle, attrlist, num);
		}
		if (rv == KMF_ERR_KEY_NOT_FOUND)
			rv = KMF_OK;

		if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) {
			int num = numattr;

			keyclass = KMF_SYMMETRIC;
			kmf_set_attr_at_index(attrlist, num,
			    KMF_KEYCLASS_ATTR, &keyclass,
			    sizeof (keyclass));
			num++;

			format = KMF_FORMAT_RAWKEY;
			kmf_set_attr_at_index(attrlist, num,
			    KMF_ENCODE_FORMAT_ATTR, &format,
			    sizeof (format));
			num++;

			/* list symmetric keys */
			rv = pk_list_keys(kmfhandle, attrlist, num);
		}
		if (rv == KMF_ERR_KEY_NOT_FOUND)
			rv = KMF_OK;
		if (rv != KMF_OK)
			return (rv);
	}

	numattr = 0;
	if (oclass & PK_CERT_OBJ) {
		kmf_set_attr_at_index(attrlist, numattr,
		    KMF_KEYSTORE_TYPE_ATTR, &kstype,
		    sizeof (kstype));
		numattr++;

		if (issuer != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_ISSUER_NAME_ATTR, issuer,
			    strlen(issuer));
			numattr++;
		}

		if (subject != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_SUBJECT_NAME_ATTR, subject,
			    strlen(subject));
			numattr++;
		}

		if (serial != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_BIGINT_ATTR, serial,
			    sizeof (KMF_BIGINT));
			numattr++;
		}

		if (filename != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_CERT_FILENAME_ATTR, filename,
			    strlen(filename));
			numattr++;
		}

		if (dir != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_DIRPATH_ATTR, dir,
			    strlen(dir));
			numattr++;
		}

		kmf_set_attr_at_index(attrlist, numattr,
		    KMF_CERT_VALIDITY_ATTR, &find_criteria_flag,
		    sizeof (KMF_CERT_VALIDITY));
		numattr++;

		rv = pk_find_certs(kmfhandle, attrlist, numattr);
		if (rv != KMF_OK)
			return (rv);
	}

	numattr = 0;
	if (oclass & PK_CRL_OBJ) {
		char *crldata = NULL;

		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
		    &kstype, sizeof (kstype));
		numattr++;

		if (dir != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_DIRPATH_ATTR, dir, strlen(dir));
			numattr++;
		}
		if (filename != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_CRL_FILENAME_ATTR,
			    filename, strlen(filename));
			numattr++;
		}
		kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_DATA_ATTR,
		    &crldata, sizeof (char *));
		numattr++;

		rv = kmf_list_crl(kmfhandle, numattr, attrlist);
		if (rv == KMF_OK && crldata != NULL) {
			(void) printf("%s\n", crldata);
			free(crldata);
		}
	}

	return (rv);
}

static int
list_nss_objects(KMF_HANDLE_T kmfhandle,
	int oclass, char *token_spec, char *dir, char *prefix,
	char *nickname, KMF_BIGINT *serial, char *issuer, char *subject,
	KMF_CREDENTIAL *tokencred,
	KMF_CERT_VALIDITY find_criteria_flag)
{
	KMF_RETURN rv = KMF_OK;
	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS;
	int numattr = 0;
	KMF_ATTRIBUTE attrlist[16];
	KMF_KEY_CLASS keyclass;
	KMF_ENCODE_FORMAT format;

	rv = configure_nss(kmfhandle, dir, prefix);
	if (rv != KMF_OK)
		return (rv);

	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
	    &kstype, sizeof (kstype));
	numattr++;

	if (oclass & PK_KEY_OBJ) {
		if (tokencred != NULL && tokencred->credlen > 0) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_CREDENTIAL_ATTR, tokencred,
			    sizeof (KMF_CREDENTIAL));
			numattr++;
		}

		if (token_spec && strlen(token_spec)) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_TOKEN_LABEL_ATTR, token_spec,
			    strlen(token_spec));
			numattr++;
		}

		if (nickname != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_KEYLABEL_ATTR, nickname,
			    strlen(nickname));
			numattr++;
		}
	}

	if (oclass & PK_PRIKEY_OBJ) {
		int num = numattr;

		keyclass = KMF_ASYM_PRI;
		kmf_set_attr_at_index(attrlist, num,
		    KMF_KEYCLASS_ATTR, &keyclass,
		    sizeof (keyclass));
		num++;

		/* list asymmetric private keys */
		rv = pk_list_keys(kmfhandle, attrlist, num);
	}

	if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) {
		int num = numattr;

		keyclass = KMF_SYMMETRIC;
		kmf_set_attr_at_index(attrlist, num,
		    KMF_KEYCLASS_ATTR, &keyclass,
		    sizeof (keyclass));
		num++;

		format = KMF_FORMAT_RAWKEY;
		kmf_set_attr_at_index(attrlist, num,
		    KMF_ENCODE_FORMAT_ATTR, &format,
		    sizeof (format));
		num++;

		/* list symmetric keys */
		rv = pk_list_keys(kmfhandle, attrlist, num);
	}

	if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) {
		int num = numattr;

		keyclass = KMF_ASYM_PUB;
		kmf_set_attr_at_index(attrlist, num,
		    KMF_KEYCLASS_ATTR, &keyclass,
		    sizeof (keyclass));
		num++;

		/* list asymmetric public keys */
		rv = pk_list_keys(kmfhandle, attrlist, num);
	}

	/* If searching for public objects or certificates, find certs now */
	numattr = 0;
	if (rv == KMF_OK && (oclass & PK_CERT_OBJ)) {
		kmf_set_attr_at_index(attrlist, numattr,
		    KMF_KEYSTORE_TYPE_ATTR, &kstype,
		    sizeof (kstype));
		numattr++;

		if (nickname != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_CERT_LABEL_ATTR, nickname,
			    strlen(nickname));
			numattr++;
		}

		if (issuer != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_ISSUER_NAME_ATTR, issuer,
			    strlen(issuer));
			numattr++;
		}

		if (subject != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_SUBJECT_NAME_ATTR, subject,
			    strlen(subject));
			numattr++;
		}

		if (serial != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_BIGINT_ATTR, serial,
			    sizeof (KMF_BIGINT));
			numattr++;
		}

		if (token_spec != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_TOKEN_LABEL_ATTR, token_spec,
			    strlen(token_spec));
			numattr++;
		}

		kmf_set_attr_at_index(attrlist, numattr,
		    KMF_CERT_VALIDITY_ATTR, &find_criteria_flag,
		    sizeof (KMF_CERT_VALIDITY));
		numattr++;

		rv = pk_find_certs(kmfhandle, attrlist, numattr);
	}

	numattr = 0;
	if (rv == KMF_OK && (oclass & PK_CRL_OBJ)) {
		int numcrls;

		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
		    &kstype, sizeof (kstype));
		numattr++;

		if (token_spec != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_TOKEN_LABEL_ATTR,
			    token_spec, strlen(token_spec));
			numattr++;
		}
		kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_COUNT_ATTR,
		    &numcrls, sizeof (int));
		numattr++;

		rv = kmf_find_crl(kmfhandle, numattr, attrlist);
		if (rv == KMF_OK) {
			char **p;
			if (numcrls == 0) {
				(void) printf(gettext("No CRLs found in "
				    "NSS keystore.\n"));

				return (KMF_OK);
			}
			p = malloc(numcrls * sizeof (char *));
			if (p == NULL) {
				return (KMF_ERR_MEMORY);
			}
			(void) memset(p, 0, numcrls * sizeof (char *));

			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_CRL_NAMELIST_ATTR, p, sizeof (char *));
			numattr++;
			rv = kmf_find_crl(kmfhandle, numattr, attrlist);
			if (rv == KMF_OK) {
				int i;
				for (i = 0; i < numcrls; i++) {
					(void) printf("%d. Name = %s\n",
					    i + 1, p[i]);
					free(p[i]);
				}
			}
			free(p);
		}
	}
	return (rv);
}

/*
 * List token object.
 */
int
pk_list(int argc, char *argv[])
{
	int			opt;
	extern int		optind_av;
	extern char		*optarg_av;
	char			*token_spec = NULL;
	char			*subject = NULL;
	char			*issuer = NULL;
	char			*dir = NULL;
	char			*prefix = NULL;
	char			*filename = NULL;
	char			*serstr = NULL;
	KMF_BIGINT		serial = { NULL, 0 };

	char			*list_label = NULL;
	int			oclass = 0;
	KMF_KEYSTORE_TYPE	kstype = 0;
	KMF_RETURN		rv = KMF_OK;
	KMF_HANDLE_T		kmfhandle = NULL;
	char			*find_criteria = NULL;
	KMF_CERT_VALIDITY	find_criteria_flag = KMF_ALL_CERTS;
	KMF_CREDENTIAL		tokencred = {NULL, 0};

	/* Parse command line options.  Do NOT i18n/l10n. */
	while ((opt = getopt_av(argc, argv,
	    "k:(keystore)t:(objtype)T:(token)d:(dir)"
	    "p:(prefix)n:(nickname)S:(serial)s:(subject)"
	    "c:(criteria)"
	    "i:(issuer)l:(label)f:(infile)")) != EOF) {
		if (EMPTYSTRING(optarg_av))
			return (PK_ERR_USAGE);
		switch (opt) {
			case 'k':
				if (kstype != 0)
					return (PK_ERR_USAGE);
				kstype = KS2Int(optarg_av);
				if (kstype == 0)
					return (PK_ERR_USAGE);
				break;
			case 't':
				if (oclass != 0)
					return (PK_ERR_USAGE);
				oclass = OT2Int(optarg_av);
				if (oclass == -1)
					return (PK_ERR_USAGE);
				break;
			case 's':
				if (subject)
					return (PK_ERR_USAGE);
				subject = optarg_av;
				break;
			case 'i':
				if (issuer)
					return (PK_ERR_USAGE);
				issuer = optarg_av;
				break;
			case 'd':
				if (dir)
					return (PK_ERR_USAGE);
				dir = optarg_av;
				break;
			case 'p':
				if (prefix)
					return (PK_ERR_USAGE);
				prefix = optarg_av;
				break;
			case 'S':
				serstr = optarg_av;
				break;
			case 'f':
				if (filename)
					return (PK_ERR_USAGE);
				filename = optarg_av;
				break;
			case 'T':	/* token specifier */
				if (token_spec)
					return (PK_ERR_USAGE);
				token_spec = optarg_av;
				break;
			case 'n':
			case 'l':	/* object with specific label */
				if (list_label)
					return (PK_ERR_USAGE);
				list_label = optarg_av;
				break;
			case 'c':
				find_criteria = optarg_av;
				if (!strcasecmp(find_criteria, "valid"))
					find_criteria_flag =
					    KMF_NONEXPIRED_CERTS;
				else if (!strcasecmp(find_criteria, "expired"))
					find_criteria_flag = KMF_EXPIRED_CERTS;
				else if (!strcasecmp(find_criteria, "both"))
					find_criteria_flag = KMF_ALL_CERTS;
				else
					return (PK_ERR_USAGE);
				break;
			default:
				return (PK_ERR_USAGE);
		}
	}
	/* No additional args allowed. */
	argc -= optind_av;
	argv += optind_av;
	if (argc)
		return (PK_ERR_USAGE);

	if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
		/* Error message ? */
		return (rv);
	}

	/* Assume keystore = PKCS#11 if not specified. */
	if (kstype == 0)
		kstype = KMF_KEYSTORE_PK11TOKEN;

	/* if PUBLIC or PRIVATE obj was given, the old syntax was used. */
	if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) &&
	    kstype != KMF_KEYSTORE_PK11TOKEN) {

		(void) fprintf(stderr, gettext("The objtype parameter "
		    "is only relevant if keystore=pkcs11\n"));
		return (PK_ERR_USAGE);
	}

	/* If no object class specified, list certificate objects. */
	if (oclass == 0)
		oclass = PK_CERT_OBJ;

	if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) {
		token_spec = PK_DEFAULT_PK11TOKEN;
	} else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) {
		token_spec = DEFAULT_NSS_TOKEN;
	}

	if (serstr != NULL) {
		uchar_t *bytes = NULL;
		size_t bytelen;

		rv = kmf_hexstr_to_bytes((uchar_t *)serstr, &bytes, &bytelen);
		if (rv != KMF_OK || bytes == NULL) {
			(void) fprintf(stderr, gettext("serial number "
			    "must be specified as a hex number "
			    "(ex: 0x0102030405ffeeddee)\n"));
			return (PK_ERR_USAGE);
		}
		serial.val = bytes;
		serial.len = bytelen;
	}

	if ((kstype == KMF_KEYSTORE_PK11TOKEN ||
	    kstype == KMF_KEYSTORE_NSS) &&
	    (oclass & (PK_PRIKEY_OBJ | PK_PRIVATE_OBJ))) {

		(void) get_token_password(kstype, token_spec,
		    &tokencred);
	}
	if (kstype == KMF_KEYSTORE_PK11TOKEN) {
		rv = list_pk11_objects(kmfhandle, token_spec,
		    oclass, list_label, &serial,
		    issuer, subject, dir, filename,
		    &tokencred, find_criteria_flag);

	} else if (kstype == KMF_KEYSTORE_NSS) {
		if (dir == NULL)
			dir = PK_DEFAULT_DIRECTORY;
		rv = list_nss_objects(kmfhandle,
		    oclass, token_spec, dir, prefix,
		    list_label, &serial, issuer, subject,
		    &tokencred, find_criteria_flag);

	} else if (kstype == KMF_KEYSTORE_OPENSSL) {

		rv = list_file_objects(kmfhandle,
		    oclass, dir, filename,
		    &serial, issuer, subject, find_criteria_flag);
	}

	if (rv != KMF_OK) {
		display_error(kmfhandle, rv,
		    gettext("Error listing objects"));
	}

	if (serial.val != NULL)
		free(serial.val);

	if (tokencred.cred != NULL)
		free(tokencred.cred);

	(void) kmf_finalize(kmfhandle);
	return (rv);
}