diff options
Diffstat (limited to 'usr/src/cmd/cmd-crypto/pktool/genkey.c')
-rw-r--r-- | usr/src/cmd/cmd-crypto/pktool/genkey.c | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-crypto/pktool/genkey.c b/usr/src/cmd/cmd-crypto/pktool/genkey.c new file mode 100644 index 0000000000..f94093029e --- /dev/null +++ b/usr/src/cmd/cmd-crypto/pktool/genkey.c @@ -0,0 +1,450 @@ +/* + * 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, ¶ms, &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); +} |