199ebb4caSwyllys /* 299ebb4caSwyllys * CDDL HEADER START 399ebb4caSwyllys * 499ebb4caSwyllys * The contents of this file are subject to the terms of the 599ebb4caSwyllys * Common Development and Distribution License (the "License"). 699ebb4caSwyllys * You may not use this file except in compliance with the License. 799ebb4caSwyllys * 899ebb4caSwyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 999ebb4caSwyllys * or http://www.opensolaris.org/os/licensing. 1099ebb4caSwyllys * See the License for the specific language governing permissions 1199ebb4caSwyllys * and limitations under the License. 1299ebb4caSwyllys * 1399ebb4caSwyllys * When distributing Covered Code, include this CDDL HEADER in each 1499ebb4caSwyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1599ebb4caSwyllys * If applicable, add the following below this CDDL HEADER, with the 1699ebb4caSwyllys * fields enclosed by brackets "[]" replaced with your own identifying 1799ebb4caSwyllys * information: Portions Copyright [yyyy] [name of copyright owner] 1899ebb4caSwyllys * 1999ebb4caSwyllys * CDDL HEADER END 2099ebb4caSwyllys * 2199ebb4caSwyllys * 22*e65e5c2dSWyllys Ingersoll * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 2399ebb4caSwyllys * Use is subject to license terms. 2499ebb4caSwyllys */ 2599ebb4caSwyllys 2699ebb4caSwyllys #include <stdio.h> 2799ebb4caSwyllys #include <string.h> 2899ebb4caSwyllys #include <ctype.h> 2999ebb4caSwyllys #include <malloc.h> 3099ebb4caSwyllys #include <libgen.h> 3199ebb4caSwyllys #include <errno.h> 3299ebb4caSwyllys #include <cryptoutil.h> 3399ebb4caSwyllys #include <security/cryptoki.h> 3499ebb4caSwyllys #include "common.h" 3599ebb4caSwyllys 3699ebb4caSwyllys #include <kmfapi.h> 3799ebb4caSwyllys 3899ebb4caSwyllys #define SET_VALUE(f, s) \ 3999ebb4caSwyllys kmfrv = f; \ 4099ebb4caSwyllys if (kmfrv != KMF_OK) { \ 4199ebb4caSwyllys cryptoerror(LOG_STDERR, \ 4299ebb4caSwyllys gettext("Failed to %s: 0x%02\n"), \ 4399ebb4caSwyllys s, kmfrv); \ 4499ebb4caSwyllys goto cleanup; \ 4599ebb4caSwyllys } 4699ebb4caSwyllys 4799ebb4caSwyllys static KMF_RETURN 4899ebb4caSwyllys gencsr_pkcs11(KMF_HANDLE_T kmfhandle, 4999ebb4caSwyllys char *token, char *subject, char *altname, 5099ebb4caSwyllys KMF_GENERALNAMECHOICES alttype, int altcrit, 5199ebb4caSwyllys char *certlabel, KMF_KEY_ALG keyAlg, 52d00756ccSwyllys int keylen, uint16_t kubits, int kucrit, 5399ebb4caSwyllys KMF_ENCODE_FORMAT fmt, char *csrfile, 54*e65e5c2dSWyllys Ingersoll KMF_CREDENTIAL *tokencred, EKU_LIST *ekulist, 55*e65e5c2dSWyllys Ingersoll KMF_ALGORITHM_INDEX sigAlg, KMF_OID *curveoid) 5699ebb4caSwyllys { 5799ebb4caSwyllys KMF_RETURN kmfrv = KMF_OK; 5899ebb4caSwyllys KMF_KEY_HANDLE pubk, prik; 5999ebb4caSwyllys KMF_X509_NAME csrSubject; 6099ebb4caSwyllys KMF_CSR_DATA csr; 6199ebb4caSwyllys KMF_DATA signedCsr = {NULL, 0}; 6299ebb4caSwyllys 6330a5e8faSwyllys KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; 6430a5e8faSwyllys int numattr = 0; 6530a5e8faSwyllys KMF_ATTRIBUTE attrlist[16]; 6630a5e8faSwyllys 6799ebb4caSwyllys (void) memset(&csr, 0, sizeof (csr)); 6899ebb4caSwyllys (void) memset(&csrSubject, 0, sizeof (csrSubject)); 6999ebb4caSwyllys 7099ebb4caSwyllys /* If the subject name cannot be parsed, flag it now and exit */ 71*e65e5c2dSWyllys Ingersoll if ((kmfrv = kmf_dn_parser(subject, &csrSubject)) != KMF_OK) 7299ebb4caSwyllys return (kmfrv); 7399ebb4caSwyllys 7499ebb4caSwyllys /* Select a PKCS11 token */ 7599ebb4caSwyllys kmfrv = select_token(kmfhandle, token, FALSE); 76*e65e5c2dSWyllys Ingersoll if (kmfrv != KMF_OK) 7799ebb4caSwyllys return (kmfrv); 78*e65e5c2dSWyllys Ingersoll /* 79*e65e5c2dSWyllys Ingersoll * Share the "genkeypair" routine for creating the keypair. 80*e65e5c2dSWyllys Ingersoll */ 81*e65e5c2dSWyllys Ingersoll kmfrv = genkeypair_pkcs11(kmfhandle, token, certlabel, 82*e65e5c2dSWyllys Ingersoll keyAlg, keylen, tokencred, curveoid, &prik, &pubk); 83*e65e5c2dSWyllys Ingersoll if (kmfrv != KMF_OK) 8499ebb4caSwyllys return (kmfrv); 8599ebb4caSwyllys 8630a5e8faSwyllys SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "keypair"); 8799ebb4caSwyllys 8830a5e8faSwyllys SET_VALUE(kmf_set_csr_version(&csr, 2), "version number"); 8999ebb4caSwyllys 9030a5e8faSwyllys SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), "subject name"); 9199ebb4caSwyllys 9230a5e8faSwyllys SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), 9399ebb4caSwyllys "SignatureAlgorithm"); 9499ebb4caSwyllys 9599ebb4caSwyllys if (altname != NULL) { 9630a5e8faSwyllys SET_VALUE(kmf_set_csr_subject_altname(&csr, altname, altcrit, 9799ebb4caSwyllys alttype), "SetCSRSubjectAltName"); 9899ebb4caSwyllys } 9999ebb4caSwyllys 10099ebb4caSwyllys if (kubits != 0) { 10130a5e8faSwyllys SET_VALUE(kmf_set_csr_ku(&csr, kucrit, kubits), 10299ebb4caSwyllys "SetCSRKeyUsage"); 10399ebb4caSwyllys } 104d00756ccSwyllys if (ekulist != NULL) { 105d00756ccSwyllys int i; 106d00756ccSwyllys for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { 107d00756ccSwyllys SET_VALUE(kmf_add_csr_eku(&csr, 108d00756ccSwyllys &ekulist->ekulist[i], 109d00756ccSwyllys ekulist->critlist[i]), 110d00756ccSwyllys "Extended Key Usage"); 111d00756ccSwyllys } 112d00756ccSwyllys } 11330a5e8faSwyllys if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) == 11499ebb4caSwyllys KMF_OK) { 11530a5e8faSwyllys kmfrv = kmf_create_csr_file(&signedCsr, fmt, csrfile); 11699ebb4caSwyllys } 11799ebb4caSwyllys 11899ebb4caSwyllys cleanup: 11930a5e8faSwyllys (void) kmf_free_data(&signedCsr); 120a44b45c8SHuie-Ying Lee (void) kmf_free_signed_csr(&csr); 121a44b45c8SHuie-Ying Lee 122a44b45c8SHuie-Ying Lee /* delete the public key */ 12330a5e8faSwyllys numattr = 0; 12430a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, 12530a5e8faSwyllys &kstype, sizeof (kstype)); 12630a5e8faSwyllys numattr++; 12730a5e8faSwyllys 12830a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_PUBKEY_HANDLE_ATTR, 12930a5e8faSwyllys &pubk, sizeof (KMF_KEY_HANDLE)); 13030a5e8faSwyllys numattr++; 13130a5e8faSwyllys 132a44b45c8SHuie-Ying Lee if (tokencred != NULL && tokencred->cred != NULL) { 133a44b45c8SHuie-Ying Lee kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, 134a44b45c8SHuie-Ying Lee tokencred, sizeof (KMF_CREDENTIAL)); 135a44b45c8SHuie-Ying Lee numattr++; 136a44b45c8SHuie-Ying Lee } 137a44b45c8SHuie-Ying Lee 13830a5e8faSwyllys (void) kmf_delete_key_from_keystore(kmfhandle, numattr, attrlist); 13930a5e8faSwyllys 140a44b45c8SHuie-Ying Lee /* 141a44b45c8SHuie-Ying Lee * If there is an error, then we need to remove the private key 142a44b45c8SHuie-Ying Lee * from the token. 143a44b45c8SHuie-Ying Lee */ 144a44b45c8SHuie-Ying Lee if (kmfrv != KMF_OK) { 145a44b45c8SHuie-Ying Lee numattr = 0; 146a44b45c8SHuie-Ying Lee kmf_set_attr_at_index(attrlist, numattr, 147a44b45c8SHuie-Ying Lee KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); 148a44b45c8SHuie-Ying Lee numattr++; 14999ebb4caSwyllys 150a44b45c8SHuie-Ying Lee kmf_set_attr_at_index(attrlist, numattr, 151a44b45c8SHuie-Ying Lee KMF_KEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); 152a44b45c8SHuie-Ying Lee numattr++; 153a44b45c8SHuie-Ying Lee 154a44b45c8SHuie-Ying Lee if (tokencred != NULL && tokencred->cred != NULL) { 155a44b45c8SHuie-Ying Lee kmf_set_attr_at_index(attrlist, numattr, 156a44b45c8SHuie-Ying Lee KMF_CREDENTIAL_ATTR, tokencred, 157a44b45c8SHuie-Ying Lee sizeof (KMF_CREDENTIAL)); 158a44b45c8SHuie-Ying Lee numattr++; 159a44b45c8SHuie-Ying Lee } 160a44b45c8SHuie-Ying Lee 161a44b45c8SHuie-Ying Lee (void) kmf_delete_key_from_keystore(kmfhandle, numattr, 162a44b45c8SHuie-Ying Lee attrlist); 163a44b45c8SHuie-Ying Lee } 164a44b45c8SHuie-Ying Lee 165a44b45c8SHuie-Ying Lee (void) kmf_free_kmf_key(kmfhandle, &prik); 16699ebb4caSwyllys return (kmfrv); 16799ebb4caSwyllys } 16899ebb4caSwyllys 16999ebb4caSwyllys static KMF_RETURN 17099ebb4caSwyllys gencsr_file(KMF_HANDLE_T kmfhandle, 17199ebb4caSwyllys KMF_KEY_ALG keyAlg, 17299ebb4caSwyllys int keylen, KMF_ENCODE_FORMAT fmt, 17399ebb4caSwyllys char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, 17499ebb4caSwyllys int altcrit, uint16_t kubits, int kucrit, 175*e65e5c2dSWyllys Ingersoll char *outcsr, char *outkey, EKU_LIST *ekulist, 176*e65e5c2dSWyllys Ingersoll KMF_ALGORITHM_INDEX sigAlg) 17799ebb4caSwyllys { 17899ebb4caSwyllys KMF_RETURN kmfrv; 17999ebb4caSwyllys KMF_KEY_HANDLE pubk, prik; 18099ebb4caSwyllys KMF_X509_NAME csrSubject; 18199ebb4caSwyllys KMF_CSR_DATA csr; 18299ebb4caSwyllys KMF_DATA signedCsr = {NULL, 0}; 18399ebb4caSwyllys char *fullcsrpath = NULL; 18499ebb4caSwyllys char *fullkeypath = NULL; 18599ebb4caSwyllys 18630a5e8faSwyllys 18799ebb4caSwyllys (void) memset(&csr, 0, sizeof (csr)); 18899ebb4caSwyllys (void) memset(&csrSubject, 0, sizeof (csrSubject)); 18999ebb4caSwyllys 19099ebb4caSwyllys if (EMPTYSTRING(outcsr) || EMPTYSTRING(outkey)) { 19199ebb4caSwyllys cryptoerror(LOG_STDERR, 19299ebb4caSwyllys gettext("No output file was specified for " 19399ebb4caSwyllys "the csr or key\n")); 19499ebb4caSwyllys return (KMF_ERR_BAD_PARAMETER); 19599ebb4caSwyllys } 19699ebb4caSwyllys fullcsrpath = strdup(outcsr); 19799ebb4caSwyllys if (verify_file(fullcsrpath)) { 19899ebb4caSwyllys cryptoerror(LOG_STDERR, 19999ebb4caSwyllys gettext("Cannot write the indicated output " 20099ebb4caSwyllys "certificate file (%s).\n"), fullcsrpath); 20199ebb4caSwyllys free(fullcsrpath); 20299ebb4caSwyllys return (PK_ERR_USAGE); 20399ebb4caSwyllys } 204448b8615Swyllys 20599ebb4caSwyllys /* If the subject name cannot be parsed, flag it now and exit */ 20630a5e8faSwyllys if ((kmfrv = kmf_dn_parser(subject, &csrSubject)) != KMF_OK) { 20799ebb4caSwyllys return (kmfrv); 20899ebb4caSwyllys } 209*e65e5c2dSWyllys Ingersoll /* 210*e65e5c2dSWyllys Ingersoll * Share the "genkeypair" routine for creating the keypair. 211*e65e5c2dSWyllys Ingersoll */ 212*e65e5c2dSWyllys Ingersoll kmfrv = genkeypair_file(kmfhandle, keyAlg, keylen, 213*e65e5c2dSWyllys Ingersoll fmt, outkey, &prik, &pubk); 214*e65e5c2dSWyllys Ingersoll if (kmfrv != KMF_OK) 215*e65e5c2dSWyllys Ingersoll return (kmfrv); 21699ebb4caSwyllys 21730a5e8faSwyllys SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), 21899ebb4caSwyllys "SetCSRPubKey"); 21999ebb4caSwyllys 22030a5e8faSwyllys SET_VALUE(kmf_set_csr_version(&csr, 2), "SetCSRVersion"); 22199ebb4caSwyllys 22230a5e8faSwyllys SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), 22330a5e8faSwyllys "kmf_set_csr_subject"); 22499ebb4caSwyllys 22530a5e8faSwyllys SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "kmf_set_csr_sig_alg"); 22699ebb4caSwyllys 22799ebb4caSwyllys if (altname != NULL) { 22830a5e8faSwyllys SET_VALUE(kmf_set_csr_subject_altname(&csr, altname, altcrit, 22930a5e8faSwyllys alttype), "kmf_set_csr_subject_altname"); 23099ebb4caSwyllys } 23199ebb4caSwyllys if (kubits != NULL) { 23230a5e8faSwyllys SET_VALUE(kmf_set_csr_ku(&csr, kucrit, kubits), 23330a5e8faSwyllys "kmf_set_csr_ku"); 23499ebb4caSwyllys } 235d00756ccSwyllys if (ekulist != NULL) { 236d00756ccSwyllys int i; 237d00756ccSwyllys for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { 238d00756ccSwyllys SET_VALUE(kmf_add_csr_eku(&csr, 239d00756ccSwyllys &ekulist->ekulist[i], 240d00756ccSwyllys ekulist->critlist[i]), 241d00756ccSwyllys "Extended Key Usage"); 242d00756ccSwyllys } 243d00756ccSwyllys } 24430a5e8faSwyllys if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) == 24599ebb4caSwyllys KMF_OK) { 24630a5e8faSwyllys kmfrv = kmf_create_csr_file(&signedCsr, fmt, fullcsrpath); 24799ebb4caSwyllys } 24899ebb4caSwyllys 24999ebb4caSwyllys cleanup: 25099ebb4caSwyllys if (fullkeypath) 25199ebb4caSwyllys free(fullkeypath); 25299ebb4caSwyllys if (fullcsrpath) 25399ebb4caSwyllys free(fullcsrpath); 25499ebb4caSwyllys 25530a5e8faSwyllys kmf_free_data(&signedCsr); 25630a5e8faSwyllys kmf_free_kmf_key(kmfhandle, &prik); 25730a5e8faSwyllys kmf_free_signed_csr(&csr); 25899ebb4caSwyllys 25999ebb4caSwyllys return (kmfrv); 26099ebb4caSwyllys } 26199ebb4caSwyllys 26299ebb4caSwyllys static KMF_RETURN 26399ebb4caSwyllys gencsr_nss(KMF_HANDLE_T kmfhandle, 26499ebb4caSwyllys char *token, char *subject, char *altname, 26599ebb4caSwyllys KMF_GENERALNAMECHOICES alttype, int altcrit, 26699ebb4caSwyllys char *nickname, char *dir, char *prefix, 26799ebb4caSwyllys KMF_KEY_ALG keyAlg, int keylen, 26899ebb4caSwyllys uint16_t kubits, int kucrit, 26999ebb4caSwyllys KMF_ENCODE_FORMAT fmt, char *csrfile, 270*e65e5c2dSWyllys Ingersoll KMF_CREDENTIAL *tokencred, EKU_LIST *ekulist, 271*e65e5c2dSWyllys Ingersoll KMF_ALGORITHM_INDEX sigAlg, KMF_OID *curveoid) 27299ebb4caSwyllys { 27399ebb4caSwyllys KMF_RETURN kmfrv; 27499ebb4caSwyllys KMF_KEY_HANDLE pubk, prik; 27599ebb4caSwyllys KMF_X509_NAME csrSubject; 27699ebb4caSwyllys KMF_CSR_DATA csr; 27799ebb4caSwyllys KMF_DATA signedCsr = {NULL, 0}; 27830a5e8faSwyllys 27930a5e8faSwyllys KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; 28030a5e8faSwyllys int numattr = 0; 28130a5e8faSwyllys KMF_ATTRIBUTE attrlist[16]; 28299ebb4caSwyllys 28399ebb4caSwyllys if (token == NULL) 28499ebb4caSwyllys token = DEFAULT_NSS_TOKEN; 28599ebb4caSwyllys 28699ebb4caSwyllys kmfrv = configure_nss(kmfhandle, dir, prefix); 28799ebb4caSwyllys if (kmfrv != KMF_OK) 28899ebb4caSwyllys return (kmfrv); 28999ebb4caSwyllys 29099ebb4caSwyllys (void) memset(&csr, 0, sizeof (csr)); 29199ebb4caSwyllys (void) memset(&csrSubject, 0, sizeof (csrSubject)); 292448b8615Swyllys (void) memset(&pubk, 0, sizeof (pubk)); 293448b8615Swyllys (void) memset(&prik, 0, sizeof (prik)); 29499ebb4caSwyllys 29599ebb4caSwyllys /* If the subject name cannot be parsed, flag it now and exit */ 29630a5e8faSwyllys if ((kmfrv = kmf_dn_parser(subject, &csrSubject)) != KMF_OK) { 29799ebb4caSwyllys return (kmfrv); 29899ebb4caSwyllys } 29999ebb4caSwyllys 300*e65e5c2dSWyllys Ingersoll kmfrv = genkeypair_nss(kmfhandle, token, nickname, dir, 301*e65e5c2dSWyllys Ingersoll prefix, keyAlg, keylen, tokencred, curveoid, 302*e65e5c2dSWyllys Ingersoll &prik, &pubk); 303*e65e5c2dSWyllys Ingersoll if (kmfrv != KMF_OK) 304*e65e5c2dSWyllys Ingersoll return (kmfrv); 30599ebb4caSwyllys 30630a5e8faSwyllys SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), 30730a5e8faSwyllys "kmf_set_csr_pubkey"); 30830a5e8faSwyllys SET_VALUE(kmf_set_csr_version(&csr, 2), "kmf_set_csr_version"); 30930a5e8faSwyllys SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), 31030a5e8faSwyllys "kmf_set_csr_subject"); 31130a5e8faSwyllys SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "kmf_set_csr_sig_alg"); 31299ebb4caSwyllys 31399ebb4caSwyllys if (altname != NULL) { 31430a5e8faSwyllys SET_VALUE(kmf_set_csr_subject_altname(&csr, altname, altcrit, 31530a5e8faSwyllys alttype), "kmf_set_csr_subject_altname"); 31699ebb4caSwyllys } 31799ebb4caSwyllys if (kubits != NULL) { 31830a5e8faSwyllys SET_VALUE(kmf_set_csr_ku(&csr, kucrit, kubits), 31930a5e8faSwyllys "kmf_set_csr_ku"); 32099ebb4caSwyllys } 321d00756ccSwyllys if (ekulist != NULL) { 322d00756ccSwyllys int i; 323d00756ccSwyllys for (i = 0; kmfrv == KMF_OK && i < ekulist->eku_count; i++) { 324d00756ccSwyllys SET_VALUE(kmf_add_csr_eku(&csr, 325d00756ccSwyllys &ekulist->ekulist[i], 326d00756ccSwyllys ekulist->critlist[i]), 327d00756ccSwyllys "Extended Key Usage"); 328d00756ccSwyllys } 329d00756ccSwyllys } 33030a5e8faSwyllys if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) == 33199ebb4caSwyllys KMF_OK) { 33230a5e8faSwyllys kmfrv = kmf_create_csr_file(&signedCsr, fmt, csrfile); 33399ebb4caSwyllys } 33499ebb4caSwyllys 33599ebb4caSwyllys cleanup: 33630a5e8faSwyllys (void) kmf_free_data(&signedCsr); 33730a5e8faSwyllys (void) kmf_free_kmf_key(kmfhandle, &prik); 33830a5e8faSwyllys 33999ebb4caSwyllys /* delete the key */ 34030a5e8faSwyllys numattr = 0; 34130a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, 34230a5e8faSwyllys &kstype, sizeof (kstype)); 34330a5e8faSwyllys numattr++; 34430a5e8faSwyllys 34530a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_PUBKEY_HANDLE_ATTR, 34630a5e8faSwyllys &pubk, sizeof (KMF_KEY_HANDLE)); 34730a5e8faSwyllys numattr++; 34830a5e8faSwyllys 34930a5e8faSwyllys if (tokencred != NULL && tokencred->credlen > 0) { 35030a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, 35130a5e8faSwyllys tokencred, sizeof (KMF_CREDENTIAL)); 35230a5e8faSwyllys numattr++; 35330a5e8faSwyllys } 35430a5e8faSwyllys 35530a5e8faSwyllys if (token && strlen(token)) { 35630a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, 35730a5e8faSwyllys token, strlen(token)); 35830a5e8faSwyllys numattr++; 35930a5e8faSwyllys } 36030a5e8faSwyllys 36130a5e8faSwyllys (void) kmf_delete_key_from_keystore(kmfhandle, numattr, attrlist); 36230a5e8faSwyllys 36330a5e8faSwyllys (void) kmf_free_signed_csr(&csr); 36499ebb4caSwyllys 36599ebb4caSwyllys return (kmfrv); 36699ebb4caSwyllys } 36799ebb4caSwyllys 36899ebb4caSwyllys int 36999ebb4caSwyllys pk_gencsr(int argc, char *argv[]) 37099ebb4caSwyllys { 37199ebb4caSwyllys KMF_RETURN rv; 37299ebb4caSwyllys int opt; 37399ebb4caSwyllys extern int optind_av; 37499ebb4caSwyllys extern char *optarg_av; 37599ebb4caSwyllys KMF_KEYSTORE_TYPE kstype = 0; 37699ebb4caSwyllys char *subject = NULL; 37799ebb4caSwyllys char *tokenname = NULL; 37899ebb4caSwyllys char *dir = NULL; 37999ebb4caSwyllys char *prefix = NULL; 38099ebb4caSwyllys int keylen = PK_DEFAULT_KEYLENGTH; 38199ebb4caSwyllys char *certlabel = NULL; 38299ebb4caSwyllys char *outcsr = NULL; 38399ebb4caSwyllys char *outkey = NULL; 38499ebb4caSwyllys char *format = NULL; 38599ebb4caSwyllys char *altname = NULL; 38699ebb4caSwyllys char *kustr = NULL; 387d00756ccSwyllys char *ekustr = NULL; 388*e65e5c2dSWyllys Ingersoll char *hashname = NULL; 38999ebb4caSwyllys uint16_t kubits = 0; 39099ebb4caSwyllys char *keytype = PK_DEFAULT_KEYTYPE; 39199ebb4caSwyllys KMF_HANDLE_T kmfhandle = NULL; 39299ebb4caSwyllys KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1; 39399ebb4caSwyllys KMF_KEY_ALG keyAlg = KMF_RSA; 3944165f465SWyllys Ingersoll KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_SHA1WithRSA; 39599ebb4caSwyllys boolean_t interactive = B_FALSE; 39699ebb4caSwyllys char *subname = NULL; 39799ebb4caSwyllys KMF_CREDENTIAL tokencred = {NULL, 0}; 39899ebb4caSwyllys KMF_GENERALNAMECHOICES alttype = 0; 39999ebb4caSwyllys int altcrit = 0, kucrit = 0; 400d00756ccSwyllys EKU_LIST *ekulist = NULL; 401*e65e5c2dSWyllys Ingersoll KMF_OID *curveoid = NULL; /* ECC */ 402*e65e5c2dSWyllys Ingersoll KMF_OID *hashoid = NULL; 403*e65e5c2dSWyllys Ingersoll int y_flag = 0; 40499ebb4caSwyllys 40599ebb4caSwyllys while ((opt = getopt_av(argc, argv, 40699ebb4caSwyllys "ik:(keystore)s:(subject)n:(nickname)A:(altname)" 40799ebb4caSwyllys "u:(keyusage)T:(token)d:(dir)p:(prefix)t:(keytype)" 408*e65e5c2dSWyllys Ingersoll "y:(keylen)l:(label)c:(outcsr)e:(eku)C:(curve)" 409*e65e5c2dSWyllys Ingersoll "K:(outkey)F:(format)E(listcurves)h:(hash)")) != EOF) { 41099ebb4caSwyllys 41199ebb4caSwyllys switch (opt) { 41299ebb4caSwyllys case 'A': 41399ebb4caSwyllys altname = optarg_av; 41499ebb4caSwyllys break; 41599ebb4caSwyllys case 'i': 416592106a2SWyllys Ingersoll if (interactive) 41799ebb4caSwyllys return (PK_ERR_USAGE); 418592106a2SWyllys Ingersoll else if (subject) { 419592106a2SWyllys Ingersoll cryptoerror(LOG_STDERR, 420592106a2SWyllys Ingersoll gettext("Interactive (-i) and " 421592106a2SWyllys Ingersoll "subject options are mutually " 422592106a2SWyllys Ingersoll "exclusive.\n")); 423592106a2SWyllys Ingersoll return (PK_ERR_USAGE); 424592106a2SWyllys Ingersoll } else 42599ebb4caSwyllys interactive = B_TRUE; 42699ebb4caSwyllys break; 42799ebb4caSwyllys case 'k': 42899ebb4caSwyllys kstype = KS2Int(optarg_av); 42999ebb4caSwyllys if (kstype == 0) 43099ebb4caSwyllys return (PK_ERR_USAGE); 43199ebb4caSwyllys break; 43299ebb4caSwyllys case 's': 433592106a2SWyllys Ingersoll if (subject) 43499ebb4caSwyllys return (PK_ERR_USAGE); 435592106a2SWyllys Ingersoll else if (interactive) { 436592106a2SWyllys Ingersoll cryptoerror(LOG_STDERR, 437592106a2SWyllys Ingersoll gettext("Interactive (-i) and " 438592106a2SWyllys Ingersoll "subject options are mutually " 439592106a2SWyllys Ingersoll "exclusive.\n")); 440592106a2SWyllys Ingersoll return (PK_ERR_USAGE); 441592106a2SWyllys Ingersoll } else 44299ebb4caSwyllys subject = optarg_av; 44399ebb4caSwyllys break; 44499ebb4caSwyllys case 'l': 44599ebb4caSwyllys case 'n': 44699ebb4caSwyllys if (certlabel) 44799ebb4caSwyllys return (PK_ERR_USAGE); 44899ebb4caSwyllys certlabel = optarg_av; 44999ebb4caSwyllys break; 45099ebb4caSwyllys case 'T': 45199ebb4caSwyllys if (tokenname) 45299ebb4caSwyllys return (PK_ERR_USAGE); 45399ebb4caSwyllys tokenname = optarg_av; 45499ebb4caSwyllys break; 45599ebb4caSwyllys case 'd': 45699ebb4caSwyllys dir = optarg_av; 45799ebb4caSwyllys break; 45899ebb4caSwyllys case 'p': 45999ebb4caSwyllys if (prefix) 46099ebb4caSwyllys return (PK_ERR_USAGE); 46199ebb4caSwyllys prefix = optarg_av; 46299ebb4caSwyllys break; 46399ebb4caSwyllys case 't': 46499ebb4caSwyllys keytype = optarg_av; 46599ebb4caSwyllys break; 46699ebb4caSwyllys case 'u': 46799ebb4caSwyllys kustr = optarg_av; 46899ebb4caSwyllys break; 46999ebb4caSwyllys case 'y': 47099ebb4caSwyllys if (sscanf(optarg_av, "%d", 47199ebb4caSwyllys &keylen) != 1) { 47299ebb4caSwyllys cryptoerror(LOG_STDERR, 47399ebb4caSwyllys gettext("Unrecognized " 47430a5e8faSwyllys "key length (%s)\n"), optarg_av); 47599ebb4caSwyllys return (PK_ERR_USAGE); 47699ebb4caSwyllys } 477*e65e5c2dSWyllys Ingersoll y_flag++; 47899ebb4caSwyllys break; 47999ebb4caSwyllys case 'c': 48099ebb4caSwyllys if (outcsr) 48199ebb4caSwyllys return (PK_ERR_USAGE); 48299ebb4caSwyllys outcsr = optarg_av; 48399ebb4caSwyllys break; 48499ebb4caSwyllys case 'K': 48599ebb4caSwyllys if (outkey) 48699ebb4caSwyllys return (PK_ERR_USAGE); 48799ebb4caSwyllys outkey = optarg_av; 48899ebb4caSwyllys break; 48999ebb4caSwyllys case 'F': 49099ebb4caSwyllys if (format) 49199ebb4caSwyllys return (PK_ERR_USAGE); 49299ebb4caSwyllys format = optarg_av; 49399ebb4caSwyllys break; 494d00756ccSwyllys case 'e': 495d00756ccSwyllys ekustr = optarg_av; 496d00756ccSwyllys break; 497*e65e5c2dSWyllys Ingersoll case 'C': 498*e65e5c2dSWyllys Ingersoll curveoid = ecc_name_to_oid(optarg_av); 499*e65e5c2dSWyllys Ingersoll if (curveoid == NULL) { 500*e65e5c2dSWyllys Ingersoll cryptoerror(LOG_STDERR, 501*e65e5c2dSWyllys Ingersoll gettext("Unrecognized ECC " 502*e65e5c2dSWyllys Ingersoll "curve.\n")); 503*e65e5c2dSWyllys Ingersoll return (PK_ERR_USAGE); 504*e65e5c2dSWyllys Ingersoll } 505*e65e5c2dSWyllys Ingersoll break; 506*e65e5c2dSWyllys Ingersoll case 'E': 507*e65e5c2dSWyllys Ingersoll /* 508*e65e5c2dSWyllys Ingersoll * This argument is only to be used 509*e65e5c2dSWyllys Ingersoll * by itself, no other options should 510*e65e5c2dSWyllys Ingersoll * be present. 511*e65e5c2dSWyllys Ingersoll */ 512*e65e5c2dSWyllys Ingersoll if (argc != 2) { 513*e65e5c2dSWyllys Ingersoll cryptoerror(LOG_STDERR, 514*e65e5c2dSWyllys Ingersoll gettext("listcurves has no other " 515*e65e5c2dSWyllys Ingersoll "options.\n")); 516*e65e5c2dSWyllys Ingersoll return (PK_ERR_USAGE); 517*e65e5c2dSWyllys Ingersoll } 518*e65e5c2dSWyllys Ingersoll show_ecc_curves(); 519*e65e5c2dSWyllys Ingersoll return (0); 520*e65e5c2dSWyllys Ingersoll case 'h': 521*e65e5c2dSWyllys Ingersoll hashname = optarg_av; 522*e65e5c2dSWyllys Ingersoll hashoid = ecc_name_to_oid(optarg_av); 523*e65e5c2dSWyllys Ingersoll if (hashoid == NULL) { 524*e65e5c2dSWyllys Ingersoll cryptoerror(LOG_STDERR, 525*e65e5c2dSWyllys Ingersoll gettext("Unrecognized hash.\n")); 526*e65e5c2dSWyllys Ingersoll return (PK_ERR_USAGE); 527*e65e5c2dSWyllys Ingersoll } 528*e65e5c2dSWyllys Ingersoll break; 52999ebb4caSwyllys default: 53099ebb4caSwyllys cryptoerror(LOG_STDERR, gettext( 53199ebb4caSwyllys "unrecognized gencsr option '%s'\n"), 53299ebb4caSwyllys argv[optind_av]); 53399ebb4caSwyllys return (PK_ERR_USAGE); 53499ebb4caSwyllys } 53599ebb4caSwyllys } 53699ebb4caSwyllys /* No additional args allowed. */ 53799ebb4caSwyllys argc -= optind_av; 53899ebb4caSwyllys argv += optind_av; 53999ebb4caSwyllys if (argc) { 54099ebb4caSwyllys return (PK_ERR_USAGE); 54199ebb4caSwyllys } 54299ebb4caSwyllys 54399ebb4caSwyllys /* Assume keystore = PKCS#11 if not specified. */ 54499ebb4caSwyllys if (kstype == 0) 54599ebb4caSwyllys kstype = KMF_KEYSTORE_PK11TOKEN; 54699ebb4caSwyllys 547577f4726Swyllys DIR_OPTION_CHECK(kstype, dir); 548577f4726Swyllys 5492cbed729Swyllys if (EMPTYSTRING(outcsr) && interactive) { 5502cbed729Swyllys (void) get_filename("CSR", &outcsr); 5512cbed729Swyllys } 55299ebb4caSwyllys if (EMPTYSTRING(outcsr)) { 55399ebb4caSwyllys (void) printf(gettext("A filename must be specified to hold" 55499ebb4caSwyllys "the final certificate request data.\n")); 55599ebb4caSwyllys return (PK_ERR_USAGE); 5562cbed729Swyllys } 55799ebb4caSwyllys /* 55899ebb4caSwyllys * verify that the outcsr file does not already exist 55999ebb4caSwyllys * and that it can be created. 56099ebb4caSwyllys */ 56199ebb4caSwyllys rv = verify_file(outcsr); 56299ebb4caSwyllys if (rv != KMF_OK) { 56399ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("output file (%s) " 56499ebb4caSwyllys "cannot be created.\n"), outcsr); 56599ebb4caSwyllys return (PK_ERR_USAGE); 56699ebb4caSwyllys } 56799ebb4caSwyllys 5682cbed729Swyllys if ((kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN)) { 5692cbed729Swyllys if (EMPTYSTRING(certlabel) && interactive) 5702cbed729Swyllys (void) get_certlabel(&certlabel); 5712cbed729Swyllys 5722cbed729Swyllys if (EMPTYSTRING(certlabel)) { 5732cbed729Swyllys cryptoerror(LOG_STDERR, gettext("A label must be " 57499ebb4caSwyllys "specified to create a certificate request.\n")); 57599ebb4caSwyllys return (PK_ERR_USAGE); 57699ebb4caSwyllys } 5772cbed729Swyllys } else if (kstype == KMF_KEYSTORE_OPENSSL) { 5782cbed729Swyllys if (EMPTYSTRING(outkey) && interactive) 5792cbed729Swyllys (void) get_filename("private key", &outkey); 5802cbed729Swyllys 5812cbed729Swyllys if (EMPTYSTRING(outkey)) { 5822cbed729Swyllys cryptoerror(LOG_STDERR, gettext("A key filename " 5832cbed729Swyllys "must be specified to create a certificate " 5842cbed729Swyllys "request.\n")); 5852cbed729Swyllys return (PK_ERR_USAGE); 5862cbed729Swyllys } 5872cbed729Swyllys } 58899ebb4caSwyllys 58999ebb4caSwyllys if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) { 59099ebb4caSwyllys cryptoerror(LOG_STDERR, 59130a5e8faSwyllys gettext("Error parsing format string (%s).\n"), format); 59299ebb4caSwyllys return (PK_ERR_USAGE); 59399ebb4caSwyllys } 59499ebb4caSwyllys if (format && fmt != KMF_FORMAT_ASN1 && fmt != KMF_FORMAT_PEM) { 59599ebb4caSwyllys cryptoerror(LOG_STDERR, 59699ebb4caSwyllys gettext("CSR must be DER or PEM format.\n")); 59799ebb4caSwyllys return (PK_ERR_USAGE); 59899ebb4caSwyllys } 59999ebb4caSwyllys 60099ebb4caSwyllys /* 60199ebb4caSwyllys * Check the subject name. 60299ebb4caSwyllys * If interactive is true, get it now interactively. 60399ebb4caSwyllys */ 60499ebb4caSwyllys if (interactive) { 60599ebb4caSwyllys if (get_subname(&subname) != KMF_OK) { 60699ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("Failed to get the " 60799ebb4caSwyllys "subject name interactively.\n")); 60899ebb4caSwyllys return (PK_ERR_USAGE); 60999ebb4caSwyllys } 61099ebb4caSwyllys } else { 61199ebb4caSwyllys if (EMPTYSTRING(subject)) { 61299ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("A subject name or " 61399ebb4caSwyllys "-i must be specified to create a certificate " 61499ebb4caSwyllys "request.\n")); 61599ebb4caSwyllys return (PK_ERR_USAGE); 61699ebb4caSwyllys } else { 61799ebb4caSwyllys subname = strdup(subject); 61899ebb4caSwyllys if (subname == NULL) { 61999ebb4caSwyllys cryptoerror(LOG_STDERR, 62099ebb4caSwyllys gettext("Out of memory.\n")); 62199ebb4caSwyllys return (PK_ERR_SYSTEM); 62299ebb4caSwyllys } 62399ebb4caSwyllys } 62499ebb4caSwyllys } 62599ebb4caSwyllys if (altname != NULL) { 62699ebb4caSwyllys rv = verify_altname(altname, &alttype, &altcrit); 62799ebb4caSwyllys if (rv != KMF_OK) { 62899ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("Subject AltName " 62999ebb4caSwyllys "must be specified as a name=value pair. " 63099ebb4caSwyllys "See the man page for details.")); 63199ebb4caSwyllys goto end; 63299ebb4caSwyllys } else { 63399ebb4caSwyllys /* advance the altname past the '=' sign */ 63499ebb4caSwyllys char *p = strchr(altname, '='); 63599ebb4caSwyllys if (p != NULL) 63699ebb4caSwyllys altname = p + 1; 63799ebb4caSwyllys } 63899ebb4caSwyllys } 63999ebb4caSwyllys 64099ebb4caSwyllys if (kustr != NULL) { 64199ebb4caSwyllys rv = verify_keyusage(kustr, &kubits, &kucrit); 64299ebb4caSwyllys if (rv != KMF_OK) { 64399ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("KeyUsage " 64499ebb4caSwyllys "must be specified as a comma-separated list. " 64599ebb4caSwyllys "See the man page for details.")); 64699ebb4caSwyllys goto end; 64799ebb4caSwyllys } 64899ebb4caSwyllys } 649d00756ccSwyllys if (ekustr != NULL) { 650d00756ccSwyllys rv = verify_ekunames(ekustr, &ekulist); 651d00756ccSwyllys if (rv != KMF_OK) { 652d00756ccSwyllys (void) fprintf(stderr, gettext("EKUs must " 653d00756ccSwyllys "be specified as a comma-separated list. " 654d00756ccSwyllys "See the man page for details.\n")); 655d00756ccSwyllys rv = PK_ERR_USAGE; 656d00756ccSwyllys goto end; 657d00756ccSwyllys } 658d00756ccSwyllys } 659*e65e5c2dSWyllys Ingersoll if ((rv = Str2KeyType(keytype, hashoid, &keyAlg, &sigAlg)) != 0) { 660*e65e5c2dSWyllys Ingersoll cryptoerror(LOG_STDERR, 661*e65e5c2dSWyllys Ingersoll gettext("Unsupported key/hash combination (%s/%s).\n"), 662*e65e5c2dSWyllys Ingersoll keytype, (hashname ? hashname : "none")); 66399ebb4caSwyllys goto end; 66499ebb4caSwyllys } 665*e65e5c2dSWyllys Ingersoll if (curveoid != NULL && keyAlg != KMF_ECDSA) { 666*e65e5c2dSWyllys Ingersoll cryptoerror(LOG_STDERR, gettext("EC curves are only " 667*e65e5c2dSWyllys Ingersoll "valid for EC keytypes.\n")); 668*e65e5c2dSWyllys Ingersoll return (PK_ERR_USAGE); 669*e65e5c2dSWyllys Ingersoll } 670*e65e5c2dSWyllys Ingersoll if (keyAlg == KMF_ECDSA && curveoid == NULL) { 671*e65e5c2dSWyllys Ingersoll cryptoerror(LOG_STDERR, gettext("A curve must be " 672*e65e5c2dSWyllys Ingersoll "specifed when using EC keys.\n")); 673*e65e5c2dSWyllys Ingersoll return (PK_ERR_USAGE); 674*e65e5c2dSWyllys Ingersoll } 675*e65e5c2dSWyllys Ingersoll if (keyAlg == KMF_ECDSA && kstype == KMF_KEYSTORE_OPENSSL) { 676*e65e5c2dSWyllys Ingersoll (void) fprintf(stderr, gettext("ECC certificates are" 677*e65e5c2dSWyllys Ingersoll "only supported with the pkcs11 and nss keystores\n")); 678*e65e5c2dSWyllys Ingersoll rv = PK_ERR_USAGE; 679*e65e5c2dSWyllys Ingersoll goto end; 680*e65e5c2dSWyllys Ingersoll } 681*e65e5c2dSWyllys Ingersoll 682*e65e5c2dSWyllys Ingersoll /* Adjust default keylength for NSS and DSA */ 683*e65e5c2dSWyllys Ingersoll if (keyAlg == KMF_DSA && !y_flag && kstype == KMF_KEYSTORE_NSS) 684*e65e5c2dSWyllys Ingersoll keylen = 1024; 68599ebb4caSwyllys 68699ebb4caSwyllys if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) { 68799ebb4caSwyllys if (tokenname == NULL || !strlen(tokenname)) { 68899ebb4caSwyllys if (kstype == KMF_KEYSTORE_NSS) { 68999ebb4caSwyllys tokenname = "internal"; 69099ebb4caSwyllys } else { 69199ebb4caSwyllys tokenname = PK_DEFAULT_PK11TOKEN; 69299ebb4caSwyllys } 69399ebb4caSwyllys } 69499ebb4caSwyllys 69599ebb4caSwyllys (void) get_token_password(kstype, tokenname, &tokencred); 69699ebb4caSwyllys } 69799ebb4caSwyllys 698577f4726Swyllys if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { 699577f4726Swyllys cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); 700577f4726Swyllys return (PK_ERR_USAGE); 701577f4726Swyllys } 702577f4726Swyllys 703577f4726Swyllys 70499ebb4caSwyllys if (kstype == KMF_KEYSTORE_NSS) { 70599ebb4caSwyllys if (dir == NULL) 70699ebb4caSwyllys dir = PK_DEFAULT_DIRECTORY; 70799ebb4caSwyllys 70899ebb4caSwyllys rv = gencsr_nss(kmfhandle, 70999ebb4caSwyllys tokenname, subname, altname, alttype, altcrit, 71099ebb4caSwyllys certlabel, dir, prefix, 71199ebb4caSwyllys keyAlg, keylen, kubits, kucrit, 712*e65e5c2dSWyllys Ingersoll fmt, outcsr, &tokencred, ekulist, 713*e65e5c2dSWyllys Ingersoll sigAlg, curveoid); 71499ebb4caSwyllys 71599ebb4caSwyllys } else if (kstype == KMF_KEYSTORE_PK11TOKEN) { 71699ebb4caSwyllys rv = gencsr_pkcs11(kmfhandle, 71799ebb4caSwyllys tokenname, subname, altname, alttype, altcrit, 71899ebb4caSwyllys certlabel, keyAlg, keylen, 719*e65e5c2dSWyllys Ingersoll kubits, kucrit, fmt, outcsr, &tokencred, 720*e65e5c2dSWyllys Ingersoll ekulist, sigAlg, curveoid); 72199ebb4caSwyllys 72299ebb4caSwyllys } else if (kstype == KMF_KEYSTORE_OPENSSL) { 72399ebb4caSwyllys rv = gencsr_file(kmfhandle, 72499ebb4caSwyllys keyAlg, keylen, fmt, subname, altname, 72599ebb4caSwyllys alttype, altcrit, kubits, kucrit, 726*e65e5c2dSWyllys Ingersoll outcsr, outkey, ekulist, sigAlg); 72799ebb4caSwyllys } 72899ebb4caSwyllys 72999ebb4caSwyllys end: 730592106a2SWyllys Ingersoll if (rv != KMF_OK) { 73199ebb4caSwyllys display_error(kmfhandle, rv, 73299ebb4caSwyllys gettext("Error creating CSR or keypair")); 73399ebb4caSwyllys 734592106a2SWyllys Ingersoll if (rv == KMF_ERR_RDN_PARSER) { 735592106a2SWyllys Ingersoll cryptoerror(LOG_STDERR, gettext("subject or " 736592106a2SWyllys Ingersoll "issuer name must be in proper DN format.\n")); 737592106a2SWyllys Ingersoll } 738592106a2SWyllys Ingersoll } 739592106a2SWyllys Ingersoll 740d00756ccSwyllys if (ekulist != NULL) 741d00756ccSwyllys free_eku_list(ekulist); 742d00756ccSwyllys 74399ebb4caSwyllys if (subname) 74499ebb4caSwyllys free(subname); 74599ebb4caSwyllys 74699ebb4caSwyllys if (tokencred.cred != NULL) 74799ebb4caSwyllys free(tokencred.cred); 74899ebb4caSwyllys 74930a5e8faSwyllys (void) kmf_finalize(kmfhandle); 75099ebb4caSwyllys if (rv != KMF_OK) 75199ebb4caSwyllys return (PK_ERR_USAGE); 75299ebb4caSwyllys 75399ebb4caSwyllys return (0); 75499ebb4caSwyllys } 755