changeset 3812:07894abe087c

PSARC 2007/094 encrypt(1) / mac(1) token key support 4868006 encrypt(1) and mac(1) needs to support token objects 6517162 pktool genkey needs to support generic secret key
author hylee
date Tue, 13 Mar 2007 17:01:48 -0700
parents 7f48bd1c24e5
children c7c433a53b1a
files usr/src/cmd/cmd-crypto/decrypt/Makefile usr/src/cmd/cmd-crypto/decrypt/decrypt.c usr/src/cmd/cmd-crypto/digest/Makefile usr/src/cmd/cmd-crypto/digest/digest.c usr/src/cmd/cmd-crypto/pktool/common.c usr/src/cmd/cmd-crypto/pktool/genkey.c usr/src/cmd/cmd-crypto/pktool/pktool.c usr/src/lib/libkmf/include/kmftypes.h usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c
diffstat 11 files changed, 617 insertions(+), 131 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/cmd-crypto/decrypt/Makefile	Tue Mar 13 16:38:14 2007 -0700
+++ b/usr/src/cmd/cmd-crypto/decrypt/Makefile	Tue Mar 13 17:01:48 2007 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -36,7 +35,7 @@
 
 CFLAGS += $(CCVERBOSE) -D_FILE_OFFSET_BITS=64
 
-LDLIBS += -lpkcs11 -lcryptoutil
+LDLIBS += -lkmf -lpkcs11 -lcryptoutil
 
 .KEEP_STATE:
 
--- a/usr/src/cmd/cmd-crypto/decrypt/decrypt.c	Tue Mar 13 16:38:14 2007 -0700
+++ b/usr/src/cmd/cmd-crypto/decrypt/decrypt.c	Tue Mar 13 17:01:48 2007 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
  */
 /* Portions Copyright 2005 Richard Lowe */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -74,6 +73,7 @@
 #include <netinet/in.h>
 #include <security/cryptoki.h>
 #include <cryptoutil.h>
+#include <kmfapi.h>
 
 #define	BUFFERSIZE	(2048)		/* Buffer size for reading file */
 #define	BLOCKSIZE	(128)		/* Largest guess for block size */
@@ -97,9 +97,11 @@
 #define	RANDOM_DEVICE	"/dev/urandom"	/* random device name */
 
 #define	ENCRYPT_NAME	"encrypt"	/* name of encrypt command */
-#define	ENCRYPT_OPTIONS "a:k:i:o:lv"	/* options for encrypt */
+#define	ENCRYPT_OPTIONS "a:T:K:k:i:o:lv"	/* options for encrypt */
 #define	DECRYPT_NAME	"decrypt"	/* name of decrypt command */
-#define	DECRYPT_OPTIONS "a:k:i:o:lv"	/* options for decrypt */
+#define	DECRYPT_OPTIONS "a:T:K:k:i:o:lv"	/* options for decrypt */
+#define	DEFAULT_TOKEN_PROMPT	"Enter PIN for %s: "
+#define	PK_DEFAULT_PK11TOKEN	SOFT_TOKEN_LABEL
 
 /*
  * Structure containing info for encrypt/decrypt
@@ -170,10 +172,14 @@
 static boolean_t oflag = B_FALSE; /* -o <outfile> flag, use stdout if absent */
 static boolean_t lflag = B_FALSE; /* -l flag (list) */
 static boolean_t vflag = B_FALSE; /* -v flag (verbose) */
+static boolean_t Tflag = B_FALSE;
+static boolean_t Kflag = B_FALSE;
 
 static char *keyfile = NULL;	/* name of keyfile */
 static char *inputfile = NULL;	/* name of input file */
 static char *outputfile = NULL;	/* name of output file */
+static char *token_label = NULL;
+static char *key_label = NULL;
 
 static int status_pos = 0; /* current position of progress bar element */
 
@@ -182,7 +188,7 @@
  */
 static void usage(struct CommandInfo *cmd);
 static int execute_cmd(struct CommandInfo *cmd, char *algo_str);
-static int cryptogetkey(CK_BYTE_PTR *pkeydata, CK_ULONG_PTR pkeysize);
+static int cryptogetdata(char *, CK_BYTE_PTR *pkeydata, CK_ULONG_PTR pkeysize);
 static int cryptoreadfile(char *filename, CK_BYTE_PTR *pdata,
 	CK_ULONG_PTR pdatalen);
 static int get_random_data(CK_BYTE_PTR pivbuf, int ivlen);
@@ -240,6 +246,14 @@
 			kflag = B_TRUE;
 			keyfile = optarg;
 			break;
+		case 'T':
+			Tflag = B_TRUE;
+			token_label = optarg;
+			break;
+		case 'K':
+			Kflag = B_TRUE;
+			key_label = optarg;
+			break;
 		case 'i':
 			iflag = B_TRUE;
 			inputfile = optarg;
@@ -260,6 +274,7 @@
 	}
 
 	if (errflag || (!aflag && !lflag) || (lflag && argc > 2) ||
+	    (kflag && Kflag) || (Tflag && !Kflag) ||
 	    (optind < argc)) {
 		usage(cmd);
 		exit(EXIT_USAGE);
@@ -274,14 +289,18 @@
 static void
 usage(struct CommandInfo *cmd)
 {
+	(void) fprintf(stderr, gettext("Usage:\n"));
 	if (cmd->type == CKA_ENCRYPT) {
-		cryptoerror(LOG_STDERR, gettext("usage: encrypt -l | -a "
-		    "<algorithm> [-v] [-k <keyfile>] [-i <infile>]"
-		    "\n\t\t\t[-o <outfile>]"));
+		(void) fprintf(stderr, gettext("  encrypt -l\n"));
+		(void) fprintf(stderr, gettext("  encrypt -a <algorithm> "
+		    "[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] "
+		    "[-i <infile>] [-o <outfile>]\n"));
+
 	} else {
-		cryptoerror(LOG_STDERR, gettext("usage: decrypt -l | -a "
-		    "<algorithm> [-v] [-k <keyfile>] [-i <infile>]"
-		    "\n\t\t\t[-o <outfile>]"));
+		(void) fprintf(stderr, gettext("  decrypt -l\n"));
+		(void) fprintf(stderr, gettext("  decrypt -a <algorithm> "
+		    "[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] "
+		    "[-i <infile>] [-o <outfile>]\n"));
 	}
 }
 
@@ -381,6 +400,84 @@
 	return (rv);
 }
 
+/*
+ * This function will login into the token with the provided password and
+ * find the token key object with the specified keytype and keylabel.
+ */
+static int
+get_token_key(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keytype,
+    char *keylabel, CK_BYTE *password, int password_len,
+    CK_OBJECT_HANDLE *keyobj)
+{
+	CK_RV	rv;
+	CK_ATTRIBUTE pTmpl[10];
+	CK_OBJECT_CLASS class = CKO_SECRET_KEY;
+	CK_BBOOL true = 1;
+	CK_BBOOL is_token = 1;
+	CK_ULONG key_obj_count = 1;
+	int i;
+	CK_KEY_TYPE ckKeyType = keytype;
+
+
+	rv = C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)password,
+	    (CK_ULONG)password_len);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot login to the token."
+		    " error = %s\n", pkcs11_strerror(rv));
+		return (-1);
+	}
+
+	i = 0;
+	pTmpl[i].type = CKA_TOKEN;
+	pTmpl[i].pValue = &is_token;
+	pTmpl[i].ulValueLen = sizeof (CK_BBOOL);
+	i++;
+
+	pTmpl[i].type = CKA_CLASS;
+	pTmpl[i].pValue = &class;
+	pTmpl[i].ulValueLen = sizeof (class);
+	i++;
+
+	pTmpl[i].type = CKA_LABEL;
+	pTmpl[i].pValue = keylabel;
+	pTmpl[i].ulValueLen = strlen(keylabel);
+	i++;
+
+	pTmpl[i].type = CKA_KEY_TYPE;
+	pTmpl[i].pValue = &ckKeyType;
+	pTmpl[i].ulValueLen = sizeof (ckKeyType);
+	i++;
+
+	pTmpl[i].type = CKA_PRIVATE;
+	pTmpl[i].pValue = &true;
+	pTmpl[i].ulValueLen = sizeof (true);
+	i++;
+
+	rv = C_FindObjectsInit(hSession, pTmpl, i);
+	if (rv != CKR_OK) {
+		goto out;
+	}
+
+	rv = C_FindObjects(hSession, keyobj, 1, &key_obj_count);
+
+	(void) C_FindObjectsFinal(hSession);
+
+out:
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr,
+		    "Cannot retrieve key object. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (-1);
+	}
+
+	if (key_obj_count == 0) {
+		(void) fprintf(stderr, "Cannot find the key object.\n");
+		return (-1);
+	}
+
+	return (0);
+}
+
 
 /*
  * Execute the command.
@@ -419,6 +516,8 @@
 	CK_ULONG	keylen;
 	int version = SUNW_ENCRYPT_FILE_VERSION;
 	CK_KEY_TYPE keytype;
+	KMF_RETURN kmfrv;
+	CK_SLOT_ID token_slot_id;
 
 	if (aflag) {
 		/* Determine if algorithm is valid */
@@ -438,27 +537,40 @@
 		}
 
 		/*
-		 * Process keyfile
+		 * Process keyfile or get the token pin if -K is specified.
 		 *
 		 * If a keyfile is provided, get the key data from
 		 * the file. Otherwise, prompt for a passphrase. The
 		 * passphrase is used as the key data.
 		 */
-		if (kflag) {
+		if (Kflag) {
+			/* get the pin of the token */
+			if (token_label == NULL || !strlen(token_label)) {
+				token_label = PK_DEFAULT_PK11TOKEN;
+			}
+
+			status = cryptogetdata(token_label, &pkeydata,
+			    &keysize);
+		} else if (kflag) {
+			/* get the key file */
 			status = cryptoreadfile(keyfile, &pkeydata, &keysize);
 		} else {
-			status = cryptogetkey(&pkeydata, &keysize);
+			/* get the key from input */
+			status = cryptogetdata(NULL, &pkeydata, &keysize);
 		}
 
 		if (status == -1 || keysize == 0L) {
-			cryptoerror(LOG_STDERR, gettext("invalid key."));
+			cryptoerror(LOG_STDERR,
+			    Kflag ? gettext("invalid password.") :
+			    gettext("invalid key."));
 			return (EXIT_FAILURE);
 		}
 	}
 
 	bzero(salt, sizeof (salt));
 	/* Initialize pkcs */
-	if ((rv = C_Initialize(NULL)) != CKR_OK) {
+	rv = C_Initialize(NULL);
+	if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
 		cryptoerror(LOG_STDERR, gettext("failed to initialize "
 		    "PKCS #11 framework: %s"), pkcs11_strerror(rv));
 		goto cleanup;
@@ -529,29 +641,52 @@
 		goto cleanup;
 	}
 
-	/* Find a slot with matching mechanism */
-	for (i = 0; i < slotcount; i++) {
-		slotID = pSlotList[i];
-		rv = C_GetMechanismInfo(slotID, mech_type, &info);
-		if (rv != CKR_OK) {
-			continue; /* to the next slot */
-		} else {
-			/*
-			 * If the slot support the crypto, also
-			 * make sure it supports the correct
-			 * key generation mech if needed.
-			 *
-			 * We need PKCS5 when RC4 is used or
-			 * when the key is entered on cmd line.
-			 */
-			if ((info.flags & cmd->flags) &&
-			    (mech_type == CKM_RC4) || (keyfile == NULL)) {
-				rv = C_GetMechanismInfo(slotID,
-					CKM_PKCS5_PBKD2, &kg_info);
-				if (rv == CKR_OK)
+
+	/*
+	 * Find a slot with matching mechanism
+	 *
+	 * If -K is specified, we find the slot id for the token first, then
+	 * check if the slot supports the algorithm.
+	 */
+	i = 0;
+	if (Kflag) {
+		kmfrv = KMF_PK11TokenLookup(NULL, token_label, &token_slot_id);
+		if (kmfrv != KMF_OK) {
+			cryptoerror(LOG_STDERR,
+			    gettext("no matching PKCS#11 token"));
+			errflag = B_TRUE;
+			goto cleanup;
+		}
+		rv = C_GetMechanismInfo(token_slot_id, mech_type, &info);
+		if (rv == CKR_OK && (info.flags & cmd->flags))
+			slotID = token_slot_id;
+		else
+			i = slotcount;
+	} else {
+		for (i = 0; i < slotcount; i++) {
+			slotID = pSlotList[i];
+			rv = C_GetMechanismInfo(slotID, mech_type, &info);
+			if (rv != CKR_OK) {
+				continue; /* to the next slot */
+			} else {
+				/*
+				 * If the slot support the crypto, also
+				 * make sure it supports the correct
+				 * key generation mech if needed.
+				 *
+				 * We need PKCS5 when RC4 is used or
+				 * when the key is entered on cmd line.
+				 */
+				if ((info.flags & cmd->flags) &&
+				    (mech_type == CKM_RC4) ||
+				    (keyfile == NULL)) {
+					rv = C_GetMechanismInfo(slotID,
+					    CKM_PKCS5_PBKD2, &kg_info);
+					if (rv == CKR_OK)
+						break;
+				} else if (info.flags & cmd->flags) {
 					break;
-			} else if (info.flags & cmd->flags) {
-				break;
+				}
 			}
 		}
 	}
@@ -564,7 +699,6 @@
 		goto cleanup;
 	}
 
-
 	/* Open a session */
 	rv = C_OpenSession(slotID, CKF_SERIAL_SESSION,
 		NULL_PTR, NULL, &hSession);
@@ -726,13 +860,26 @@
 			break;
 		}
 	}
+
 	/*
-	 * If encrypting, we need some random
+	 * If Kflag is set, let's find the token key now.
+	 *
+	 * If Kflag is not set and if encrypting, we need some random
 	 * salt data to create the key.  If decrypting,
 	 * the salt should come from head of the file
 	 * to be decrypted.
 	 */
-	if (cmd->type == CKA_ENCRYPT) {
+	if (Kflag) {
+		rv = get_token_key(hSession, keytype, key_label, pkeydata,
+		    keysize, &key);
+		if (rv != CKR_OK) {
+			cryptoerror(LOG_STDERR, gettext(
+			    "Can not find the token key"));
+			goto cleanup;
+		} else {
+			goto do_crypto;
+		}
+	} else if (cmd->type == CKA_ENCRYPT) {
 		rv = get_random_data(salt, sizeof (salt));
 		if (rv != 0) {
 			cryptoerror(LOG_STDERR,
@@ -742,6 +889,7 @@
 		}
 	}
 
+
 	/*
 	 * If key input is read from  a file, treat it as
 	 * raw key data, unless it is to be used with RC4,
@@ -810,6 +958,8 @@
 		goto cleanup;
 	}
 
+
+do_crypto:
 	/* Setup up mechanism */
 	mech.mechanism = mech_type;
 	mech.pParameter = (CK_VOID_PTR)pivbuf;
@@ -878,7 +1028,7 @@
 	}
 
 	/* Destroy key object */
-	if (key != (CK_OBJECT_HANDLE) 0) {
+	if (Kflag != B_FALSE && key != (CK_OBJECT_HANDLE) 0) {
 		(void) C_DestroyObject(hSession, key);
 	}
 
@@ -1200,38 +1350,44 @@
 
 	return (0);
 }
+
 /*
- * cryptogetkey - prompt user for a key
+ * cryptogetdata - prompt user for a key or the PIN for a token
  *
- *   pkeydata - buffer for returning key data
+ *   pdata - buffer for returning key or pin data
  *	must be freed by caller using free()
- *   pkeysize - size of buffer returned
+ *   psize - size of buffer returned
  *
  * returns
  *   0 for success, -1 for failure
  */
 
 static int
-cryptogetkey(CK_BYTE_PTR *pkeydata, CK_ULONG_PTR pkeysize)
-
+cryptogetdata(char *token_spec, CK_BYTE_PTR *pdata, CK_ULONG_PTR psize)
 {
-	char *keybuf;
-	char *tmpbuf;
+	char *databuf = NULL;
+	char *tmpbuf = NULL;
+	char prompt[1024];
 
-
-
-	tmpbuf = getpassphrase(gettext("Enter key:"));
+	if (token_spec != NULL) {
+		(void) snprintf(prompt, sizeof (prompt),
+		    DEFAULT_TOKEN_PROMPT, token_spec);
+		tmpbuf = getpassphrase(gettext(prompt));
+	} else {
+		tmpbuf = getpassphrase(gettext("Enter key:"));
+	}
 
 	if (tmpbuf == NULL) {
 		return (-1);	/* error */
 	} else {
-		keybuf = strdup(tmpbuf);
-		(void) memset(tmpbuf, 0, strlen(tmpbuf));
+		databuf = strdup(tmpbuf);
+		(void) memset(tmpbuf, 0, strlen(tmpbuf)); /* clean up */
+		if (databuf == NULL)
+			return (-1);
 	}
 
-	*pkeydata = (CK_BYTE_PTR)keybuf;
-	*pkeysize = (CK_ULONG)strlen(keybuf);
-
+	*pdata = (CK_BYTE_PTR)databuf;
+	*psize = (CK_ULONG)strlen(databuf);
 
 	return (0);
 }
--- a/usr/src/cmd/cmd-crypto/digest/Makefile	Tue Mar 13 16:38:14 2007 -0700
+++ b/usr/src/cmd/cmd-crypto/digest/Makefile	Tue Mar 13 17:01:48 2007 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -36,7 +35,7 @@
 
 CFLAGS += $(CCVERBOSE) -D_FILE_OFFSET_BITS=64
 
-LDLIBS += -lpkcs11 -lcryptoutil
+LDLIBS += -lkmf -lpkcs11 -lcryptoutil
 
 .KEEP_STATE:
 
--- a/usr/src/cmd/cmd-crypto/digest/digest.c	Tue Mar 13 16:38:14 2007 -0700
+++ b/usr/src/cmd/cmd-crypto/digest/digest.c	Tue Mar 13 17:01:48 2007 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -52,6 +51,7 @@
 #include <security/cryptoki.h>
 #include <limits.h>
 #include <cryptoutil.h>
+#include <kmfapi.h>
 
 #define	BUFFERSIZE	(4096)		/* Buffer size for reading file */
 
@@ -78,15 +78,23 @@
 #define	EXIT_USAGE	2	/* usage/syntax error */
 
 #define	MAC_NAME	"mac"		/* name of mac command */
-#define	MAC_OPTIONS	"lva:k:"		/* for getopt */
+#define	MAC_OPTIONS	"lva:k:T:K:"		/* for getopt */
 #define	DIGEST_NAME	"digest"	/* name of mac command */
 #define	DIGEST_OPTIONS	"lva:"		/* for getopt */
+#define	DEFAULT_TOKEN_PROMPT	"Enter PIN for %s: "
+#define	PK_DEFAULT_PK11TOKEN	SOFT_TOKEN_LABEL
 
 static boolean_t vflag = B_FALSE;	/* -v (verbose) flag, optional */
 static boolean_t aflag = B_FALSE;	/* -a <algorithm> flag, required */
 static boolean_t lflag = B_FALSE;	/* -l flag, for mac and digest */
+static boolean_t kflag = B_FALSE;
+static boolean_t Tflag = B_FALSE;
+static boolean_t Kflag = B_FALSE;
 
 static char *keyfile = NULL;	/* name of keyfile */
+static char *token_label = NULL;
+static char *key_label = NULL;
+
 static CK_BYTE buf[BUFFERSIZE];
 
 struct mech_alias {
@@ -125,6 +133,7 @@
 static CK_RV do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
 	int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen);
 static int getkey(char *filename, CK_BYTE_PTR *pkeydata);
+static int getpasswd(char *token_spec, CK_BYTE_PTR *pdata, CK_ULONG_PTR psize);
 
 int
 main(int argc, char **argv)
@@ -184,11 +193,20 @@
 			algo_str = optarg;
 			break;
 		case 'k':
+			kflag = B_TRUE;
 			keyfile = optarg;
 			break;
 		case 'l':
 			lflag = B_TRUE;
 			break;
+		case 'T':
+			Tflag = B_TRUE;
+			token_label = optarg;
+			break;
+		case 'K':
+			Kflag = B_TRUE;
+			key_label = optarg;
+			break;
 		default:
 			errflag++;
 		}
@@ -196,7 +214,7 @@
 
 	filecount = argc - optind;
 	if (errflag || (!aflag && !lflag) || (lflag && argc > 2) ||
-	    filecount < 0) {
+	    (kflag && Kflag) || (Tflag && !Kflag) || filecount < 0) {
 		usage(mac_cmd);
 		exit(EXIT_USAGE);
 	}
@@ -216,14 +234,15 @@
 static void
 usage(boolean_t mac_cmd)
 {
+	(void) fprintf(stderr, gettext("Usage:\n"));
 	if (mac_cmd) {
-		cryptoerror(LOG_STDERR, gettext(
-		"usage: mac -l | [-v] -a <algorithm> [-k <keyfile>] "
-		    "[file...]"));
+		(void) fprintf(stderr, gettext("  mac -l\n"));
+		(void) fprintf(stderr, gettext("  mac [-v] -a <algorithm> "
+		    "[-k <keyfile> | -K <keylabel> [-T <tokenspec>]] "
+		    "[file...]\n"));
 	} else {
-		cryptoerror(LOG_STDERR,
-		    gettext("usage: digest -l | [-v] -a <algorithm> "
-			"[file...]"));
+		(void) fprintf(stderr, gettext("  digest -l | [-v] "
+		    "-a <algorithm> [file...]\n"));
 	}
 }
 
@@ -325,6 +344,80 @@
 }
 
 
+static int
+get_token_key(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keytype,
+    char *keylabel, CK_BYTE *password, int password_len,
+    CK_OBJECT_HANDLE *keyobj)
+{
+	CK_RV rv;
+	CK_ATTRIBUTE pTmpl[10];
+	CK_OBJECT_CLASS class = CKO_SECRET_KEY;
+	CK_BBOOL true = 1;
+	CK_BBOOL is_token = 1;
+	CK_ULONG key_obj_count = 1;
+	int i;
+	CK_KEY_TYPE ckKeyType = keytype;
+
+
+	rv = C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)password,
+	    password_len);
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr, "Cannot login to the token."
+		    " error = %s\n", pkcs11_strerror(rv));
+		return (-1);
+	}
+
+	i = 0;
+	pTmpl[i].type = CKA_TOKEN;
+	pTmpl[i].pValue = &is_token;
+	pTmpl[i].ulValueLen = sizeof (CK_BBOOL);
+	i++;
+
+	pTmpl[i].type = CKA_CLASS;
+	pTmpl[i].pValue = &class;
+	pTmpl[i].ulValueLen = sizeof (class);
+	i++;
+
+	pTmpl[i].type = CKA_LABEL;
+	pTmpl[i].pValue = keylabel;
+	pTmpl[i].ulValueLen = strlen(keylabel);
+	i++;
+
+	pTmpl[i].type = CKA_KEY_TYPE;
+	pTmpl[i].pValue = &ckKeyType;
+	pTmpl[i].ulValueLen = sizeof (ckKeyType);
+	i++;
+
+	pTmpl[i].type = CKA_PRIVATE;
+	pTmpl[i].pValue = &true;
+	pTmpl[i].ulValueLen = sizeof (true);
+	i++;
+
+	rv = C_FindObjectsInit(hSession, pTmpl, i);
+	if (rv != CKR_OK) {
+		goto out;
+	}
+
+	rv = C_FindObjects(hSession, keyobj, 1, &key_obj_count);
+	(void) C_FindObjectsFinal(hSession);
+
+out:
+	if (rv != CKR_OK) {
+		(void) fprintf(stderr,
+		    "Cannot retrieve key object. error = %s\n",
+		    pkcs11_strerror(rv));
+		return (-1);
+	}
+
+	if (key_obj_count == 0) {
+		(void) fprintf(stderr, "Cannot find the key object.\n");
+		return (-1);
+	}
+
+	return (0);
+}
+
+
 /*
  * Execute the command.
  *   algo_str - name of algorithm
@@ -359,6 +452,9 @@
 	CK_BYTE		salt[PBKD2_SALT_SIZE];
 	CK_ULONG	keysize;
 	CK_ULONG	iterations = PBKD2_ITERATIONS;
+	CK_KEY_TYPE keytype;
+	KMF_RETURN kmfrv;
+	CK_SLOT_ID token_slot_id;
 
 	if (aflag) {
 		/*
@@ -382,17 +478,36 @@
 
 		/* Get key to do a MAC operation */
 		if (mac_cmd) {
-			keylen = getkey(keyfile, &pkeydata);
-			if (keylen <= 0 || pkeydata == NULL) {
-				cryptoerror(LOG_STDERR,
-				    gettext("invalid key."));
-				return (EXIT_FAILURE);
+			if (Kflag) {
+				int status;
+
+				if (token_label == NULL ||
+				    !strlen(token_label)) {
+					token_label = PK_DEFAULT_PK11TOKEN;
+				}
+
+				status = getpasswd(token_label, &pkeydata,
+				    (CK_ULONG *)&keylen);
+				if (status == -1) {
+					cryptoerror(LOG_STDERR,
+					    gettext("invalid passphrase."));
+					return (EXIT_FAILURE);
+				}
+
+			} else {
+				keylen = getkey(keyfile, &pkeydata);
+				if (keylen <= 0 || pkeydata == NULL) {
+					cryptoerror(LOG_STDERR,
+					    gettext("invalid key."));
+					return (EXIT_FAILURE);
+				}
 			}
 		}
 	}
 
 	/* Initialize, and get list of slots */
-	if ((rv = C_Initialize(NULL)) != CKR_OK) {
+	rv = C_Initialize(NULL);
+	if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
 		cryptoerror(LOG_STDERR,
 		    gettext("failed to initialize PKCS #11 framework: %s"),
 		    pkcs11_strerror(rv));
@@ -472,34 +587,56 @@
 		goto cleanup;
 	}
 
-	/* Find a slot with matching mechanism */
-	for (i = 0; i < slotcount; i++) {
-		slotID = pSlotList[i];
-		rv = C_GetMechanismInfo(slotID, mech_type, &info);
-		if (rv != CKR_OK) {
-			continue; /* to the next slot */
-		} else {
-			if (mac_cmd) {
-				/*
-				 * Make sure the slot supports
-				 * PKCS5 key generation if we
-				 * will be using it later.
-				 * We use it whenever the key
-				 * is entered at command line.
-				 */
-				if ((info.flags & CKF_SIGN) &&
-				    (keyfile == NULL)) {
-					CK_MECHANISM_INFO kg_info;
-					rv = C_GetMechanismInfo(slotID,
-					    CKM_PKCS5_PBKD2, &kg_info);
-					if (rv == CKR_OK)
-					    break;
-				} else if (info.flags & CKF_SIGN) {
-					break;
+	/*
+	 * Find a slot with matching mechanism
+	 *
+	 * If -K is specified, we find the slot id for the token first, then
+	 * check if the slot supports the algorithm.
+	 */
+	i = 0;
+	if (Kflag) {
+		kmfrv = KMF_PK11TokenLookup(NULL, token_label, &token_slot_id);
+		if (kmfrv != KMF_OK) {
+			cryptoerror(LOG_STDERR,
+			    gettext("no matching PKCS#11 token"));
+			exitcode = EXIT_FAILURE;
+			goto cleanup;
+		}
+		rv = C_GetMechanismInfo(token_slot_id, mech_type, &info);
+		if (rv == CKR_OK && (info.flags & CKF_SIGN))
+			slotID = token_slot_id;
+		else
+			i = slotcount;
+
+	} else {
+		for (i = 0; i < slotcount; i++) {
+			slotID = pSlotList[i];
+			rv = C_GetMechanismInfo(slotID, mech_type, &info);
+			if (rv != CKR_OK) {
+				continue; /* to the next slot */
+			} else {
+				if (mac_cmd) {
+					/*
+					 * Make sure the slot supports
+					 * PKCS5 key generation if we
+					 * will be using it later.
+					 * We use it whenever the key
+					 * is entered at command line.
+					 */
+					if ((info.flags & CKF_SIGN) &&
+					    (keyfile == NULL)) {
+						CK_MECHANISM_INFO kg_info;
+						rv = C_GetMechanismInfo(slotID,
+						    CKM_PKCS5_PBKD2, &kg_info);
+						if (rv == CKR_OK)
+							break;
+					} else if (info.flags & CKF_SIGN) {
+						break;
+					}
+				} else {
+					if (info.flags & CKF_DIGEST)
+						break;
 				}
-			} else {
-				if (info.flags & CKF_DIGEST)
-					break;
 			}
 		}
 	}
@@ -570,6 +707,21 @@
 
 			rv = C_CreateObject(hSession, template,
 				nattr, &key);
+
+		} else if (Kflag) {
+
+			if (mech_type == CKM_DES_MAC) {
+				keytype = CKK_DES;
+			} else {
+				keytype = CKK_GENERIC_SECRET;
+			}
+
+			rv = get_token_key(hSession, keytype, key_label,
+			    pkeydata, keylen, &key);
+			if (rv != CKR_OK) {
+				exitcode = EXIT_FAILURE;
+				goto cleanup;
+			}
 		} else {
 			CK_KEY_TYPE keytype;
 			if (mech_type == CKM_DES_MAC) {
@@ -716,7 +868,7 @@
 		free(pSlotList);
 	}
 
-	if (key != (CK_OBJECT_HANDLE) 0) {
+	if (!Kflag && key != (CK_OBJECT_HANDLE) 0) {
 		(void) C_DestroyObject(hSession, key);
 	}
 
@@ -939,3 +1091,32 @@
 
 	return (keylen);
 }
+
+static int
+getpasswd(char *token_spec, CK_BYTE_PTR *pdata, CK_ULONG *psize)
+{
+	char *databuf;
+	char *tmpbuf;
+	char prompt[1024];
+
+	if (token_spec == NULL)
+		return (-1);
+
+	(void) snprintf(prompt, sizeof (prompt), DEFAULT_TOKEN_PROMPT,
+	    token_spec);
+	tmpbuf = getpassphrase(gettext(prompt));
+
+	if (tmpbuf == NULL) {
+		return (-1);	/* error */
+	}
+
+	databuf = strdup(tmpbuf);
+	(void) memset(tmpbuf, 0, strlen(tmpbuf));
+	if (databuf == NULL)
+		return (-1);
+
+	*pdata = (CK_BYTE_PTR)databuf;
+	*psize = (CK_ULONG)strlen(databuf);
+
+	return (0);
+}
--- a/usr/src/cmd/cmd-crypto/pktool/common.c	Tue Mar 13 16:38:14 2007 -0700
+++ b/usr/src/cmd/cmd-crypto/pktool/common.c	Tue Mar 13 17:01:48 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -493,6 +493,8 @@
 		*ktype = KMF_DES;
 	else if (strcasecmp(algm, "3des") == 0)
 		*ktype = KMF_DES3;
+	else if (strcasecmp(algm, "generic") == 0)
+		*ktype = KMF_GENERIC_SECRET;
 	else
 		return (-1);
 
--- a/usr/src/cmd/cmd-crypto/pktool/genkey.c	Tue Mar 13 16:38:14 2007 -0700
+++ b/usr/src/cmd/cmd-crypto/pktool/genkey.c	Tue Mar 13 17:01:48 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -359,11 +359,11 @@
 		keylen = 64;  /* fixed size; ignore input */
 	else if (keyAlg == KMF_DES3)
 		keylen = 192; /* fixed size; ignore input */
-	else /* AES or ARCFOUR */ {
+	else /* AES, ARCFOUR, or GENERIC SECRET */ {
 		if (keylenstr == NULL) {
 			cryptoerror(LOG_STDERR,
-				gettext("Key length must be specified "
-				"for AES and ARCFOUR symmetric keys.\n"));
+				gettext("Key length must be specified for "
+				"AES, ARCFOUR or GENERIC symmetric keys.\n"));
 			return (PK_ERR_USAGE);
 		}
 		if (sscanf(keylenstr, "%d", &keylen) != 1) {
--- a/usr/src/cmd/cmd-crypto/pktool/pktool.c	Tue Mar 13 16:38:14 2007 -0700
+++ b/usr/src/cmd/cmd-crypto/pktool/pktool.c	Tue Mar 13 17:01:48 2007 -0700
@@ -378,8 +378,8 @@
 
 	"genkey [ keystore=pkcs11 ]\n\t\t"
 		"label=key-label\n\t\t"
-		"[ keytype=aes|arcfour|des|3des ]\n\t\t"
-		"[ keylen=key-size (AES or ARCFOUR only)]\n\t\t"
+		"[ keytype=aes|arcfour|des|3des|generic ]\n\t\t"
+		"[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t"
 		"[ token=token[:manuf[:serial]]]\n\t\t"
 		"[ sensitive=y|n ]\n\t\t"
 		"[ extractable=y|n ]\n\t\t"
@@ -387,16 +387,16 @@
 
 	"genkey keystore=nss\n\t\t"
 		"label=key-label\n\t\t"
-		"[ keytype=aes|arcfour|des|3des ]\n\t\t"
-		"[ keylen=key-size (AES or ARCFOUR only)]\n\t\t"
+		"[ keytype=aes|arcfour|des|3des|generic ]\n\t\t"
+		"[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t"
 		"[ token=token[:manuf[:serial]]]\n\t\t"
 		"[ dir=directory-path ]\n\t\t"
 		"[ prefix=DBprefix ]\n\t"
 
 	"genkey keystore=file\n\t\t"
 		"outkey=key-fn\n\t\t"
-		"[ keytype=aes|arcfour|des|3des ]\n\t\t"
-		"[ keylen=key-size (AES or ARCFOUR only)]\n\t\t"
+		"[ keytype=aes|arcfour|des|3des|generic ]\n\t\t"
+		"[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t"
 		"[ dir=directory-path ]\n\t\t"
 		"[ print=y|n ]\n\t"
 	},
--- a/usr/src/lib/libkmf/include/kmftypes.h	Tue Mar 13 16:38:14 2007 -0700
+++ b/usr/src/lib/libkmf/include/kmftypes.h	Tue Mar 13 17:01:48 2007 -0700
@@ -220,7 +220,6 @@
 typedef struct {
 	KMF_KEYSTORE_TYPE	kstype;
 	KMF_DATA		*certificate;
-	KMF_BIGINT		*serial;
 	KMF_DATA		*ocsp_response;
 
 	union {
@@ -237,7 +236,8 @@
 	KMF_AES = 3,
 	KMF_RC4 = 4,
 	KMF_DES = 5,
-	KMF_DES3 = 6
+	KMF_DES3 = 6,
+	KMF_GENERIC_SECRET = 7
 }KMF_KEY_ALG;
 
 typedef enum {
--- a/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c	Tue Mar 13 16:38:14 2007 -0700
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c	Tue Mar 13 17:01:48 2007 -0700
@@ -2360,6 +2360,12 @@
 		keyType = CKM_DES3_KEY_GEN;
 		keySize = 0; /* required by PK11_TokenKeyGen() */
 		break;
+	case KMF_GENERIC_SECRET:
+		keyType = CKM_GENERIC_SECRET_KEY_GEN;
+		keySize = params->keylength;
+		if (keySize == 0 || (keySize % 8) != 0)
+			return (KMF_ERR_BAD_KEY_SIZE);
+		break;
 	default:
 		rv = KMF_ERR_BAD_KEY_TYPE;
 		goto out;
--- a/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c	Tue Mar 13 16:38:14 2007 -0700
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c	Tue Mar 13 17:01:48 2007 -0700
@@ -4379,8 +4379,8 @@
 		rkey->keydata.val = (uchar_t *)des3key;
 		rkey->keydata.len = DES3_KEY_SIZE;
 		symkey->keyalg = KMF_DES3;
-
-	} else if (params->keytype == KMF_AES || params->keytype == KMF_RC4) {
+	} else if (params->keytype == KMF_AES || params->keytype == KMF_RC4 ||
+	    params->keytype == KMF_GENERIC_SECRET) {
 		int bytes;
 
 		if (params->keylength % 8 != 0) {
--- a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c	Tue Mar 13 16:38:14 2007 -0700
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c	Tue Mar 13 17:01:48 2007 -0700
@@ -30,6 +30,7 @@
 #include <stdio.h> /* debugging only */
 #include <errno.h>
 #include <values.h>
+#include <fcntl.h>
 
 #include <kmfapiP.h>
 #include <ber_der.h>
@@ -39,6 +40,8 @@
 #include <security/cryptoki.h>
 #include <security/pkcs11.h>
 
+#define	DEV_RANDOM	"/dev/random"
+
 #define	SETATTR(t, n, atype, value, size) \
 	t[n].type = atype; \
 	t[n].pValue = (CK_BYTE *)value; \
@@ -62,6 +65,10 @@
 static KMF_RETURN
 keyObj2RawKey(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_KEY_DATA **);
 
+static KMF_RETURN
+create_generic_secret_key(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *,
+    CK_OBJECT_HANDLE *);
+
 KMF_RETURN
 KMFPK11_ConfigureKeystore(KMF_HANDLE_T, KMF_CONFIG_PARAMS *);
 
@@ -2225,7 +2232,8 @@
 	} else if (inkey->keyalg == KMF_AES ||
 	    inkey->keyalg == KMF_RC4 ||
 	    inkey->keyalg == KMF_DES ||
-	    inkey->keyalg == KMF_DES3) {
+	    inkey->keyalg == KMF_DES3 ||
+	    inkey->keyalg == KMF_GENERIC_SECRET) {
 		rv = get_raw_sym(kmfh, (CK_OBJECT_HANDLE)inkey->keyp,
 		    &rkey->rawdata.sym);
 	} else {
@@ -2265,6 +2273,9 @@
 	case KMF_DES3:
 		*type = CKK_DES3;
 		break;
+	case KMF_GENERIC_SECRET:
+		*type = CKK_GENERIC_SECRET;
+		break;
 	default:
 		return (KMF_ERR_BAD_KEY_TYPE);
 	}
@@ -2462,6 +2473,9 @@
 						keys[n].keyalg = KMF_DES;
 					else if (keytype == CKK_DES3)
 						keys[n].keyalg = KMF_DES3;
+					else if (keytype == CKK_GENERIC_SECRET)
+						keys[n].keyalg =
+						    KMF_GENERIC_SECRET;
 
 				}
 				n++;
@@ -2474,6 +2488,7 @@
 		/* "numkeys" indicates the number that were actually found */
 		*numkeys = n;
 	}
+
 	if (ckrv == KMF_OK && keys != NULL && (*numkeys) > 0) {
 		if (parms->format == KMF_FORMAT_RAWKEY) {
 			/* Convert keys to "rawkey" format */
@@ -2784,6 +2799,22 @@
 	if (params == NULL)
 		return (KMF_ERR_BAD_PARAMETER);
 
+	/*
+	 * For AES, RC4, DES and 3DES, call C_GenerateKey() to create a key.
+	 *
+	 * For a generic secret key, because it may not be supported in
+	 * C_GenerateKey() for some PKCS11 providers, we will handle it
+	 * differently.
+	 */
+	if (params->keytype == KMF_GENERIC_SECRET) {
+		rv = create_generic_secret_key(handle, params, &keyhandle);
+		if (rv != KMF_OK)
+			goto out;
+		else
+			goto setup;
+	}
+
+	/* Other keytypes */
 	keyGenMech.pParameter = NULL_PTR;
 	keyGenMech.ulParameterLen = 0;
 	switch (params->keytype) {
@@ -2868,6 +2899,7 @@
 		goto out;
 	}
 
+setup:
 	symkey->kstype = KMF_KEYSTORE_PK11TOKEN;
 	symkey->keyalg = params->keytype;
 	symkey->keyclass = KMF_SYMMETRIC;
@@ -3130,3 +3162,114 @@
 
 	return (ret);
 }
+
+static KMF_RETURN
+create_generic_secret_key(KMF_HANDLE_T handle,
+    KMF_CREATESYMKEY_PARAMS *params, CK_OBJECT_HANDLE *key)
+{
+	KMF_RETURN		rv = KMF_OK;
+	KMF_HANDLE		*kmfh = (KMF_HANDLE *)handle;
+	CK_RV			ckrv;
+	CK_SESSION_HANDLE	hSession = kmfh->pk11handle;
+	CK_OBJECT_CLASS		class = CKO_SECRET_KEY;
+	CK_ULONG		secKeyType = CKK_GENERIC_SECRET;
+	CK_ULONG		secKeyLen;
+	CK_BBOOL		true = TRUE;
+	CK_BBOOL		false = FALSE;
+	CK_ATTRIBUTE		templ[15];
+	int			i;
+	int			random_fd = -1;
+	int			nread;
+	char			*buf = NULL;
+
+	/*
+	 * Check the key size.
+	 */
+	if ((params->keylength % 8) != 0) {
+		return (KMF_ERR_BAD_KEY_SIZE);
+	} else {
+		secKeyLen = params->keylength/8;  /* in bytes */
+	}
+
+	/*
+	 * Generate a random number with the key size first.
+	 */
+	buf = malloc(secKeyLen);
+	if (buf == NULL)
+		return (KMF_ERR_MEMORY);
+
+	while ((random_fd = open(DEV_RANDOM, O_RDONLY)) < 0) {
+		if (errno != EINTR)
+			break;
+	}
+
+	if (random_fd < 0) {
+		rv = KMF_ERR_KEYGEN_FAILED;
+		goto out;
+	}
+
+	nread = read(random_fd, buf, secKeyLen);
+	if (nread <= 0 || nread != secKeyLen) {
+		rv = KMF_ERR_KEYGEN_FAILED;
+		goto out;
+	}
+
+	/*
+	 * Authenticate into the token and call C_CreateObject to generate
+	 * a generic secret token key.
+	 */
+	rv = pk11_authenticate(handle, &params->cred);
+	if (rv != KMF_OK) {
+		goto out;
+	}
+
+	i = 0;
+	SETATTR(templ, i, CKA_CLASS, &class, sizeof (class));
+	i++;
+	SETATTR(templ, i, CKA_KEY_TYPE, &secKeyType, sizeof (secKeyType));
+	i++;
+	SETATTR(templ, i, CKA_VALUE, buf, secKeyLen);
+	i++;
+
+	if (params->keylabel != NULL) {
+		SETATTR(templ, i, CKA_LABEL, params->keylabel,
+		    strlen(params->keylabel));
+		i++;
+	}
+
+	if (params->pkcs11parms.sensitive == B_TRUE) {
+		SETATTR(templ, i, CKA_SENSITIVE, &true, sizeof (true));
+	} else {
+		SETATTR(templ, i, CKA_SENSITIVE, &false, sizeof (false));
+	}
+	i++;
+
+	if (params->pkcs11parms.not_extractable == B_TRUE) {
+		SETATTR(templ, i, CKA_EXTRACTABLE, &false, sizeof (false));
+	} else {
+		SETATTR(templ, i, CKA_EXTRACTABLE, &true, sizeof (true));
+	}
+	i++;
+
+	SETATTR(templ, i, CKA_TOKEN, &true, sizeof (true));
+	i++;
+	SETATTR(templ, i, CKA_PRIVATE, &true, sizeof (true));
+	i++;
+	SETATTR(templ, i, CKA_SIGN, &true, sizeof (true));
+	i++;
+
+	ckrv = C_CreateObject(hSession, templ, i, key);
+	if (ckrv != CKR_OK) {
+		SET_ERROR(kmfh, ckrv);
+		rv = KMF_ERR_KEYGEN_FAILED;
+	}
+
+out:
+	if (buf != NULL)
+		free(buf);
+
+	if (random_fd != -1)
+		(void) close(random_fd);
+
+	return (rv);
+}