Mercurial > illumos > illumos-gate
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, ¶ms->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); +}