OpenSolaris_b135/cmd/cmd-crypto/pktool/list.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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 2008 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, char *label)
{
	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 %s keys.\n"),
		    numkeys, label);
		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[18];
	boolean_t token_bool = B_TRUE;
	boolean_t private = B_FALSE;
	KMF_KEY_CLASS keyclass;
	KMF_ENCODE_FORMAT format;
	int auth = 0;
	KMF_CREDENTIAL cred = {NULL, 0};

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

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

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

	rv = token_auth_needed(kmfhandle, token, &auth);
	if (rv != KMF_OK)
		return (rv);

	if (tokencred != NULL)
		cred = *tokencred;

	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,
			    "asymmetric private");
		}

		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,
			    "symmetric");
		}

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

			if (auth > 0 && (tokencred == NULL ||
			    tokencred->cred == NULL) &&
			    (cred.cred == NULL)) {
				(void) get_token_password(kstype, token, &cred);
				kmf_set_attr_at_index(attrlist, numattr,
				    KMF_CREDENTIAL_ATTR,
				    &cred, sizeof (KMF_CREDENTIAL));
				numattr++;
			}

			private = B_FALSE;
			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,
			    "asymmetric public");
		}

		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 (auth > 0 && (cred.cred == NULL)) {
			(void) get_token_password(kstype, token, &cred);
		}

		if (cred.cred != NULL) {
			kmf_set_attr_at_index(attrlist, numattr,
			    KMF_CREDENTIAL_ATTR,
			    &cred, sizeof (KMF_CREDENTIAL));
			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 && serial->val != 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)
{
	KMF_RETURN rv = KMF_OK;
	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,
			    "asymmetric private");
		}
		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,
			    "symmetric");
		}
		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 && serial->val != 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,
		    "asymmetric private");
	}

	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, "symmetric");
	}

	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,
		    "asymmetric public");
	}

	/* 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 (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 objtype was not given, it must be for certs */
		if (oclass == 0)
			oclass = PK_CERT_OBJ;
	}
	if (oclass == 0 && (issuer != NULL || subject != NULL))
		oclass = PK_CERT_OBJ;

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

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