genkey.c revision 99ebb4ca412cb0a19d77a3899a87c055b9c30fa8
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <malloc.h>
#include <libgen.h>
#include <errno.h>
#include <cryptoutil.h>
#include <security/cryptoki.h>
#include "common.h"
#include <kmfapi.h>
static KMF_RETURN
genkey_nss(KMF_HANDLE_T kmfhandle, char *token, char *dir, char *prefix,
char *keylabel, KMF_KEY_ALG keyAlg, int keylen, KMF_CREDENTIAL *tokencred)
{
KMF_RETURN kmfrv = KMF_OK;
KMF_CREATESYMKEY_PARAMS csk_params;
KMF_KEY_HANDLE key;
if (keylabel == NULL) {
cryptoerror(LOG_STDERR,
gettext("A key label must be specified \n"));
return (KMF_ERR_BAD_PARAMETER);
}
kmfrv = configure_nss(kmfhandle, dir, prefix);
if (kmfrv != KMF_OK)
return (kmfrv);
(void) memset(&key, 0, sizeof (KMF_KEY_HANDLE));
csk_params.kstype = KMF_KEYSTORE_NSS;
csk_params.nssparms.slotlabel = token;
csk_params.keytype = keyAlg;
csk_params.keylength = keylen;
csk_params.keylabel = keylabel;
csk_params.cred.cred = tokencred->cred;
csk_params.cred.credlen = tokencred->credlen;
kmfrv = KMF_CreateSymKey(kmfhandle, &csk_params, &key);
return (kmfrv);
}
static KMF_RETURN
genkey_pkcs11(KMF_HANDLE_T kmfhandle, char *token,
char *keylabel, KMF_KEY_ALG keyAlg, int keylen,
char *senstr, char *extstr, boolean_t print_hex,
KMF_CREDENTIAL *tokencred)
{
KMF_RETURN kmfrv = KMF_OK;
KMF_CREATESYMKEY_PARAMS params;
KMF_KEY_HANDLE key;
KMF_RAW_SYM_KEY *rkey = NULL;
boolean_t sensitive = B_FALSE;
boolean_t not_extractable = B_FALSE;
char *hexstr = NULL;
int hexstrlen;
if (keylabel == NULL) {
cryptoerror(LOG_STDERR,
gettext("A key label must be specified \n"));
return (KMF_ERR_BAD_PARAMETER);
}
/* Check the sensitive option value if specified. */
if (senstr != NULL) {
if (tolower(senstr[0]) == 'y')
sensitive = B_TRUE;
else if (tolower(senstr[0]) == 'n')
sensitive = B_FALSE;
else {
cryptoerror(LOG_STDERR,
gettext("Incorrect sensitive option value.\n"));
return (KMF_ERR_BAD_PARAMETER);
}
}
/* Check the extractable option value if specified. */
if (extstr != NULL) {
if (tolower(extstr[0]) == 'y')
not_extractable = B_FALSE;
else if (tolower(extstr[0]) == 'n')
not_extractable = B_TRUE;
else {
cryptoerror(LOG_STDERR,
gettext("Incorrect extractable option value.\n"));
return (KMF_ERR_BAD_PARAMETER);
}
}
/* Select a PKCS11 token first */
kmfrv = select_token(kmfhandle, token, FALSE);
if (kmfrv != KMF_OK) {
return (kmfrv);
}
(void) memset(&key, 0, sizeof (KMF_KEY_HANDLE));
params.kstype = KMF_KEYSTORE_PK11TOKEN;
params.keytype = keyAlg;
params.keylength = keylen; /* bits */
params.keylabel = keylabel;
params.pkcs11parms.sensitive = sensitive;
params.pkcs11parms.not_extractable = not_extractable;
params.cred.cred = tokencred->cred;
params.cred.credlen = tokencred->credlen;
kmfrv = KMF_CreateSymKey(kmfhandle, &params, &key);
if (kmfrv != KMF_OK) {
goto out;
}
if (print_hex) {
if (sensitive == B_TRUE || not_extractable == B_TRUE) {
cryptoerror(LOG_STDERR,
gettext("Warning: can not reveal the key value "
"for a sensitive or non-extractable key.\n"));
goto out;
} else {
rkey = malloc(sizeof (KMF_RAW_SYM_KEY));
if (rkey == NULL) {
kmfrv = KMF_ERR_MEMORY;
goto out;
}
(void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY));
kmfrv = KMF_GetSymKeyValue(kmfhandle, &key, rkey);
if (kmfrv != KMF_OK) {
goto out;
}
hexstrlen = 2 * rkey->keydata.len + 1;
hexstr = malloc(hexstrlen);
if (hexstr == NULL) {
kmfrv = KMF_ERR_MEMORY;
goto out;
}
tohexstr(rkey->keydata.val, rkey->keydata.len, hexstr,
hexstrlen);
(void) printf(gettext("\tKey Value =\"%s\"\n"), hexstr);
}
}
out:
KMF_FreeRawSymKey(rkey);
if (hexstr != NULL)
free(hexstr);
return (kmfrv);
}
static KMF_RETURN
genkey_file(KMF_HANDLE_T kmfhandle, KMF_KEY_ALG keyAlg, int keylen, char *dir,
char *outkey, boolean_t print_hex)
{
KMF_RETURN kmfrv = KMF_OK;
KMF_CREATESYMKEY_PARAMS csk_params;
KMF_KEY_HANDLE key;
KMF_RAW_SYM_KEY *rkey = NULL;
char *hexstr = NULL;
int hexstrlen;
if (EMPTYSTRING(outkey)) {
cryptoerror(LOG_STDERR,
gettext("No output key file was specified for the key\n"));
return (KMF_ERR_BAD_PARAMETER);
}
if (verify_file(outkey)) {
cryptoerror(LOG_STDERR,
gettext("Cannot write the indicated output "
"key file (%s).\n"), outkey);
return (KMF_ERR_BAD_PARAMETER);
}
(void) memset(&key, 0, sizeof (KMF_KEY_HANDLE));
csk_params.kstype = KMF_KEYSTORE_OPENSSL;
csk_params.keytype = keyAlg;
csk_params.keylength = keylen;
csk_params.cred.cred = NULL;
csk_params.cred.credlen = 0;
csk_params.sslparms.dirpath = (dir == NULL) ? "." : dir;
csk_params.sslparms.keyfile = outkey;
kmfrv = KMF_CreateSymKey(kmfhandle, &csk_params, &key);
if (kmfrv != KMF_OK) {
goto out;
}
if (print_hex) {
rkey = malloc(sizeof (KMF_RAW_SYM_KEY));
if (rkey == NULL) {
kmfrv = KMF_ERR_MEMORY;
goto out;
}
(void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY));
kmfrv = KMF_GetSymKeyValue(kmfhandle, &key, rkey);
if (kmfrv != KMF_OK) {
goto out;
}
hexstrlen = 2 * rkey->keydata.len + 1;
hexstr = malloc(hexstrlen);
if (hexstr == NULL) {
kmfrv = KMF_ERR_MEMORY;
goto out;
}
tohexstr(rkey->keydata.val, rkey->keydata.len, hexstr,
hexstrlen);
(void) printf(gettext("\tKey Value =\"%s\"\n"), hexstr);
}
out:
KMF_FreeRawSymKey(rkey);
if (hexstr != NULL)
free(hexstr);
return (kmfrv);
}
int
pk_genkey(int argc, char *argv[])
{
int rv;
int opt;
extern int optind_av;
extern char *optarg_av;
KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
char *tokenname = NULL;
char *dir = NULL;
char *prefix = NULL;
char *keytype = "AES";
char *keylenstr = NULL;
int keylen = 0;
char *keylabel = NULL;
char *outkey = NULL;
char *senstr = NULL;
char *extstr = NULL;
char *printstr = NULL;
KMF_HANDLE_T kmfhandle = NULL;
KMF_KEY_ALG keyAlg = KMF_AES;
boolean_t print_hex = B_FALSE;
KMF_CREDENTIAL tokencred = {NULL, 0};
while ((opt = getopt_av(argc, argv,
"k:(keystore)l:(label)T:(token)d:(dir)p:(prefix)"
"t:(keytype)y:(keylen)K:(outkey)P:(print)"
"s:(sensitive)e:(extractable)")) != EOF) {
if (EMPTYSTRING(optarg_av))
return (PK_ERR_USAGE);
switch (opt) {
case 'k':
kstype = KS2Int(optarg_av);
if (kstype == 0)
return (PK_ERR_USAGE);
break;
case 'l':
if (keylabel)
return (PK_ERR_USAGE);
keylabel = optarg_av;
break;
case 'T':
if (tokenname)
return (PK_ERR_USAGE);
tokenname = 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 't':
keytype = optarg_av;
break;
case 'y':
if (keylenstr)
return (PK_ERR_USAGE);
keylenstr = optarg_av;
break;
case 'K':
if (outkey)
return (PK_ERR_USAGE);
outkey = optarg_av;
break;
case 'P':
if (printstr)
return (PK_ERR_USAGE);
printstr = optarg_av;
break;
case 's':
if (senstr)
return (PK_ERR_USAGE);
senstr = optarg_av;
break;
case 'e':
if (extstr)
return (PK_ERR_USAGE);
extstr = optarg_av;
break;
default:
return (PK_ERR_USAGE);
}
}
/* No additional args allowed. */
argc -= optind_av;
argv += optind_av;
if (argc) {
return (PK_ERR_USAGE);
}
/* Check keytype. If not specified, default to AES */
if (keytype != NULL && Str2SymKeyType(keytype, &keyAlg) != 0) {
cryptoerror(LOG_STDERR, gettext("Unrecognized keytype(%s).\n"),
keytype);
return (PK_ERR_USAGE);
}
/*
* Check and set the key length.
* - For DES and 3DES, the key size are fixed. Ingore the keylen
* option, even if it is specified.
* - For AES and ARCFOUR, if keylen is not specified, default to
* 128 bits.
*/
if (keyAlg == KMF_DES)
keylen = 64; /* fixed size; ignore input */
else if (keyAlg == KMF_DES3)
keylen = 192; /* fixed size; ignore input */
else /* AES or ARCFOUR */ {
if (keylenstr == NULL) {
cryptoerror(LOG_STDERR,
gettext("Key length must be specified "
"for AES and ARCFOUR symmetric keys.\n"));
return (PK_ERR_USAGE);
}
if (sscanf(keylenstr, "%d", &keylen) != 1) {
cryptoerror(LOG_STDERR,
gettext("Unrecognized key length (%s).\n"),
keytype);
return (PK_ERR_USAGE);
}
if (keylen == 0 || (keylen % 8) != 0) {
cryptoerror(LOG_STDERR,
gettext("Key length bitlength must be a "
"multiple of 8.\n"));
return (PK_ERR_USAGE);
}
}
/* check the print option */
if (printstr != NULL) {
if (kstype == KMF_KEYSTORE_NSS) {
cryptoerror(LOG_STDERR,
gettext("The print option does not apply "
"to the NSS keystore.\n"));
return (PK_ERR_USAGE);
}
if (tolower(printstr[0]) == 'y')
print_hex = B_TRUE;
else if (tolower(printstr[0]) == 'n')
print_hex = B_FALSE;
else {
cryptoerror(LOG_STDERR,
gettext("Incorrect print option value.\n"));
return (PK_ERR_USAGE);
}
}
/* check the sensitive and extractable options */
if ((senstr != NULL || extstr != NULL) &&
(kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_OPENSSL)) {
cryptoerror(LOG_STDERR,
gettext("The sensitive or extractable option applies "
"to the PKCS11 keystore only.\n"));
return (PK_ERR_USAGE);
}
if (kstype == KMF_KEYSTORE_PK11TOKEN && tokenname == NULL) {
tokenname = PK_DEFAULT_PK11TOKEN;
} else if (kstype == KMF_KEYSTORE_NSS && tokenname == NULL) {
tokenname = DEFAULT_NSS_TOKEN;
}
if (kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS)
(void) get_token_password(kstype, tokenname, &tokencred);
if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
goto end;
}
if (kstype == KMF_KEYSTORE_NSS) {
rv = genkey_nss(kmfhandle, tokenname, dir, prefix,
keylabel, keyAlg, keylen, &tokencred);
} else if (kstype == KMF_KEYSTORE_OPENSSL) {
rv = genkey_file(kmfhandle, keyAlg, keylen, dir, outkey,
print_hex);
} else {
rv = genkey_pkcs11(kmfhandle, tokenname, keylabel, keyAlg,
keylen, senstr, extstr, print_hex, &tokencred);
}
end:
if (rv != KMF_OK)
display_error(kmfhandle, rv,
gettext("Error generating key"));
if (tokencred.cred != NULL)
free(tokencred.cred);
(void) KMF_Finalize(kmfhandle);
if (rv != KMF_OK)
return (PK_ERR_USAGE);
return (0);
}