# # 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 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG = pktool OBJS = pktool.o \ common.o \ setpin.o \ list.o \ delete.o \ import.o \ inittoken.o \ export.o \ tokens.o \ gencert.o \ gencsr.o \ download.o \ genkey.o \ signcsr.o \ genkeypair.o include ../../Makefile.cmd KMFDIR = $(SRC)/lib/libkmf SRCS = $(OBJS:%.o=%.c) POFILES = $(OBJS:%.o=%.po) POFILE = $(PROG)_msg.po MSGFILES=$(SRCS:%.c=%.i) CPPFLAGS += -I. -I$(KMFDIR)/include -I$(ROOT)/usr/include/libxml2 \ -I$(KMFDIR)/ber_der/inc CFLAGS += $(CCVERBOSE) -DDEBUG CERRWARN += $(CNOWARN_UNINIT) # not linted, too much mess, but it should be SMATCH=off LDLIBS += -lkmf -lpkcs11 -lcryptoutil .KEEP_STATE: all : $(PROG) $(PROG) : $(OBJS) $(LINK.c) -o $@ $(OBJS) $(DYNFLAGS) $(LDLIBS) $(POST_PROCESS) $(POFILE) : $(POFILES) $(RM) $@; $(CAT) $(POFILES) > $@ install : all $(ROOTPROG) clean : $(RM) $(OBJS) include ../../Makefile.targ /* * 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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * This file contains the functions that are shared among * the various services this tool will ultimately provide. * The functions in this file return PKCS#11 CK_RV errors. * Only one session and one login per token is supported * at this time. */ #include #include #include #include #include #include #include #include #include #include #include #include "common.h" /* Local status variables. */ static boolean_t initialized = B_FALSE; static boolean_t session_opened = B_FALSE; static boolean_t logged_in = B_FALSE; /* Supporting structures and global variables for getopt_av(). */ typedef struct av_opts_s { int shortnm; /* short name character */ char *longnm; /* long name string, NOT terminated */ int longnm_len; /* length of long name string */ boolean_t has_arg; /* takes optional argument */ } av_opts; static av_opts *opts_av = NULL; static const char *_save_optstr = NULL; static int _save_numopts = 0; int optind_av = 1; char *optarg_av = NULL; static void close_sess(CK_SESSION_HANDLE); static void logout_token(CK_SESSION_HANDLE); struct oid_table_entry { const KMF_OID *oid; char *name; }; struct oid_table_entry oid_table[] = { { &KMFOID_ECC_secp112r1, "secp112r1"}, { &KMFOID_ECC_secp112r2, "secp112r2"}, { &KMFOID_ECC_secp128r1, "secp128r1"}, { &KMFOID_ECC_secp128r2, "secp128r2"}, { &KMFOID_ECC_secp160k1, "secp160k1"}, { &KMFOID_ECC_secp160r1, "secp160r1"}, { &KMFOID_ECC_secp160r2, "secp160r2"}, { &KMFOID_ECC_secp192k1, "secp192k1"}, { &KMFOID_ECC_secp192r1, "secp192r1"}, { &KMFOID_ECC_secp224k1, "secp224k1"}, { &KMFOID_ECC_secp224r1, "secp224r1"}, { &KMFOID_ECC_secp256k1, "secp256k1"}, { &KMFOID_ECC_secp256r1, "secp256r1"}, { &KMFOID_ECC_secp384r1, "secp384r1"}, { &KMFOID_ECC_secp521r1, "secp521r1"}, { &KMFOID_ECC_sect113r1, "sect113r1"}, { &KMFOID_ECC_sect113r2, "sect113r2"}, { &KMFOID_ECC_sect131r1, "sect131r1"}, { &KMFOID_ECC_sect131r2, "sect131r2"}, { &KMFOID_ECC_sect163k1, "sect163k1"}, { &KMFOID_ECC_sect163r1, "sect163r1"}, { &KMFOID_ECC_sect163r2, "sect163r2"}, { &KMFOID_ECC_sect193r1, "sect193r1"}, { &KMFOID_ECC_sect193r2, "sect193r2"}, { &KMFOID_ECC_sect233k1, "sect233k1"}, { &KMFOID_ECC_sect233r1, "sect233r1"}, { &KMFOID_ECC_sect239k1, "sect239k1"}, { &KMFOID_ECC_sect283k1, "sect283k1"}, { &KMFOID_ECC_sect283r1, "sect283r1"}, { &KMFOID_ECC_sect409k1, "sect409k1"}, { &KMFOID_ECC_sect409r1, "sect409r1"}, { &KMFOID_ECC_sect571k1, "sect571k1"}, { &KMFOID_ECC_sect571r1, "sect571r1"}, { &KMFOID_ECC_c2pnb163v1, "c2pnb163v1"}, { &KMFOID_ECC_c2pnb163v2, "c2pnb163v2"}, { &KMFOID_ECC_c2pnb163v3, "c2pnb163v3"}, { &KMFOID_ECC_c2pnb176v1, "c2pnb176v1"}, { &KMFOID_ECC_c2tnb191v1, "c2tnb191v1"}, { &KMFOID_ECC_c2tnb191v2, "c2tnb191v2"}, { &KMFOID_ECC_c2tnb191v3, "c2tnb191v3"}, { &KMFOID_ECC_c2pnb208w1, "c2pnb208w1"}, { &KMFOID_ECC_c2tnb239v1, "c2tnb239v1"}, { &KMFOID_ECC_c2tnb239v2, "c2tnb239v2"}, { &KMFOID_ECC_c2tnb239v3, "c2tnb239v3"}, { &KMFOID_ECC_c2pnb272w1, "c2pnb272w1"}, { &KMFOID_ECC_c2pnb304w1, "c2pnb304w1"}, { &KMFOID_ECC_c2tnb359v1, "c2tnb359v1"}, { &KMFOID_ECC_c2pnb368w1, "c2pnb368w1"}, { &KMFOID_ECC_c2tnb431r1, "c2tnb431r1"}, { &KMFOID_ECC_prime192v2, "prime192v2"}, { &KMFOID_ECC_prime192v3, "prime192v3"}, { &KMFOID_MD5, "md5"}, { &KMFOID_SHA1, "sha1"}, { &KMFOID_SHA256, "sha256"}, { &KMFOID_SHA384, "sha384"}, { &KMFOID_SHA512, "sha512"} }; int number_of_oids = sizeof (oid_table) / sizeof (struct oid_table_entry); #define number_of_curves (number_of_oids - 5) /* * Perform PKCS#11 setup here. Currently only C_Initialize is required, * along with setting/resetting state variables. */ static CK_RV init_pkcs11(void) { CK_RV rv = CKR_OK; /* If C_Initialize() already called, nothing to do here. */ if (initialized == B_TRUE) return (CKR_OK); /* Reset state variables because C_Initialize() not yet done. */ session_opened = B_FALSE; logged_in = B_FALSE; /* Initialize PKCS#11 library. */ if ((rv = C_Initialize(NULL_PTR)) != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { return (rv); } initialized = B_TRUE; return (CKR_OK); } /* * Finalize PKCS#11 library and reset state variables. Open sessions, * if any, are closed, and thereby any logins are logged out also. */ void final_pk11(CK_SESSION_HANDLE sess) { /* If the library wasn't initialized, nothing to do here. */ if (!initialized) return; /* Make sure the sesion is closed first. */ close_sess(sess); (void) C_Finalize(NULL); initialized = B_FALSE; } /* * Close PKCS#11 session and reset state variables. Any logins are * logged out. */ static void close_sess(CK_SESSION_HANDLE sess) { if (sess == 0) { return; } /* If session is already closed, nothing to do here. */ if (!session_opened) return; /* Make sure user is logged out of token. */ logout_token(sess); (void) C_CloseSession(sess); session_opened = B_FALSE; } /* * Log user out of token and reset status variable. */ static void logout_token(CK_SESSION_HANDLE sess) { if (sess == 0) { return; } /* If already logged out, nothing to do here. */ if (!logged_in) return; (void) C_Logout(sess); logged_in = B_FALSE; } /* * Gets PIN from user. Caller needs to free the returned PIN when done. * If two prompts are given, the PIN is confirmed with second prompt. * Note that getphassphrase() may return data in static memory area. */ CK_RV get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen) { char *save_phrase, *phrase1, *phrase2; /* Prompt user for a PIN. */ if (prompt1 == NULL) { return (CKR_ARGUMENTS_BAD); } if ((phrase1 = getpassphrase(prompt1)) == NULL) { return (CKR_FUNCTION_FAILED); } /* Duplicate 1st PIN in separate chunk of memory. */ if ((save_phrase = strdup(phrase1)) == NULL) return (CKR_HOST_MEMORY); /* If second prompt given, PIN confirmation is requested. */ if (prompt2 != NULL) { if ((phrase2 = getpassphrase(prompt2)) == NULL) { free(save_phrase); return (CKR_FUNCTION_FAILED); } if (strcmp(save_phrase, phrase2) != 0) { free(save_phrase); return (CKR_PIN_INCORRECT); } } *pin = (CK_UTF8CHAR_PTR)save_phrase; *pinlen = strlen(save_phrase); return (CKR_OK); } int yn_to_int(char *ynstr) { char *y = gettext("yes"); char *n = gettext("no"); if (ynstr == NULL) return (-1); if (strncasecmp(ynstr, y, 1) == 0) return (1); else if (strncasecmp(ynstr, n, 1) == 0) return (0); else return (-1); } /* * Gets yes/no response from user. If either no prompt is supplied, a * default prompt is used. If not message for invalid input is supplied, * a default will not be provided. If the user provides no response, * the input default B_TRUE == yes, B_FALSE == no is returned. * Otherwise, B_TRUE is returned for yes, and B_FALSE for no. */ boolean_t yesno(char *prompt, char *invalid, boolean_t dflt) { char *response, buf[1024]; int ans; if (prompt == NULL) prompt = gettext("Enter (y)es or (n)o? "); for (;;) { /* Prompt user. */ (void) printf("%s", prompt); (void) fflush(stdout); /* Get the response. */ if ((response = fgets(buf, sizeof (buf), stdin)) == NULL) break; /* go to default response */ /* Skip any leading white space. */ while (isspace(*response)) response++; if (*response == '\0') break; /* go to default response */ ans = yn_to_int(response); if (ans == 1) return (B_TRUE); else if (ans == 0) return (B_FALSE); /* Indicate invalid input, and try again. */ if (invalid != NULL) (void) printf("%s", invalid); } return (dflt); } /* * Gets the list of slots which have tokens in them. Keeps adjusting * the size of the slot list buffer until the call is successful or an * irrecoverable error occurs. */ CK_RV get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) { CK_ULONG tmp_count = 0; CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR; int rv = CKR_OK; if (!initialized) if ((rv = init_pkcs11()) != CKR_OK) return (rv); /* * Get the slot count first because we don't know how many * slots there are and how many of those slots even have tokens. * Don't specify an arbitrary buffer size for the slot list; * it may be too small (see section 11.5 of PKCS#11 spec). * Also select only those slots that have tokens in them, * because this tool has no need to know about empty slots. */ if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK) return (rv); if (tmp_count == 0) { *slot_list = NULL_PTR; *slot_count = 0; return (CKR_OK); } /* Allocate initial space for the slot list. */ if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count * sizeof (CK_SLOT_ID))) == NULL) return (CKR_HOST_MEMORY); /* Then get the slot list itself. */ for (;;) { if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) { *slot_list = tmp_list; *slot_count = tmp_count; break; } if (rv != CKR_BUFFER_TOO_SMALL) { free(tmp_list); break; } /* If the number of slots grew, try again. */ if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list, tmp_count * sizeof (CK_SLOT_ID))) == NULL) { free(tmp_list); rv = CKR_HOST_MEMORY; break; } tmp_list = tmp2_list; } return (rv); } /* * Breaks out the getopt-style option string into a structure that can be * traversed later for calls to getopt_av(). Option string is NOT altered, * but the struct fields point to locations within option string. */ static int populate_opts(char *optstring) { int i; av_opts *temp; char *marker; if (optstring == NULL || *optstring == '\0') return (0); /* * This tries to imitate getopt(3c) Each option must conform to: * [ ':' ] [ '(' ')' ] * If long name is missing, the short name is used for long name. */ for (i = 0; *optstring != '\0'; i++) { if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { if (opts_av != NULL) free(opts_av); opts_av = NULL; return (0); } else { opts_av = (av_opts *)temp; } (void) memset(&opts_av[i], 0, sizeof (av_opts)); marker = optstring; /* may need optstring later */ opts_av[i].shortnm = *marker++; /* set short name */ if (*marker == ':') { /* check for opt arg */ marker++; opts_av[i].has_arg = B_TRUE; } if (*marker == '(') { /* check and set long name */ marker++; opts_av[i].longnm = marker; opts_av[i].longnm_len = strcspn(marker, ")"); optstring = marker + opts_av[i].longnm_len + 1; } else { /* use short name option character */ opts_av[i].longnm = optstring; opts_av[i].longnm_len = 1; optstring = marker; } } return (i); } /* * getopt_av() is very similar to getopt(3c) in that the takes an option * string, compares command line arguments for matches, and returns a single * letter option when a match is found. However, getopt_av() differs from * getopt(3c) by requiring that only longname options and values be found * on the command line and all leading dashes are omitted. In other words, * it tries to enforce only longname "option=value" arguments on the command * line. Boolean options are not allowed either. */ int getopt_av(int argc, char * const *argv, const char *optstring) { int i; int len; char *cur_option; if (optind_av >= argc) return (EOF); /* First time or when optstring changes from previous one */ if (_save_optstr != optstring) { if (opts_av != NULL) free(opts_av); opts_av = NULL; _save_optstr = optstring; _save_numopts = populate_opts((char *)optstring); } for (i = 0; i < _save_numopts; i++) { cur_option = argv[optind_av]; if (strcmp(cur_option, "--") == 0) { optind_av++; break; } if (cur_option[0] == '-' && strlen(cur_option) == 2) { len = 1; cur_option++; /* remove "-" */ } else { len = strcspn(cur_option, "="); } if (len == opts_av[i].longnm_len && strncmp(cur_option, opts_av[i].longnm, opts_av[i].longnm_len) == 0) { /* matched */ if (!opts_av[i].has_arg) { optind_av++; return (opts_av[i].shortnm); } /* needs optarg */ if (cur_option[len] == '=') { optarg_av = &(cur_option[len+1]); optind_av++; return (opts_av[i].shortnm); } optarg_av = NULL; optind_av++; return ((int)'?'); } } return (EOF); } KMF_KEYSTORE_TYPE KS2Int(char *keystore_str) { if (keystore_str == NULL) return (0); if (strcasecmp(keystore_str, "pkcs11") == 0) return (KMF_KEYSTORE_PK11TOKEN); else if (strcasecmp(keystore_str, "nss") == 0) return (KMF_KEYSTORE_NSS); else if (strcasecmp(keystore_str, "file") == 0) return (KMF_KEYSTORE_OPENSSL); else return (0); } /* * compare_oids * return 1 if equal */ boolean_t compare_oids(KMF_OID *oid1, const KMF_OID *oid2) { return ((oid1->Length == oid2->Length) && !memcmp(oid1->Data, oid2->Data, oid1->Length)); } int Str2KeyType(char *algm, KMF_OID *hashoid, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg) { if (algm == NULL) { /* Default to SHA1+RSA */ *sigAlg = KMF_ALGID_SHA1WithRSA; *ktype = KMF_RSA; } else if (strcasecmp(algm, "DSA") == 0) { if (hashoid == NULL || compare_oids(hashoid, &KMFOID_SHA1)) *sigAlg = KMF_ALGID_SHA1WithDSA; else if (compare_oids(hashoid, &KMFOID_SHA256)) *sigAlg = KMF_ALGID_SHA256WithDSA; else return (-1); /* unsupported hash/key combo */ *ktype = KMF_DSA; } else if (strcasecmp(algm, "RSA") == 0) { if (hashoid == NULL || compare_oids(hashoid, &KMFOID_SHA1)) *sigAlg = KMF_ALGID_SHA1WithRSA; else if (compare_oids(hashoid, &KMFOID_SHA256)) *sigAlg = KMF_ALGID_SHA256WithRSA; else if (compare_oids(hashoid, &KMFOID_SHA384)) *sigAlg = KMF_ALGID_SHA384WithRSA; else if (compare_oids(hashoid, &KMFOID_SHA512)) *sigAlg = KMF_ALGID_SHA512WithRSA; else if (compare_oids(hashoid, &KMFOID_MD5)) *sigAlg = KMF_ALGID_MD5WithRSA; else return (-1); /* unsupported hash/key combo */ *ktype = KMF_RSA; } else if (strcasecmp(algm, "EC") == 0) { /* EC keys may be used with some SHA2 hashes */ if (hashoid == NULL || compare_oids(hashoid, &KMFOID_SHA1)) *sigAlg = KMF_ALGID_SHA1WithECDSA; else if (compare_oids(hashoid, &KMFOID_SHA256)) *sigAlg = KMF_ALGID_SHA256WithECDSA; else if (compare_oids(hashoid, &KMFOID_SHA384)) *sigAlg = KMF_ALGID_SHA384WithECDSA; else if (compare_oids(hashoid, &KMFOID_SHA512)) *sigAlg = KMF_ALGID_SHA512WithECDSA; else return (-1); /* unsupported hash/key combo */ *ktype = KMF_ECDSA; } else { return (-1); } return (0); } int Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype) { if (algm == NULL) *ktype = KMF_AES; else if (strcasecmp(algm, "aes") == 0) *ktype = KMF_AES; else if (strcasecmp(algm, "arcfour") == 0) *ktype = KMF_RC4; else if (strcasecmp(algm, "des") == 0) *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); return (0); } int Str2Lifetime(char *ltimestr, uint32_t *ltime) { int num; char timetok[6]; if (ltimestr == NULL || strlen(ltimestr) == 0) { /* default to 1 year lifetime */ *ltime = SECSPERDAY * DAYSPERNYEAR; return (0); } (void) memset(timetok, 0, sizeof (timetok)); if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2) return (-1); if (strcasecmp(timetok, "day") == 0|| strcasecmp(timetok, "days") == 0) { *ltime = num * SECSPERDAY; } else if (strcasecmp(timetok, "hour") == 0|| strcasecmp(timetok, "hours") == 0) { *ltime = num * SECSPERHOUR; } else if (strcasecmp(timetok, "year") == 0 || strcasecmp(timetok, "years") == 0) { *ltime = num * SECSPERDAY * DAYSPERNYEAR; } else { *ltime = 0; return (-1); } return (0); } int OT2Int(char *objclass) { char *c = NULL; int retval = 0; if (objclass == NULL) return (-1); c = strchr(objclass, ':'); if (c != NULL) { if (strcasecmp(c, ":private") == 0) retval = PK_PRIVATE_OBJ; else if (strcasecmp(c, ":public") == 0) retval = PK_PUBLIC_OBJ; else if (strcasecmp(c, ":both") == 0) retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ; else /* unrecognized option */ return (-1); *c = '\0'; } if (strcasecmp(objclass, "public") == 0) { if (retval) return (-1); return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | PK_PUBKEY_OBJ); } else if (strcasecmp(objclass, "private") == 0) { if (retval) return (-1); return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ); } else if (strcasecmp(objclass, "both") == 0) { if (retval) return (-1); return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ); } else if (strcasecmp(objclass, "cert") == 0) { return (retval | PK_CERT_OBJ); } else if (strcasecmp(objclass, "key") == 0) { if (retval == 0) /* return all keys */ return (retval | PK_KEY_OBJ); else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ)) /* return all keys */ return (retval | PK_KEY_OBJ); else if (retval & PK_PUBLIC_OBJ) /* Only return public keys */ return (retval | PK_PUBKEY_OBJ); else if (retval & PK_PRIVATE_OBJ) /* Only return private keys */ return (retval | PK_PRIKEY_OBJ); } else if (strcasecmp(objclass, "crl") == 0) { if (retval) return (-1); return (retval | PK_CRL_OBJ); } if (retval == 0) /* No matches found */ retval = -1; return (retval); } KMF_ENCODE_FORMAT Str2Format(char *formstr) { if (formstr == NULL || strcasecmp(formstr, "der") == 0) return (KMF_FORMAT_ASN1); if (strcasecmp(formstr, "pem") == 0) return (KMF_FORMAT_PEM); if (strcasecmp(formstr, "pkcs12") == 0) return (KMF_FORMAT_PKCS12); if (strcasecmp(formstr, "raw") == 0) return (KMF_FORMAT_RAWKEY); return (KMF_FORMAT_UNDEF); } KMF_RETURN select_token(void *kmfhandle, char *token, int readonly) { KMF_ATTRIBUTE attlist[10]; int i = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_RETURN rv = KMF_OK; if (token == NULL) return (KMF_ERR_BAD_PARAMETER); kmf_set_attr_at_index(attlist, i, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); i++; if (token) { kmf_set_attr_at_index(attlist, i, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); i++; } kmf_set_attr_at_index(attlist, i, KMF_READONLY_ATTR, &readonly, sizeof (readonly)); i++; rv = kmf_configure_keystore(kmfhandle, i, attlist); if (rv == KMF_ERR_TOKEN_SELECTED) rv = KMF_OK; return (rv); } KMF_RETURN configure_nss(void *kmfhandle, char *dir, char *prefix) { KMF_ATTRIBUTE attlist[10]; int i = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; KMF_RETURN rv = KMF_OK; kmf_set_attr_at_index(attlist, i, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); i++; if (dir) { kmf_set_attr_at_index(attlist, i, KMF_DIRPATH_ATTR, dir, strlen(dir)); i++; } if (prefix) { kmf_set_attr_at_index(attlist, i, KMF_CERTPREFIX_ATTR, prefix, strlen(prefix)); i++; kmf_set_attr_at_index(attlist, i, KMF_KEYPREFIX_ATTR, prefix, strlen(prefix)); i++; } rv = kmf_configure_keystore(kmfhandle, i, attlist); if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED) rv = KMF_OK; return (rv); } KMF_RETURN get_pk12_password(KMF_CREDENTIAL *cred) { KMF_RETURN rv = KMF_OK; char prompt[1024]; /* * Get the password to use for the PK12 encryption. */ (void) strlcpy(prompt, gettext("Enter password to use for " "accessing the PKCS12 file: "), sizeof (prompt)); if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, (ulong_t *)&cred->credlen) != CKR_OK) { cred->cred = NULL; cred->credlen = 0; } return (rv); } #define FILENAME_PROMPT gettext("Filename:") #define FILENAME_MINLEN 1 #define FILENAME_MAXLEN MAXPATHLEN #define COUNTRY_PROMPT gettext("Country Name (2 letter code) [US]:") #define STATE_PROMPT gettext("State or Province Name (full name) " \ "[Some-State]:") #define LOCALITY_PROMPT gettext("Locality Name (eg, city) []:") #define ORG_PROMPT gettext("Organization Name (eg, company) []:") #define UNIT_PROMPT gettext("Organizational Unit Name (eg, section) []:") #define NAME_PROMPT gettext("Common Name (eg, YOUR name) []:") #define EMAIL_PROMPT gettext("Email Address []:") #define SERNO_PROMPT gettext("Serial Number (hex value, example: " \ "0x01020304):") #define SERNO_MINLEN 3 #define SERNO_MAXLEN 42 #define LABEL_PROMPT gettext("Enter a label for the certificate:") #define LABEL_MINLEN 1 #define LABEL_MAXLEN 1024 #define COUNTRY_DEFAULT "US" #define STATE_DEFAULT NULL #define INVALID_INPUT gettext("Invalid input; please re-enter ...") #define SUBNAMESIZ 1024 #define RDN_MIN 1 #define RDN_MAX 64 #define COUNTRYNAME_MIN 2 #define COUNTRYNAME_MAX 2 static char * get_input_string(char *prompt, char *default_str, int min_len, int max_len) { char buf[1024]; char *response = NULL; char *ret = NULL; int len; for (;;) { (void) printf("\t%s", prompt); (void) fflush(stdout); response = fgets(buf, sizeof (buf), stdin); if (response == NULL) { if (default_str != NULL) { ret = strdup(default_str); } break; } /* Skip any leading white space. */ while (isspace(*response)) response++; if (*response == '\0') { if (default_str != NULL) { ret = strdup(default_str); } break; } len = strlen(response); response[len-1] = '\0'; /* get rid of "LF" */ len--; if (len >= min_len && len <= max_len) { ret = strdup(response); break; } (void) printf("%s\n", INVALID_INPUT); } return (ret); } int get_filename(char *txt, char **result) { char prompt[1024]; char *fname = NULL; (void) snprintf(prompt, sizeof (prompt), gettext("Enter filename for the %s: "), txt); fname = get_input_string(prompt, NULL, FILENAME_MINLEN, FILENAME_MAXLEN); *result = fname; return (0); } int get_certlabel(char **result) { char *label = NULL; label = get_input_string(LABEL_PROMPT, NULL, LABEL_MINLEN, LABEL_MAXLEN); *result = label; return (0); } int get_serial(char **result) { char *serial = NULL; serial = get_input_string(SERNO_PROMPT, NULL, SERNO_MINLEN, SERNO_MAXLEN); *result = serial; return (0); } int get_subname(char **result) { char *country = NULL; char *state = NULL; char *locality = NULL; char *org = NULL; char *unit = NULL; char *name = NULL; char *email = NULL; char *subname = NULL; (void) printf("Entering following fields for subject (a DN) ...\n"); country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT, COUNTRYNAME_MIN, COUNTRYNAME_MAX); if (country == NULL) return (-1); state = get_input_string(STATE_PROMPT, STATE_DEFAULT, RDN_MIN, RDN_MAX); locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX); org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX); unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX); name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX); email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX); /* Now create a subject name from the input strings */ if ((subname = malloc(SUBNAMESIZ)) == NULL) goto out; (void) memset(subname, 0, SUBNAMESIZ); (void) strlcpy(subname, "C=", SUBNAMESIZ); (void) strlcat(subname, country, SUBNAMESIZ); if (state != NULL) { (void) strlcat(subname, ", ST=", SUBNAMESIZ); (void) strlcat(subname, state, SUBNAMESIZ); } if (locality != NULL) { (void) strlcat(subname, ", L=", SUBNAMESIZ); (void) strlcat(subname, locality, SUBNAMESIZ); } if (org != NULL) { (void) strlcat(subname, ", O=", SUBNAMESIZ); (void) strlcat(subname, org, SUBNAMESIZ); } if (unit != NULL) { (void) strlcat(subname, ", OU=", SUBNAMESIZ); (void) strlcat(subname, unit, SUBNAMESIZ); } if (name != NULL) { (void) strlcat(subname, ", CN=", SUBNAMESIZ); (void) strlcat(subname, name, SUBNAMESIZ); } if (email != NULL) { (void) strlcat(subname, ", E=", SUBNAMESIZ); (void) strlcat(subname, email, SUBNAMESIZ); } out: if (country) free(country); if (state) free(state); if (locality) free(locality); if (org) free(org); if (unit) free(unit); if (name) free(name); if (email) free(email); if (subname == NULL) return (-1); else { *result = subname; return (0); } } /* * Parse a string of KeyUsage values and convert * them to the correct KU Bits. * The field may be marked "critical" by prepending * "critical:" to the list. * EX: critical:digitialSignature,keyEncipherment */ KMF_RETURN verify_keyusage(char *kustr, uint16_t *kubits, int *critical) { KMF_RETURN ret = KMF_OK; uint16_t kuval; char *k; *kubits = 0; if (kustr == NULL || strlen(kustr) == 0) return (KMF_ERR_BAD_PARAMETER); /* Check to see if this is critical */ if (strncasecmp(kustr, "critical:", strlen("critical:")) == 0) { *critical = TRUE; kustr += strlen("critical:"); } else { *critical = FALSE; } k = strtok(kustr, ","); while (k != NULL) { kuval = kmf_string_to_ku(k); if (kuval == 0) { *kubits = 0; return (KMF_ERR_BAD_PARAMETER); } *kubits |= kuval; k = strtok(NULL, ","); } return (ret); } /* * Verify the alternate subject label is real or invalid. * * The field may be marked "critical" by prepending * "critical:" to the list. * EX: "critical:IP=1.2.3.4" */ KMF_RETURN verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical) { char *p; KMF_RETURN rv = KMF_OK; /* Check to see if this is critical */ if (strncasecmp(arg, "critical:", strlen("critical:")) == 0) { *critical = TRUE; arg += strlen("critical:"); } else { *critical = FALSE; } /* Make sure there is an "=" sign */ p = strchr(arg, '='); if (p == NULL) return (KMF_ERR_BAD_PARAMETER); p[0] = '\0'; if (strcmp(arg, "IP") == 0) *type = GENNAME_IPADDRESS; else if (strcmp(arg, "DNS") == 0) *type = GENNAME_DNSNAME; else if (strcmp(arg, "EMAIL") == 0) *type = GENNAME_RFC822NAME; else if (strcmp(arg, "URI") == 0) *type = GENNAME_URI; else if (strcmp(arg, "DN") == 0) *type = GENNAME_DIRECTORYNAME; else if (strcmp(arg, "RID") == 0) *type = GENNAME_REGISTEREDID; else if (strcmp(arg, "KRB") == 0) *type = GENNAME_KRB5PRINC; else if (strcmp(arg, "UPN") == 0) *type = GENNAME_SCLOGON_UPN; else rv = KMF_ERR_BAD_PARAMETER; p[0] = '='; return (rv); } int get_token_password(KMF_KEYSTORE_TYPE kstype, char *token_spec, KMF_CREDENTIAL *cred) { char prompt[1024]; char temptoken[32]; char *p = NULL; char *t = NULL; int len; (void) memset(temptoken, 0, sizeof (temptoken)); if (kstype == KMF_KEYSTORE_PK11TOKEN) { p = strchr(token_spec, ':'); if (p != NULL) *p = 0; } len = strlen(token_spec); if (len > sizeof (temptoken)) len = sizeof (temptoken); (void) strncpy(temptoken, token_spec, len); /* * Strip trailing whitespace */ t = temptoken + (len - 1); while (isspace(*t) && t >= temptoken) { *t = 0x00; t--; } /* * Login to the token first. */ (void) snprintf(prompt, sizeof (prompt), gettext(DEFAULT_TOKEN_PROMPT), temptoken); if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, (ulong_t *)&cred->credlen) != CKR_OK) { cred->cred = NULL; cred->credlen = 0; } if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL) *p = ':'; return (KMF_OK); } KMF_RETURN verify_file(char *filename) { KMF_RETURN ret = KMF_OK; int fd; /* * Attempt to open with the EXCL flag so that if * it already exists, the open will fail. It will * also fail if the file cannot be created due to * permissions on the parent directory, or if the * parent directory itself does not exist. */ fd = open(filename, O_CREAT | O_EXCL, 0600); if (fd == -1) { if (errno == EEXIST) return (KMF_ERR_OPEN_FILE); else return (KMF_ERR_WRITE_FILE); } /* If we were able to create it, delete it. */ (void) close(fd); (void) unlink(filename); return (ret); } void display_error(void *handle, KMF_RETURN errcode, char *prefix) { KMF_RETURN rv1, rv2; char *plugin_errmsg = NULL; char *kmf_errmsg = NULL; rv1 = kmf_get_plugin_error_str(handle, &plugin_errmsg); rv2 = kmf_get_kmf_error_str(errcode, &kmf_errmsg); cryptoerror(LOG_STDERR, "%s:", prefix); if (rv1 == KMF_OK && plugin_errmsg) { cryptoerror(LOG_STDERR, gettext("keystore error: %s"), plugin_errmsg); kmf_free_str(plugin_errmsg); } if (rv2 == KMF_OK && kmf_errmsg) { cryptoerror(LOG_STDERR, gettext("libkmf error: %s"), kmf_errmsg); kmf_free_str(kmf_errmsg); } if (rv1 != KMF_OK && rv2 != KMF_OK) cryptoerror(LOG_STDERR, gettext("\n")); } static KMF_RETURN addToEKUList(EKU_LIST *ekus, int critical, KMF_OID *newoid) { if (newoid != NULL && ekus != NULL) { ekus->eku_count++; ekus->critlist = realloc(ekus->critlist, ekus->eku_count * sizeof (int)); if (ekus->critlist != NULL) ekus->critlist[ekus->eku_count-1] = critical; else return (KMF_ERR_MEMORY); ekus->ekulist = realloc( ekus->ekulist, ekus->eku_count * sizeof (KMF_OID)); if (ekus->ekulist != NULL) ekus->ekulist[ekus->eku_count-1] = *newoid; else return (KMF_ERR_MEMORY); } return (KMF_OK); } void free_eku_list(EKU_LIST *ekus) { if (ekus != NULL && ekus->eku_count > 0) { int i; for (i = 0; i < ekus->eku_count; i++) { kmf_free_data(&ekus->ekulist[i]); } free(ekus->ekulist); free(ekus->critlist); free(ekus); } } static KMF_RETURN parse_ekus(char *ekustr, EKU_LIST *ekus) { KMF_RETURN rv = KMF_OK; KMF_OID *newoid; int critical; if (strncasecmp(ekustr, "critical:", strlen("critical:")) == 0) { critical = TRUE; ekustr += strlen("critical:"); } else { critical = FALSE; } newoid = kmf_ekuname_to_oid(ekustr); if (newoid != NULL) { rv = addToEKUList(ekus, critical, newoid); free(newoid); } else { rv = PK_ERR_USAGE; } return (rv); } KMF_RETURN verify_ekunames(char *ekuliststr, EKU_LIST **ekulist) { KMF_RETURN rv = KMF_OK; char *p; EKU_LIST *ekus = NULL; if (ekuliststr == NULL || strlen(ekuliststr) == 0) return (0); ekus = calloc(sizeof (EKU_LIST), 1); if (ekus == NULL) return (KMF_ERR_MEMORY); /* * The list should be comma separated list of EKU Names. */ p = strtok(ekuliststr, ","); /* If no tokens found, then maybe it's just a single EKU value */ if (p == NULL) { rv = parse_ekus(ekuliststr, ekus); } while (p != NULL) { rv = parse_ekus(p, ekus); if (rv != KMF_OK) break; p = strtok(NULL, ","); } if (rv != KMF_OK) free_eku_list(ekus); else *ekulist = ekus; return (rv); } KMF_RETURN token_auth_needed(KMF_HANDLE_T handle, char *tokenlabel, int *auth) { CK_TOKEN_INFO info; CK_SLOT_ID slot; CK_RV ckrv; KMF_RETURN rv; *auth = 0; rv = kmf_pk11_token_lookup(handle, tokenlabel, &slot); if (rv != KMF_OK) return (rv); ckrv = C_GetTokenInfo(slot, &info); if (ckrv != KMF_OK) return (KMF_ERR_INTERNAL); *auth = (info.flags & CKF_LOGIN_REQUIRED); return (KMF_OK); } void show_ecc_curves() { int i; (void) printf(gettext("Supported ECC curve names:\n")); for (i = 0; i < number_of_curves; i++) { (void) printf("%s", oid_table[i].name); if (i > 0 && ((i+1) % 5) == 0) (void) printf("\n"); else if (i+1 < number_of_curves) (void) printf(", "); } (void) printf("\n"); } KMF_OID * ecc_name_to_oid(char *name) { int i; for (i = 0; i < number_of_oids; i++) { if (strcasecmp(name, oid_table[i].name) == 0) return ((KMF_OID *)oid_table[i].oid); } return (NULL); } /* * 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 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _PKTOOL_COMMON_H #define _PKTOOL_COMMON_H /* * This file contains data and functions shared between all the * modules that comprise this tool. */ #ifdef __cplusplus extern "C" { #endif #include /* I18N helpers. */ #include #include #include #include /* Defines used throughout */ /* Error codes */ #define PK_ERR_NONE 0 #define PK_ERR_USAGE 1 #define PK_ERR_QUIT 2 #define PK_ERR_PK11 3 #define PK_ERR_SYSTEM 4 #define PK_ERR_OPENSSL 5 #define PK_ERR_NSS 6 /* Types of objects for searches. */ #define PK_PRIVATE_OBJ 0x0001 #define PK_PUBLIC_OBJ 0x0002 #define PK_CERT_OBJ 0x0010 #define PK_PRIKEY_OBJ 0x0020 #define PK_PUBKEY_OBJ 0x0040 #define PK_SYMKEY_OBJ 0x0080 #define PK_CRL_OBJ 0x0100 #define PK_KEY_OBJ (PK_PRIKEY_OBJ | PK_PUBKEY_OBJ | PK_SYMKEY_OBJ) #define PK_ALL_OBJ (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ |\ PK_CERT_OBJ| PK_CRL_OBJ | PK_KEY_OBJ) #define PK_DEFAULT_KEYTYPE "rsa" #define PK_DEFAULT_KEYLENGTH 2048 #define PK_DEFAULT_DIRECTORY "." #define PK_DEFAULT_SERIALNUM 1 #define PK_DEFAULT_PK11TOKEN SOFT_TOKEN_LABEL /* Constants for attribute templates. */ extern CK_BBOOL pk_false; extern CK_BBOOL pk_true; typedef struct { int eku_count; int *critlist; KMF_OID *ekulist; } EKU_LIST; /* Common functions. */ extern void final_pk11(CK_SESSION_HANDLE sess); extern CK_RV login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess); extern CK_RV quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess); extern CK_RV get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen); extern boolean_t yesno(char *prompt, char *invalid, boolean_t dflt); extern CK_RV get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count); extern int get_subname(char **); extern int get_serial(char **); extern int get_certlabel(char **); extern int get_filename(char *, char **); extern int getopt_av(int argc, char * const argv[], const char *optstring); extern char *optarg_av; extern int optind_av; int OT2Int(char *); int PK2Int(char *); KMF_KEYSTORE_TYPE KS2Int(char *); int Str2KeyType(char *, KMF_OID *, KMF_KEY_ALG *, KMF_ALGORITHM_INDEX *); int Str2SymKeyType(char *, KMF_KEY_ALG *); int Str2Lifetime(char *, uint32_t *); KMF_RETURN select_token(void *, char *, int); KMF_RETURN configure_nss(void *, char *, char *); KMF_ENCODE_FORMAT Str2Format(char *); KMF_RETURN get_pk12_password(KMF_CREDENTIAL *); KMF_RETURN hexstring2bytes(uchar_t *, uchar_t **, size_t *); KMF_RETURN verify_altname(char *arg, KMF_GENERALNAMECHOICES *, int *); KMF_RETURN verify_keyusage(char *arg, uint16_t *, int *); KMF_RETURN verify_file(char *); KMF_RETURN verify_ekunames(char *, EKU_LIST **); KMF_RETURN token_auth_needed(KMF_HANDLE_T, char *, int *); KMF_OID *ecc_name_to_oid(char *); void show_ecc_curves(); KMF_RETURN genkeypair_pkcs11(KMF_HANDLE_T, char *, char *, KMF_KEY_ALG, int, KMF_CREDENTIAL *, KMF_OID *, KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); KMF_RETURN genkeypair_file(KMF_HANDLE_T, KMF_KEY_ALG, int, KMF_ENCODE_FORMAT, char *, KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); KMF_RETURN genkeypair_nss(KMF_HANDLE_T, char *, char *, char *, char *, KMF_KEY_ALG, int, KMF_CREDENTIAL *, KMF_OID *, KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); void free_eku_list(EKU_LIST *); int yn_to_int(char *); int get_token_password(KMF_KEYSTORE_TYPE, char *, KMF_CREDENTIAL *); void display_error(void *, KMF_RETURN, char *); #define DEFAULT_NSS_TOKEN "internal" #define DEFAULT_TOKEN_PROMPT "Enter PIN for %s: " #define EMPTYSTRING(s) (s == NULL || !strlen((char *)s)) /* * The "dir" option is only valid with the NSS keystore. This check * forces PK_ERR_USAGE when it is used with non-NSS keystore. */ #define DIR_OPTION_CHECK(k, d) \ if (k != KMF_KEYSTORE_NSS && d != NULL) { \ cryptoerror(LOG_STDERR, gettext("The 'dir' option is " \ "not supported with the indicated keystore\n")); \ return (PK_ERR_USAGE); \ } #ifdef __cplusplus } #endif #endif /* _PKTOOL_COMMON_H */ /* * 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. * Copyright 2012 Milan Jurik. All rights reserved. * Copyright 2017 Toomas Soome */ /* * This file implements the token object delete operation for this tool. * It loads the PKCS#11 modules, finds the object to delete, deletes it, * and cleans up. User must be R/W logged into the token. */ #include #include #include #include #include "common.h" #include static KMF_RETURN pk_destroy_keys(void *handle, KMF_ATTRIBUTE *attrlist, int numattr) { int i; KMF_RETURN rv = KMF_OK; uint32_t *numkeys; KMF_KEY_HANDLE *keys = NULL; int del_num = 0; KMF_ATTRIBUTE delete_attlist[16]; KMF_KEYSTORE_TYPE kstype; uint32_t len; boolean_t destroy = B_TRUE; KMF_CREDENTIAL cred; char *slotlabel = NULL; len = sizeof (kstype); rv = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr, &kstype, &len); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(delete_attlist, del_num, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); del_num++; /* "destroy" is optional. Default is TRUE */ (void) kmf_get_attr(KMF_DESTROY_BOOL_ATTR, attrlist, numattr, (void *)&destroy, NULL); kmf_set_attr_at_index(delete_attlist, del_num, KMF_DESTROY_BOOL_ATTR, &destroy, sizeof (boolean_t)); del_num++; switch (kstype) { case KMF_KEYSTORE_NSS: rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr, (void *)&cred, NULL); if (rv == KMF_OK) { if (cred.credlen > 0) { kmf_set_attr_at_index(delete_attlist, del_num, KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL)); del_num++; } } slotlabel = kmf_get_attr_ptr(KMF_TOKEN_LABEL_ATTR, attrlist, numattr); if (slotlabel != NULL) { kmf_set_attr_at_index(delete_attlist, del_num, KMF_TOKEN_LABEL_ATTR, slotlabel, strlen(slotlabel)); del_num++; } break; case KMF_KEYSTORE_OPENSSL: break; case KMF_KEYSTORE_PK11TOKEN: rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr, (void *)&cred, NULL); if (rv == KMF_OK) { if (cred.credlen > 0) { kmf_set_attr_at_index(delete_attlist, del_num, KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL)); del_num++; } } break; default: return (PK_ERR_USAGE); } numkeys = kmf_get_attr_ptr(KMF_COUNT_ATTR, attrlist, numattr); if (numkeys == NULL) return (PK_ERR_USAGE); keys = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr); if (keys == NULL) return (PK_ERR_USAGE); for (i = 0; rv == KMF_OK && i < *numkeys; i++) { int num = del_num; kmf_set_attr_at_index(delete_attlist, num, KMF_KEY_HANDLE_ATTR, &keys[i], sizeof (KMF_KEY_HANDLE)); num++; rv = kmf_delete_key_from_keystore(handle, num, delete_attlist); } return (rv); } static KMF_RETURN pk_delete_keys(KMF_HANDLE_T kmfhandle, KMF_ATTRIBUTE *attlist, int numattr, char *desc, int *keysdeleted) { KMF_RETURN rv = KMF_OK; uint32_t numkeys = 0; int num = numattr; *keysdeleted = 0; numkeys = 0; kmf_set_attr_at_index(attlist, num, KMF_COUNT_ATTR, &numkeys, sizeof (uint32_t)); num++; rv = kmf_find_key(kmfhandle, num, attlist); if (rv == KMF_OK && numkeys > 0) { KMF_KEY_HANDLE *keys = NULL; char prompt[1024]; (void) snprintf(prompt, sizeof (prompt), gettext("%d %s key(s) found, do you want " "to delete them (y/N) ?"), numkeys, (desc != NULL ? desc : "")); if (!yesno(prompt, gettext("Respond with yes or no.\n"), B_FALSE)) { *keysdeleted = numkeys; return (KMF_OK); } keys = (KMF_KEY_HANDLE *)malloc(numkeys * sizeof (KMF_KEY_HANDLE)); if (keys == NULL) return (KMF_ERR_MEMORY); (void) memset(keys, 0, numkeys * sizeof (KMF_KEY_HANDLE)); kmf_set_attr_at_index(attlist, num, KMF_KEY_HANDLE_ATTR, keys, sizeof (KMF_KEY_HANDLE)); num++; rv = kmf_find_key(kmfhandle, num, attlist); if (rv == KMF_OK) { rv = pk_destroy_keys(kmfhandle, attlist, num); } free(keys); } *keysdeleted = numkeys; return (rv); } static KMF_RETURN pk_delete_certs(KMF_HANDLE_T kmfhandle, KMF_ATTRIBUTE *attlist, int numattr) { KMF_RETURN rv = KMF_OK; uint32_t numcerts = 0; int num = numattr; kmf_set_attr_at_index(attlist, num, KMF_COUNT_ATTR, &numcerts, sizeof (uint32_t)); num++; rv = kmf_find_cert(kmfhandle, num, attlist); if (rv == KMF_OK && numcerts > 0) { char prompt[1024]; (void) snprintf(prompt, sizeof (prompt), gettext("%d certificate(s) found, do you want " "to delete them (y/N) ?"), numcerts); if (!yesno(prompt, gettext("Respond with yes or no.\n"), B_FALSE)) { return (KMF_OK); } /* * Use numattr because delete cert does not require * KMF_COUNT_ATTR attribute. */ rv = kmf_delete_cert_from_keystore(kmfhandle, numattr, attlist); } return (rv); } static KMF_RETURN delete_nss_keys(KMF_HANDLE_T kmfhandle, char *dir, char *prefix, char *token, int oclass, char *objlabel, KMF_CREDENTIAL *tokencred) { KMF_RETURN rv = KMF_OK; char *keytype = NULL; int nk, numkeys = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_CLASS keyclass; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } if (tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } if (token && strlen(token)) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } if (oclass & PK_PRIKEY_OBJ) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; keytype = "private"; rv = pk_delete_keys(kmfhandle, attrlist, num, keytype, &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_PRIKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; keytype = "symmetric"; rv = pk_delete_keys(kmfhandle, attrlist, num, keytype, &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_SYMKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { int num = numattr; keyclass = KMF_ASYM_PUB; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; keytype = "public"; rv = pk_delete_keys(kmfhandle, attrlist, num, keytype, &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_PUBKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && numkeys == 0) rv = KMF_ERR_KEY_NOT_FOUND; return (rv); } static KMF_RETURN delete_nss_certs(KMF_HANDLE_T kmfhandle, char *dir, char *prefix, char *token, char *objlabel, KMF_BIGINT *serno, char *issuer, char *subject, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serno != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serno, sizeof (KMF_BIGINT)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; if (token != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } rv = pk_delete_certs(kmfhandle, attrlist, numattr); return (rv); } static KMF_RETURN delete_nss_crl(void *kmfhandle, char *dir, char *prefix, char *token, char *issuer, char *subject) { KMF_RETURN rv = KMF_OK; int numattr = 0; KMF_ATTRIBUTE attrlist[8]; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (token != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } rv = kmf_delete_crl(kmfhandle, numattr, attrlist); return (rv); } static KMF_RETURN delete_pk11_keys(KMF_HANDLE_T kmfhandle, char *token, int oclass, char *objlabel, KMF_CREDENTIAL *tokencred) { KMF_RETURN rv = KMF_OK; int nk, numkeys = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_CLASS keyclass; boolean_t token_bool = B_TRUE; boolean_t private; /* * Symmetric keys and RSA/DSA private keys are always * created with the "CKA_PRIVATE" field == TRUE, so * make sure we search for them with it also set. */ if (oclass & (PK_SYMKEY_OBJ | PK_PRIKEY_OBJ)) oclass |= PK_PRIVATE_OBJ; rv = select_token(kmfhandle, token, FALSE); if (rv != KMF_OK) { return (rv); } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } private = ((oclass & PK_PRIVATE_OBJ) > 0); kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVATE_BOOL_ATTR, &private, sizeof (private)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR, &token_bool, sizeof (token_bool)); numattr++; if (oclass & PK_PRIKEY_OBJ) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; rv = pk_delete_keys(kmfhandle, attrlist, num, "private", &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_PRIKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; rv = pk_delete_keys(kmfhandle, attrlist, num, "symmetric", &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_SYMKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { int num = numattr; private = B_FALSE; keyclass = KMF_ASYM_PUB; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; rv = pk_delete_keys(kmfhandle, attrlist, num, "public", &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && oclass != PK_PUBKEY_OBJ) rv = KMF_OK; } if (rv == KMF_OK && numkeys == 0) rv = KMF_ERR_KEY_NOT_FOUND; return (rv); } static KMF_RETURN delete_pk11_certs(KMF_HANDLE_T kmfhandle, char *token, char *objlabel, KMF_BIGINT *serno, char *issuer, char *subject, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN kmfrv; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; kmfrv = select_token(kmfhandle, token, FALSE); if (kmfrv != KMF_OK) { return (kmfrv); } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serno != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serno, sizeof (KMF_BIGINT)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; kmfrv = pk_delete_certs(kmfhandle, attrlist, numattr); return (kmfrv); } static KMF_RETURN delete_file_certs(KMF_HANDLE_T kmfhandle, char *dir, char *filename, KMF_BIGINT *serial, char *issuer, char *subject, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN rv; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } if (filename != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; rv = pk_delete_certs(kmfhandle, attrlist, numattr); return (rv); } static KMF_RETURN delete_file_keys(KMF_HANDLE_T kmfhandle, int oclass, char *dir, char *infile) { KMF_RETURN rv = KMF_OK; char *keytype = ""; int nk, numkeys = 0; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_CLASS keyclass; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } if (infile != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, infile, strlen(infile)); numattr++; } if (oclass & (PK_PUBKEY_OBJ | PK_PRIKEY_OBJ)) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; keytype = "Asymmetric"; rv = pk_delete_keys(kmfhandle, attrlist, num, keytype, &nk); numkeys += nk; } if (oclass & PK_SYMKEY_OBJ) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; keytype = "symmetric"; rv = pk_delete_keys(kmfhandle, attrlist, num, keytype, &nk); numkeys += nk; if (rv == KMF_ERR_KEY_NOT_FOUND && numkeys > 0) rv = KMF_OK; } if (rv == KMF_OK && numkeys == 0) rv = KMF_ERR_KEY_NOT_FOUND; return (rv); } static KMF_RETURN delete_file_crl(void *kmfhandle, char *filename) { KMF_RETURN rv; int numattr = 0; KMF_ATTRIBUTE attrlist[4]; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; if (filename == NULL || strlen(filename) == 0) return (KMF_ERR_BAD_PARAMETER); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (filename) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_FILENAME_ATTR, filename, strlen(filename)); numattr++; } rv = kmf_delete_crl(kmfhandle, numattr, attrlist); return (rv); } /* * Delete token objects. */ int pk_delete(int argc, char *argv[]) { int opt; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *subject = NULL; char *issuer = NULL; char *dir = NULL; char *prefix = NULL; char *infile = NULL; char *object_label = NULL; char *serstr = NULL; int oclass = 0; KMF_BIGINT serial = { NULL, 0 }; KMF_HANDLE_T kmfhandle = NULL; KMF_KEYSTORE_TYPE kstype = 0; KMF_RETURN kmfrv, keyrv, certrv, crlrv; int rv = 0; char *find_criteria = NULL; KMF_CERT_VALIDITY find_criteria_flag = KMF_ALL_CERTS; KMF_CREDENTIAL tokencred = { NULL, 0 }; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "T:(token)y:(objtype)l:(label)" "k:(keystore)s:(subject)n:(nickname)" "d:(dir)p:(prefix)S:(serial)i:(issuer)" "c:(criteria)" "f:(infile)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = optarg_av; break; case 'y': /* object type: public, private, both */ if (oclass) return (PK_ERR_USAGE); oclass = OT2Int(optarg_av); if (oclass == -1) return (PK_ERR_USAGE); break; case 'l': /* objects with specific label */ case 'n': if (object_label) return (PK_ERR_USAGE); object_label = (char *)optarg_av; break; case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 's': subject = optarg_av; break; case 'i': issuer = optarg_av; break; case 'd': dir = optarg_av; break; case 'p': prefix = optarg_av; break; case 'S': serstr = optarg_av; break; case 'f': infile = optarg_av; break; case 'c': find_criteria = optarg_av; if (!strcasecmp(find_criteria, "valid")) find_criteria_flag = KMF_NONEXPIRED_CERTS; else if (!strcasecmp(find_criteria, "expired")) find_criteria_flag = KMF_EXPIRED_CERTS; else if (!strcasecmp(find_criteria, "both")) find_criteria_flag = KMF_ALL_CERTS; else return (PK_ERR_USAGE); break; default: return (PK_ERR_USAGE); } } /* Assume keystore = PKCS#11 if not specified */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && kstype != KMF_KEYSTORE_PK11TOKEN) { (void) fprintf(stderr, gettext("The objtype parameter " "is only relevant if keystore=pkcs11\n")); return (PK_ERR_USAGE); } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) return (PK_ERR_USAGE); /* Done parsing command line options. */ DIR_OPTION_CHECK(kstype, dir); if (kstype == KMF_KEYSTORE_PK11TOKEN && token_spec == NULL) { token_spec = PK_DEFAULT_PK11TOKEN; } else if (kstype == KMF_KEYSTORE_NSS && token_spec == NULL) { token_spec = DEFAULT_NSS_TOKEN; } if (serstr != NULL) { uchar_t *bytes = NULL; size_t bytelen; rv = kmf_hexstr_to_bytes((uchar_t *)serstr, &bytes, &bytelen); if (rv != KMF_OK || bytes == NULL) { (void) fprintf(stderr, gettext("serial number " "must be specified as a hex number " "(ex: 0x0102030405ffeeddee)\n")); return (PK_ERR_USAGE); } serial.val = bytes; serial.len = bytelen; /* If serial number was given, it must be a cert search */ if (oclass == 0) oclass = PK_CERT_OBJ; } /* * If no object type was given but subject or issuer was, * it must be a certificate we are looking to delete. */ if ((issuer != NULL || subject != NULL) && oclass == 0) oclass = PK_CERT_OBJ; /* If no object class specified, delete everything but CRLs */ if (oclass == 0) oclass = PK_CERT_OBJ | PK_KEY_OBJ; if ((kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS) && (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ))) { (void) get_token_password(kstype, token_spec, &tokencred); } if ((kmfrv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) return (kmfrv); keyrv = certrv = crlrv = KMF_OK; switch (kstype) { case KMF_KEYSTORE_PK11TOKEN: if (oclass & PK_KEY_OBJ) { keyrv = delete_pk11_keys(kmfhandle, token_spec, oclass, object_label, &tokencred); /* * If deleting groups of objects, it is OK * to ignore the "key not found" case so that * we can continue to find other objects. */ if (keyrv != KMF_OK && keyrv != KMF_ERR_KEY_NOT_FOUND) break; } if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { certrv = delete_pk11_certs(kmfhandle, token_spec, object_label, &serial, issuer, subject, find_criteria_flag); /* * If cert delete failed, but we are looking at * other objects, then it is OK. */ if (certrv != KMF_OK && certrv != KMF_ERR_CERT_NOT_FOUND) break; } if (oclass & PK_CRL_OBJ) crlrv = delete_file_crl(kmfhandle, infile); break; case KMF_KEYSTORE_NSS: keyrv = certrv = crlrv = KMF_OK; if (oclass & PK_KEY_OBJ) { keyrv = delete_nss_keys(kmfhandle, dir, prefix, token_spec, oclass, (char *)object_label, &tokencred); if (keyrv != KMF_OK && keyrv != KMF_ERR_KEY_NOT_FOUND) break; } if (oclass & PK_CERT_OBJ) { certrv = delete_nss_certs(kmfhandle, dir, prefix, token_spec, (char *)object_label, &serial, issuer, subject, find_criteria_flag); if (certrv != KMF_OK && certrv != KMF_ERR_CERT_NOT_FOUND) break; } if (oclass & PK_CRL_OBJ) crlrv = delete_nss_crl(kmfhandle, dir, prefix, token_spec, (char *)object_label, subject); break; case KMF_KEYSTORE_OPENSSL: if (oclass & PK_KEY_OBJ) { keyrv = delete_file_keys(kmfhandle, oclass, dir, infile); if (keyrv != KMF_OK) break; } if (oclass & (PK_CERT_OBJ)) { certrv = delete_file_certs(kmfhandle, dir, infile, &serial, issuer, subject, find_criteria_flag); if (certrv != KMF_OK) break; } if (oclass & PK_CRL_OBJ) crlrv = delete_file_crl(kmfhandle, infile); break; default: rv = PK_ERR_USAGE; break; } /* * Logic here: * If searching for more than just one class of object (key or cert) * and only 1 of the classes was not found, it is not an error. * If searching for just one class of object, that failure should * be reported. * * Any error other than "KMF_ERR_[key/cert]_NOT_FOUND" should * be reported either way. */ if (keyrv != KMF_ERR_KEY_NOT_FOUND && keyrv != KMF_OK) kmfrv = keyrv; else if (certrv != KMF_OK && certrv != KMF_ERR_CERT_NOT_FOUND) kmfrv = certrv; else if (crlrv != KMF_OK && crlrv != KMF_ERR_CRL_NOT_FOUND) kmfrv = crlrv; /* * If nothing was found, return error. */ if ((keyrv == KMF_ERR_KEY_NOT_FOUND && (oclass & PK_KEY_OBJ)) && (certrv == KMF_ERR_CERT_NOT_FOUND && (oclass & PK_CERT_OBJ))) kmfrv = KMF_ERR_KEY_NOT_FOUND; if (kmfrv != KMF_OK) goto out; if (keyrv != KMF_OK && (oclass == PK_KEY_OBJ)) kmfrv = keyrv; else if (certrv != KMF_OK && (oclass == PK_CERT_OBJ)) kmfrv = certrv; else if (crlrv != KMF_OK && (oclass == PK_CRL_OBJ)) kmfrv = crlrv; out: if (kmfrv != KMF_OK) { display_error(kmfhandle, kmfrv, gettext("Error deleting objects")); } if (serial.val != NULL) free(serial.val); (void) kmf_finalize(kmfhandle); return (kmfrv); } /* * 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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include "common.h" #include int pk_download(int argc, char *argv[]) { int rv; int opt; extern int optind_av; extern char *optarg_av; int oclass = 0; char *url = NULL; char *http_proxy = NULL; char *dir = NULL; char *outfile = NULL; char *proxy = NULL; int proxy_port = 0; KMF_HANDLE_T kmfhandle = NULL; KMF_ENCODE_FORMAT format; KMF_RETURN ch_rv = KMF_OK; char *fullpath = NULL; KMF_DATA cert = { 0, NULL }; KMF_DATA cert_der = { 0, NULL }; while ((opt = getopt_av(argc, argv, "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 't': if (oclass) return (PK_ERR_USAGE); oclass = OT2Int(optarg_av); if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ))) return (PK_ERR_USAGE); break; case 'u': if (url) return (PK_ERR_USAGE); url = optarg_av; break; case 'h': if (http_proxy) return (PK_ERR_USAGE); http_proxy = optarg_av; break; case 'o': if (outfile) return (PK_ERR_USAGE); outfile = optarg_av; break; case 'd': if (dir) return (PK_ERR_USAGE); dir = optarg_av; break; default: cryptoerror(LOG_STDERR, gettext( "unrecognized download option '%s'\n"), argv[optind_av]); return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) { return (PK_ERR_USAGE); } /* Check the dir and outfile options */ if (outfile == NULL) { /* If outfile is not specified, use the basename of URI */ outfile = basename(url); } fullpath = get_fullpath(dir, outfile); if (fullpath == NULL) { cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile " "option value \n")); return (PK_ERR_USAGE); } /* Check if the file exists and might be overwritten. */ if (verify_file(fullpath) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Warning: file \"%s\" exists, " "will be overwritten."), fullpath); if (yesno(gettext("Continue with download? "), gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { return (0); } } /* URI MUST be specified */ if (url == NULL) { cryptoerror(LOG_STDERR, gettext("A URL must be specified\n")); rv = PK_ERR_USAGE; goto end; } /* * Get the http proxy from the command "http_proxy" option or the * environment variable. The command option has a higher priority. */ if (http_proxy == NULL) http_proxy = getenv("http_proxy"); if (http_proxy != NULL) { char *ptmp = http_proxy; char *proxy_port_s; if (strncasecmp(ptmp, "http://", 7) == 0) ptmp += 7; /* skip the scheme prefix */ proxy = strtok(ptmp, ":"); proxy_port_s = strtok(NULL, "\0"); if (proxy_port_s != NULL) proxy_port = strtol(proxy_port_s, NULL, 0); else proxy_port = 8080; } /* If objtype is not specified, default to CRL */ if (oclass == 0) { oclass = PK_CRL_OBJ; } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); rv = PK_ERR_USAGE; goto end; } /* Now we are ready to download */ if (oclass & PK_CRL_OBJ) { rv = kmf_download_crl(kmfhandle, url, proxy, proxy_port, 30, fullpath, &format); } else if (oclass & PK_CERT_OBJ) { rv = kmf_download_cert(kmfhandle, url, proxy, proxy_port, 30, fullpath, &format); } if (rv != KMF_OK) { switch (rv) { case KMF_ERR_BAD_URI: cryptoerror(LOG_STDERR, gettext("Error in parsing URI\n")); rv = PK_ERR_USAGE; break; case KMF_ERR_OPEN_FILE: cryptoerror(LOG_STDERR, gettext("Error in opening file\n")); rv = PK_ERR_USAGE; break; case KMF_ERR_WRITE_FILE: cryptoerror(LOG_STDERR, gettext("Error in writing file\n")); rv = PK_ERR_USAGE; break; case KMF_ERR_BAD_CRLFILE: cryptoerror(LOG_STDERR, gettext("Not a CRL file\n")); rv = PK_ERR_USAGE; break; case KMF_ERR_BAD_CERTFILE: cryptoerror(LOG_STDERR, gettext("Not a certificate file\n")); rv = PK_ERR_USAGE; break; case KMF_ERR_MEMORY: cryptoerror(LOG_STDERR, gettext("Not enough memory\n")); rv = PK_ERR_SYSTEM; break; default: cryptoerror(LOG_STDERR, gettext("Error in downloading the file.\n")); rv = PK_ERR_SYSTEM; break; } goto end; } /* * If the file is successfully downloaded, we also check the date. * If the downloaded file is outdated, give a warning. */ if (oclass & PK_CRL_OBJ) { ch_rv = kmf_check_crl_date(kmfhandle, fullpath); } else { /* certificate */ ch_rv = kmf_read_input_file(kmfhandle, fullpath, &cert); if (ch_rv != KMF_OK) goto end; if (format == KMF_FORMAT_PEM) { int len; ch_rv = kmf_pem_to_der(cert.Data, cert.Length, &cert_der.Data, &len); if (ch_rv != KMF_OK) goto end; cert_der.Length = (size_t)len; } ch_rv = kmf_check_cert_date(kmfhandle, format == KMF_FORMAT_ASN1 ? &cert : &cert_der); } end: if (ch_rv == KMF_ERR_VALIDITY_PERIOD) { cryptoerror(LOG_STDERR, gettext("Warning: the downloaded file is expired.\n")); } else if (ch_rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Warning: failed to check the validity.\n")); } if (fullpath) free(fullpath); kmf_free_data(&cert); kmf_free_data(&cert_der); (void) kmf_finalize(kmfhandle); return (rv); } /* * 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * This file implements the export operation for this tool. * The basic flow of the process is to find the soft token, * log into it, find the PKCS#11 objects in the soft token * to be exported matching keys with their certificates, export * them to the PKCS#12 file encrypting them with a file password * if desired, and log out. */ #include #include #include #include #include #include "common.h" #include static KMF_RETURN pk_find_export_cert(KMF_HANDLE_T kmfhandle, KMF_ATTRIBUTE *attrlist, int numattr, KMF_X509_DER_CERT *cert) { KMF_RETURN rv = KMF_OK; uint32_t numcerts = 0; numcerts = 0; (void) memset(cert, 0, sizeof (KMF_X509_DER_CERT)); kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &numcerts, sizeof (uint32_t)); numattr++; rv = kmf_find_cert(kmfhandle, numattr, attrlist); if (rv != KMF_OK) { return (rv); } if (numcerts == 0) { cryptoerror(LOG_STDERR, gettext("No matching certificates found.")); return (KMF_ERR_CERT_NOT_FOUND); } else if (numcerts == 1) { kmf_set_attr_at_index(attrlist, numattr, KMF_X509_DER_CERT_ATTR, cert, sizeof (KMF_X509_DER_CERT)); numattr++; rv = kmf_find_cert(kmfhandle, numattr, attrlist); } else if (numcerts > 1) { cryptoerror(LOG_STDERR, gettext("%d certificates found, refine the " "search parameters to eliminate ambiguity\n"), numcerts); return (KMF_ERR_BAD_PARAMETER); } return (rv); } static KMF_RETURN pk_export_file_objects(KMF_HANDLE_T kmfhandle, int oclass, char *issuer, char *subject, KMF_BIGINT *serial, char *infile, char *filename) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT kmfcert; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; /* If searching for public objects or certificates, find certs now */ if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (infile != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, infile, strlen(infile)); numattr++; } rv = pk_find_export_cert(kmfhandle, attrlist, numattr, &kmfcert); if (rv == KMF_OK) { kstype = KMF_KEYSTORE_OPENSSL; numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &kmfcert.certificate, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); numattr++; rv = kmf_store_cert(kmfhandle, numattr, attrlist); kmf_free_kmf_cert(kmfhandle, &kmfcert); } } return (rv); } static KMF_RETURN pk_export_pk12_nss(KMF_HANDLE_T kmfhandle, char *token_spec, char *dir, char *prefix, char *certlabel, char *issuer, char *subject, KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred, char *filename) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype; KMF_CREDENTIAL p12cred = { NULL, 0 }; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); if (token_spec == NULL) token_spec = DEFAULT_NSS_TOKEN; kstype = KMF_KEYSTORE_NSS; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (certlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (tokencred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; (void) get_pk12_password(&p12cred); kmf_set_attr_at_index(attrlist, numattr, KMF_PK12CRED_ATTR, &p12cred, sizeof (KMF_CREDENTIAL)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_OUTPUT_FILENAME_ATTR, filename, strlen(filename)); numattr++; rv = kmf_export_pk12(kmfhandle, numattr, attrlist); if (p12cred.cred) free(p12cred.cred); return (rv); } static KMF_RETURN pk_export_pk12_files(KMF_HANDLE_T kmfhandle, char *certfile, char *keyfile, char *outfile) { KMF_RETURN rv; KMF_KEYSTORE_TYPE kstype; KMF_CREDENTIAL p12cred = { NULL, 0 }; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; kstype = KMF_KEYSTORE_OPENSSL; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (certfile != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, certfile, strlen(certfile)); numattr++; } if (keyfile != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, keyfile, strlen(keyfile)); numattr++; } (void) get_pk12_password(&p12cred); kmf_set_attr_at_index(attrlist, numattr, KMF_PK12CRED_ATTR, &p12cred, sizeof (KMF_CREDENTIAL)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_OUTPUT_FILENAME_ATTR, outfile, strlen(outfile)); numattr++; rv = kmf_export_pk12(kmfhandle, numattr, attrlist); if (p12cred.cred) free(p12cred.cred); return (rv); } static KMF_RETURN pk_export_nss_objects(KMF_HANDLE_T kmfhandle, char *token_spec, int oclass, char *certlabel, char *issuer, char *subject, KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt, char *dir, char *prefix, char *filename) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT kmfcert; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); /* If searching for public objects or certificates, find certs now */ if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (certlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } rv = pk_find_export_cert(kmfhandle, attrlist, numattr, &kmfcert); if (rv == KMF_OK) { kstype = KMF_KEYSTORE_OPENSSL; numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &kmfcert.certificate, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &kfmt, sizeof (kfmt)); numattr++; rv = kmf_store_cert(kmfhandle, numattr, attrlist); kmf_free_kmf_cert(kmfhandle, &kmfcert); } } return (rv); } static KMF_RETURN pk_export_pk12_pk11(KMF_HANDLE_T kmfhandle, char *token_spec, char *certlabel, char *issuer, char *subject, KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred, char *filename) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype; KMF_CREDENTIAL p12cred = { NULL, 0 }; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; rv = select_token(kmfhandle, token_spec, TRUE); if (rv != KMF_OK) { return (rv); } kstype = KMF_KEYSTORE_PK11TOKEN; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (certlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (tokencred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } (void) get_pk12_password(&p12cred); kmf_set_attr_at_index(attrlist, numattr, KMF_PK12CRED_ATTR, &p12cred, sizeof (KMF_CREDENTIAL)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_OUTPUT_FILENAME_ATTR, filename, strlen(filename)); numattr++; rv = kmf_export_pk12(kmfhandle, numattr, attrlist); if (p12cred.cred) free(p12cred.cred); return (rv); } static KMF_RETURN pk_export_pk11_keys(KMF_HANDLE_T kmfhandle, char *token, KMF_CREDENTIAL *cred, KMF_ENCODE_FORMAT format, char *label, char *filename, int oclass) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_KEY_CLASS kclass = KMF_KEYCLASS_NONE; int numattr = 0; uint32_t numkeys = 1; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_HANDLE key; boolean_t is_token = B_TRUE; if (EMPTYSTRING(label)) { cryptoerror(LOG_STDERR, gettext("A label " "must be specified to export a key.")); return (KMF_ERR_BAD_PARAMETER); } rv = select_token(kmfhandle, token, TRUE); if (rv != KMF_OK) { return (rv); } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, label, strlen(label)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &numkeys, sizeof (numkeys)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &key, sizeof (key)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR, &is_token, sizeof (is_token)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); numattr++; /* Check to see if we are exporting private or public only */ if ((oclass & PK_KEY_OBJ) == PK_PRIKEY_OBJ) kclass = KMF_ASYM_PRI; else if ((oclass & PK_KEY_OBJ) == PK_PUBKEY_OBJ) kclass = KMF_ASYM_PUB; else if ((oclass & PK_KEY_OBJ) == PK_SYMKEY_OBJ) kclass = KMF_SYMMETRIC; else /* only 1 key at a time can be exported here, so default to pri */ kclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, &kclass, sizeof (kclass)); numattr++; rv = kmf_find_key(kmfhandle, numattr, attrlist); /* * If nothing found but caller wanted ALL keys, try symmetric * this time. */ if (rv == KMF_ERR_KEY_NOT_FOUND && (oclass == PK_KEY_OBJ)) { kclass = KMF_SYMMETRIC; rv = kmf_find_key(kmfhandle, numattr, attrlist); } /* * If nothing found but caller wanted ALL keys, try asymmetric * public this time. */ if (rv == KMF_ERR_KEY_NOT_FOUND && (oclass == PK_KEY_OBJ)) { kclass = KMF_ASYM_PUB; rv = kmf_find_key(kmfhandle, numattr, attrlist); } if (rv == KMF_OK && key.keyclass == KMF_SYMMETRIC) { KMF_RAW_SYM_KEY rkey; (void) memset(&rkey, 0, sizeof (KMF_RAW_SYM_KEY)); rv = kmf_get_sym_key_value(kmfhandle, &key, &rkey); if (rv == KMF_OK) { int fd, n, total = 0; fd = open(filename, O_CREAT | O_RDWR |O_TRUNC, 0600); if (fd == -1) { rv = KMF_ERR_OPEN_FILE; goto done; } do { n = write(fd, rkey.keydata.val + total, rkey.keydata.len - total); if (n < 0) { if (errno == EINTR) continue; (void) close(fd); rv = KMF_ERR_WRITE_FILE; goto done; } total += n; } while (total < rkey.keydata.len); (void) close(fd); } done: kmf_free_bigint(&rkey.keydata); kmf_free_kmf_key(kmfhandle, &key); } else if (rv == KMF_OK) { KMF_KEYSTORE_TYPE sslks = KMF_KEYSTORE_OPENSSL; (void) printf(gettext("Found %d asymmetric keys\n"), numkeys); numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &sslks, sizeof (sslks)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_RAW_KEY_ATTR, key.keyp, sizeof (KMF_RAW_KEY_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, filename, strlen(filename)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, &key.keyclass, sizeof (KMF_KEY_CLASS)); numattr++; rv = kmf_store_key(kmfhandle, numattr, attrlist); kmf_free_kmf_key(kmfhandle, &key); } return (rv); } static KMF_RETURN pk_export_pk11_objects(KMF_HANDLE_T kmfhandle, char *token_spec, KMF_CREDENTIAL *cred, char *certlabel, char *issuer, char *subject, KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt, char *filename) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT kmfcert; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; rv = select_token(kmfhandle, token_spec, TRUE); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL)); numattr++; } if (certlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } rv = pk_find_export_cert(kmfhandle, attrlist, numattr, &kmfcert); if (rv == KMF_OK) { kstype = KMF_KEYSTORE_OPENSSL; numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &kmfcert.certificate, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &kfmt, sizeof (kfmt)); numattr++; rv = kmf_store_cert(kmfhandle, numattr, attrlist); kmf_free_kmf_cert(kmfhandle, &kmfcert); } return (rv); } /* * Export objects from one keystore to a file. */ int pk_export(int argc, char *argv[]) { int opt; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *filename = NULL; char *dir = NULL; char *prefix = NULL; char *certlabel = NULL; char *subject = NULL; char *issuer = NULL; char *infile = NULL; char *keyfile = NULL; char *certfile = NULL; char *serstr = NULL; KMF_KEYSTORE_TYPE kstype = 0; KMF_ENCODE_FORMAT kfmt = KMF_FORMAT_PKCS12; KMF_RETURN rv = KMF_OK; int oclass = PK_CERT_OBJ; KMF_BIGINT serial = { NULL, 0 }; KMF_HANDLE_T kmfhandle = NULL; KMF_CREDENTIAL tokencred = { NULL, 0 }; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "k:(keystore)y:(objtype)T:(token)" "d:(dir)p:(prefix)" "l:(label)n:(nickname)s:(subject)" "i:(issuer)S:(serial)" "K:(keyfile)c:(certfile)" "F:(outformat)" "I:(infile)o:(outfile)")) != 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 'y': oclass = OT2Int(optarg_av); if (oclass == -1) return (PK_ERR_USAGE); break; case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = 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 'n': case 'l': if (certlabel) return (PK_ERR_USAGE); certlabel = optarg_av; break; case 's': if (subject) return (PK_ERR_USAGE); subject = optarg_av; break; case 'i': if (issuer) return (PK_ERR_USAGE); issuer = optarg_av; break; case 'S': serstr = optarg_av; break; case 'F': kfmt = Str2Format(optarg_av); if (kfmt == KMF_FORMAT_UNDEF) return (PK_ERR_USAGE); break; case 'I': /* output file name */ if (infile) return (PK_ERR_USAGE); infile = optarg_av; break; case 'o': /* output file name */ if (filename) return (PK_ERR_USAGE); filename = optarg_av; break; case 'c': /* input cert file name */ if (certfile) return (PK_ERR_USAGE); certfile = optarg_av; break; case 'K': /* input key file name */ if (keyfile) return (PK_ERR_USAGE); keyfile = optarg_av; break; default: return (PK_ERR_USAGE); } } /* Assume keystore = PKCS#11 if not specified */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; /* Filename arg is required. */ if (EMPTYSTRING(filename)) { cryptoerror(LOG_STDERR, gettext("You must specify " "an 'outfile' parameter when exporting.\n")); return (PK_ERR_USAGE); } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) return (PK_ERR_USAGE); DIR_OPTION_CHECK(kstype, dir); /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && kstype != KMF_KEYSTORE_PK11TOKEN) { (void) fprintf(stderr, gettext("The objtype parameter " "is only relevant if keystore=pkcs11\n")); return (PK_ERR_USAGE); } if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) token_spec = PK_DEFAULT_PK11TOKEN; else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) token_spec = DEFAULT_NSS_TOKEN; if (kstype == KMF_KEYSTORE_OPENSSL) { if (kfmt != KMF_FORMAT_PKCS12) { cryptoerror(LOG_STDERR, gettext("PKCS12 " "is the only export format " "supported for the 'file' " "keystore.\n")); return (PK_ERR_USAGE); } if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) { cryptoerror(LOG_STDERR, gettext("A cert file" "and a key file must be specified " "when exporting to PKCS12 from the " "'file' keystore.\n")); return (PK_ERR_USAGE); } } /* Check if the file exists */ if (verify_file(filename) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Warning: file \"%s\" exists, " "will be overwritten."), filename); if (yesno(gettext("Continue with export? "), gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { return (0); } else { /* remove the file */ (void) unlink(filename); } } if (serstr != NULL) { uchar_t *bytes = NULL; size_t bytelen; rv = kmf_hexstr_to_bytes((uchar_t *)serstr, &bytes, &bytelen); if (rv != KMF_OK || bytes == NULL) { (void) fprintf(stderr, gettext("serial number " "must be specified as a hex number " "(ex: 0x0102030405ffeeddee)\n")); return (PK_ERR_USAGE); } serial.val = bytes; serial.len = bytelen; } /* * We need a password in the following situations: * 1. When accessing PKCS11 token * 2. If NSS keystore, when making a PKCS12 file or when * accessing any private object or key. */ if (kstype == KMF_KEYSTORE_PK11TOKEN || ((kstype == KMF_KEYSTORE_NSS) && ((oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ)) || (kfmt == KMF_FORMAT_PKCS12)))) { (void) get_token_password(kstype, token_spec, &tokencred); } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing " "KMF: 0x%02x\n"), rv); return (rv); } switch (kstype) { case KMF_KEYSTORE_PK11TOKEN: if (kfmt == KMF_FORMAT_PKCS12) rv = pk_export_pk12_pk11(kmfhandle, token_spec, certlabel, issuer, subject, &serial, &tokencred, filename); else if ((oclass & PK_KEY_OBJ) || kfmt == KMF_FORMAT_RAWKEY) rv = pk_export_pk11_keys(kmfhandle, token_spec, &tokencred, kfmt, certlabel, filename, oclass); else rv = pk_export_pk11_objects(kmfhandle, token_spec, &tokencred, certlabel, issuer, subject, &serial, kfmt, filename); break; case KMF_KEYSTORE_NSS: if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; if (kfmt == KMF_FORMAT_PKCS12) rv = pk_export_pk12_nss(kmfhandle, token_spec, dir, prefix, certlabel, issuer, subject, &serial, &tokencred, filename); else rv = pk_export_nss_objects(kmfhandle, token_spec, oclass, certlabel, issuer, subject, &serial, kfmt, dir, prefix, filename); break; case KMF_KEYSTORE_OPENSSL: if (kfmt == KMF_FORMAT_PKCS12) rv = pk_export_pk12_files(kmfhandle, certfile, keyfile, filename); else rv = pk_export_file_objects(kmfhandle, oclass, issuer, subject, &serial, infile, filename); break; default: rv = PK_ERR_USAGE; break; } if (rv != KMF_OK) { display_error(kmfhandle, rv, gettext("Error exporting objects")); } if (serial.val != NULL) free(serial.val); (void) kmf_finalize(kmfhandle); return (rv); } /* * 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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include "common.h" #include #define SET_VALUE(f, s) { \ kmfrv = f; \ if (kmfrv != KMF_OK) { \ cryptoerror(LOG_STDERR, \ gettext("Failed to set %s: 0x%02x\n"), \ s, kmfrv); \ goto cleanup; \ } \ } static int gencert_pkcs11(KMF_HANDLE_T kmfhandle, char *token, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, char *certlabel, KMF_KEY_ALG keyAlg, KMF_ALGORITHM_INDEX sigAlg, int keylen, uint32_t ltime, KMF_BIGINT *serial, uint16_t kubits, int kucrit, KMF_CREDENTIAL *tokencred, EKU_LIST *ekulist, KMF_OID *curveoid) { KMF_RETURN kmfrv = KMF_OK; KMF_KEY_HANDLE pubk, prik; KMF_X509_CERTIFICATE signedCert; KMF_X509_NAME certSubject; KMF_X509_NAME certIssuer; KMF_DATA x509DER; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; KMF_KEY_ALG keytype; uint32_t keylength; (void) memset(&signedCert, 0, sizeof (signedCert)); (void) memset(&certSubject, 0, sizeof (certSubject)); (void) memset(&certIssuer, 0, sizeof (certIssuer)); (void) memset(&x509DER, 0, sizeof (x509DER)); /* If the subject name cannot be parsed, flag it now and exit */ if (kmf_dn_parser(subject, &certSubject) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed.\n")); return (PK_ERR_USAGE); } /* For a self-signed cert, the issuser and subject are the same */ if (kmf_dn_parser(subject, &certIssuer) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed.\n")); return (PK_ERR_USAGE); } keylength = keylen; /* bits */ keytype = keyAlg; /* Select a PKCS11 token */ kmfrv = select_token(kmfhandle, token, FALSE); if (kmfrv != KMF_OK) { return (kmfrv); } /* * Share the "genkeypair" routine for creating the keypair. */ kmfrv = genkeypair_pkcs11(kmfhandle, token, certlabel, keytype, keylength, tokencred, curveoid, &prik, &pubk); if (kmfrv != KMF_OK) return (kmfrv); SET_VALUE(kmf_set_cert_pubkey(kmfhandle, &pubk, &signedCert), "keypair"); SET_VALUE(kmf_set_cert_version(&signedCert, 2), "version number"); SET_VALUE(kmf_set_cert_serial(&signedCert, serial), "serial number"); SET_VALUE(kmf_set_cert_validity(&signedCert, 0, ltime), "validity time"); SET_VALUE(kmf_set_cert_sig_alg(&signedCert, sigAlg), "signature algorithm"); SET_VALUE(kmf_set_cert_subject(&signedCert, &certSubject), "subject name"); SET_VALUE(kmf_set_cert_issuer(&signedCert, &certIssuer), "issuer name"); if (altname != NULL) SET_VALUE(kmf_set_cert_subject_altname(&signedCert, altcrit, alttype, altname), "subjectAltName"); if (kubits != 0) SET_VALUE(kmf_set_cert_ku(&signedCert, kucrit, kubits), "KeyUsage"); if (ekulist != NULL) { int i; for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { SET_VALUE(kmf_add_cert_eku(&signedCert, &ekulist->ekulist[i], ekulist->critlist[i]), "Extended Key Usage"); } } /* * Construct attributes for the kmf_sign_cert operation. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE_ATTR)); numattr++; /* cert data that is to be signed */ kmf_set_attr_at_index(attrlist, numattr, KMF_X509_CERTIFICATE_ATTR, &signedCert, sizeof (KMF_X509_CERTIFICATE)); numattr++; /* output buffer for the signed cert */ kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &x509DER, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ALGORITHM_INDEX_ATTR, &sigAlg, sizeof (sigAlg)); numattr++; if ((kmfrv = kmf_sign_cert(kmfhandle, numattr, attrlist)) != KMF_OK) { goto cleanup; } /* * Store the cert in the DB. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &x509DER, sizeof (KMF_DATA)); numattr++; if (certlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel)); numattr++; } kmfrv = kmf_store_cert(kmfhandle, numattr, attrlist); cleanup: kmf_free_data(&x509DER); kmf_free_dn(&certSubject); kmf_free_dn(&certIssuer); /* * If kmf_sign_cert or kmf_store_cert failed, then we need to clean up * the key pair from the token. */ if (kmfrv != KMF_OK) { /* delete the public key */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); numattr++; if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } (void) kmf_delete_key_from_keystore(kmfhandle, numattr, attrlist); /* delete the private key */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); numattr++; if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } (void) kmf_delete_key_from_keystore(kmfhandle, numattr, attrlist); } return (kmfrv); } static int gencert_file(KMF_HANDLE_T kmfhandle, KMF_KEY_ALG keyAlg, KMF_ALGORITHM_INDEX sigAlg, int keylen, KMF_ENCODE_FORMAT fmt, uint32_t ltime, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, KMF_BIGINT *serial, uint16_t kubits, int kucrit, char *outcert, char *outkey, EKU_LIST *ekulist) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; KMF_X509_CERTIFICATE signedCert; KMF_X509_NAME certSubject; KMF_X509_NAME certIssuer; KMF_DATA x509DER; char *fullcertpath = NULL; char *fullkeypath = NULL; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; KMF_ATTRIBUTE attrlist[10]; int numattr = 0; (void) memset(&signedCert, 0, sizeof (signedCert)); (void) memset(&certSubject, 0, sizeof (certSubject)); (void) memset(&certIssuer, 0, sizeof (certIssuer)); (void) memset(&x509DER, 0, sizeof (x509DER)); if (EMPTYSTRING(outcert) || EMPTYSTRING(outkey)) { cryptoerror(LOG_STDERR, gettext("No output file was specified for " "the cert or key\n")); return (PK_ERR_USAGE); } fullcertpath = strdup(outcert); if (verify_file(fullcertpath)) { cryptoerror(LOG_STDERR, gettext("Cannot write the indicated output " "certificate file (%s).\n"), fullcertpath); free(fullcertpath); return (PK_ERR_USAGE); } /* If the subject name cannot be parsed, flag it now and exit */ if (kmf_dn_parser(subject, &certSubject) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed (%s)\n"), subject); return (PK_ERR_USAGE); } /* For a self-signed cert, the issuser and subject are the same */ if (kmf_dn_parser(subject, &certIssuer) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed (%s)\n"), subject); kmf_free_dn(&certSubject); return (PK_ERR_USAGE); } /* * Share the "genkeypair" routine for creating the keypair. */ kmfrv = genkeypair_file(kmfhandle, keyAlg, keylen, fmt, outkey, &prik, &pubk); if (kmfrv != KMF_OK) return (kmfrv); SET_VALUE(kmf_set_cert_pubkey(kmfhandle, &pubk, &signedCert), "keypair"); SET_VALUE(kmf_set_cert_version(&signedCert, 2), "version number"); SET_VALUE(kmf_set_cert_serial(&signedCert, serial), "serial number"); SET_VALUE(kmf_set_cert_validity(&signedCert, 0, ltime), "validity time"); SET_VALUE(kmf_set_cert_sig_alg(&signedCert, sigAlg), "signature algorithm"); SET_VALUE(kmf_set_cert_subject(&signedCert, &certSubject), "subject name"); SET_VALUE(kmf_set_cert_issuer(&signedCert, &certIssuer), "issuer name"); if (altname != NULL) SET_VALUE(kmf_set_cert_subject_altname(&signedCert, altcrit, alttype, altname), "subjectAltName"); if (kubits != 0) SET_VALUE(kmf_set_cert_ku(&signedCert, kucrit, kubits), "KeyUsage"); if (ekulist != NULL) { int i; for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { SET_VALUE(kmf_add_cert_eku(&signedCert, &ekulist->ekulist[i], ekulist->critlist[i]), "Extended Key Usage"); } } /* * Construct attributes for the kmf_sign_cert operation. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE_ATTR)); numattr++; /* cert data that is to be signed */ kmf_set_attr_at_index(attrlist, numattr, KMF_X509_CERTIFICATE_ATTR, &signedCert, sizeof (KMF_X509_CERTIFICATE)); numattr++; /* output buffer for the signed cert */ kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &x509DER, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ALGORITHM_INDEX_ATTR, &sigAlg, sizeof (sigAlg)); numattr++; if ((kmfrv = kmf_sign_cert(kmfhandle, numattr, attrlist)) != KMF_OK) { goto cleanup; } /* * Store the cert in the DB. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &x509DER, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, fullcertpath, strlen(fullcertpath)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &fmt, sizeof (fmt)); numattr++; kmfrv = kmf_store_cert(kmfhandle, numattr, attrlist); cleanup: if (fullkeypath != NULL) free(fullkeypath); if (fullcertpath != NULL) free(fullcertpath); kmf_free_data(&x509DER); kmf_free_dn(&certSubject); kmf_free_dn(&certIssuer); return (kmfrv); } static KMF_RETURN gencert_nss(KMF_HANDLE_T kmfhandle, char *token, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, char *nickname, char *dir, char *prefix, KMF_KEY_ALG keyAlg, KMF_ALGORITHM_INDEX sigAlg, int keylen, char *trust, uint32_t ltime, KMF_BIGINT *serial, uint16_t kubits, int kucrit, KMF_CREDENTIAL *tokencred, EKU_LIST *ekulist, KMF_OID *curveoid) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; KMF_X509_CERTIFICATE signedCert; KMF_X509_NAME certSubject; KMF_X509_NAME certIssuer; KMF_DATA x509DER; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; if (token == NULL) token = DEFAULT_NSS_TOKEN; kmfrv = configure_nss(kmfhandle, dir, prefix); if (kmfrv != KMF_OK) return (kmfrv); (void) memset(&signedCert, 0, sizeof (signedCert)); (void) memset(&certSubject, 0, sizeof (certSubject)); (void) memset(&certIssuer, 0, sizeof (certIssuer)); (void) memset(&x509DER, 0, sizeof (x509DER)); /* If the subject name cannot be parsed, flag it now and exit */ if (kmf_dn_parser(subject, &certSubject) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed.\n")); return (PK_ERR_USAGE); } /* For a self-signed cert, the issuser and subject are the same */ if (kmf_dn_parser(subject, &certIssuer) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed.\n")); return (PK_ERR_USAGE); } kmfrv = genkeypair_nss(kmfhandle, token, nickname, dir, prefix, keyAlg, keylen, tokencred, curveoid, &prik, &pubk); if (kmfrv != KMF_OK) return (kmfrv); SET_VALUE(kmf_set_cert_pubkey(kmfhandle, &pubk, &signedCert), "keypair"); SET_VALUE(kmf_set_cert_version(&signedCert, 2), "version number"); SET_VALUE(kmf_set_cert_serial(&signedCert, serial), "serial number"); SET_VALUE(kmf_set_cert_validity(&signedCert, 0, ltime), "validity time"); SET_VALUE(kmf_set_cert_sig_alg(&signedCert, sigAlg), "signature algorithm"); SET_VALUE(kmf_set_cert_subject(&signedCert, &certSubject), "subject name"); SET_VALUE(kmf_set_cert_issuer(&signedCert, &certIssuer), "issuer name"); if (altname != NULL) SET_VALUE(kmf_set_cert_subject_altname(&signedCert, altcrit, alttype, altname), "subjectAltName"); if (kubits) SET_VALUE(kmf_set_cert_ku(&signedCert, kucrit, kubits), "subjectAltName"); if (ekulist != NULL) { int i; for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { SET_VALUE(kmf_add_cert_eku(&signedCert, &ekulist->ekulist[i], ekulist->critlist[i]), "Extended Key Usage"); } } /* * Construct attributes for the kmf_sign_cert operation. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE_ATTR)); numattr++; /* cert data that is to be signed */ kmf_set_attr_at_index(attrlist, numattr, KMF_X509_CERTIFICATE_ATTR, &signedCert, sizeof (KMF_X509_CERTIFICATE)); numattr++; /* output buffer for the signed cert */ kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &x509DER, sizeof (KMF_DATA)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ALGORITHM_INDEX_ATTR, &sigAlg, sizeof (sigAlg)); numattr++; if ((kmfrv = kmf_sign_cert(kmfhandle, numattr, attrlist)) != KMF_OK) { goto cleanup; } /* * Store the cert in the DB. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &x509DER, sizeof (KMF_DATA)); numattr++; if (nickname != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, nickname, strlen(nickname)); numattr++; } if (trust != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TRUSTFLAG_ATTR, trust, strlen(trust)); numattr++; } if (token != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } kmfrv = kmf_store_cert(kmfhandle, numattr, attrlist); cleanup: kmf_free_data(&x509DER); kmf_free_dn(&certSubject); kmf_free_dn(&certIssuer); return (kmfrv); } int pk_gencert(int argc, char *argv[]) { int rv; int opt; extern int optind_av; extern char *optarg_av; KMF_KEYSTORE_TYPE kstype = 0; char *subject = NULL; char *tokenname = NULL; char *dir = NULL; char *prefix = NULL; char *keytype = PK_DEFAULT_KEYTYPE; int keylen = PK_DEFAULT_KEYLENGTH; char *trust = NULL; char *lifetime = NULL; char *certlabel = NULL; char *outcert = NULL; char *outkey = NULL; char *format = NULL; char *serstr = NULL; char *altname = NULL; char *keyusagestr = NULL; char *ekustr = NULL; char *hashname = NULL; KMF_GENERALNAMECHOICES alttype = 0; KMF_BIGINT serial = { NULL, 0 }; uint32_t ltime; KMF_HANDLE_T kmfhandle = NULL; KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1; KMF_KEY_ALG keyAlg = KMF_RSA; KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_SHA1WithRSA; boolean_t interactive = B_FALSE; char *subname = NULL; KMF_CREDENTIAL tokencred = { NULL, 0 }; uint16_t kubits = 0; int altcrit = 0, kucrit = 0; EKU_LIST *ekulist = NULL; KMF_OID *curveoid = NULL; /* ECC */ KMF_OID *hashoid = NULL; int y_flag = 0; while ((opt = getopt_av(argc, argv, "ik:(keystore)s:(subject)n:(nickname)A:(altname)" "T:(token)d:(dir)p:(prefix)t:(keytype)y:(keylen)" "r:(trust)L:(lifetime)l:(label)c:(outcert)e:(eku)" "K:(outkey)S:(serial)F:(format)u:(keyusage)C:(curve)" "E(listcurves)h:(hash)")) != EOF) { if (opt != 'i' && opt != 'E' && EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'A': altname = optarg_av; break; case 'i': if (interactive || subject) return (PK_ERR_USAGE); else interactive = B_TRUE; break; case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 's': if (interactive || subject) return (PK_ERR_USAGE); else subject = optarg_av; break; case 'l': case 'n': if (certlabel) return (PK_ERR_USAGE); certlabel = 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 'u': keyusagestr = optarg_av; break; case 'y': if (sscanf(optarg_av, "%d", &keylen) != 1) { cryptoerror(LOG_STDERR, gettext("key length must be" "a numeric value (%s)\n"), optarg_av); return (PK_ERR_USAGE); } y_flag++; break; case 'r': if (trust) return (PK_ERR_USAGE); trust = optarg_av; break; case 'L': if (lifetime) return (PK_ERR_USAGE); lifetime = optarg_av; break; case 'c': if (outcert) return (PK_ERR_USAGE); outcert = optarg_av; break; case 'K': if (outkey) return (PK_ERR_USAGE); outkey = optarg_av; break; case 'S': serstr = optarg_av; break; case 'F': if (format) return (PK_ERR_USAGE); format = optarg_av; break; case 'e': ekustr = optarg_av; break; case 'C': curveoid = ecc_name_to_oid(optarg_av); if (curveoid == NULL) { cryptoerror(LOG_STDERR, gettext("Unrecognized ECC " "curve.\n")); return (PK_ERR_USAGE); } break; case 'E': /* * This argument is only to be used * by itself, no other options should * be present. */ if (argc != 2) { cryptoerror(LOG_STDERR, gettext("listcurves has no other " "options.\n")); return (PK_ERR_USAGE); } show_ecc_curves(); return (0); case 'h': hashname = optarg_av; hashoid = ecc_name_to_oid(optarg_av); if (hashoid == NULL) { cryptoerror(LOG_STDERR, gettext("Unrecognized hash.\n")); return (PK_ERR_USAGE); } break; default: return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) { return (PK_ERR_USAGE); } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); return (PK_ERR_USAGE); } /* Assume keystore = PKCS#11 if not specified. */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; if ((kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN)) { if (interactive && EMPTYSTRING(certlabel)) { (void) get_certlabel(&certlabel); } /* It better not be empty now */ if (EMPTYSTRING(certlabel)) { cryptoerror(LOG_STDERR, gettext("A label must be " "specified to create a self-signed certificate." "\n")); return (PK_ERR_USAGE); } } else if (kstype == KMF_KEYSTORE_OPENSSL && EMPTYSTRING(outcert)) { cryptoerror(LOG_STDERR, gettext("A certificate filename must " "be specified to create a self-signed certificate.\n")); return (PK_ERR_USAGE); } DIR_OPTION_CHECK(kstype, dir); if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) { cryptoerror(LOG_STDERR, gettext("Error parsing format string (%s).\n"), format); return (PK_ERR_USAGE); } if (Str2Lifetime(lifetime, <ime) != 0) { cryptoerror(LOG_STDERR, gettext("Error parsing lifetime string\n")); return (PK_ERR_USAGE); } if (Str2KeyType(keytype, hashoid, &keyAlg, &sigAlg) != 0) { cryptoerror(LOG_STDERR, gettext("Unsupported key/hash combination (%s/%s).\n"), keytype, (hashname ? hashname : "none")); return (PK_ERR_USAGE); } if (curveoid != NULL && keyAlg != KMF_ECDSA) { cryptoerror(LOG_STDERR, gettext("EC curves are only " "valid for EC keytypes.\n")); return (PK_ERR_USAGE); } if (keyAlg == KMF_ECDSA && curveoid == NULL) { cryptoerror(LOG_STDERR, gettext("A curve must be " "specifed when using EC keys.\n")); return (PK_ERR_USAGE); } /* Adjust default keylength for NSS and DSA */ if (keyAlg == KMF_DSA && !y_flag && kstype == KMF_KEYSTORE_NSS) keylen = 1024; /* * Check the subject name. * If interactive is true, get it now interactively. */ if (interactive) { subname = NULL; if (get_subname(&subname) != KMF_OK || subname == NULL) { cryptoerror(LOG_STDERR, gettext("Failed to get the " "subject name interactively.\n")); return (PK_ERR_USAGE); } if (serstr == NULL) { (void) get_serial(&serstr); } } else { if (EMPTYSTRING(subject)) { cryptoerror(LOG_STDERR, gettext("A subject name or " "-i must be specified to create a self-signed " "certificate.\n")); return (PK_ERR_USAGE); } else { subname = strdup(subject); if (subname == NULL) { cryptoerror(LOG_STDERR, gettext("Out of memory.\n")); return (PK_ERR_SYSTEM); } } } if (serstr == NULL) { (void) fprintf(stderr, gettext("A serial number " "must be specified as a hex number when creating" " a self-signed certificate " "(ex: serial=0x0102030405feedface)\n")); rv = PK_ERR_USAGE; goto end; } else { uchar_t *bytes = NULL; size_t bytelen; rv = kmf_hexstr_to_bytes((uchar_t *)serstr, &bytes, &bytelen); if (rv != KMF_OK || bytes == NULL) { (void) fprintf(stderr, gettext("serial number " "must be specified as a hex number " "(ex: 0x0102030405ffeeddee)\n")); rv = PK_ERR_USAGE; goto end; } serial.val = bytes; serial.len = bytelen; } if (altname != NULL) { rv = verify_altname(altname, &alttype, &altcrit); if (rv != KMF_OK) { (void) fprintf(stderr, gettext("Subject AltName " "must be specified as a name=value pair. " "See the man page for details.\n")); rv = PK_ERR_USAGE; goto end; } else { /* advance the altname past the '=' sign */ char *p = strchr(altname, '='); if (p != NULL) altname = p + 1; } } if (keyusagestr != NULL) { rv = verify_keyusage(keyusagestr, &kubits, &kucrit); if (rv != KMF_OK) { (void) fprintf(stderr, gettext("KeyUsage " "must be specified as a comma-separated list. " "See the man page for details.\n")); rv = PK_ERR_USAGE; goto end; } } if (ekustr != NULL) { rv = verify_ekunames(ekustr, &ekulist); if (rv != KMF_OK) { (void) fprintf(stderr, gettext("EKUs must " "be specified as a comma-separated list. " "See the man page for details.\n")); rv = PK_ERR_USAGE; goto end; } } if (keyAlg == KMF_ECDSA && kstype == KMF_KEYSTORE_OPENSSL) { (void) fprintf(stderr, gettext("ECC certificates are" "only supported with the pkcs11 and nss keystores\n")); rv = PK_ERR_USAGE; goto end; } if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) { if (tokenname == NULL || !strlen(tokenname)) { if (kstype == KMF_KEYSTORE_NSS) { tokenname = "internal"; } else { tokenname = PK_DEFAULT_PK11TOKEN; } } (void) get_token_password(kstype, tokenname, &tokencred); } if (kstype == KMF_KEYSTORE_NSS) { if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; rv = gencert_nss(kmfhandle, tokenname, subname, altname, alttype, altcrit, certlabel, dir, prefix, keyAlg, sigAlg, keylen, trust, ltime, &serial, kubits, kucrit, &tokencred, ekulist, curveoid); } else if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = gencert_pkcs11(kmfhandle, tokenname, subname, altname, alttype, altcrit, certlabel, keyAlg, sigAlg, keylen, ltime, &serial, kubits, kucrit, &tokencred, ekulist, curveoid); } else if (kstype == KMF_KEYSTORE_OPENSSL) { rv = gencert_file(kmfhandle, keyAlg, sigAlg, keylen, fmt, ltime, subname, altname, alttype, altcrit, &serial, kubits, kucrit, outcert, outkey, ekulist); } if (rv != KMF_OK) display_error(kmfhandle, rv, gettext("Error creating certificate and keypair")); end: if (ekulist != NULL) free_eku_list(ekulist); if (subname) free(subname); if (tokencred.cred != NULL) free(tokencred.cred); if (serial.val != NULL) free(serial.val); (void) kmf_finalize(kmfhandle); return (rv); } /* * 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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include "common.h" #include #define SET_VALUE(f, s) \ kmfrv = f; \ if (kmfrv != KMF_OK) { \ cryptoerror(LOG_STDERR, \ gettext("Failed to %s: 0x%02\n"), \ s, kmfrv); \ goto cleanup; \ } static KMF_RETURN gencsr_pkcs11(KMF_HANDLE_T kmfhandle, char *token, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, char *certlabel, KMF_KEY_ALG keyAlg, int keylen, uint16_t kubits, int kucrit, KMF_ENCODE_FORMAT fmt, char *csrfile, KMF_CREDENTIAL *tokencred, EKU_LIST *ekulist, KMF_ALGORITHM_INDEX sigAlg, KMF_OID *curveoid) { KMF_RETURN kmfrv = KMF_OK; KMF_KEY_HANDLE pubk, prik; KMF_X509_NAME csrSubject; KMF_CSR_DATA csr; KMF_DATA signedCsr = { 0, NULL }; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; (void) memset(&csr, 0, sizeof (csr)); (void) memset(&csrSubject, 0, sizeof (csrSubject)); /* If the subject name cannot be parsed, flag it now and exit */ if ((kmfrv = kmf_dn_parser(subject, &csrSubject)) != KMF_OK) return (kmfrv); /* Select a PKCS11 token */ kmfrv = select_token(kmfhandle, token, FALSE); if (kmfrv != KMF_OK) return (kmfrv); /* * Share the "genkeypair" routine for creating the keypair. */ kmfrv = genkeypair_pkcs11(kmfhandle, token, certlabel, keyAlg, keylen, tokencred, curveoid, &prik, &pubk); if (kmfrv != KMF_OK) return (kmfrv); SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "keypair"); SET_VALUE(kmf_set_csr_version(&csr, 2), "version number"); SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), "subject name"); SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "SignatureAlgorithm"); if (altname != NULL) { SET_VALUE(kmf_set_csr_subject_altname(&csr, altname, altcrit, alttype), "SetCSRSubjectAltName"); } if (kubits != 0) { SET_VALUE(kmf_set_csr_ku(&csr, kucrit, kubits), "SetCSRKeyUsage"); } if (ekulist != NULL) { int i; for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { SET_VALUE(kmf_add_csr_eku(&csr, &ekulist->ekulist[i], ekulist->critlist[i]), "Extended Key Usage"); } } if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) == KMF_OK) { kmfrv = kmf_create_csr_file(&signedCsr, fmt, csrfile); } cleanup: (void) kmf_free_data(&signedCsr); (void) kmf_free_signed_csr(&csr); /* delete the public key */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); numattr++; if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } (void) kmf_delete_key_from_keystore(kmfhandle, numattr, attrlist); /* * If there is an error, then we need to remove the private key * from the token. */ if (kmfrv != KMF_OK) { numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); numattr++; if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } (void) kmf_delete_key_from_keystore(kmfhandle, numattr, attrlist); } (void) kmf_free_kmf_key(kmfhandle, &prik); return (kmfrv); } static KMF_RETURN gencsr_file(KMF_HANDLE_T kmfhandle, KMF_KEY_ALG keyAlg, int keylen, KMF_ENCODE_FORMAT fmt, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, uint16_t kubits, int kucrit, char *outcsr, char *outkey, EKU_LIST *ekulist, KMF_ALGORITHM_INDEX sigAlg) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; KMF_X509_NAME csrSubject; KMF_CSR_DATA csr; KMF_DATA signedCsr = { 0, NULL }; char *fullcsrpath = NULL; char *fullkeypath = NULL; (void) memset(&csr, 0, sizeof (csr)); (void) memset(&csrSubject, 0, sizeof (csrSubject)); if (EMPTYSTRING(outcsr) || EMPTYSTRING(outkey)) { cryptoerror(LOG_STDERR, gettext("No output file was specified for " "the csr or key\n")); return (KMF_ERR_BAD_PARAMETER); } fullcsrpath = strdup(outcsr); if (verify_file(fullcsrpath)) { cryptoerror(LOG_STDERR, gettext("Cannot write the indicated output " "certificate file (%s).\n"), fullcsrpath); free(fullcsrpath); return (PK_ERR_USAGE); } /* If the subject name cannot be parsed, flag it now and exit */ if ((kmfrv = kmf_dn_parser(subject, &csrSubject)) != KMF_OK) { return (kmfrv); } /* * Share the "genkeypair" routine for creating the keypair. */ kmfrv = genkeypair_file(kmfhandle, keyAlg, keylen, fmt, outkey, &prik, &pubk); if (kmfrv != KMF_OK) return (kmfrv); SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "SetCSRPubKey"); SET_VALUE(kmf_set_csr_version(&csr, 2), "SetCSRVersion"); SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), "kmf_set_csr_subject"); SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "kmf_set_csr_sig_alg"); if (altname != NULL) { SET_VALUE(kmf_set_csr_subject_altname(&csr, altname, altcrit, alttype), "kmf_set_csr_subject_altname"); } if (kubits != 0) { SET_VALUE(kmf_set_csr_ku(&csr, kucrit, kubits), "kmf_set_csr_ku"); } if (ekulist != NULL) { int i; for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { SET_VALUE(kmf_add_csr_eku(&csr, &ekulist->ekulist[i], ekulist->critlist[i]), "Extended Key Usage"); } } if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) == KMF_OK) { kmfrv = kmf_create_csr_file(&signedCsr, fmt, fullcsrpath); } cleanup: if (fullkeypath) free(fullkeypath); if (fullcsrpath) free(fullcsrpath); kmf_free_data(&signedCsr); kmf_free_kmf_key(kmfhandle, &prik); kmf_free_signed_csr(&csr); return (kmfrv); } static KMF_RETURN gencsr_nss(KMF_HANDLE_T kmfhandle, char *token, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, char *nickname, char *dir, char *prefix, KMF_KEY_ALG keyAlg, int keylen, uint16_t kubits, int kucrit, KMF_ENCODE_FORMAT fmt, char *csrfile, KMF_CREDENTIAL *tokencred, EKU_LIST *ekulist, KMF_ALGORITHM_INDEX sigAlg, KMF_OID *curveoid) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; KMF_X509_NAME csrSubject; KMF_CSR_DATA csr; KMF_DATA signedCsr = { 0, NULL }; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; if (token == NULL) token = DEFAULT_NSS_TOKEN; kmfrv = configure_nss(kmfhandle, dir, prefix); if (kmfrv != KMF_OK) return (kmfrv); (void) memset(&csr, 0, sizeof (csr)); (void) memset(&csrSubject, 0, sizeof (csrSubject)); (void) memset(&pubk, 0, sizeof (pubk)); (void) memset(&prik, 0, sizeof (prik)); /* If the subject name cannot be parsed, flag it now and exit */ if ((kmfrv = kmf_dn_parser(subject, &csrSubject)) != KMF_OK) { return (kmfrv); } kmfrv = genkeypair_nss(kmfhandle, token, nickname, dir, prefix, keyAlg, keylen, tokencred, curveoid, &prik, &pubk); if (kmfrv != KMF_OK) return (kmfrv); SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "kmf_set_csr_pubkey"); SET_VALUE(kmf_set_csr_version(&csr, 2), "kmf_set_csr_version"); SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), "kmf_set_csr_subject"); SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "kmf_set_csr_sig_alg"); if (altname != NULL) { SET_VALUE(kmf_set_csr_subject_altname(&csr, altname, altcrit, alttype), "kmf_set_csr_subject_altname"); } if (kubits != 0) { SET_VALUE(kmf_set_csr_ku(&csr, kucrit, kubits), "kmf_set_csr_ku"); } if (ekulist != NULL) { int i; for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { SET_VALUE(kmf_add_csr_eku(&csr, &ekulist->ekulist[i], ekulist->critlist[i]), "Extended Key Usage"); } } if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) == KMF_OK) { kmfrv = kmf_create_csr_file(&signedCsr, fmt, csrfile); } cleanup: (void) kmf_free_data(&signedCsr); (void) kmf_free_kmf_key(kmfhandle, &prik); /* delete the key */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); numattr++; if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } if (token && strlen(token)) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } (void) kmf_delete_key_from_keystore(kmfhandle, numattr, attrlist); (void) kmf_free_signed_csr(&csr); return (kmfrv); } int pk_gencsr(int argc, char *argv[]) { KMF_RETURN rv; int opt; extern int optind_av; extern char *optarg_av; KMF_KEYSTORE_TYPE kstype = 0; char *subject = NULL; char *tokenname = NULL; char *dir = NULL; char *prefix = NULL; int keylen = PK_DEFAULT_KEYLENGTH; char *certlabel = NULL; char *outcsr = NULL; char *outkey = NULL; char *format = NULL; char *altname = NULL; char *kustr = NULL; char *ekustr = NULL; char *hashname = NULL; uint16_t kubits = 0; char *keytype = PK_DEFAULT_KEYTYPE; KMF_HANDLE_T kmfhandle = NULL; KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1; KMF_KEY_ALG keyAlg = KMF_RSA; KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_SHA1WithRSA; boolean_t interactive = B_FALSE; char *subname = NULL; KMF_CREDENTIAL tokencred = { NULL, 0 }; KMF_GENERALNAMECHOICES alttype = 0; int altcrit = 0, kucrit = 0; EKU_LIST *ekulist = NULL; KMF_OID *curveoid = NULL; /* ECC */ KMF_OID *hashoid = NULL; int y_flag = 0; while ((opt = getopt_av(argc, argv, "ik:(keystore)s:(subject)n:(nickname)A:(altname)" "u:(keyusage)T:(token)d:(dir)p:(prefix)t:(keytype)" "y:(keylen)l:(label)c:(outcsr)e:(eku)C:(curve)" "K:(outkey)F:(format)E(listcurves)h:(hash)")) != EOF) { switch (opt) { case 'A': altname = optarg_av; break; case 'i': if (interactive) return (PK_ERR_USAGE); else if (subject) { cryptoerror(LOG_STDERR, gettext("Interactive (-i) and " "subject options are mutually " "exclusive.\n")); return (PK_ERR_USAGE); } else interactive = B_TRUE; break; case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 's': if (subject) return (PK_ERR_USAGE); else if (interactive) { cryptoerror(LOG_STDERR, gettext("Interactive (-i) and " "subject options are mutually " "exclusive.\n")); return (PK_ERR_USAGE); } else subject = optarg_av; break; case 'l': case 'n': if (certlabel) return (PK_ERR_USAGE); certlabel = optarg_av; break; case 'T': if (tokenname) return (PK_ERR_USAGE); tokenname = optarg_av; break; case 'd': dir = optarg_av; break; case 'p': if (prefix) return (PK_ERR_USAGE); prefix = optarg_av; break; case 't': keytype = optarg_av; break; case 'u': kustr = optarg_av; break; case 'y': if (sscanf(optarg_av, "%d", &keylen) != 1) { cryptoerror(LOG_STDERR, gettext("Unrecognized " "key length (%s)\n"), optarg_av); return (PK_ERR_USAGE); } y_flag++; break; case 'c': if (outcsr) return (PK_ERR_USAGE); outcsr = optarg_av; break; case 'K': if (outkey) return (PK_ERR_USAGE); outkey = optarg_av; break; case 'F': if (format) return (PK_ERR_USAGE); format = optarg_av; break; case 'e': ekustr = optarg_av; break; case 'C': curveoid = ecc_name_to_oid(optarg_av); if (curveoid == NULL) { cryptoerror(LOG_STDERR, gettext("Unrecognized ECC " "curve.\n")); return (PK_ERR_USAGE); } break; case 'E': /* * This argument is only to be used * by itself, no other options should * be present. */ if (argc != 2) { cryptoerror(LOG_STDERR, gettext("listcurves has no other " "options.\n")); return (PK_ERR_USAGE); } show_ecc_curves(); return (0); case 'h': hashname = optarg_av; hashoid = ecc_name_to_oid(optarg_av); if (hashoid == NULL) { cryptoerror(LOG_STDERR, gettext("Unrecognized hash.\n")); return (PK_ERR_USAGE); } break; default: cryptoerror(LOG_STDERR, gettext( "unrecognized gencsr option '%s'\n"), argv[optind_av]); return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) { return (PK_ERR_USAGE); } /* Assume keystore = PKCS#11 if not specified. */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; DIR_OPTION_CHECK(kstype, dir); if (EMPTYSTRING(outcsr) && interactive) { (void) get_filename("CSR", &outcsr); } if (EMPTYSTRING(outcsr)) { (void) printf(gettext("A filename must be specified to hold" "the final certificate request data.\n")); return (PK_ERR_USAGE); } /* * verify that the outcsr file does not already exist * and that it can be created. */ rv = verify_file(outcsr); if (rv == KMF_ERR_OPEN_FILE) { cryptoerror(LOG_STDERR, gettext("Warning: file \"%s\" exists, " "will be overwritten."), outcsr); if (yesno(gettext("Continue with gencsr? "), gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { return (0); } else { /* remove the file */ (void) unlink(outcsr); } } else if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Warning: error accessing \"%s\""), outcsr); return (rv); } if ((kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN)) { if (EMPTYSTRING(certlabel) && interactive) (void) get_certlabel(&certlabel); if (EMPTYSTRING(certlabel)) { cryptoerror(LOG_STDERR, gettext("A label must be " "specified to create a certificate request.\n")); return (PK_ERR_USAGE); } } else if (kstype == KMF_KEYSTORE_OPENSSL) { if (EMPTYSTRING(outkey) && interactive) (void) get_filename("private key", &outkey); if (EMPTYSTRING(outkey)) { cryptoerror(LOG_STDERR, gettext("A key filename " "must be specified to create a certificate " "request.\n")); return (PK_ERR_USAGE); } } if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) { cryptoerror(LOG_STDERR, gettext("Error parsing format string (%s).\n"), format); return (PK_ERR_USAGE); } if (format && fmt != KMF_FORMAT_ASN1 && fmt != KMF_FORMAT_PEM) { cryptoerror(LOG_STDERR, gettext("CSR must be DER or PEM format.\n")); return (PK_ERR_USAGE); } /* * Check the subject name. * If interactive is true, get it now interactively. */ if (interactive) { if (get_subname(&subname) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Failed to get the " "subject name interactively.\n")); return (PK_ERR_USAGE); } } else { if (EMPTYSTRING(subject)) { cryptoerror(LOG_STDERR, gettext("A subject name or " "-i must be specified to create a certificate " "request.\n")); return (PK_ERR_USAGE); } else { subname = strdup(subject); if (subname == NULL) { cryptoerror(LOG_STDERR, gettext("Out of memory.\n")); return (PK_ERR_SYSTEM); } } } if (altname != NULL) { rv = verify_altname(altname, &alttype, &altcrit); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject AltName " "must be specified as a name=value pair. " "See the man page for details.")); goto end; } else { /* advance the altname past the '=' sign */ char *p = strchr(altname, '='); if (p != NULL) altname = p + 1; } } if (kustr != NULL) { rv = verify_keyusage(kustr, &kubits, &kucrit); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("KeyUsage " "must be specified as a comma-separated list. " "See the man page for details.")); goto end; } } if (ekustr != NULL) { rv = verify_ekunames(ekustr, &ekulist); if (rv != KMF_OK) { (void) fprintf(stderr, gettext("EKUs must " "be specified as a comma-separated list. " "See the man page for details.\n")); rv = PK_ERR_USAGE; goto end; } } if ((rv = Str2KeyType(keytype, hashoid, &keyAlg, &sigAlg)) != 0) { cryptoerror(LOG_STDERR, gettext("Unsupported key/hash combination (%s/%s).\n"), keytype, (hashname ? hashname : "none")); goto end; } if (curveoid != NULL && keyAlg != KMF_ECDSA) { cryptoerror(LOG_STDERR, gettext("EC curves are only " "valid for EC keytypes.\n")); return (PK_ERR_USAGE); } if (keyAlg == KMF_ECDSA && curveoid == NULL) { cryptoerror(LOG_STDERR, gettext("A curve must be " "specifed when using EC keys.\n")); return (PK_ERR_USAGE); } if (keyAlg == KMF_ECDSA && kstype == KMF_KEYSTORE_OPENSSL) { (void) fprintf(stderr, gettext("ECC certificates are" "only supported with the pkcs11 and nss keystores\n")); rv = PK_ERR_USAGE; goto end; } /* Adjust default keylength for NSS and DSA */ if (keyAlg == KMF_DSA && !y_flag && kstype == KMF_KEYSTORE_NSS) keylen = 1024; if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) { if (tokenname == NULL || !strlen(tokenname)) { if (kstype == KMF_KEYSTORE_NSS) { tokenname = "internal"; } else { tokenname = PK_DEFAULT_PK11TOKEN; } } (void) get_token_password(kstype, tokenname, &tokencred); } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); return (PK_ERR_USAGE); } if (kstype == KMF_KEYSTORE_NSS) { if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; rv = gencsr_nss(kmfhandle, tokenname, subname, altname, alttype, altcrit, certlabel, dir, prefix, keyAlg, keylen, kubits, kucrit, fmt, outcsr, &tokencred, ekulist, sigAlg, curveoid); } else if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = gencsr_pkcs11(kmfhandle, tokenname, subname, altname, alttype, altcrit, certlabel, keyAlg, keylen, kubits, kucrit, fmt, outcsr, &tokencred, ekulist, sigAlg, curveoid); } else if (kstype == KMF_KEYSTORE_OPENSSL) { rv = gencsr_file(kmfhandle, keyAlg, keylen, fmt, subname, altname, alttype, altcrit, kubits, kucrit, outcsr, outkey, ekulist, sigAlg); } end: if (rv != KMF_OK) { display_error(kmfhandle, rv, gettext("Error creating CSR or keypair")); if (rv == KMF_ERR_RDN_PARSER) { cryptoerror(LOG_STDERR, gettext("subject or " "issuer name must be in proper DN format.\n")); } } if (ekulist != NULL) free_eku_list(ekulist); if (subname) free(subname); if (tokencred.cred != NULL) free(tokencred.cred); (void) kmf_finalize(kmfhandle); if (rv != KMF_OK) return (PK_ERR_USAGE); return (0); } /* * 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. */ #include #include #include #include #include #include #include #include #include "common.h" #include 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, ¬_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; } DIR_OPTION_CHECK(kstype, dir); 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); } /* * 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 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include "common.h" #include #define SET_VALUE(f, s) \ kmfrv = f; \ if (kmfrv != KMF_OK) { \ cryptoerror(LOG_STDERR, \ gettext("Failed to set %s: 0x%02x\n"), \ s, kmfrv); \ goto cleanup; \ } KMF_RETURN genkeypair_pkcs11(KMF_HANDLE_T kmfhandle, char *token, char *keylabel, KMF_KEY_ALG keyAlg, int keylen, KMF_CREDENTIAL *tokencred, KMF_OID *curveoid, KMF_KEY_HANDLE *outPriKey, KMF_KEY_HANDLE *outPubKey) { KMF_RETURN kmfrv = KMF_OK; KMF_KEY_HANDLE pubk, prik; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; KMF_KEY_ALG keytype; uint32_t keylength; keylength = keylen; /* bits */ keytype = keyAlg; /* Select a PKCS11 token */ kmfrv = select_token(kmfhandle, token, FALSE); if (kmfrv != KMF_OK) return (kmfrv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength)); numattr++; if (keylabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, keylabel, strlen(keylabel)); numattr++; } if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); numattr++; if (keytype == KMF_ECDSA && curveoid != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ECC_CURVE_OID_ATTR, curveoid, sizeof (KMF_OID)); numattr++; } kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist); if (kmfrv != KMF_OK) { return (kmfrv); } if (kmfrv == KMF_OK) { if (outPriKey != NULL) *outPriKey = prik; if (outPubKey != NULL) *outPubKey = pubk; } return (kmfrv); } KMF_RETURN genkeypair_file(KMF_HANDLE_T kmfhandle, KMF_KEY_ALG keyAlg, int keylen, KMF_ENCODE_FORMAT fmt, char *outkey, KMF_KEY_HANDLE *outPriKey, KMF_KEY_HANDLE *outPubKey) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; char *fullkeypath = NULL; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; KMF_ATTRIBUTE attrlist[10]; int numattr = 0; KMF_KEY_ALG keytype; uint32_t keylength; KMF_ENCODE_FORMAT format; if (EMPTYSTRING(outkey)) { cryptoerror(LOG_STDERR, gettext("No output file was specified for " "the key\n")); return (PK_ERR_USAGE); } fullkeypath = strdup(outkey); if (verify_file(fullkeypath)) { cryptoerror(LOG_STDERR, gettext("Cannot write the indicated output " "key file (%s).\n"), fullkeypath); free(fullkeypath); return (PK_ERR_USAGE); } keylength = keylen; /* bits */ keytype = keyAlg; format = fmt; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength)); numattr++; if (fullkeypath != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, fullkeypath, strlen(fullkeypath)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); numattr++; kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist); if (kmfrv != KMF_OK) { goto cleanup; } cleanup: if (fullkeypath != NULL) free(fullkeypath); if (kmfrv == KMF_OK) { if (outPriKey != NULL) *outPriKey = prik; if (outPubKey != NULL) *outPubKey = pubk; } return (kmfrv); } KMF_RETURN genkeypair_nss(KMF_HANDLE_T kmfhandle, char *token, char *nickname, char *dir, char *prefix, KMF_KEY_ALG keyAlg, int keylen, KMF_CREDENTIAL *tokencred, KMF_OID *curveoid, KMF_KEY_HANDLE *outPriKey, KMF_KEY_HANDLE *outPubKey) { KMF_RETURN kmfrv; KMF_KEY_HANDLE pubk, prik; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; KMF_KEY_ALG keytype; uint32_t keylength; if (token == NULL) token = DEFAULT_NSS_TOKEN; kmfrv = configure_nss(kmfhandle, dir, prefix); if (kmfrv != KMF_OK) return (kmfrv); keylength = keylen; /* bits */ keytype = keyAlg; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength)); numattr++; if (nickname != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, nickname, strlen(nickname)); numattr++; } if (tokencred != NULL && tokencred->cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } if (token != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); numattr++; if (keytype == KMF_ECDSA && curveoid != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ECC_CURVE_OID_ATTR, curveoid, sizeof (KMF_OID)); numattr++; } kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist); if (kmfrv != KMF_OK) { return (kmfrv); } if (kmfrv == KMF_OK) { if (outPriKey != NULL) *outPriKey = prik; if (outPubKey != NULL) *outPubKey = pubk; } return (kmfrv); } int pk_genkeypair(int argc, char *argv[]) { int rv; int opt; extern int optind_av; extern char *optarg_av; KMF_KEYSTORE_TYPE kstype = 0; char *tokenname = NULL; char *dir = NULL; char *prefix = NULL; char *keytype = PK_DEFAULT_KEYTYPE; int keylen = PK_DEFAULT_KEYLENGTH; char *label = NULL; char *outkey = NULL; char *format = NULL; KMF_HANDLE_T kmfhandle = NULL; KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1; KMF_KEY_ALG keyAlg = KMF_RSA; KMF_ALGORITHM_INDEX sigAlg; KMF_CREDENTIAL tokencred = { NULL, 0 }; KMF_OID *curveoid = NULL; /* ECC */ int y_flag = 0; while ((opt = getopt_av(argc, argv, "k:(keystore)s:(subject)n:(nickname)" "T:(token)d:(dir)p:(prefix)t:(keytype)y:(keylen)" "l:(label)K:(outkey)F:(format)C:(curve)" "E(listcurves)")) != EOF) { if (opt != 'i' && opt != 'E' && 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': case 'n': if (label) return (PK_ERR_USAGE); label = 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 (sscanf(optarg_av, "%d", &keylen) != 1) { cryptoerror(LOG_STDERR, gettext("key length must be" "a numeric value (%s)\n"), optarg_av); return (PK_ERR_USAGE); } y_flag++; break; case 'K': if (outkey) return (PK_ERR_USAGE); outkey = optarg_av; break; case 'F': if (format) return (PK_ERR_USAGE); format = optarg_av; break; case 'C': curveoid = ecc_name_to_oid(optarg_av); if (curveoid == NULL) { cryptoerror(LOG_STDERR, gettext( "Unrecognized ECC curve.\n")); return (PK_ERR_USAGE); } break; case 'E': show_ecc_curves(); return (0); default: return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) { return (PK_ERR_USAGE); } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); return (PK_ERR_USAGE); } /* Assume keystore = PKCS#11 if not specified. */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; DIR_OPTION_CHECK(kstype, dir); if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) { cryptoerror(LOG_STDERR, gettext("Error parsing format string (%s).\n"), format); return (PK_ERR_USAGE); } if (Str2KeyType(keytype, NULL, &keyAlg, &sigAlg) != 0) { cryptoerror(LOG_STDERR, gettext("Unrecognized keytype (%s).\n"), keytype); return (PK_ERR_USAGE); } if (curveoid != NULL && keyAlg != KMF_ECDSA) { cryptoerror(LOG_STDERR, gettext("EC curves are only " "valid for EC keytypes.\n")); return (PK_ERR_USAGE); } if (keyAlg == KMF_ECDSA && curveoid == NULL) { cryptoerror(LOG_STDERR, gettext("A curve must be " "specifed when using EC keys.\n")); return (PK_ERR_USAGE); } if (keyAlg == KMF_ECDSA && kstype == KMF_KEYSTORE_OPENSSL) { (void) fprintf(stderr, gettext("ECC certificates are" "only supported with the pkcs11 and nss keystores\n")); rv = PK_ERR_USAGE; goto end; } /* Adjust default keylength for NSS and DSA */ if (keyAlg == KMF_DSA && kstype == KMF_KEYSTORE_NSS) { /* NSS only allows for 512-1024 bit DSA keys */ if (!y_flag) /* If nothing was given, default to 1024 */ keylen = 1024; else if (keylen > 1024 || keylen < 512) { (void) fprintf(stderr, gettext("NSS keystore only " "supports DSA keylengths of 512 - 1024 bits\n")); rv = PK_ERR_USAGE; goto end; } } if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) { if (label == NULL) { (void) fprintf(stderr, gettext("No key label specified\n")); rv = PK_ERR_USAGE; goto end; } if (tokenname == NULL || !strlen(tokenname)) { if (kstype == KMF_KEYSTORE_NSS) { tokenname = "internal"; } else { tokenname = PK_DEFAULT_PK11TOKEN; } } (void) get_token_password(kstype, tokenname, &tokencred); } if (kstype == KMF_KEYSTORE_NSS) { if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; rv = genkeypair_nss(kmfhandle, tokenname, label, dir, prefix, keyAlg, keylen, &tokencred, curveoid, NULL, NULL); } else if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = genkeypair_pkcs11(kmfhandle, tokenname, label, keyAlg, keylen, &tokencred, curveoid, NULL, NULL); } else if (kstype == KMF_KEYSTORE_OPENSSL) { rv = genkeypair_file(kmfhandle, keyAlg, keylen, fmt, outkey, NULL, NULL); } if (rv != KMF_OK) display_error(kmfhandle, rv, gettext("Error creating and keypair")); end: if (tokencred.cred != NULL) free(tokencred.cred); (void) kmf_finalize(kmfhandle); return (rv); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * This file implements the import operation for this tool. * The basic flow of the process is to decrypt the PKCS#12 * input file if it has a password, parse the elements in * the file, find the soft token, log into it, import the * PKCS#11 objects into the soft token, and log out. */ #include #include #include #include #include #include #include #include #include "common.h" #include #define NEW_ATTRLIST(a, n) \ { \ a = (KMF_ATTRIBUTE *)malloc(n * sizeof (KMF_ATTRIBUTE)); \ if (a == NULL) { \ rv = KMF_ERR_MEMORY; \ goto end; \ } \ (void) memset(a, 0, n * sizeof (KMF_ATTRIBUTE)); \ } static KMF_RETURN pk_import_pk12_files(KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *cred, char *outfile, char *certfile, char *keyfile, KMF_ENCODE_FORMAT outformat) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT *certs = NULL; KMF_RAW_KEY_DATA *keys = NULL; int ncerts = 0; int nkeys = 0; int i; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; KMF_ATTRIBUTE *attrlist = NULL; int numattr = 0; rv = kmf_import_objects(kmfhandle, outfile, cred, &certs, &ncerts, &keys, &nkeys); if (rv == KMF_OK) { (void) printf(gettext("Found %d certificate(s) and %d " "key(s) in %s\n"), ncerts, nkeys, outfile); } if (rv == KMF_OK && ncerts > 0) { char newcertfile[MAXPATHLEN]; NEW_ATTRLIST(attrlist, (3 + (3 * ncerts))); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &outformat, sizeof (outformat)); numattr++; for (i = 0; rv == KMF_OK && i < ncerts; i++) { int num = numattr; /* * If storing more than 1 cert, gotta change * the name so we don't overwrite the previous one. * Just append a _# to the name. */ if (i > 0) { (void) snprintf(newcertfile, sizeof (newcertfile), "%s_%d", certfile, i); kmf_set_attr_at_index(attrlist, num, KMF_CERT_FILENAME_ATTR, newcertfile, strlen(newcertfile)); num++; } else { kmf_set_attr_at_index(attrlist, num, KMF_CERT_FILENAME_ATTR, certfile, strlen(certfile)); num++; } if (certs[i].kmf_private.label != NULL) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_LABEL_ATTR, certs[i].kmf_private.label, strlen(certs[i].kmf_private.label)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i].certificate, sizeof (KMF_DATA)); num++; rv = kmf_store_cert(kmfhandle, num, attrlist); } free(attrlist); } if (rv == KMF_OK && nkeys > 0) { char newkeyfile[MAXPATHLEN]; numattr = 0; NEW_ATTRLIST(attrlist, (4 + (4 * nkeys))); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &outformat, sizeof (outformat)); numattr++; if (cred != NULL && cred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL)); numattr++; } /* The order of certificates and keys should match */ for (i = 0; rv == KMF_OK && i < nkeys; i++) { int num = numattr; if (i > 0) { (void) snprintf(newkeyfile, sizeof (newkeyfile), "%s_%d", keyfile, i); kmf_set_attr_at_index(attrlist, num, KMF_KEY_FILENAME_ATTR, newkeyfile, strlen(newkeyfile)); num++; } else { kmf_set_attr_at_index(attrlist, num, KMF_KEY_FILENAME_ATTR, keyfile, strlen(keyfile)); num++; } if (i < ncerts) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i], sizeof (KMF_CERT_DATA_ATTR)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_RAW_KEY_ATTR, &keys[i], sizeof (KMF_RAW_KEY_DATA)); num++; rv = kmf_store_key(kmfhandle, num, attrlist); } free(attrlist); } end: /* * Cleanup memory. */ if (certs) { for (i = 0; i < ncerts; i++) kmf_free_kmf_cert(kmfhandle, &certs[i]); free(certs); } if (keys) { for (i = 0; i < nkeys; i++) kmf_free_raw_key(&keys[i]); free(keys); } return (rv); } static KMF_RETURN pk_import_pk12_nss( KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *kmfcred, KMF_CREDENTIAL *tokencred, char *token_spec, char *dir, char *prefix, char *nickname, char *trustflags, char *filename) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT *certs = NULL; KMF_RAW_KEY_DATA *keys = NULL; int ncerts = 0; int nkeys = 0; int i; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; KMF_ATTRIBUTE *attrlist = NULL; int numattr = 0; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); rv = kmf_import_objects(kmfhandle, filename, kmfcred, &certs, &ncerts, &keys, &nkeys); if (rv == KMF_OK) (void) printf(gettext("Found %d certificate(s) and %d " "key(s) in %s\n"), ncerts, nkeys, filename); if (rv == KMF_OK) { numattr = 0; NEW_ATTRLIST(attrlist, (4 + (2 * nkeys))); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } if (nickname != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, nickname, strlen(nickname)); numattr++; } if (tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } /* The order of certificates and keys should match */ for (i = 0; i < nkeys; i++) { int num = numattr; if (i < ncerts) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i], sizeof (KMF_DATA)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_RAW_KEY_ATTR, &keys[i], sizeof (KMF_RAW_KEY_DATA)); num++; rv = kmf_store_key(kmfhandle, num, attrlist); } free(attrlist); attrlist = NULL; } if (rv == KMF_OK) { numattr = 0; NEW_ATTRLIST(attrlist, (3 + (2 * ncerts))); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } if (trustflags != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TRUSTFLAG_ATTR, trustflags, strlen(trustflags)); numattr++; } for (i = 0; rv == KMF_OK && i < ncerts; i++) { int num = numattr; if (certs[i].kmf_private.label != NULL) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_LABEL_ATTR, certs[i].kmf_private.label, strlen(certs[i].kmf_private.label)); num++; } else if (i == 0 && nickname != NULL) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_LABEL_ATTR, nickname, strlen(nickname)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i].certificate, sizeof (KMF_DATA)); num++; rv = kmf_store_cert(kmfhandle, num, attrlist); } free(attrlist); attrlist = NULL; if (rv != KMF_OK) { display_error(kmfhandle, rv, gettext("Error storing certificate in NSS token")); } } end: /* * Cleanup memory. */ if (certs) { for (i = 0; i < ncerts; i++) kmf_free_kmf_cert(kmfhandle, &certs[i]); free(certs); } if (keys) { for (i = 0; i < nkeys; i++) kmf_free_raw_key(&keys[i]); free(keys); } return (rv); } static KMF_RETURN pk_import_cert( KMF_HANDLE_T kmfhandle, KMF_KEYSTORE_TYPE kstype, char *label, char *token_spec, char *filename, char *dir, char *prefix, char *trustflags) { KMF_RETURN rv = KMF_OK; KMF_ATTRIBUTE attrlist[32]; KMF_CREDENTIAL tokencred; int i = 0; if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = select_token(kmfhandle, token_spec, FALSE); } else if (kstype == KMF_KEYSTORE_NSS) { rv = configure_nss(kmfhandle, dir, prefix); } if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, i, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (KMF_KEYSTORE_TYPE)); i++; kmf_set_attr_at_index(attrlist, i, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); i++; if (label != NULL) { kmf_set_attr_at_index(attrlist, i, KMF_CERT_LABEL_ATTR, label, strlen(label)); i++; } if (kstype == KMF_KEYSTORE_NSS) { if (trustflags != NULL) { kmf_set_attr_at_index(attrlist, i, KMF_TRUSTFLAG_ATTR, trustflags, strlen(trustflags)); i++; } if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, i, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); i++; } } rv = kmf_import_cert(kmfhandle, i, attrlist); if (rv == KMF_ERR_AUTH_FAILED) { /* * The token requires a credential, prompt and try again. */ (void) get_token_password(kstype, token_spec, &tokencred); kmf_set_attr_at_index(attrlist, i, KMF_CREDENTIAL_ATTR, &tokencred, sizeof (KMF_CREDENTIAL)); i++; rv = kmf_import_cert(kmfhandle, i, attrlist); } return (rv); } static KMF_RETURN pk_import_file_crl(void *kmfhandle, char *infile, char *outfile, KMF_ENCODE_FORMAT outfmt) { int numattr = 0; KMF_ATTRIBUTE attrlist[8]; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (infile) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_FILENAME_ATTR, infile, strlen(infile)); numattr++; } if (outfile) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_OUTFILE_ATTR, outfile, strlen(outfile)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR, &outfmt, sizeof (outfmt)); numattr++; return (kmf_import_crl(kmfhandle, numattr, attrlist)); } static KMF_RETURN pk_import_nss_crl(void *kmfhandle, boolean_t verify_crl_flag, char *infile, char *outdir, char *prefix) { KMF_RETURN rv; int numattr = 0; KMF_ATTRIBUTE attrlist[4]; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; rv = configure_nss(kmfhandle, outdir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (infile) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_FILENAME_ATTR, infile, strlen(infile)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_CHECK_ATTR, &verify_crl_flag, sizeof (verify_crl_flag)); numattr++; return (kmf_import_crl(kmfhandle, numattr, attrlist)); } static KMF_RETURN pk_import_pk12_pk11( KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *p12cred, KMF_CREDENTIAL *tokencred, char *label, char *token_spec, char *filename) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT *certs = NULL; KMF_RAW_KEY_DATA *keys = NULL; int ncerts = 0; int nkeys = 0; int i; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_ATTRIBUTE *attrlist = NULL; int numattr = 0; rv = select_token(kmfhandle, token_spec, FALSE); if (rv != KMF_OK) { return (rv); } rv = kmf_import_objects(kmfhandle, filename, p12cred, &certs, &ncerts, &keys, &nkeys); if (rv == KMF_OK) { NEW_ATTRLIST(attrlist, (3 + (2 * nkeys))); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (label != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, label, strlen(label)); numattr++; } if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } /* The order of certificates and keys should match */ for (i = 0; i < nkeys; i++) { int num = numattr; if (i < ncerts) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i].certificate, sizeof (KMF_DATA)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_RAW_KEY_ATTR, &keys[i], sizeof (KMF_RAW_KEY_DATA)); num++; rv = kmf_store_key(kmfhandle, num, attrlist); } free(attrlist); } if (rv == KMF_OK) { numattr = 0; NEW_ATTRLIST(attrlist, (1 + (2 * ncerts))); (void) printf(gettext("Found %d certificate(s) and %d " "key(s) in %s\n"), ncerts, nkeys, filename); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; for (i = 0; rv == KMF_OK && i < ncerts; i++) { int num = numattr; if (certs[i].kmf_private.label != NULL) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_LABEL_ATTR, certs[i].kmf_private.label, strlen(certs[i].kmf_private.label)); num++; } else if (i == 0 && label != NULL) { kmf_set_attr_at_index(attrlist, num, KMF_CERT_LABEL_ATTR, label, strlen(label)); num++; } kmf_set_attr_at_index(attrlist, num, KMF_CERT_DATA_ATTR, &certs[i].certificate, sizeof (KMF_DATA)); num++; rv = kmf_store_cert(kmfhandle, num, attrlist); } free(attrlist); } end: /* * Cleanup memory. */ if (certs) { for (i = 0; i < ncerts; i++) kmf_free_kmf_cert(kmfhandle, &certs[i]); free(certs); } if (keys) { for (i = 0; i < nkeys; i++) kmf_free_raw_key(&keys[i]); free(keys); } return (rv); } /*ARGSUSED*/ static KMF_RETURN pk_import_keys(KMF_HANDLE_T kmfhandle, KMF_KEYSTORE_TYPE kstype, char *token_spec, KMF_CREDENTIAL *cred, char *filename, char *label, char *senstr, char *extstr) { KMF_RETURN rv = KMF_OK; KMF_ATTRIBUTE attrlist[16]; KMF_KEYSTORE_TYPE fileks = KMF_KEYSTORE_OPENSSL; int numattr = 0; KMF_KEY_HANDLE key; KMF_RAW_KEY_DATA rawkey; KMF_KEY_CLASS class = KMF_ASYM_PRI; int numkeys = 1; if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = select_token(kmfhandle, token_spec, FALSE); } if (rv != KMF_OK) return (rv); /* * First, set up to read the keyfile using the FILE plugin * mechanisms. */ kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &fileks, sizeof (fileks)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &numkeys, sizeof (numkeys)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &key, sizeof (key)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_RAW_KEY_ATTR, &rawkey, sizeof (rawkey)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, &class, sizeof (class)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, filename, strlen(filename)); numattr++; rv = kmf_find_key(kmfhandle, numattr, attrlist); if (rv == KMF_OK) { numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (cred != NULL && cred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL)); numattr++; } if (label != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, label, strlen(label)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_RAW_KEY_ATTR, &rawkey, sizeof (rawkey)); numattr++; rv = kmf_store_key(kmfhandle, numattr, attrlist); if (rv == KMF_OK) { (void) printf(gettext("Importing %d keys\n"), numkeys); } kmf_free_kmf_key(kmfhandle, &key); kmf_free_raw_key(&rawkey); } else { cryptoerror(LOG_STDERR, gettext("Failed to load key from file (%s)\n"), filename); } return (rv); } static KMF_RETURN pk_import_rawkey(KMF_HANDLE_T kmfhandle, KMF_KEYSTORE_TYPE kstype, char *token, KMF_CREDENTIAL *cred, char *filename, char *label, KMF_KEY_ALG keyAlg, char *senstr, char *extstr) { KMF_RETURN rv = KMF_OK; KMF_ATTRIBUTE attrlist[16]; int numattr = 0; uint32_t keylen; boolean_t sensitive = B_FALSE; boolean_t not_extractable = B_FALSE; KMF_DATA keydata = { 0, NULL }; KMF_KEY_HANDLE rawkey; rv = kmf_read_input_file(kmfhandle, filename, &keydata); if (rv != KMF_OK) return (rv); rv = select_token(kmfhandle, token, FALSE); if (rv != KMF_OK) { return (rv); } 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); } } 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); } } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &rawkey, sizeof (rawkey)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYALG_ATTR, &keyAlg, sizeof (KMF_KEY_ALG)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_DATA_ATTR, keydata.Data, keydata.Length); numattr++; /* Key length is given in bits not bytes */ keylen = keydata.Length * 8; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLENGTH_ATTR, &keylen, sizeof (keydata.Length)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_SENSITIVE_BOOL_ATTR, &sensitive, sizeof (sensitive)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_NON_EXTRACTABLE_BOOL_ATTR, ¬_extractable, sizeof (not_extractable)); numattr++; if (label != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, label, strlen(label)); numattr++; } if (cred != NULL && cred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL)); numattr++; } rv = kmf_create_sym_key(kmfhandle, numattr, attrlist); return (rv); } /* * Import objects from into KMF repositories. */ int pk_import(int argc, char *argv[]) { int opt; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *filename = NULL; char *keyfile = NULL; char *certfile = NULL; char *crlfile = NULL; char *label = NULL; char *dir = NULL; char *prefix = NULL; char *trustflags = NULL; char *verify_crl = NULL; char *keytype = "generic"; char *senstr = NULL; char *extstr = NULL; boolean_t verify_crl_flag = B_FALSE; int oclass = 0; KMF_KEYSTORE_TYPE kstype = 0; KMF_ENCODE_FORMAT kfmt = 0; KMF_ENCODE_FORMAT okfmt = KMF_FORMAT_ASN1; KMF_RETURN rv = KMF_OK; KMF_CREDENTIAL pk12cred = { NULL, 0 }; KMF_CREDENTIAL tokencred = { NULL, 0 }; KMF_HANDLE_T kmfhandle = NULL; KMF_KEY_ALG keyAlg = KMF_GENERIC_SECRET; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "T:(token)i:(infile)" "k:(keystore)y:(objtype)" "d:(dir)p:(prefix)" "n:(certlabel)N:(label)" "K:(outkey)c:(outcert)" "v:(verifycrl)l:(outcrl)" "E:(keytype)s:(sensitive)x:(extractable)" "t:(trust)F:(outformat)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = optarg_av; break; case 'c': /* output cert file name */ if (certfile) return (PK_ERR_USAGE); certfile = optarg_av; break; case 'l': /* output CRL file name */ if (crlfile) return (PK_ERR_USAGE); crlfile = optarg_av; break; case 'K': /* output key file name */ if (keyfile) return (PK_ERR_USAGE); keyfile = optarg_av; break; case 'i': /* input file name */ if (filename) return (PK_ERR_USAGE); filename = optarg_av; break; case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 'y': oclass = OT2Int(optarg_av); if (oclass == -1) return (PK_ERR_USAGE); break; case 'd': dir = optarg_av; break; case 'p': if (prefix) return (PK_ERR_USAGE); prefix = optarg_av; break; case 'n': case 'N': if (label) return (PK_ERR_USAGE); label = optarg_av; break; case 'F': okfmt = Str2Format(optarg_av); if (okfmt == KMF_FORMAT_UNDEF) return (PK_ERR_USAGE); break; case 't': if (trustflags) return (PK_ERR_USAGE); trustflags = optarg_av; break; case 'v': verify_crl = optarg_av; if (tolower(verify_crl[0]) == 'y') verify_crl_flag = B_TRUE; else if (tolower(verify_crl[0]) == 'n') verify_crl_flag = B_FALSE; else return (PK_ERR_USAGE); break; case 'E': keytype = optarg_av; break; case 's': if (senstr) return (PK_ERR_USAGE); senstr = optarg_av; break; case 'x': if (extstr) return (PK_ERR_USAGE); extstr = optarg_av; break; default: return (PK_ERR_USAGE); } } /* Assume keystore = PKCS#11 if not specified */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; /* Filename arg is required. */ if (EMPTYSTRING(filename)) { cryptoerror(LOG_STDERR, gettext("The 'infile' parameter" "is required for the import operation.\n")); return (PK_ERR_USAGE); } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) return (PK_ERR_USAGE); DIR_OPTION_CHECK(kstype, dir); /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && kstype != KMF_KEYSTORE_PK11TOKEN) { (void) fprintf(stderr, gettext("The objtype parameter " "is only relevant if keystore=pkcs11\n")); return (PK_ERR_USAGE); } /* * You must specify a certlabel (cert label) when importing * into NSS or PKCS#11. */ if (kstype == KMF_KEYSTORE_NSS && (oclass != PK_CRL_OBJ) && EMPTYSTRING(label)) { cryptoerror(LOG_STDERR, gettext("The 'label' argument " "is required for this operation\n")); return (PK_ERR_USAGE); } if ((rv = kmf_get_file_format(filename, &kfmt)) != KMF_OK) { char *kmferrstr = NULL; KMF_RETURN rv2; /* * Allow for raw key data to be imported. */ if (rv == KMF_ERR_ENCODING) { rv = KMF_OK; kfmt = KMF_FORMAT_RAWKEY; /* * Set the object class only if it was not * given on the command line or if it was * specified as a symmetric key object. */ if (oclass == 0 || (oclass & PK_SYMKEY_OBJ)) { oclass = PK_SYMKEY_OBJ; } else { cryptoerror(LOG_STDERR, gettext( "The input file does not contain the " "object type indicated on command " "line.")); return (KMF_ERR_BAD_PARAMETER); } } else { if (rv == KMF_ERR_OPEN_FILE) { cryptoerror(LOG_STDERR, gettext("Cannot open file (%s)\n."), filename); } else { rv2 = kmf_get_kmf_error_str(rv, &kmferrstr); if (rv2 == KMF_OK && kmferrstr) { cryptoerror(LOG_STDERR, gettext("libkmf error: %s"), kmferrstr); kmf_free_str(kmferrstr); } } return (rv); } } /* Check parameters for raw key import operation */ if (kfmt == KMF_FORMAT_RAWKEY) { if (keytype != NULL && Str2SymKeyType(keytype, &keyAlg) != 0) { cryptoerror(LOG_STDERR, gettext("Unrecognized keytype(%s).\n"), keytype); return (PK_ERR_USAGE); } if (senstr != NULL && extstr != NULL && kstype != KMF_KEYSTORE_PK11TOKEN) { cryptoerror(LOG_STDERR, gettext("The sensitive or extractable option " "applies only when importing a key from a file " "into a PKCS#11 keystore.\n")); return (PK_ERR_USAGE); } } /* If no objtype was given, treat it as a certificate */ if (oclass == 0 && (kfmt == KMF_FORMAT_ASN1 || kfmt == KMF_FORMAT_PEM)) oclass = PK_CERT_OBJ; if (kstype == KMF_KEYSTORE_NSS) { if (oclass == PK_CRL_OBJ && (kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) { cryptoerror(LOG_STDERR, gettext( "CRL data can only be imported as DER or " "PEM format")); return (PK_ERR_USAGE); } if (oclass == PK_CERT_OBJ && (kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) { cryptoerror(LOG_STDERR, gettext( "Certificates can only be imported as DER or " "PEM format")); return (PK_ERR_USAGE); } /* we do not import private keys except in PKCS12 bundles */ if (oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)) { cryptoerror(LOG_STDERR, gettext( "Private key data can only be imported as part " "of a PKCS12 file.\n")); return (PK_ERR_USAGE); } } if (kstype == KMF_KEYSTORE_OPENSSL && oclass != PK_CRL_OBJ) { if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) { cryptoerror(LOG_STDERR, gettext( "The 'outkey' and 'outcert' parameters " "are required for the import operation " "when the 'file' keystore is used.\n")); return (PK_ERR_USAGE); } } if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) token_spec = PK_DEFAULT_PK11TOKEN; else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) token_spec = DEFAULT_NSS_TOKEN; if (kfmt == KMF_FORMAT_PKCS12) { (void) get_pk12_password(&pk12cred); } if ((kfmt == KMF_FORMAT_PKCS12 || kfmt == KMF_FORMAT_RAWKEY || (kfmt == KMF_FORMAT_PEM && (oclass & PK_KEY_OBJ))) && (kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS)) { (void) get_token_password(kstype, token_spec, &tokencred); } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing " "KMF: 0x%02x\n"), rv); goto end; } switch (kstype) { case KMF_KEYSTORE_PK11TOKEN: if (kfmt == KMF_FORMAT_PKCS12) rv = pk_import_pk12_pk11( kmfhandle, &pk12cred, &tokencred, label, token_spec, filename); else if (oclass == PK_CERT_OBJ) rv = pk_import_cert( kmfhandle, kstype, label, token_spec, filename, NULL, NULL, NULL); else if (oclass == PK_CRL_OBJ) rv = pk_import_file_crl( kmfhandle, filename, crlfile, okfmt); else if (kfmt == KMF_FORMAT_RAWKEY && oclass == PK_SYMKEY_OBJ) { rv = pk_import_rawkey(kmfhandle, kstype, token_spec, &tokencred, filename, label, keyAlg, senstr, extstr); } else if (kfmt == KMF_FORMAT_PEM || kfmt == KMF_FORMAT_PEM_KEYPAIR) { rv = pk_import_keys(kmfhandle, kstype, token_spec, &tokencred, filename, label, senstr, extstr); } else { rv = PK_ERR_USAGE; } break; case KMF_KEYSTORE_NSS: if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; if (kfmt == KMF_FORMAT_PKCS12) rv = pk_import_pk12_nss( kmfhandle, &pk12cred, &tokencred, token_spec, dir, prefix, label, trustflags, filename); else if (oclass == PK_CERT_OBJ) { rv = pk_import_cert( kmfhandle, kstype, label, token_spec, filename, dir, prefix, trustflags); } else if (oclass == PK_CRL_OBJ) { rv = pk_import_nss_crl( kmfhandle, verify_crl_flag, filename, dir, prefix); } break; case KMF_KEYSTORE_OPENSSL: if (kfmt == KMF_FORMAT_PKCS12) rv = pk_import_pk12_files( kmfhandle, &pk12cred, filename, certfile, keyfile, okfmt); else if (oclass == PK_CRL_OBJ) { rv = pk_import_file_crl( kmfhandle, filename, crlfile, okfmt); } else /* * It doesn't make sense to import anything * else for the files plugin. */ return (PK_ERR_USAGE); break; default: rv = PK_ERR_USAGE; break; } end: if (rv != KMF_OK) display_error(kmfhandle, rv, gettext("Error importing objects")); if (tokencred.cred != NULL) free(tokencred.cred); if (pk12cred.cred != NULL) free(pk12cred.cred); (void) kmf_finalize(kmfhandle); if (rv != KMF_OK) return (PK_ERR_USAGE); return (0); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * This file implements the inittoken operation for this tool. * The basic flow of the process is to load the PKCS#11 module, * find the token to be initialize , login using the SO pin, * and call C_InitToken. */ #include #include #include #include #include #include #include "common.h" int pk_inittoken(int argc, char *argv[]) /* ARGSUSED */ { int opt; int rv; extern int optind_av; extern char *optarg_av; char *newlabel = NULL; char *currlabel = NULL; CK_UTF8CHAR_PTR sopin; CK_ULONG sopinlen; KMF_HANDLE_T handle; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "n:(newlabel)" "l:(currlabel)")) != EOF) { switch (opt) { case 'l': /* token specifier */ if (currlabel) return (PK_ERR_USAGE); currlabel = optarg_av; break; case 'n': /* token specifier */ if (newlabel) return (PK_ERR_USAGE); newlabel = optarg_av; break; default: return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc != 0) return (PK_ERR_USAGE); if ((rv = kmf_initialize(&handle, NULL, NULL)) != KMF_OK) return (rv); if ((rv = get_pin(gettext("Enter SO PIN:"), NULL, &sopin, &sopinlen)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get SO PIN for token")); return (PK_ERR_SYSTEM); } if ((currlabel == NULL || !strlen(currlabel))) { cryptoerror(LOG_STDERR, gettext("The current token is not identified by label.")); return (PK_ERR_SYSTEM); } rv = kmf_pk11_init_token(handle, currlabel, newlabel, sopin, sopinlen); (void) kmf_finalize(handle); free(sopin); if (rv == KMF_ERR_AUTH_FAILED) { cryptoerror(LOG_STDERR, gettext("Incorrect passphrase.")); return (PK_ERR_SYSTEM); } else if (rv != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to initialize token.")); return (PK_ERR_SYSTEM); } else { (void) fprintf(stdout, gettext("Token %s initialized.\n"), (newlabel ? newlabel : currlabel)); } return (0); } /* * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * This file implements the token object list operation for this tool. * It loads the PKCS#11 modules, finds the object to list, lists it, * and cleans up. User must be logged into the token to list private * objects. */ #include #include #include #include #include #include "common.h" #include static void pk_show_certs(KMF_HANDLE_T kmfhandle, KMF_X509_DER_CERT *certs, int num_certs) { int i; char *subject, *issuer, *serial, *id, *altname; char *start, *end, *keyusage, *extkeyusage; for (i = 0; i < num_certs; i++) { subject = NULL; issuer = NULL; serial = NULL; id = NULL; altname = NULL; start = end = NULL; keyusage = extkeyusage = NULL; (void) fprintf(stdout, gettext("%d. (X.509 certificate)\n"), i + 1); if (certs[i].kmf_private.label != NULL) (void) fprintf(stdout, gettext("\t%s: %s\n"), (certs[i].kmf_private.keystore_type == KMF_KEYSTORE_OPENSSL ? "Filename" : "Label"), certs[i].kmf_private.label); if (kmf_get_cert_id_str(&certs[i].certificate, &id) == KMF_OK) (void) fprintf(stdout, gettext("\tID: %s\n"), id); if (kmf_get_cert_subject_str(kmfhandle, &certs[i].certificate, &subject) == KMF_OK) (void) fprintf(stdout, gettext("\tSubject: %s\n"), subject); if (kmf_get_cert_issuer_str(kmfhandle, &certs[i].certificate, &issuer) == KMF_OK) (void) fprintf(stdout, gettext("\tIssuer: %s\n"), issuer); if (kmf_get_cert_start_date_str(kmfhandle, &certs[i].certificate, &start) == KMF_OK) (void) fprintf(stdout, gettext("\tNot Before: %s\n"), start); if (kmf_get_cert_end_date_str(kmfhandle, &certs[i].certificate, &end) == KMF_OK) (void) fprintf(stdout, gettext("\tNot After: %s\n"), end); if (kmf_get_cert_serial_str(kmfhandle, &certs[i].certificate, &serial) == KMF_OK) (void) fprintf(stdout, gettext("\tSerial: %s\n"), serial); if (kmf_get_cert_extn_str(kmfhandle, &certs[i].certificate, KMF_X509_EXT_SUBJ_ALTNAME, &altname) == KMF_OK) { (void) fprintf(stdout, gettext("\t%s\n"), altname); } if (kmf_get_cert_extn_str(kmfhandle, &certs[i].certificate, KMF_X509_EXT_KEY_USAGE, &keyusage) == KMF_OK) { (void) fprintf(stdout, gettext("\t%s\n"), keyusage); } if (kmf_get_cert_extn_str(kmfhandle, &certs[i].certificate, KMF_X509_EXT_EXT_KEY_USAGE, &extkeyusage) == KMF_OK) { (void) fprintf(stdout, gettext("\t%s\n"), extkeyusage); } kmf_free_str(subject); kmf_free_str(issuer); kmf_free_str(serial); kmf_free_str(id); kmf_free_str(altname); kmf_free_str(keyusage); kmf_free_str(extkeyusage); kmf_free_str(start); kmf_free_str(end); (void) fprintf(stdout, "\n"); } } static char * describeKey(KMF_KEY_HANDLE *key) { if (key->keyclass == KMF_ASYM_PUB) { if (key->keyalg == KMF_RSA) return (gettext("RSA public key")); if (key->keyalg == KMF_DSA) return (gettext("DSA public key")); if (key->keyalg == KMF_ECDSA) return (gettext("ECDSA public key")); } if (key->keyclass == KMF_ASYM_PRI) { if (key->keyalg == KMF_RSA) return (gettext("RSA private key")); if (key->keyalg == KMF_DSA) return (gettext("DSA private key")); if (key->keyalg == KMF_ECDSA) return (gettext("ECDSA private key")); } if (key->keyclass == KMF_SYMMETRIC) { switch (key->keyalg) { case KMF_AES: return (gettext("AES")); case KMF_RC4: return (gettext("ARCFOUR")); case KMF_DES: return (gettext("DES")); case KMF_DES3: return (gettext("Triple-DES")); default: return (gettext("symmetric")); } } return (gettext("unrecognized key object")); } static void pk_show_keys(void *handle, KMF_KEY_HANDLE *keys, int numkeys) { int i; for (i = 0; i < numkeys; i++) { (void) fprintf(stdout, gettext("Key #%d - %s: %s"), i+1, describeKey(&keys[i]), keys[i].keylabel ? keys[i].keylabel : gettext("No label")); if (keys[i].keyclass == KMF_SYMMETRIC) { KMF_RETURN rv; KMF_RAW_SYM_KEY rkey; (void) memset(&rkey, 0, sizeof (rkey)); rv = kmf_get_sym_key_value(handle, &keys[i], &rkey); if (rv == KMF_OK) { (void) fprintf(stdout, " (%d bits)", rkey.keydata.len * 8); kmf_free_bigint(&rkey.keydata); } else if (keys[i].kstype == KMF_KEYSTORE_PK11TOKEN) { if (rv == KMF_ERR_SENSITIVE_KEY) { (void) fprintf(stdout, " (sensitive)"); } else if (rv == KMF_ERR_UNEXTRACTABLE_KEY) { (void) fprintf(stdout, " (non-extractable)"); } else { char *err = NULL; if (kmf_get_kmf_error_str(rv, &err) == KMF_OK) (void) fprintf(stdout, " (error: %s)", err); if (err != NULL) free(err); } } } (void) fprintf(stdout, "\n"); } } /* * Generic routine used by all "list cert" operations to find * all matching certificates. */ static KMF_RETURN pk_find_certs(KMF_HANDLE_T kmfhandle, KMF_ATTRIBUTE *attrlist, int numattr) { KMF_RETURN rv = KMF_OK; KMF_X509_DER_CERT *certlist = NULL; uint32_t numcerts = 0; KMF_KEYSTORE_TYPE kstype; rv = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr, &kstype, NULL); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &numcerts, sizeof (uint32_t)); numattr++; rv = kmf_find_cert(kmfhandle, numattr, attrlist); if (rv == KMF_OK && numcerts > 0) { (void) printf(gettext("Found %d certificates.\n"), numcerts); certlist = (KMF_X509_DER_CERT *)malloc(numcerts * sizeof (KMF_X509_DER_CERT)); if (certlist == NULL) return (KMF_ERR_MEMORY); (void) memset(certlist, 0, numcerts * sizeof (KMF_X509_DER_CERT)); kmf_set_attr_at_index(attrlist, numattr, KMF_X509_DER_CERT_ATTR, certlist, sizeof (KMF_X509_DER_CERT)); numattr++; rv = kmf_find_cert(kmfhandle, numattr, attrlist); if (rv == KMF_OK) { int i; (void) pk_show_certs(kmfhandle, certlist, numcerts); for (i = 0; i < numcerts; i++) kmf_free_kmf_cert(kmfhandle, &certlist[i]); } free(certlist); } if (rv == KMF_ERR_CERT_NOT_FOUND && kstype != KMF_KEYSTORE_OPENSSL) rv = KMF_OK; return (rv); } static KMF_RETURN pk_list_keys(void *handle, KMF_ATTRIBUTE *attrlist, int numattr, char *label) { KMF_RETURN rv; KMF_KEY_HANDLE *keys; uint32_t numkeys = 0; KMF_KEYSTORE_TYPE kstype; rv = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr, &kstype, NULL); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &numkeys, sizeof (uint32_t)); numattr++; rv = kmf_find_key(handle, numattr, attrlist); if (rv == KMF_OK && numkeys > 0) { int i; (void) printf(gettext("Found %d %s keys.\n"), numkeys, label); keys = (KMF_KEY_HANDLE *)malloc(numkeys * sizeof (KMF_KEY_HANDLE)); if (keys == NULL) return (KMF_ERR_MEMORY); (void) memset(keys, 0, numkeys * sizeof (KMF_KEY_HANDLE)); kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, keys, sizeof (KMF_KEY_HANDLE)); numattr++; rv = kmf_find_key(handle, numattr, attrlist); if (rv == KMF_OK) pk_show_keys(handle, keys, numkeys); for (i = 0; i < numkeys; i++) kmf_free_kmf_key(handle, &keys[i]); free(keys); } if (rv == KMF_ERR_KEY_NOT_FOUND && kstype != KMF_KEYSTORE_OPENSSL) rv = KMF_OK; return (rv); } static KMF_RETURN list_pk11_objects(KMF_HANDLE_T kmfhandle, char *token, int oclass, char *objlabel, KMF_BIGINT *serial, char *issuer, char *subject, char *dir, char *filename, KMF_CREDENTIAL *tokencred, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN rv; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; int numattr = 0; KMF_ATTRIBUTE attrlist[18]; boolean_t token_bool = B_TRUE; boolean_t private = B_FALSE; KMF_KEY_CLASS keyclass; KMF_ENCODE_FORMAT format; int auth = 0; KMF_CREDENTIAL cred = { NULL, 0 }; /* * Symmetric keys and RSA/DSA/ECDSA private keys are always * created with the "CKA_PRIVATE" field == TRUE, so * make sure we search for them with it also set. */ if (oclass & (PK_SYMKEY_OBJ | PK_PRIKEY_OBJ)) oclass |= PK_PRIVATE_OBJ; rv = select_token(kmfhandle, token, !(oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ))); if (rv != KMF_OK) { return (rv); } rv = token_auth_needed(kmfhandle, token, &auth); if (rv != KMF_OK) return (rv); if (tokencred != NULL) cred = *tokencred; if (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ)) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } private = ((oclass & PK_PRIVATE_OBJ) > 0); kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVATE_BOOL_ATTR, &private, sizeof (private)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR, &token_bool, sizeof (token_bool)); numattr++; if (oclass & PK_PRIKEY_OBJ) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, num, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); num++; } /* list asymmetric private keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "asymmetric private"); } if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, num, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); num++; } format = KMF_FORMAT_RAWKEY; kmf_set_attr_at_index(attrlist, num, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); num++; /* list symmetric keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "symmetric"); } if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { int num = numattr; if (auth > 0 && (tokencred == NULL || tokencred->cred == NULL) && (cred.cred == NULL)) { (void) get_token_password(kstype, token, &cred); kmf_set_attr_at_index(attrlist, num, KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL)); num++; } private = B_FALSE; keyclass = KMF_ASYM_PUB; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; /* list asymmetric public keys (if any) */ rv = pk_list_keys(kmfhandle, attrlist, num, "asymmetric public"); } if (rv != KMF_OK) return (rv); } numattr = 0; if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (auth > 0 && (cred.cred == NULL)) { (void) get_token_password(kstype, token, &cred); } if (cred.cred != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL)); numattr++; } if (objlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, objlabel, strlen(objlabel)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL && serial->val != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVATE_BOOL_ATTR, &private, sizeof (private)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; rv = pk_find_certs(kmfhandle, attrlist, numattr); if (rv != KMF_OK) return (rv); } numattr = 0; kstype = KMF_KEYSTORE_OPENSSL; /* CRL is file-based */ if (oclass & PK_CRL_OBJ) { char *crldata = NULL; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } if (filename != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_FILENAME_ATTR, filename, strlen(filename)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_DATA_ATTR, &crldata, sizeof (char *)); numattr++; rv = kmf_list_crl(kmfhandle, numattr, attrlist); if (rv == KMF_OK && crldata != NULL) { (void) printf("%s\n", crldata); free(crldata); } } return (rv); } static int list_file_objects(KMF_HANDLE_T kmfhandle, int oclass, char *dir, char *filename, KMF_BIGINT *serial, char *issuer, char *subject, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_CLASS keyclass; KMF_ENCODE_FORMAT format; char *defaultdir = "."; if (oclass & PK_KEY_OBJ) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (dir == NULL && filename == NULL) dir = defaultdir; if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } if (filename != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, filename, strlen(filename)); numattr++; } if (oclass & PK_PRIKEY_OBJ) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; /* list asymmetric private keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "asymmetric private"); } if (rv == KMF_ERR_KEY_NOT_FOUND) rv = KMF_OK; if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; format = KMF_FORMAT_RAWKEY; kmf_set_attr_at_index(attrlist, num, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); num++; /* list symmetric keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "symmetric"); } if (rv == KMF_ERR_KEY_NOT_FOUND) rv = KMF_OK; if (rv != KMF_OK) return (rv); } numattr = 0; if (oclass & PK_CERT_OBJ) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL && serial->val != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (filename != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_FILENAME_ATTR, filename, strlen(filename)); numattr++; } if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; rv = pk_find_certs(kmfhandle, attrlist, numattr); if (rv != KMF_OK) return (rv); } numattr = 0; if (oclass & PK_CRL_OBJ) { char *crldata = NULL; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (dir != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_DIRPATH_ATTR, dir, strlen(dir)); numattr++; } if (filename != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_FILENAME_ATTR, filename, strlen(filename)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_DATA_ATTR, &crldata, sizeof (char *)); numattr++; rv = kmf_list_crl(kmfhandle, numattr, attrlist); if (rv == KMF_OK && crldata != NULL) { (void) printf("%s\n", crldata); free(crldata); } } return (rv); } static int list_nss_objects(KMF_HANDLE_T kmfhandle, int oclass, char *token_spec, char *dir, char *prefix, char *nickname, KMF_BIGINT *serial, char *issuer, char *subject, KMF_CREDENTIAL *tokencred, KMF_CERT_VALIDITY find_criteria_flag) { KMF_RETURN rv = KMF_OK; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; int numattr = 0; KMF_ATTRIBUTE attrlist[16]; KMF_KEY_CLASS keyclass; KMF_ENCODE_FORMAT format; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (oclass & PK_KEY_OBJ) { if (tokencred != NULL && tokencred->credlen > 0) { kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL)); numattr++; } if (token_spec && strlen(token_spec)) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } if (nickname != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, nickname, strlen(nickname)); numattr++; } } if (oclass & PK_PRIKEY_OBJ) { int num = numattr; keyclass = KMF_ASYM_PRI; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; /* list asymmetric private keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "asymmetric private"); } if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { int num = numattr; keyclass = KMF_SYMMETRIC; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; format = KMF_FORMAT_RAWKEY; kmf_set_attr_at_index(attrlist, num, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); num++; /* list symmetric keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "symmetric"); } if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { int num = numattr; keyclass = KMF_ASYM_PUB; kmf_set_attr_at_index(attrlist, num, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); num++; /* list asymmetric public keys */ rv = pk_list_keys(kmfhandle, attrlist, num, "asymmetric public"); } /* If searching for public objects or certificates, find certs now */ numattr = 0; if (rv == KMF_OK && (oclass & PK_CERT_OBJ)) { kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (nickname != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, nickname, strlen(nickname)); numattr++; } if (issuer != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer)); numattr++; } if (subject != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_SUBJECT_NAME_ATTR, subject, strlen(subject)); numattr++; } if (serial != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT)); numattr++; } if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_VALIDITY_ATTR, &find_criteria_flag, sizeof (KMF_CERT_VALIDITY)); numattr++; rv = pk_find_certs(kmfhandle, attrlist, numattr); } numattr = 0; if (rv == KMF_OK && (oclass & PK_CRL_OBJ)) { int numcrls; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (token_spec != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_COUNT_ATTR, &numcrls, sizeof (int)); numattr++; rv = kmf_find_crl(kmfhandle, numattr, attrlist); if (rv == KMF_OK) { char **p; if (numcrls == 0) { (void) printf(gettext("No CRLs found in " "NSS keystore.\n")); return (KMF_OK); } p = malloc(numcrls * sizeof (char *)); if (p == NULL) { return (KMF_ERR_MEMORY); } (void) memset(p, 0, numcrls * sizeof (char *)); kmf_set_attr_at_index(attrlist, numattr, KMF_CRL_NAMELIST_ATTR, p, sizeof (char *)); numattr++; rv = kmf_find_crl(kmfhandle, numattr, attrlist); if (rv == KMF_OK) { int i; for (i = 0; i < numcrls; i++) { (void) printf("%d. Name = %s\n", i + 1, p[i]); free(p[i]); } } free(p); } } return (rv); } /* * List token object. */ int pk_list(int argc, char *argv[]) { int opt; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *subject = NULL; char *issuer = NULL; char *dir = NULL; char *prefix = NULL; char *filename = NULL; char *serstr = NULL; KMF_BIGINT serial = { NULL, 0 }; char *list_label = NULL; int oclass = 0; KMF_KEYSTORE_TYPE kstype = 0; KMF_RETURN rv = KMF_OK; KMF_HANDLE_T kmfhandle = NULL; char *find_criteria = NULL; KMF_CERT_VALIDITY find_criteria_flag = KMF_ALL_CERTS; KMF_CREDENTIAL tokencred = { NULL, 0 }; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "k:(keystore)t:(objtype)T:(token)d:(dir)" "p:(prefix)n:(nickname)S:(serial)s:(subject)" "c:(criteria)" "i:(issuer)l:(label)f:(infile)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'k': if (kstype != 0) return (PK_ERR_USAGE); kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 't': if (oclass != 0) return (PK_ERR_USAGE); oclass = OT2Int(optarg_av); if (oclass == -1) return (PK_ERR_USAGE); break; case 's': if (subject) return (PK_ERR_USAGE); subject = optarg_av; break; case 'i': if (issuer) return (PK_ERR_USAGE); issuer = 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 'S': serstr = optarg_av; break; case 'f': if (filename) return (PK_ERR_USAGE); filename = optarg_av; break; case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = optarg_av; break; case 'n': case 'l': /* object with specific label */ if (list_label) return (PK_ERR_USAGE); list_label = optarg_av; break; case 'c': find_criteria = optarg_av; if (!strcasecmp(find_criteria, "valid")) find_criteria_flag = KMF_NONEXPIRED_CERTS; else if (!strcasecmp(find_criteria, "expired")) find_criteria_flag = KMF_EXPIRED_CERTS; else if (!strcasecmp(find_criteria, "both")) find_criteria_flag = KMF_ALL_CERTS; else return (PK_ERR_USAGE); break; default: return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) return (PK_ERR_USAGE); if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { /* Error message ? */ return (rv); } /* Assume keystore = PKCS#11 if not specified. */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && kstype != KMF_KEYSTORE_PK11TOKEN) { (void) fprintf(stderr, gettext("The objtype parameter " "is only relevant if keystore=pkcs11\n")); return (PK_ERR_USAGE); } if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) { token_spec = PK_DEFAULT_PK11TOKEN; } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) { token_spec = DEFAULT_NSS_TOKEN; } if (serstr != NULL) { uchar_t *bytes = NULL; size_t bytelen; rv = kmf_hexstr_to_bytes((uchar_t *)serstr, &bytes, &bytelen); if (rv != KMF_OK || bytes == NULL) { (void) fprintf(stderr, gettext("serial number " "must be specified as a hex number " "(ex: 0x0102030405ffeeddee)\n")); return (PK_ERR_USAGE); } serial.val = bytes; serial.len = bytelen; /* if objtype was not given, it must be for certs */ if (oclass == 0) oclass = PK_CERT_OBJ; } if (oclass == 0 && (issuer != NULL || subject != NULL)) oclass = PK_CERT_OBJ; /* If no object class specified, list public objects. */ if (oclass == 0) oclass = PK_CERT_OBJ | PK_PUBKEY_OBJ; if ((kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS) && (oclass & (PK_PRIKEY_OBJ | PK_PRIVATE_OBJ))) { (void) get_token_password(kstype, token_spec, &tokencred); } if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = list_pk11_objects(kmfhandle, token_spec, oclass, list_label, &serial, issuer, subject, dir, filename, &tokencred, find_criteria_flag); } else if (kstype == KMF_KEYSTORE_NSS) { if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; rv = list_nss_objects(kmfhandle, oclass, token_spec, dir, prefix, list_label, &serial, issuer, subject, &tokencred, find_criteria_flag); } else if (kstype == KMF_KEYSTORE_OPENSSL) { rv = list_file_objects(kmfhandle, oclass, dir, filename, &serial, issuer, subject, find_criteria_flag); } if (rv != KMF_OK) { display_error(kmfhandle, rv, gettext("Error listing objects")); } if (serial.val != NULL) free(serial.val); if (tokencred.cred != NULL) free(tokencred.cred); (void) kmf_finalize(kmfhandle); return (rv); } /* * 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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * This file comprises the main driver for this tool. * Upon parsing the command verbs from user input, it * branches to the appropriate modules to perform the * requested task. */ #include #include #include #include #include #include #include #include #include #include "common.h" /* * The verbcmd construct allows genericizing information about a verb so * that it is easier to manipulate. Makes parsing code easier to read, * fix, and extend with new verbs. */ typedef struct verbcmd_s { char *verb; int (*action)(int, char *[]); int mode; char *summary; char *synopsis; } verbcmd; /* External declarations for supported verb actions. */ extern int pk_setpin(int argc, char *argv[]); extern int pk_list(int argc, char *argv[]); extern int pk_delete(int argc, char *argv[]); extern int pk_import(int argc, char *argv[]); extern int pk_export(int argc, char *argv[]); extern int pk_tokens(int argc, char *argv[]); extern int pk_gencert(int argc, char *argv[]); extern int pk_gencsr(int argc, char *argv[]); extern int pk_download(int argc, char *argv[]); extern int pk_genkey(int argc, char *argv[]); extern int pk_signcsr(int argc, char *argv[]); extern int pk_inittoken(int argc, char *argv[]); extern int pk_genkeypair(int argc, char *argv[]); /* Forward declarations for "built-in" verb actions. */ static int pk_help(int argc, char *argv[]); #define TOKEN_IDX 0 #define TOKEN_VERB "tokens" #define TOKEN_SUMM gettext("lists all visible PKCS#11 tokens") #define TOKEN_SYN "tokens" #define SETPIN_IDX 1 #define SETPIN_VERB "setpin" #define SETPIN_SUMM gettext("changes user authentication passphrase "\ "for keystore access") #define SETPIN_SYN \ "setpin [ keystore=pkcs11 ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ usertype=so|user ]\n\t" \ \ "setpin keystore=nss\n\t\t" \ "[ token=token ]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t" #define LIST_IDX 2 #define LIST_VERB "list" #define LIST_SUMM gettext("lists a summary of objects in the keystore") #define LIST_SYN \ "list [ token=token[:manuf[:serial]]]\n\t\t" \ "[ objtype=private|public|both ]\n\t\t" \ "[ label=label ]\n\t" \ \ "list objtype=cert[:[public | private | both ]]\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ keystore=pkcs11 ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ label=cert-label ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "list objtype=key[:[public | private | both ]]\n\t\t" \ "[ keystore=pkcs11 ]\n\t\t" \ "[ label=key-label ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t" \ \ "list keystore=pkcs11 objtype=crl\n\t\t" \ "infile=crl-fn\n\t" \ \ "list keystore=nss objtype=cert\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ nickname=cert-nickname ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "list keystore=nss objtype=key\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ nickname=key-nickname ]\n\t" \ \ "list keystore=file objtype=cert\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ infile=cert-fn ]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "list keystore=file objtype=key\n\t\t" \ "[ infile=key-fn ]\n\t\t" \ "[ dir=directory-path ]\n\t" \ \ "list keystore=file objtype=crl\n\t\t" \ "infile=crl-fn\n\t" #define DELETE_IDX 3 #define DELETE_VERB "delete" #define DELETE_SUMM gettext("deletes objects in the keystore") #define DELETE_SYN \ "delete [ token=token[:manuf[:serial]]]\n\t\t" \ "[ objtype=private|public|both ]\n\t\t" \ "[ label=object-label ]\n\t" \ \ "delete keystore=nss objtype=cert\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ label=cert-label ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "delete keystore=nss objtype=key\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ nickname=key-nickname ]\n\t\t" \ \ "delete keystore=nss objtype=crl\n\t\t" \ "[ nickname=issuer-nickname ]\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t" \ \ "delete keystore=pkcs11 " \ "objtype=cert[:[public | private | both]]\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ label=cert-label ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "delete keystore=pkcs11 " \ "objtype=key[:[public | private | both]]\n\t\t" \ "[ label=key-label ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t" \ \ "delete keystore=pkcs11 objtype=crl\n\t\t" \ "infile=crl-fn\n\t" \ \ "delete keystore=file objtype=cert\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ infile=cert-fn ]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ criteria=valid|expired|both ]\n\t" \ \ "delete keystore=file objtype=key\n\t\t" \ "[ infile=key-fn ]\n\t\t" \ "[ dir=directory-path ]\n\t" \ \ "delete keystore=file objtype=crl\n\t\t" \ "infile=crl-fn\n\t" #define IMPORT_IDX 4 #define IMPORT_VERB "import" #define IMPORT_SUMM gettext("imports objects from an external source") #define IMPORT_SYN \ "import [token=token[:manuf[:serial]]]\n\t\t" \ "infile=input-fn\n\t" \ \ "import keystore=nss objtype=cert\n\t\t" \ "infile=input-fn\n\t\t" \ "label=cert-label\n\t\t" \ "[ trust=trust-value ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t" \ \ "import keystore=nss objtype=crl\n\t\t" \ "infile=input-fn\n\t\t" \ "[ verifycrl=y|n ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t" \ \ "import keystore=pkcs11\n\t\t" \ "infile=input-fn\n\t\t" \ "label=label\n\t\t" \ "[ objtype=cert|key ]\n\t\t" \ "[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" \ "[ sensitive=y|n ]\n\t\t" \ "[ extractable=y|n ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t" \ \ "import keystore=pkcs11 objtype=crl\n\t\t" \ "infile=input-crl-fn\n\t\t" \ "outcrl=output-crl-fn\n\t\t" \ "outformat=pem|der\n\t" \ \ "import keystore=file\n\t\t" \ "infile=input-fn\n\t\t" \ "outkey=output-key-fn\n\t\t" \ "outcert=output-cert-fn\n\t\t" \ "[ outformat=pem|der|pkcs12 ]\n\t" \ \ "import keystore=file objtype=crl\n\t\t" \ "infile=input-crl-fn\n\t\t" \ "outcrl=output-crl-fn\n\t\t" \ "outformat=pem|der\n\t" #define EXPORT_IDX 5 #define EXPORT_VERB "export" #define EXPORT_SUMM gettext("exports objects from the keystore to a file") #define EXPORT_SYN \ "export [token=token[:manuf[:serial]]]\n\t\t" \ "outfile=output-fn\n\t" \ \ "export keystore=nss\n\t\t" \ "outfile=output-fn\n\t\t" \ "[ objtype=cert|key ]\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ nickname=cert-nickname ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBPrefix ]\n\t\t" \ "[ outformat=pem|der|pkcs12 ]\n\t" \ \ "export keystore=pkcs11\n\t\t" \ "outfile=output-fn\n\t\t" \ "[ objtype=cert|key ]\n\t\t" \ "[ label=label ]\n\t\t" \ "[ subject=subject-DN ]\n\t\t" \ "[ issuer=issuer-DN ]\n\t\t" \ "[ serial=serial number ]\n\t\t" \ "[ outformat=pem|der|pkcs12|raw ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t" \ \ "export keystore=file\n\t\t" \ "certfile=cert-input-fn\n\t\t" \ "keyfile=key-input-fn\n\t\t" \ "outfile=output-pkcs12-fn\n\t" #define GENCERT_IDX 6 #define GENCERT_VERB "gencert" #define GENCERT_SUMM gettext("creates a self-signed X.509v3 certificate") #define GENCERT_SYN \ "gencert listcurves\n\t" \ \ "gencert keystore=nss\n\t\t" \ "label=cert-nickname\n\t\t" \ "serial=serial number hex string\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ keytype=rsa | ec [curve=ECC Curve Name] " \ "[hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ trust=trust-value ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t" \ \ "gencert [ keystore=pkcs11 ]\n\t\t" \ "label=key/cert-label\n\t\t" \ "serial=serial number hex string\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ keytype=rsa | ec [curve=ECC Curve Name] " \ "[hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1 | sha256 ]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t" \ \ "gencert keystore=file\n\t\t" \ "outcert=cert_filename\n\t\t" \ "outkey=key_filename\n\t\t" \ "serial=serial number hex string\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ format=der|pem ]\n\t\t" \ "[ keytype=rsa [hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1 | sha256 ]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t" #define GENCSR_IDX 7 #define GENCSR_VERB "gencsr" #define GENCSR_SUMM gettext("creates a PKCS#10 certificate signing " \ "request file") #define GENCSR_SYN \ "gencsr listcurves\n\t" \ \ "gencsr keystore=nss \n\t\t" \ "nickname=cert-nickname\n\t\t" \ "outcsr=csr-fn\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ keytype=rsa | ec [curve=ECC Curve Name] " \ "[hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ format=pem|der ]\n\t" \ \ "gencsr [ keystore=pkcs11 ]\n\t\t" \ "label=key-label\n\t\t" \ "outcsr=csr-fn\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ keytype=rsa | ec [curve=ECC Curve Name] " \ "[hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1 | sha256 ]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ format=pem|der ]]\n\t" \ \ "gencsr keystore=file\n\t\t" \ "outcsr=csr-fn\n\t\t" \ "outkey=key-fn\n\t\t" \ "[ -i ] | [subject=subject-DN]\n\t\t" \ "[ altname=[critical:]SubjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,usage,...]\n\t\t" \ "[ keytype=rsa [hash=md5 | sha1 | sha256 | sha384 | sha512]]\n\t\t" \ "[ keytype=dsa [hash=sha1 | sha256 ]]\n\t\t" \ "[ keylen=key-size ]\n\t\t" \ "[ eku=[critical:]EKU name,...]\n\t\t" \ "[ format=pem|der ]\n\t" #define DOWNLOAD_IDX 8 #define DOWNLOAD_VERB "download" #define DOWNLOAD_SUMM gettext("downloads a CRL or certificate file " \ "from an external source") #define DOWNLOAD_SYN \ "download url=url_str\n\t\t" \ "[ objtype=crl|cert ]\n\t\t" \ "[ http_proxy=proxy_str ]\n\t\t" \ "[ outfile = outfile ]\n\t" #define GENKEY_IDX 9 #define GENKEY_VERB "genkey" #define GENKEY_SUMM gettext("creates a symmetric key in the keystore") #define GENKEY_SYN \ "genkey [ keystore=pkcs11 ]\n\t\t" \ "label=key-label\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" \ "[ print=y|n ]\n\t" \ \ "genkey keystore=nss\n\t\t" \ "label=key-label\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|generic ]\n\t\t" \ "[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t" \ "[ print=y|n ]\n\t" #define SIGNCSR_IDX 10 #define SIGNCSR_VERB "signcsr" #define SIGNCSR_SUMM gettext("Sign a PKCS#10 Certificate Signing Request") #define SIGNCSR_SYN \ "signcsr keystore=pkcs11\n\t\t" \ "signkey=label (label of signing key)\n\t\t" \ "csr=CSR filename\n\t\t" \ "serial=serial number hex string\n\t\t" \ "outcert=filename for final certificate\n\t\t" \ "issuer=issuer-DN\n\t\t" \ "[ store=y|n ] (store the new cert on the token, default=n)\n\t\t" \ "[ outlabel=certificate label ]\n\t\t" \ "[ format=pem|der ] (output format)\n\t\t" \ "[ subject=subject-DN ] (new subject name)\n\t\t" \ "[ altname=subjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,...]\n\t\t" \ "[ eku=[critical:]EKU Name,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t" \ \ "signcsr keystore=file\n\t\t" \ "signkey=filename\n\t\t" \ "csr=CSR filename\n\t\t" \ "serial=serial number hex string\n\t\t" \ "outcert=filename for final certificate\n\t\t" \ "issuer=issuer-DN\n\t\t" \ "[ format=pem|der ] (output format)\n\t\t" \ "[ subject=subject-DN ] (new subject name)\n\t\t" \ "[ altname=subjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t\t" \ "[ eku=[critical:]EKU Name,...]\n\t" \ \ "signcsr keystore=nss\n\t\t" \ "signkey=label (label of signing key)\n\t\t" \ "csr=CSR filename\n\t\t" \ "serial=serial number hex string\n\t\t" \ "outcert=filename for final certificate\n\t\t" \ "issuer=issuer-DN\n\t\t" \ "[ store=y|n ] (store the new cert in NSS DB, default=n)\n\t\t" \ "[ outlabel=certificate label ]\n\t\t" \ "[ format=pem|der ] (output format)\n\t\t" \ "[ subject=subject-DN ] (new subject name)\n\t\t" \ "[ altname=subjectAltName ]\n\t\t" \ "[ keyusage=[critical:]usage,...]\n\t\t" \ "[ eku=[critical:]EKU Name,...]\n\t\t" \ "[ lifetime=number-hour|number-day|number-year ]\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t" #define INITTOKEN_IDX 11 #define INITTOKEN_VERB "inittoken" #define INITTOKEN_SUMM gettext("Initialize a PKCS11 token") #define INITTOKEN_SYN \ "inittoken \n\t\t" \ "[ currlabel=token[:manuf[:serial]]]\n\t\t" \ "[ newlabel=new token label ]\n\t" #define GENKEYPAIR_IDX 12 #define GENKEYPAIR_VERB "genkeypair" #define GENKEYPAIR_SUMM gettext("creates an asymmetric keypair") #define GENKEYPAIR_SYN \ "genkeypair listcurves\n\t" \ \ "genkeypair keystore=nss\n\t\t" \ "label=key-nickname\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ dir=directory-path ]\n\t\t" \ "[ prefix=DBprefix ]\n\t\t" \ "[ keytype=rsa | dsa | ec [curve=ECC Curve Name]]\n\t\t" \ "[ keylen=key-size ]\n\t" \ \ "genkeypair [ keystore=pkcs11 ]\n\t\t" \ "label=key-label\n\t\t" \ "[ token=token[:manuf[:serial]]]\n\t\t" \ "[ keytype=rsa | dsa | ec [curve=ECC Curve Name]]\n\t\t" \ "[ keylen=key-size ]\n\t" \ \ "genkeypair keystore=file\n\t\t" \ "outkey=key_filename\n\t\t" \ "[ format=der|pem ]\n\t\t" \ "[ keytype=rsa|dsa ]\n\t\t" \ "[ keylen=key-size ]\n\t" #define HELP_IDX 13 #define HELP_VERB "help" #define HELP_SUMM gettext("displays help message") #define HELP_SYN "help\t(help and usage)" /* Command structure for verbs and their actions. Do NOT i18n/l10n. */ static verbcmd cmds[] = { { NULL, pk_tokens, 0, NULL, NULL }, { NULL, pk_setpin, 0, NULL, NULL }, { NULL, pk_list, 0, NULL, NULL }, { NULL, pk_delete, 0, NULL, NULL }, { NULL, pk_import, 0, NULL, NULL }, { NULL, pk_export, 0, NULL, NULL }, { NULL, pk_gencert, 0, NULL, NULL }, { NULL, pk_gencsr, 0, NULL, NULL }, { NULL, pk_download, 0, NULL, NULL }, { NULL, pk_genkey, 0, NULL, NULL }, { NULL, pk_signcsr, 0, NULL, NULL }, { NULL, pk_inittoken, 0, NULL, NULL }, { NULL, pk_genkeypair, 0, NULL, NULL }, { NULL, pk_help, 0, NULL, NULL } }; static int num_cmds = sizeof (cmds) / sizeof (verbcmd); static char *prog; static void usage(int); static void init_command_list() { cmds[TOKEN_IDX].verb = TOKEN_VERB; cmds[TOKEN_IDX].summary = TOKEN_SUMM; cmds[TOKEN_IDX].synopsis = TOKEN_SYN; cmds[SETPIN_IDX].verb = SETPIN_VERB; cmds[SETPIN_IDX].summary = SETPIN_SUMM; cmds[SETPIN_IDX].synopsis = SETPIN_SYN; cmds[LIST_IDX].verb = LIST_VERB; cmds[LIST_IDX].summary = LIST_SUMM; cmds[LIST_IDX].synopsis = LIST_SYN; cmds[DELETE_IDX].verb = DELETE_VERB; cmds[DELETE_IDX].summary = DELETE_SUMM; cmds[DELETE_IDX].synopsis = DELETE_SYN; cmds[IMPORT_IDX].verb = IMPORT_VERB; cmds[IMPORT_IDX].summary = IMPORT_SUMM; cmds[IMPORT_IDX].synopsis = IMPORT_SYN; cmds[EXPORT_IDX].verb = EXPORT_VERB; cmds[EXPORT_IDX].summary = EXPORT_SUMM; cmds[EXPORT_IDX].synopsis = EXPORT_SYN; cmds[GENCERT_IDX].verb = GENCERT_VERB; cmds[GENCERT_IDX].summary = GENCERT_SUMM; cmds[GENCERT_IDX].synopsis = GENCERT_SYN; cmds[GENCSR_IDX].verb = GENCSR_VERB; cmds[GENCSR_IDX].summary = GENCSR_SUMM; cmds[GENCSR_IDX].synopsis = GENCSR_SYN; cmds[DOWNLOAD_IDX].verb = DOWNLOAD_VERB; cmds[DOWNLOAD_IDX].summary = DOWNLOAD_SUMM; cmds[DOWNLOAD_IDX].synopsis = DOWNLOAD_SYN; cmds[GENKEY_IDX].verb = GENKEY_VERB; cmds[GENKEY_IDX].summary = GENKEY_SUMM; cmds[GENKEY_IDX].synopsis = GENKEY_SYN; cmds[SIGNCSR_IDX].verb = SIGNCSR_VERB; cmds[SIGNCSR_IDX].summary = SIGNCSR_SUMM; cmds[SIGNCSR_IDX].synopsis = SIGNCSR_SYN; cmds[INITTOKEN_IDX].verb = INITTOKEN_VERB; cmds[INITTOKEN_IDX].summary = INITTOKEN_SUMM; cmds[INITTOKEN_IDX].synopsis = INITTOKEN_SYN; cmds[GENKEYPAIR_IDX].verb = GENKEYPAIR_VERB; cmds[GENKEYPAIR_IDX].summary = GENKEYPAIR_SUMM; cmds[GENKEYPAIR_IDX].synopsis = GENKEYPAIR_SYN; cmds[HELP_IDX].verb = HELP_VERB; cmds[HELP_IDX].summary = HELP_SUMM; cmds[HELP_IDX].synopsis = HELP_SYN; } /* * Usage information. This function must be updated when new verbs or * options are added. */ static void usage(int idx) { int i; /* Display this block only in command-line mode. */ (void) fprintf(stdout, gettext("Usage:\n")); (void) fprintf(stdout, gettext(" %s -?\t(help and usage)\n"), prog); (void) fprintf(stdout, gettext(" %s -f option_file\n"), prog); (void) fprintf(stdout, gettext(" %s subcommand [options...]\n"), prog); (void) fprintf(stdout, gettext("where subcommands may be:\n")); /* Display only those verbs that match the current tool mode. */ if (idx == -1) { for (i = 0; i < num_cmds; i++) { /* Do NOT i18n/l10n. */ (void) fprintf(stdout, " %-8s - %s\n", cmds[i].verb, cmds[i].summary); } (void) fprintf(stdout, "%s \'help\'.\n" "Ex: pktool gencert help\n\n", gettext("\nFurther details on the " "subcommands can be found by adding")); } else { (void) fprintf(stdout, "\t%s\n", cmds[idx].synopsis); } } /* * Provide help, in the form of displaying the usage. */ static int pk_help(int argc, char *argv[]) /* ARGSUSED */ { usage(-1); return (0); } /* * Process arguments from the argfile and create a new * argv/argc list to be processed later. */ static int process_arg_file(char *argfile, char ***argv, int *argc) { FILE *fp; char argline[2 * BUFSIZ]; /* 2048 bytes should be plenty */ char *p; int nargs = 0; if ((fp = fopen(argfile, "rF")) == NULL) { (void) fprintf(stderr, gettext("Cannot read argfile %s: %s\n"), argfile, strerror(errno)); return (errno); } while (fgets(argline, sizeof (argline), fp) != NULL) { int j; /* remove trailing whitespace */ j = strlen(argline) - 1; while (j >= 0 && isspace(argline[j])) { argline[j] = 0; j--; } /* If it was a blank line, get the next one. */ if (!strlen(argline)) continue; (*argv) = realloc((*argv), (nargs + 1) * sizeof (char *)); if ((*argv) == NULL) { perror("memory error"); (void) fclose(fp); return (errno); } p = (char *)strdup(argline); if (p == NULL) { perror("memory error"); (void) fclose(fp); return (errno); } (*argv)[nargs] = p; nargs++; } *argc = nargs; (void) fclose(fp); return (0); } /* * MAIN() -- where all the action is */ int main(int argc, char *argv[], char *envp[]) /* ARGSUSED2 */ { int i, found = -1; int rv; int pk_argc = 0; char **pk_argv = NULL; int save_errno = 0; /* Set up for i18n/l10n. */ (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D. */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */ #endif (void) textdomain(TEXT_DOMAIN); init_command_list(); /* Get program base name and move pointer over 0th arg. */ prog = basename(argv[0]); argv++, argc--; /* Set up for debug and error output. */ if (argc == 0) { usage(-1); return (1); } /* Check for help options. For CLIP-compliance. */ if (strcmp(argv[0], "-?") == 0) { return (pk_help(argc, argv)); } else if (strcmp(argv[0], "-f") == 0 && argc == 2) { rv = process_arg_file(argv[1], &pk_argv, &pk_argc); if (rv) return (rv); } else if (argc >= 1 && argv[0][0] == '-') { usage(-1); return (1); } /* Always turns off Metaslot so that we can see softtoken. */ if (setenv("METASLOT_ENABLED", "false", 1) < 0) { save_errno = errno; cryptoerror(LOG_STDERR, gettext("Disabling Metaslot failed (%s)."), strerror(save_errno)); return (1); } /* Begin parsing command line. */ if (pk_argc == 0 && pk_argv == NULL) { pk_argc = argc; pk_argv = argv; } /* Check for valid verb (or an abbreviation of it). */ found = -1; for (i = 0; i < num_cmds; i++) { if (strcmp(cmds[i].verb, pk_argv[0]) == 0) { if (found < 0) { found = i; break; } } } /* Stop here if no valid verb found. */ if (found < 0) { cryptoerror(LOG_STDERR, gettext("Invalid verb: %s"), pk_argv[0]); return (1); } /* Get to work! */ rv = (*cmds[found].action)(pk_argc, pk_argv); switch (rv) { case PK_ERR_NONE: break; /* Command succeeded, do nothing. */ case PK_ERR_USAGE: usage(found); break; case PK_ERR_QUIT: exit(0); /* NOTREACHED */ case PK_ERR_PK11: case PK_ERR_SYSTEM: case PK_ERR_OPENSSL: case PK_ERR_NSS: default: break; } return (rv); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * This file implements the setpin operation for this tool. * The basic flow of the process is to load the PKCS#11 module, * finds the soft token, prompt the user for the old PIN (if * any) and the new PIN, change the token's PIN, and clean up. */ #include #include #include #include #include #include #include "common.h" static int setpin_nss(KMF_HANDLE_T handle, char *token_spec, char *dir, char *prefix) { int rv = 0; KMF_CREDENTIAL oldcred = { NULL, 0 }; KMF_CREDENTIAL newpincred = { NULL, 0 }; CK_UTF8CHAR_PTR old_pin = NULL, new_pin = NULL; CK_ULONG old_pinlen = 0, new_pinlen = 0; KMF_ATTRIBUTE setpinattrs[6]; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; int numattrs = 0; rv = configure_nss(handle, dir, prefix); if (rv != KMF_OK) return (rv); kmf_set_attr_at_index(setpinattrs, numattrs, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattrs++; if (token_spec != NULL) { kmf_set_attr_at_index(setpinattrs, numattrs, KMF_TOKEN_LABEL_ATTR, token_spec, strlen(token_spec)); numattrs++; } if ((rv = get_pin(gettext("Enter current token passphrase " "( if not set):"), NULL, &old_pin, &old_pinlen)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get token passphrase.")); return (PK_ERR_NSS); } /* Get the user's new PIN. */ if ((rv = get_pin(gettext("Create new passphrase:"), gettext( "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) { if (rv == CKR_PIN_INCORRECT) cryptoerror(LOG_STDERR, gettext( "Passphrases do not match.")); else cryptoerror(LOG_STDERR, gettext( "Unable to get and confirm new passphrase.")); if (old_pin != NULL) free(old_pin); return (PK_ERR_NSS); } oldcred.cred = (char *)old_pin; oldcred.credlen = old_pinlen; kmf_set_attr_at_index(setpinattrs, numattrs, KMF_CREDENTIAL_ATTR, &oldcred, sizeof (oldcred)); numattrs++; newpincred.cred = (char *)new_pin; newpincred.credlen = new_pinlen; kmf_set_attr_at_index(setpinattrs, numattrs, KMF_NEWPIN_ATTR, &newpincred, sizeof (newpincred)); numattrs++; rv = kmf_set_token_pin(handle, numattrs, setpinattrs); if (new_pin) free(new_pin); if (old_pin) free(old_pin); return (rv); } static int setpin_pkcs11(KMF_HANDLE_T handle, char *token_spec, boolean_t souser) { CK_SLOT_ID slot_id; CK_FLAGS pin_state; CK_UTF8CHAR_PTR old_pin = NULL, new_pin = NULL; CK_ULONG old_pinlen = 0, new_pinlen = 0; CK_RV rv = CKR_OK; char *token_name = NULL; CK_TOKEN_INFO token_info; KMF_CREDENTIAL newpincred = { NULL, 0 }; KMF_CREDENTIAL oldcred = { NULL, 0 }; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_ATTRIBUTE attrlist[6]; CK_USER_TYPE user = CKU_USER; int numattr = 0; /* If nothing is specified, default is to use softtoken. */ if (token_spec == NULL) { token_spec = SOFT_TOKEN_LABEL ":" SOFT_MANUFACTURER_ID; token_name = SOFT_TOKEN_LABEL; } rv = kmf_pk11_token_lookup(NULL, token_spec, &slot_id); if (rv == KMF_OK) { /* find the pin state for the selected token */ if (C_GetTokenInfo(slot_id, &token_info) != CKR_OK) return (PK_ERR_PK11); pin_state = token_info.flags & CKF_USER_PIN_TO_BE_CHANGED; if (token_name == NULL) token_name = (char *)token_info.label; } /* * If the token is the softtoken, check if the token flags show the * PIN has not been set yet. If not then set the old PIN to the * default "changeme". Otherwise, let user type in the correct old * PIN to unlock token. */ if (pin_state == CKF_USER_PIN_TO_BE_CHANGED && strcmp(token_name, SOFT_TOKEN_LABEL) == 0) { if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) == NULL) { cryptoerror(LOG_STDERR, "%s.", strerror(errno)); final_pk11(0); return (PK_ERR_PK11); } old_pinlen = strlen(SOFT_DEFAULT_PIN); } else { if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &old_pin, &old_pinlen)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get token passphrase (%s)."), pkcs11_strerror(rv)); final_pk11(0); return (PK_ERR_PK11); } } /* Get the user's new PIN. */ if ((rv = get_pin(gettext("Create new passphrase:"), gettext( "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) { if (rv == CKR_PIN_INCORRECT) cryptoerror(LOG_STDERR, gettext( "Passphrases do not match.")); else cryptoerror(LOG_STDERR, gettext( "Unable to get and confirm new passphrase (%s)."), pkcs11_strerror(rv)); free(old_pin); final_pk11(0); return (PK_ERR_PK11); } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (token_name != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token_name, strlen(token_name)); numattr++; } oldcred.cred = (char *)old_pin; oldcred.credlen = old_pinlen; kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, &oldcred, sizeof (oldcred)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_SLOT_ID_ATTR, &slot_id, sizeof (slot_id)); numattr++; newpincred.cred = (char *)new_pin; newpincred.credlen = new_pinlen; kmf_set_attr_at_index(attrlist, numattr, KMF_NEWPIN_ATTR, &newpincred, sizeof (newpincred)); numattr++; if (souser) { user = CKU_SO; kmf_set_attr_at_index(attrlist, numattr, KMF_PK11_USER_TYPE_ATTR, &user, sizeof (user)); numattr++; } rv = kmf_set_token_pin(handle, numattr, attrlist); /* Clean up. */ if (old_pin != NULL) free(old_pin); if (new_pin != NULL) free(new_pin); return (rv); } /* * Changes the token's PIN. */ int pk_setpin(int argc, char *argv[]) /* ARGSUSED */ { int opt; int rv; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *dir = NULL; char *prefix = NULL; char *utype = NULL; KMF_HANDLE_T handle; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; boolean_t souser = 0; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "T:(token)k:(keystore)d:(dir)" "p:(prefix)u:(usertype)")) != EOF) { switch (opt) { case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = 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 'u': utype = optarg_av; break; default: return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc != 0) return (PK_ERR_USAGE); /* Done parsing command line options. */ if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) { token_spec = PK_DEFAULT_PK11TOKEN; } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) { token_spec = DEFAULT_NSS_TOKEN; } if ((rv = kmf_initialize(&handle, NULL, NULL)) != KMF_OK) return (rv); if (utype != NULL) { if (strcmp(utype, "so") == 0) souser = 1; else if (strcmp(utype, "user") == 0) souser = 0; else /* Wrong option string */ return (PK_ERR_USAGE); } switch (kstype) { case KMF_KEYSTORE_PK11TOKEN: rv = setpin_pkcs11(handle, token_spec, souser); break; case KMF_KEYSTORE_NSS: rv = setpin_nss(handle, token_spec, dir, prefix); break; default: cryptoerror(LOG_STDERR, gettext("incorrect keystore.")); return (PK_ERR_USAGE); } (void) kmf_finalize(handle); if (rv == KMF_ERR_AUTH_FAILED) { cryptoerror(LOG_STDERR, gettext("Incorrect passphrase.")); return (PK_ERR_SYSTEM); } else if (rv != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to change passphrase.")); return (PK_ERR_SYSTEM); } else { (void) fprintf(stdout, gettext("Passphrase changed.\n")); } return (0); } /* * 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * This file implements the sign CSR operation for this tool. */ #include #include #include #include #include #include "common.h" #include #include #define SET_VALUE(f, s) \ rv = f; \ if (rv != KMF_OK) { \ cryptoerror(LOG_STDERR, \ gettext("Failed to set %s: 0x%02x\n"), s, rv); \ goto cleanup; \ } static int read_csrdata(KMF_HANDLE_T handle, char *csrfile, KMF_CSR_DATA *csrdata) { KMF_RETURN rv = KMF_OK; KMF_ENCODE_FORMAT csrfmt; KMF_DATA csrfiledata = { 0, NULL }; KMF_DATA rawcsr = { 0, NULL }; rv = kmf_get_file_format(csrfile, &csrfmt); if (rv != KMF_OK) return (rv); rv = kmf_read_input_file(handle, csrfile, &csrfiledata); if (rv != KMF_OK) return (rv); if (csrfmt == KMF_FORMAT_PEM) { rv = kmf_pem_to_der(csrfiledata.Data, csrfiledata.Length, &rawcsr.Data, (int *)&rawcsr.Length); if (rv != KMF_OK) return (rv); kmf_free_data(&csrfiledata); } else { rawcsr.Data = csrfiledata.Data; rawcsr.Length = csrfiledata.Length; } rv = kmf_decode_csr(handle, &rawcsr, csrdata); kmf_free_data(&rawcsr); return (rv); } static KMF_RETURN find_csr_extn(KMF_X509_EXTENSIONS *extnlist, KMF_OID *extoid, KMF_X509_EXTENSION *outextn) { int i, found = 0; KMF_X509_EXTENSION *eptr; KMF_RETURN rv = KMF_OK; (void) memset(outextn, 0, sizeof (KMF_X509_EXTENSION)); for (i = 0; !found && i < extnlist->numberOfExtensions; i++) { eptr = &extnlist->extensions[i]; if (IsEqualOid(extoid, &eptr->extnId)) { rv = copy_extension_data(outextn, eptr); found++; } } if (found == 0 || rv != KMF_OK) return (1); else return (rv); } static int build_cert_from_csr(KMF_CSR_DATA *csrdata, KMF_X509_CERTIFICATE *signedCert, KMF_BIGINT *serial, uint32_t ltime, char *issuer, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, uint16_t kubits, int kucrit, EKU_LIST *ekulist) { KMF_RETURN rv = KMF_OK; KMF_X509_NAME issuerDN, subjectDN; /* * If the CSR is ok, now we can generate the final certificate. */ (void) memset(signedCert, 0, sizeof (KMF_X509_CERTIFICATE)); (void) memset(&issuerDN, 0, sizeof (issuerDN)); (void) memset(&subjectDN, 0, sizeof (subjectDN)); SET_VALUE(kmf_set_cert_version(signedCert, 2), "version number"); SET_VALUE(kmf_set_cert_serial(signedCert, serial), "serial number"); SET_VALUE(kmf_set_cert_validity(signedCert, 0, ltime), "validity time"); if (issuer) { if (kmf_dn_parser(issuer, &issuerDN) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Issuer name cannot be parsed\n")); return (PK_ERR_USAGE); } SET_VALUE(kmf_set_cert_issuer(signedCert, &issuerDN), "Issuer Name"); } if (subject) { if (kmf_dn_parser(subject, &subjectDN) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Subject name cannot be parsed\n")); return (PK_ERR_USAGE); } SET_VALUE(kmf_set_cert_subject(signedCert, &subjectDN), "Subject Name"); } else { signedCert->certificate.subject = csrdata->csr.subject; } signedCert->certificate.subjectPublicKeyInfo = csrdata->csr.subjectPublicKeyInfo; signedCert->certificate.extensions = csrdata->csr.extensions; signedCert->certificate.signature = csrdata->signature.algorithmIdentifier; if (kubits != 0) { KMF_X509_EXTENSION extn; uint16_t oldbits; /* * If the CSR already has KU, merge them. */ rv = find_csr_extn(&csrdata->csr.extensions, (KMF_OID *)&KMFOID_KeyUsage, &extn); if (rv == KMF_OK) { extn.critical |= kucrit; if (extn.value.tagAndValue->value.Length > 1) { oldbits = extn.value.tagAndValue->value.Data[1] << 8; } else { oldbits = extn.value.tagAndValue->value.Data[0]; } oldbits |= kubits; } else { SET_VALUE(kmf_set_cert_ku(signedCert, kucrit, kubits), "KeyUsage"); } } if (altname != NULL) { SET_VALUE(kmf_set_cert_subject_altname(signedCert, altcrit, alttype, altname), "subjectAltName"); } if (ekulist != NULL) { int i; for (i = 0; rv == KMF_OK && i < ekulist->eku_count; i++) { SET_VALUE(kmf_add_cert_eku(signedCert, &ekulist->ekulist[i], ekulist->critlist[i]), "Extended Key Usage"); } } cleanup: if (issuer != NULL) kmf_free_dn(&issuerDN); if (subject != NULL) kmf_free_dn(&subjectDN); return (rv); } static int pk_sign_cert(KMF_HANDLE_T handle, KMF_X509_CERTIFICATE *cert, KMF_KEY_HANDLE *key, KMF_OID *sigoid, KMF_DATA *outdata) { KMF_RETURN rv; int numattr; KMF_ATTRIBUTE attrlist[4]; numattr = 0; kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYSTORE_TYPE_ATTR, &key->kstype, sizeof (KMF_KEYSTORE_TYPE)); kmf_set_attr_at_index(attrlist, numattr++, KMF_KEY_HANDLE_ATTR, key, sizeof (KMF_KEY_HANDLE_ATTR)); /* cert data that is to be signed */ kmf_set_attr_at_index(attrlist, numattr++, KMF_X509_CERTIFICATE_ATTR, cert, sizeof (KMF_X509_CERTIFICATE)); /* output buffer for the signed cert */ kmf_set_attr_at_index(attrlist, numattr++, KMF_CERT_DATA_ATTR, outdata, sizeof (KMF_DATA)); /* Set the signature OID value so KMF knows how to generate the sig */ if (sigoid) { kmf_set_attr_at_index(attrlist, numattr++, KMF_OID_ATTR, sigoid, sizeof (KMF_OID)); } if ((rv = kmf_sign_cert(handle, numattr, attrlist)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Failed to sign certificate.\n")); return (rv); } return (rv); } static int pk_signcsr_files(KMF_HANDLE_T handle, char *signkey, char *csrfile, KMF_BIGINT *serial, char *certfile, char *issuer, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, uint16_t kubits, int kucrit, EKU_LIST *ekulist, uint32_t ltime, KMF_ENCODE_FORMAT fmt) { KMF_RETURN rv = KMF_OK; KMF_CSR_DATA csrdata; KMF_ATTRIBUTE attrlist[16]; KMF_X509_CERTIFICATE signedCert; KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; KMF_KEY_CLASS keyclass = KMF_ASYM_PRI; KMF_KEY_HANDLE cakey; KMF_DATA certdata = { 0, NULL }; int numattr, count; (void) memset(&cakey, 0, sizeof (cakey)); (void) memset(&signedCert, 0, sizeof (signedCert)); rv = read_csrdata(handle, csrfile, &csrdata); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error reading CSR data\n")); return (rv); } /* verify the signature first */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_CSR_DATA_ATTR, &csrdata, sizeof (csrdata)); numattr++; rv = kmf_verify_csr(handle, numattr, attrlist); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("CSR signature " "verification failed.\n")); goto cleanup; } rv = build_cert_from_csr(&csrdata, &signedCert, serial, ltime, issuer, subject, altname, alttype, altcrit, kubits, kucrit, ekulist); if (rv != KMF_OK) goto cleanup; /* * Find the signing key. */ (void) memset(&cakey, 0, sizeof (cakey)); numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, signkey, strlen(signkey)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &cakey, sizeof (cakey)); numattr++; count = 1; kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &count, sizeof (count)); numattr++; rv = kmf_find_key(handle, numattr, attrlist); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext( "Error finding CA signing key\n")); goto cleanup; } rv = pk_sign_cert(handle, &signedCert, &cakey, NULL, &certdata); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext( "Error signing certificate.\n")); goto cleanup; } rv = kmf_create_cert_file(&certdata, fmt, certfile); cleanup: kmf_free_signed_csr(&csrdata); kmf_free_data(&certdata); kmf_free_kmf_key(handle, &cakey); return (rv); } static int pk_signcsr_pk11_nss(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE kstype, char *dir, char *prefix, char *token, KMF_CREDENTIAL *cred, char *signkey, char *csrfile, KMF_BIGINT *serial, char *certfile, char *issuer, char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, uint16_t kubits, int kucrit, EKU_LIST *ekulist, uint32_t ltime, KMF_ENCODE_FORMAT fmt, int store, char *outlabel) { KMF_RETURN rv = KMF_OK; KMF_DATA outcert = { 0, NULL }; KMF_CSR_DATA csrdata = { 0, NULL }; KMF_KEY_HANDLE casignkey; KMF_KEY_CLASS keyclass = KMF_ASYM_PRI; KMF_ATTRIBUTE attrlist[16]; KMF_X509_CERTIFICATE signedCert; boolean_t token_bool = B_TRUE; boolean_t private_bool = B_TRUE; int numattr = 0; int keys = 1; (void) memset(&casignkey, 0, sizeof (KMF_KEY_HANDLE)); (void) memset(&signedCert, 0, sizeof (signedCert)); rv = read_csrdata(handle, csrfile, &csrdata); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error reading CSR data\n")); return (rv); } if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = select_token(handle, token, FALSE); } else if (kstype == KMF_KEYSTORE_NSS) { rv = configure_nss(handle, dir, prefix); } /* verify the signature first */ kmf_set_attr_at_index(attrlist, numattr, KMF_CSR_DATA_ATTR, &csrdata, sizeof (csrdata)); numattr++; rv = kmf_verify_csr(handle, numattr, attrlist); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("CSR signature " "verification failed.\n")); goto cleanup; } rv = build_cert_from_csr(&csrdata, &signedCert, serial, ltime, issuer, subject, altname, alttype, altcrit, kubits, kucrit, ekulist); if (rv != KMF_OK) goto cleanup; /* * Find the signing key. */ numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; if (kstype == KMF_KEYSTORE_NSS) { kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, signkey, strlen(signkey)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVATE_BOOL_ATTR, &private_bool, sizeof (private_bool)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR, &token_bool, sizeof (token_bool)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL_ATTR)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, &keys, sizeof (keys)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, &casignkey, sizeof (casignkey)); numattr++; rv = kmf_find_key(handle, numattr, attrlist); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Failed to find signing key\n")); goto cleanup; } /* * If we found the key, now we can sign the cert. */ rv = pk_sign_cert(handle, &signedCert, &casignkey, NULL, &outcert); if (rv != KMF_OK) { cryptoerror(LOG_STDERR, gettext( "Error signing certificate.\n")); goto cleanup; } /* * Store it on the token if the user asked for it. */ if (store) { numattr = 0; kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattr++; kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, &outcert, sizeof (KMF_DATA)); numattr++; if (outlabel != NULL) { kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, outlabel, strlen(outlabel)); numattr++; } if (kstype == KMF_KEYSTORE_NSS) { if (token != NULL) kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattr++; } rv = kmf_store_cert(handle, numattr, attrlist); if (rv != KMF_OK) { display_error(handle, rv, gettext("Failed to store cert " "on PKCS#11 token.\n")); rv = KMF_OK; /* Not fatal, we can still write it to a file. */ } } rv = kmf_create_cert_file(&outcert, fmt, certfile); cleanup: kmf_free_signed_csr(&csrdata); kmf_free_data(&outcert); kmf_free_kmf_key(handle, &casignkey); return (rv); } /* * sign a CSR and generate an x509v3 certificate file. */ int pk_signcsr(int argc, char *argv[]) { int opt; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *subject = NULL; char *issuer = NULL; char *dir = NULL; char *prefix = NULL; char *csrfile = NULL; char *serstr = NULL; char *ekustr = NULL; char *kustr = NULL; char *format = NULL; char *storestr = NULL; char *altname = NULL; char *certfile = NULL; char *lifetime = NULL; char *signkey = NULL; char *outlabel = NULL; uint32_t ltime = 365 * 24 * 60 * 60; /* 1 Year */ int store = 0; uint16_t kubits = 0; int altcrit = 0, kucrit = 0; KMF_BIGINT serial = { NULL, 0 }; EKU_LIST *ekulist = NULL; KMF_KEYSTORE_TYPE kstype = 0; KMF_RETURN rv = KMF_OK; KMF_HANDLE_T kmfhandle = NULL; KMF_CREDENTIAL tokencred = { NULL, 0 }; KMF_GENERALNAMECHOICES alttype = 0; KMF_ENCODE_FORMAT fmt = KMF_FORMAT_PEM; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "k:(keystore)c:(csr)T:(token)d:(dir)" "p:(prefix)S:(serial)s:(subject)a:(altname)" "t:(store)F:(format)K:(keyusage)l:(signkey)" "L:(lifetime)e:(eku)i:(issuer)" "n:(outlabel)o:(outcert)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'k': if (kstype != 0) return (PK_ERR_USAGE); kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 't': if (storestr != NULL) return (PK_ERR_USAGE); storestr = optarg_av; store = yn_to_int(optarg_av); if (store == -1) return (PK_ERR_USAGE); break; case 'a': if (altname) return (PK_ERR_USAGE); altname = optarg_av; break; case 's': if (subject) return (PK_ERR_USAGE); subject = optarg_av; break; case 'i': if (issuer) return (PK_ERR_USAGE); issuer = 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 'S': if (serstr != NULL) return (PK_ERR_USAGE); serstr = optarg_av; break; case 'c': if (csrfile) return (PK_ERR_USAGE); csrfile = optarg_av; break; case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = optarg_av; break; case 'l': /* object with specific label */ if (signkey) return (PK_ERR_USAGE); signkey = optarg_av; break; case 'e': if (ekustr != NULL) return (PK_ERR_USAGE); ekustr = optarg_av; break; case 'K': if (kustr != NULL) return (PK_ERR_USAGE); kustr = optarg_av; break; case 'F': if (format != NULL) return (PK_ERR_USAGE); format = optarg_av; break; case 'o': if (certfile != NULL) return (PK_ERR_USAGE); certfile = optarg_av; break; case 'L': if (lifetime != NULL) return (PK_ERR_USAGE); lifetime = optarg_av; break; case 'n': if (outlabel != NULL) return (PK_ERR_USAGE); outlabel = optarg_av; break; default: return (PK_ERR_USAGE); } } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) return (PK_ERR_USAGE); /* Assume keystore = PKCS#11 if not specified. */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; DIR_OPTION_CHECK(kstype, dir); if (signkey == NULL) { (void) fprintf(stderr, gettext("The signing key label " "or filename was not specified\n")); return (PK_ERR_USAGE); } if (csrfile == NULL) { (void) fprintf(stderr, gettext("The CSR filename was not" " specified\n")); return (PK_ERR_USAGE); } if (certfile == NULL) { (void) fprintf(stderr, gettext("The output certificate file " "was not specified\n")); return (PK_ERR_USAGE); } if (issuer == NULL) { (void) fprintf(stderr, gettext("The issuer DN " "was not specified\n")); return (PK_ERR_USAGE); } if (lifetime != NULL) { if (Str2Lifetime(lifetime, <ime) != 0) { cryptoerror(LOG_STDERR, gettext("Error parsing lifetime string\n")); return (PK_ERR_USAGE); } } if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) { token_spec = PK_DEFAULT_PK11TOKEN; } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) { token_spec = DEFAULT_NSS_TOKEN; } if (serstr != NULL) { uchar_t *bytes = NULL; size_t bytelen; rv = kmf_hexstr_to_bytes((uchar_t *)serstr, &bytes, &bytelen); if (rv != KMF_OK || bytes == NULL) { (void) fprintf(stderr, gettext("Serial number " "must be specified as a hex number " "(ex: 0x0102030405ffeeddee)\n")); return (PK_ERR_USAGE); } serial.val = bytes; serial.len = bytelen; } else { (void) fprintf(stderr, gettext("The serial number was not" " specified\n")); return (PK_ERR_USAGE); } if ((kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS)) { /* Need to get password for private key access */ (void) get_token_password(kstype, token_spec, &tokencred); } if (kustr != NULL) { rv = verify_keyusage(kustr, &kubits, &kucrit); if (rv != KMF_OK) { (void) fprintf(stderr, gettext("KeyUsage " "must be specified as a comma-separated list. " "See the man page for details.\n")); rv = PK_ERR_USAGE; goto end; } } if (ekustr != NULL) { rv = verify_ekunames(ekustr, &ekulist); if (rv != KMF_OK) { (void) fprintf(stderr, gettext("EKUs must " "be specified as a comma-separated list. " "See the man page for details.\n")); rv = PK_ERR_USAGE; goto end; } } if (altname != NULL) { char *p; rv = verify_altname(altname, &alttype, &altcrit); if (rv != KMF_OK) { (void) fprintf(stderr, gettext("Subject AltName " "must be specified as a name=value pair. " "See the man page for details.\n")); rv = PK_ERR_USAGE; goto end; } /* advance the altname past the '=' sign */ p = strchr(altname, '='); if (p != NULL) altname = p + 1; } if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) { cryptoerror(LOG_STDERR, gettext("Error parsing format string (%s).\n"), format); return (PK_ERR_USAGE); } if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { return (rv); } if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = pk_signcsr_pk11_nss(kmfhandle, kstype, dir, prefix, token_spec, &tokencred, signkey, csrfile, &serial, certfile, issuer, subject, altname, alttype, altcrit, kubits, kucrit, ekulist, ltime, fmt, store, outlabel); } else if (kstype == KMF_KEYSTORE_NSS) { if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; rv = pk_signcsr_pk11_nss(kmfhandle, kstype, dir, prefix, token_spec, &tokencred, signkey, csrfile, &serial, certfile, issuer, subject, altname, alttype, altcrit, kubits, kucrit, ekulist, ltime, fmt, store, outlabel); } else if (kstype == KMF_KEYSTORE_OPENSSL) { rv = pk_signcsr_files(kmfhandle, signkey, csrfile, &serial, certfile, issuer, subject, altname, alttype, altcrit, kubits, kucrit, ekulist, ltime, fmt); } end: if (rv != KMF_OK) { display_error(kmfhandle, rv, gettext("Error listing objects")); } if (serial.val != NULL) free(serial.val); if (tokencred.cred != NULL) free(tokencred.cred); free_eku_list(ekulist); (void) kmf_finalize(kmfhandle); return (rv); } /* * 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. */ /* * This file implements the token list operation for this tool. * It loads the PKCS#11 modules, gets the list of slots with * tokens in them, displays the list, and cleans up. */ #include #include #include #include #include "common.h" /* * Lists all slots with tokens in them. */ int pk_tokens(int argc, char *argv[]) { CK_SLOT_ID_PTR slots = NULL; CK_ULONG slot_count = 0; CK_TOKEN_INFO token_info; const char *fmt = NULL; CK_RV rv = CKR_OK; int i; /* Get rid of subcommand word "tokens". */ argc--; argv++; /* No additional args allowed. */ if (argc != 0) return (PK_ERR_USAGE); /* Done parsing command line options. */ /* Get the list of slots with tokens in them. */ if ((rv = get_token_slots(&slots, &slot_count)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get token slot list (%s)."), pkcs11_strerror(rv)); return (PK_ERR_PK11); } /* Make sure we have something to display. */ if (slot_count == 0) { cryptoerror(LOG_STDERR, gettext("No slots with tokens found.")); return (0); } /* Display the list. */ fmt = "%-30.30s %-15.15s %-15.15s %-10.10s\n"; /* No I18N/L10N. */ (void) fprintf(stdout, fmt, gettext("Token Label"), gettext("Manuf ID"), gettext("Serial No"), gettext("PIN State")); for (i = 0; i < slot_count; i++) { if ((rv = C_GetTokenInfo(slots[i], &token_info)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get slot %d token info (%s)."), i, pkcs11_strerror(rv)); continue; } (void) fprintf(stdout, fmt, token_info.label, token_info.manufacturerID, token_info.serialNumber, (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ? gettext("default") : gettext("user set")); } /* Clean up. */ free(slots); (void) C_Finalize(NULL); return (0); }