diff options
Diffstat (limited to 'usr/src/cmd/cmd-crypto/pktool/gencsr.c')
-rw-r--r-- | usr/src/cmd/cmd-crypto/pktool/gencsr.c | 631 |
1 files changed, 631 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-crypto/pktool/gencsr.c b/usr/src/cmd/cmd-crypto/pktool/gencsr.c new file mode 100644 index 0000000000..fcc00d01c8 --- /dev/null +++ b/usr/src/cmd/cmd-crypto/pktool/gencsr.c @@ -0,0 +1,631 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <malloc.h> +#include <libgen.h> +#include <errno.h> +#include <cryptoutil.h> +#include <security/cryptoki.h> +#include "common.h" + +#include <kmfapi.h> + +#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) +{ + KMF_RETURN kmfrv = KMF_OK; + KMF_CREATEKEYPAIR_PARAMS kp_params; + KMF_DELETEKEY_PARAMS dk_params; + KMF_KEY_HANDLE pubk, prik; + KMF_X509_NAME csrSubject; + KMF_CSR_DATA csr; + KMF_ALGORITHM_INDEX sigAlg; + KMF_DATA signedCsr = {NULL, 0}; + + (void) memset(&csr, 0, sizeof (csr)); + (void) memset(&csrSubject, 0, sizeof (csrSubject)); + (void) memset(&kp_params, 0, sizeof (kp_params)); + + if (keyAlg == KMF_DSA) + sigAlg = KMF_ALGID_SHA1WithDSA; + else + sigAlg = KMF_ALGID_MD5WithRSA; + + + /* If the subject name cannot be parsed, flag it now and exit */ + if ((kmfrv = KMF_DNParser(subject, &csrSubject)) != KMF_OK) { + return (kmfrv); + } + + kp_params.kstype = KMF_KEYSTORE_PK11TOKEN; + kp_params.keylabel = certlabel; + kp_params.keylength = keylen; /* bits */ + kp_params.keytype = keyAlg; + kp_params.cred.cred = tokencred->cred; + kp_params.cred.credlen = tokencred->credlen; + + /* Select a PKCS11 token */ + kmfrv = select_token(kmfhandle, token, FALSE); + if (kmfrv != KMF_OK) { + return (kmfrv); + } + + kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk); + if (kmfrv != KMF_OK) { + return (kmfrv); + } + + SET_VALUE(KMF_SetCSRPubKey(kmfhandle, &pubk, &csr), "keypair"); + + SET_VALUE(KMF_SetCSRVersion(&csr, 2), "version number"); + + SET_VALUE(KMF_SetCSRSubjectName(&csr, &csrSubject), + "subject name"); + + SET_VALUE(KMF_SetCSRSignatureAlgorithm(&csr, sigAlg), + "SignatureAlgorithm"); + + if (altname != NULL) { + SET_VALUE(KMF_SetCSRSubjectAltName(&csr, altname, altcrit, + alttype), "SetCSRSubjectAltName"); + } + + if (kubits != 0) { + SET_VALUE(KMF_SetCSRKeyUsage(&csr, kucrit, kubits), + "SetCSRKeyUsage"); + } + + if ((kmfrv = KMF_SignCSR(kmfhandle, &csr, &prik, &signedCsr)) == + KMF_OK) { + kmfrv = KMF_CreateCSRFile(&signedCsr, fmt, csrfile); + } + +cleanup: + (void) KMF_FreeData(&signedCsr); + (void) KMF_FreeKMFKey(kmfhandle, &prik); + /* delete the key */ + (void) memset(&dk_params, 0, sizeof (dk_params)); + dk_params.kstype = KMF_KEYSTORE_PK11TOKEN; + (void) KMF_DeleteKeyFromKeystore(kmfhandle, &dk_params, &pubk); + (void) KMF_FreeSignedCSR(&csr); + + 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 *dir, char *outcsr, char *outkey) +{ + KMF_RETURN kmfrv; + KMF_CREATEKEYPAIR_PARAMS kp_params; + KMF_KEY_HANDLE pubk, prik; + KMF_X509_NAME csrSubject; + KMF_CSR_DATA csr; + KMF_ALGORITHM_INDEX sigAlg; + KMF_DATA signedCsr = {NULL, 0}; + char *fullcsrpath = NULL; + char *fullkeypath = NULL; + + (void) memset(&csr, 0, sizeof (csr)); + (void) memset(&csrSubject, 0, sizeof (csrSubject)); + (void) memset(&kp_params, 0, sizeof (kp_params)); + + 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); + } + if (dir != NULL) { + fullcsrpath = get_fullpath(dir, outcsr); + if (fullcsrpath == NULL) { + cryptoerror(LOG_STDERR, + gettext("Cannot create file %s in " + "directory %s\n"), dir, outcsr); + return (PK_ERR_USAGE); + } + } else { + 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 (dir != NULL) { + fullkeypath = get_fullpath(dir, outkey); + if (fullkeypath == NULL) { + cryptoerror(LOG_STDERR, + gettext("Cannot create file %s in " + "directory %s\n"), dir, outkey); + free(fullcsrpath); + return (PK_ERR_USAGE); + } + } else { + fullkeypath = strdup(outkey); + } + if (verify_file(fullcsrpath)) { + cryptoerror(LOG_STDERR, + gettext("Cannot write the indicated output " + "key file (%s).\n"), fullkeypath); + free(fullcsrpath); + return (PK_ERR_USAGE); + } + + if (keyAlg == KMF_DSA) + sigAlg = KMF_ALGID_SHA1WithDSA; + else + sigAlg = KMF_ALGID_MD5WithRSA; + + /* If the subject name cannot be parsed, flag it now and exit */ + if ((kmfrv = KMF_DNParser(subject, &csrSubject)) != KMF_OK) { + return (kmfrv); + } + + kp_params.kstype = KMF_KEYSTORE_OPENSSL; + kp_params.keylength = keylen; /* bits */ + kp_params.keytype = keyAlg; + + kp_params.sslparms.keyfile = fullkeypath; + kp_params.sslparms.format = fmt; + + kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk); + if (kmfrv != KMF_OK) { + goto cleanup; + } + SET_VALUE(KMF_SetCSRPubKey(kmfhandle, &pubk, &csr), + "SetCSRPubKey"); + + SET_VALUE(KMF_SetCSRVersion(&csr, 2), "SetCSRVersion"); + + SET_VALUE(KMF_SetCSRSubjectName(&csr, &csrSubject), + "SetCSRSubjectName"); + + SET_VALUE(KMF_SetCSRSignatureAlgorithm(&csr, sigAlg), + "SetCSRSignatureAlgorithm"); + + if (altname != NULL) { + SET_VALUE(KMF_SetCSRSubjectAltName(&csr, altname, altcrit, + alttype), "SetCSRSubjectAltName"); + } + if (kubits != NULL) { + SET_VALUE(KMF_SetCSRKeyUsage(&csr, kucrit, kubits), + "SetCSRKeyUsage"); + } + if ((kmfrv = KMF_SignCSR(kmfhandle, &csr, &prik, &signedCsr)) == + KMF_OK) { + kmfrv = KMF_CreateCSRFile(&signedCsr, fmt, fullcsrpath); + } + +cleanup: + if (fullkeypath) + free(fullkeypath); + if (fullcsrpath) + free(fullcsrpath); + + KMF_FreeData(&signedCsr); + KMF_FreeKMFKey(kmfhandle, &prik); + KMF_FreeSignedCSR(&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) +{ + KMF_RETURN kmfrv; + KMF_CREATEKEYPAIR_PARAMS kp_params; + KMF_KEY_HANDLE pubk, prik; + KMF_X509_NAME csrSubject; + KMF_CSR_DATA csr; + KMF_ALGORITHM_INDEX sigAlg; + KMF_DATA signedCsr = {NULL, 0}; + KMF_DELETEKEY_PARAMS dk_params; + + if (token == NULL) + token = DEFAULT_NSS_TOKEN; + + if (keyAlg == KMF_DSA) + sigAlg = KMF_ALGID_SHA1WithDSA; + else + sigAlg = KMF_ALGID_MD5WithRSA; + + kmfrv = configure_nss(kmfhandle, dir, prefix); + if (kmfrv != KMF_OK) + return (kmfrv); + + (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_DNParser(subject, &csrSubject)) != KMF_OK) { + return (kmfrv); + } + + (void) memset(&kp_params, 0, sizeof (kp_params)); + + kp_params.kstype = KMF_KEYSTORE_NSS; + kp_params.keylabel = nickname; + kp_params.keylength = keylen; /* bits */ + kp_params.keytype = keyAlg; + kp_params.cred.cred = tokencred->cred; + kp_params.cred.credlen = tokencred->credlen; + kp_params.nssparms.slotlabel = token; + + kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk); + if (kmfrv != KMF_OK) { + goto cleanup; + } + + SET_VALUE(KMF_SetCSRPubKey(kmfhandle, &pubk, &csr), "SetCSRPubKey"); + SET_VALUE(KMF_SetCSRVersion(&csr, 2), "SetCSRVersion"); + SET_VALUE(KMF_SetCSRSubjectName(&csr, &csrSubject), + "SetCSRSubjectName"); + SET_VALUE(KMF_SetCSRSignatureAlgorithm(&csr, sigAlg), + "SetCSRSignatureAlgorithm"); + + if (altname != NULL) { + SET_VALUE(KMF_SetCSRSubjectAltName(&csr, altname, altcrit, + alttype), "SetCSRSubjectAltName"); + } + if (kubits != NULL) { + SET_VALUE(KMF_SetCSRKeyUsage(&csr, kucrit, kubits), + "SetCSRKeyUsage"); + } + if ((kmfrv = KMF_SignCSR(kmfhandle, &csr, &prik, &signedCsr)) == + KMF_OK) { + kmfrv = KMF_CreateCSRFile(&signedCsr, fmt, csrfile); + } + +cleanup: + (void) KMF_FreeData(&signedCsr); + (void) KMF_FreeKMFKey(kmfhandle, &prik); + /* delete the key */ + (void) memset(&dk_params, 0, sizeof (dk_params)); + dk_params.kstype = KMF_KEYSTORE_NSS; + dk_params.cred.cred = tokencred->cred; + dk_params.cred.credlen = tokencred->credlen; + dk_params.nssparms.slotlabel = token; + (void) KMF_DeleteKeyFromKeystore(kmfhandle, &dk_params, &pubk); + (void) KMF_FreeSignedCSR(&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; + 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_MD5WithRSA; + boolean_t interactive = B_FALSE; + char *subname = NULL; + KMF_CREDENTIAL tokencred = {NULL, 0}; + KMF_GENERALNAMECHOICES alttype = 0; + int altcrit = 0, kucrit = 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)" + "K:(outkey)F:(format)")) != EOF) { + + if (opt != 'i' && 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': + 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); + } + 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; + 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); + } + + 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 (EMPTYSTRING(outcsr)) { + (void) printf(gettext("A filename must be specified to hold" + "the final certificate request data.\n")); + return (PK_ERR_USAGE); + } else { + /* + * verify that the outcsr file does not already exist + * and that it can be created. + */ + rv = verify_file(outcsr); + if (rv != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("output file (%s) " + "cannot be created.\n"), outcsr); + return (PK_ERR_USAGE); + } + } + + if ((kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) && + 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 && 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 ((rv = Str2KeyType(keytype, &keyAlg, &sigAlg)) != 0) { + cryptoerror(LOG_STDERR, gettext("Unrecognized keytype (%s).\n"), + keytype); + 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 = gencsr_nss(kmfhandle, + tokenname, subname, altname, alttype, altcrit, + certlabel, dir, prefix, + keyAlg, keylen, kubits, kucrit, + fmt, outcsr, &tokencred); + + } else if (kstype == KMF_KEYSTORE_PK11TOKEN) { + rv = gencsr_pkcs11(kmfhandle, + tokenname, subname, altname, alttype, altcrit, + certlabel, keyAlg, keylen, + kubits, kucrit, fmt, outcsr, &tokencred); + + } else if (kstype == KMF_KEYSTORE_OPENSSL) { + rv = gencsr_file(kmfhandle, + keyAlg, keylen, fmt, subname, altname, + alttype, altcrit, kubits, kucrit, + dir, outcsr, outkey); + } + +end: + if (rv != KMF_OK) + display_error(kmfhandle, rv, + gettext("Error creating CSR or keypair")); + + 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); +} |