genkey.c revision fa60c371cd00bdca17de2ff18fe3e64d051ae61b
/*
* 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"
#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_KEY_HANDLE key;
KMF_ATTRIBUTE attlist[20];
int i = 0;
KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS;
KMF_KEY_ALG keytype;
uint32_t keylength;
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));
keytype = keyAlg;
keylength = keylen;
kmf_set_attr_at_index(attlist, i,
KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
i++;
kmf_set_attr_at_index(attlist, i,
KMF_KEY_HANDLE_ATTR, &key, sizeof (KMF_KEY_HANDLE));
i++;
kmf_set_attr_at_index(attlist, i,
KMF_KEYALG_ATTR, &keytype, sizeof (keytype));
i++;
kmf_set_attr_at_index(attlist, i,
KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength));
i++;
if (keylabel != NULL) {
kmf_set_attr_at_index(attlist, i,
KMF_KEYLABEL_ATTR, keylabel,
strlen(keylabel));
i++;
}
if (tokencred != NULL && tokencred->cred != NULL) {
kmf_set_attr_at_index(attlist, i,
KMF_CREDENTIAL_ATTR, tokencred,
sizeof (KMF_CREDENTIAL));
i++;
}
if (token != NULL) {
kmf_set_attr_at_index(attlist, i,
KMF_TOKEN_LABEL_ATTR, token,
strlen(token));
i++;
}
kmfrv = kmf_create_sym_key(kmfhandle, i, attlist);
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_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;
KMF_ATTRIBUTE attlist[20];
int i = 0;
KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
KMF_KEY_ALG keytype;
uint32_t keylength;
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));
keytype = keyAlg;
keylength = keylen; /* bits */
kmf_set_attr_at_index(attlist, i,
KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
i++;
kmf_set_attr_at_index(attlist, i,
KMF_KEY_HANDLE_ATTR, &key, sizeof (KMF_KEY_HANDLE));
i++;
kmf_set_attr_at_index(attlist, i,
KMF_KEYALG_ATTR, &keytype, sizeof (keytype));
i++;
kmf_set_attr_at_index(attlist, i,
KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength));
i++;
if (keylabel != NULL) {
kmf_set_attr_at_index(attlist, i,
KMF_KEYLABEL_ATTR, keylabel,
strlen(keylabel));
i++;
}
if (tokencred != NULL && tokencred->cred != NULL) {
kmf_set_attr_at_index(attlist, i,
KMF_CREDENTIAL_ATTR, tokencred,
sizeof (KMF_CREDENTIAL));
i++;
}
kmf_set_attr_at_index(attlist, i,
KMF_SENSITIVE_BOOL_ATTR, &sensitive,
sizeof (sensitive));
i++;
kmf_set_attr_at_index(attlist, i,
KMF_NON_EXTRACTABLE_BOOL_ATTR, &not_extractable,
sizeof (not_extractable));
i++;
kmfrv = kmf_create_sym_key(kmfhandle, i, attlist);
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_get_sym_key_value(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_free_raw_sym_key(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_KEY_HANDLE key;
KMF_RAW_SYM_KEY *rkey = NULL;
char *hexstr = NULL;
int hexstrlen;
KMF_ATTRIBUTE attlist[20];
int i = 0;
KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL;
KMF_KEY_ALG keytype;
uint32_t keylength;
char *dirpath;
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));
keytype = keyAlg;
keylength = keylen;
dirpath = dir;
kmf_set_attr_at_index(attlist, i,
KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
i++;
kmf_set_attr_at_index(attlist, i,
KMF_KEY_HANDLE_ATTR, &key, sizeof (KMF_KEY_HANDLE));
i++;
kmf_set_attr_at_index(attlist, i,
KMF_KEYALG_ATTR, &keytype, sizeof (keytype));
i++;
kmf_set_attr_at_index(attlist, i,
KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength));
i++;
if (dirpath != NULL) {
kmf_set_attr_at_index(attlist, i,
KMF_DIRPATH_ATTR, dirpath,
strlen(dirpath));
i++;
}
if (outkey != NULL) {
kmf_set_attr_at_index(attlist, i,
KMF_KEY_FILENAME_ATTR, outkey,
strlen(outkey));
i++;
}
kmfrv = kmf_create_sym_key(kmfhandle, i, attlist);
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_get_sym_key_value(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_free_raw_sym_key(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 = "generic";
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_GENERIC_SECRET;
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, ARCFOUR, or GENERIC SECRET */ {
if (keylenstr == NULL) {
cryptoerror(LOG_STDERR,
gettext("Key length must be specified for "
"AES, ARCFOUR or GENERIC 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);
}