xref: /onnv-gate/usr/src/cmd/cmd-crypto/pktool/signcsr.c (revision 6884:ca518f772fa0)
16051Swyllys /*
26051Swyllys  * CDDL HEADER START
36051Swyllys  *
46051Swyllys  * The contents of this file are subject to the terms of the
56051Swyllys  * Common Development and Distribution License (the "License").
66051Swyllys  * You may not use this file except in compliance with the License.
76051Swyllys  *
86051Swyllys  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96051Swyllys  * or http://www.opensolaris.org/os/licensing.
106051Swyllys  * See the License for the specific language governing permissions
116051Swyllys  * and limitations under the License.
126051Swyllys  *
136051Swyllys  * When distributing Covered Code, include this CDDL HEADER in each
146051Swyllys  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156051Swyllys  * If applicable, add the following below this CDDL HEADER, with the
166051Swyllys  * fields enclosed by brackets "[]" replaced with your own identifying
176051Swyllys  * information: Portions Copyright [yyyy] [name of copyright owner]
186051Swyllys  *
196051Swyllys  * CDDL HEADER END
206051Swyllys  */
216051Swyllys /*
226051Swyllys  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
236051Swyllys  * Use is subject to license terms.
246051Swyllys  */
256051Swyllys 
266051Swyllys #pragma ident	"%Z%%M%	%I%	%E% SMI"
276051Swyllys 
286051Swyllys /*
296051Swyllys  * This file implements the sign CSR operation for this tool.
306051Swyllys  */
316051Swyllys 
326051Swyllys #include <stdio.h>
336051Swyllys #include <errno.h>
346051Swyllys #include <string.h>
356051Swyllys #include <cryptoutil.h>
366051Swyllys #include <security/cryptoki.h>
376051Swyllys #include "common.h"
386051Swyllys 
396051Swyllys #include <kmfapi.h>
406669Swyllys #include <kmfapiP.h>
416669Swyllys 
426051Swyllys #define	SET_VALUE(f, s) \
436051Swyllys 	rv = f; \
446051Swyllys 	if (rv != KMF_OK) { \
456051Swyllys 		cryptoerror(LOG_STDERR, \
466051Swyllys 		    gettext("Failed to set %s: 0x%02x\n"), s, rv); \
476051Swyllys 		goto cleanup; \
486051Swyllys 	}
496051Swyllys 
506051Swyllys 
516051Swyllys static int
526051Swyllys read_csrdata(KMF_HANDLE_T handle, char *csrfile, KMF_CSR_DATA *csrdata)
536051Swyllys {
546051Swyllys 	KMF_RETURN rv = KMF_OK;
556051Swyllys 	KMF_ENCODE_FORMAT csrfmt;
566051Swyllys 	KMF_DATA csrfiledata = {NULL, 0};
576051Swyllys 	KMF_DATA rawcsr = {NULL, 0};
586051Swyllys 
596051Swyllys 	rv = kmf_get_file_format(csrfile, &csrfmt);
606051Swyllys 	if (rv != KMF_OK)
616051Swyllys 		return (rv);
626051Swyllys 
636051Swyllys 	rv = kmf_read_input_file(handle, csrfile, &csrfiledata);
646051Swyllys 	if (rv != KMF_OK)
656051Swyllys 		return (rv);
666051Swyllys 
676051Swyllys 	if (csrfmt == KMF_FORMAT_PEM) {
686051Swyllys 		rv = kmf_pem_to_der(csrfiledata.Data, csrfiledata.Length,
696051Swyllys 		    &rawcsr.Data, (int *)&rawcsr.Length);
706051Swyllys 		if (rv != KMF_OK)
716051Swyllys 			return (rv);
726051Swyllys 
736051Swyllys 		kmf_free_data(&csrfiledata);
746051Swyllys 	} else {
756051Swyllys 		rawcsr.Data = csrfiledata.Data;
766051Swyllys 		rawcsr.Length = csrfiledata.Length;
776051Swyllys 	}
786051Swyllys 
796051Swyllys 	rv = kmf_decode_csr(handle, &rawcsr, csrdata);
806051Swyllys 	kmf_free_data(&rawcsr);
816051Swyllys 
826051Swyllys 	return (rv);
836051Swyllys }
846051Swyllys 
856669Swyllys static KMF_RETURN
866669Swyllys find_csr_extn(KMF_X509_EXTENSIONS *extnlist, KMF_OID *extoid,
876669Swyllys 	KMF_X509_EXTENSION *outextn)
886669Swyllys {
896669Swyllys 	int i, found = 0;
906669Swyllys 	KMF_X509_EXTENSION *eptr;
916669Swyllys 	KMF_RETURN rv = KMF_OK;
926669Swyllys 
936669Swyllys 	(void) memset(outextn, 0, sizeof (KMF_X509_EXTENSION));
946669Swyllys 	for (i = 0; !found && i < extnlist->numberOfExtensions; i++) {
956669Swyllys 		eptr = &extnlist->extensions[i];
966669Swyllys 		if (IsEqualOid(extoid, &eptr->extnId)) {
976669Swyllys 			rv = copy_extension_data(outextn, eptr);
986669Swyllys 			found++;
996669Swyllys 		}
1006669Swyllys 	}
1016669Swyllys 	if (found == 0 || rv != KMF_OK)
1026669Swyllys 		return (1);
1036669Swyllys 	else
1046669Swyllys 		return (rv);
1056669Swyllys }
1066669Swyllys 
1076051Swyllys static int
1086051Swyllys build_cert_from_csr(KMF_CSR_DATA *csrdata,
1096051Swyllys 	KMF_X509_CERTIFICATE *signedCert,
1106051Swyllys 	KMF_BIGINT *serial,
1116051Swyllys 	uint32_t ltime,
1126051Swyllys 	char *issuer, char *subject,
1136051Swyllys 	char *altname,
1146051Swyllys 	KMF_GENERALNAMECHOICES alttype,
1156051Swyllys 	int altcrit,
1166051Swyllys 	uint16_t kubits,
1176051Swyllys 	int kucrit,
1186051Swyllys 	EKU_LIST *ekulist)
1196051Swyllys {
1206051Swyllys 	KMF_RETURN rv = KMF_OK;
1216051Swyllys 	KMF_X509_NAME issuerDN, subjectDN;
1226051Swyllys 
1236051Swyllys 	/*
1246051Swyllys 	 * If the CSR is ok, now we can generate the final certificate.
1256051Swyllys 	 */
1266051Swyllys 	(void) memset(signedCert, 0, sizeof (KMF_X509_CERTIFICATE));
1276051Swyllys 	(void) memset(&issuerDN, 0, sizeof (issuerDN));
1286051Swyllys 	(void) memset(&subjectDN, 0, sizeof (subjectDN));
1296051Swyllys 
1306051Swyllys 	SET_VALUE(kmf_set_cert_version(signedCert, 2), "version number");
1316051Swyllys 
1326051Swyllys 	SET_VALUE(kmf_set_cert_serial(signedCert, serial), "serial number");
1336051Swyllys 
1346051Swyllys 	SET_VALUE(kmf_set_cert_validity(signedCert, NULL, ltime),
1356051Swyllys 	    "validity time");
1366051Swyllys 
1376051Swyllys 	if (issuer) {
1386051Swyllys 		if (kmf_dn_parser(issuer, &issuerDN) != KMF_OK) {
1396051Swyllys 			cryptoerror(LOG_STDERR,
1406051Swyllys 			    gettext("Issuer name cannot be parsed\n"));
1416051Swyllys 			return (PK_ERR_USAGE);
1426051Swyllys 		}
1436051Swyllys 		SET_VALUE(kmf_set_cert_issuer(signedCert, &issuerDN),
1446051Swyllys 		    "Issuer Name");
1456051Swyllys 	}
1466051Swyllys 	if (subject) {
1476051Swyllys 		if (kmf_dn_parser(subject, &subjectDN) != KMF_OK) {
1486051Swyllys 			cryptoerror(LOG_STDERR,
1496051Swyllys 			    gettext("Subject name cannot be parsed\n"));
1506051Swyllys 			return (PK_ERR_USAGE);
1516051Swyllys 		}
1526051Swyllys 		SET_VALUE(kmf_set_cert_subject(signedCert, &subjectDN),
1536051Swyllys 		    "Subject Name");
1546051Swyllys 	} else {
1556051Swyllys 		signedCert->certificate.subject = csrdata->csr.subject;
1566051Swyllys 	}
1576051Swyllys 
1586051Swyllys 	signedCert->certificate.subjectPublicKeyInfo =
1596051Swyllys 	    csrdata->csr.subjectPublicKeyInfo;
1606051Swyllys 
1616051Swyllys 	signedCert->certificate.extensions = csrdata->csr.extensions;
1626051Swyllys 
1636051Swyllys 	signedCert->certificate.signature =
1646051Swyllys 	    csrdata->signature.algorithmIdentifier;
1656051Swyllys 
1666051Swyllys 	if (kubits != 0) {
1676669Swyllys 		KMF_X509_EXTENSION extn;
1686669Swyllys 		uint16_t oldbits;
1696669Swyllys 		/*
1706669Swyllys 		 * If the CSR already has KU, merge them.
1716669Swyllys 		 */
1726669Swyllys 		rv = find_csr_extn(&csrdata->csr.extensions,
1736669Swyllys 		    (KMF_OID *)&KMFOID_KeyUsage, &extn);
1746669Swyllys 		if (rv == KMF_OK) {
1756669Swyllys 			extn.critical |= kucrit;
1766669Swyllys 			if (extn.value.tagAndValue->value.Length > 1) {
1776669Swyllys 				oldbits =
1786669Swyllys 				    extn.value.tagAndValue->value.Data[1] << 8;
1796669Swyllys 			} else {
1806669Swyllys 				oldbits =
1816669Swyllys 				    extn.value.tagAndValue->value.Data[0];
1826669Swyllys 			}
1836669Swyllys 			oldbits |= kubits;
1846669Swyllys 		} else {
1856669Swyllys 			SET_VALUE(kmf_set_cert_ku(signedCert, kucrit, kubits),
1866669Swyllys 			    "KeyUsage");
1876669Swyllys 		}
1886051Swyllys 	}
1896051Swyllys 	if (altname != NULL) {
1906051Swyllys 		SET_VALUE(kmf_set_cert_subject_altname(signedCert,
1916051Swyllys 		    altcrit, alttype, altname), "subjectAltName");
1926051Swyllys 	}
1936051Swyllys 	if (ekulist != NULL) {
1946051Swyllys 		int i;
1956051Swyllys 		for (i = 0; rv == KMF_OK && i < ekulist->eku_count; i++) {
1966051Swyllys 			SET_VALUE(kmf_add_cert_eku(signedCert,
1976051Swyllys 			    &ekulist->ekulist[i],
1986051Swyllys 			    ekulist->critlist[i]), "Extended Key Usage");
1996051Swyllys 		}
2006051Swyllys 	}
2016051Swyllys cleanup:
2026051Swyllys 	if (issuer != NULL)
2036051Swyllys 		kmf_free_dn(&issuerDN);
2046051Swyllys 	if (subject != NULL)
2056051Swyllys 		kmf_free_dn(&subjectDN);
2066051Swyllys 
2076051Swyllys 	return (rv);
2086051Swyllys }
2096051Swyllys 
2106051Swyllys static int
2116051Swyllys pk_sign_cert(KMF_HANDLE_T handle, KMF_X509_CERTIFICATE *cert,
2126051Swyllys 	KMF_KEY_HANDLE *key, KMF_DATA *outdata)
2136051Swyllys {
2146051Swyllys 	KMF_RETURN rv;
2156051Swyllys 	int numattr;
2166051Swyllys 	KMF_ATTRIBUTE attrlist[4];
2176051Swyllys 
2186051Swyllys 	numattr = 0;
2196051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
2206051Swyllys 	    &key->kstype, sizeof (KMF_KEYSTORE_TYPE));
2216051Swyllys 	numattr++;
2226051Swyllys 
2236051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR,
2246051Swyllys 	    key, sizeof (KMF_KEY_HANDLE_ATTR));
2256051Swyllys 	numattr++;
2266051Swyllys 
2276051Swyllys 	/* cert data that is to be signed */
2286051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_X509_CERTIFICATE_ATTR,
2296051Swyllys 	    cert, sizeof (KMF_X509_CERTIFICATE));
2306051Swyllys 	numattr++;
2316051Swyllys 
2326051Swyllys 	/* output buffer for the signed cert */
2336051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR,
2346051Swyllys 	    outdata, sizeof (KMF_DATA));
2356051Swyllys 	numattr++;
2366051Swyllys 
2376051Swyllys 	if ((rv = kmf_sign_cert(handle, numattr, attrlist)) != KMF_OK) {
2386051Swyllys 		cryptoerror(LOG_STDERR,
2396051Swyllys 		    gettext("Failed to sign certificate.\n"));
2406051Swyllys 		return (rv);
2416051Swyllys 	}
2426051Swyllys 
2436051Swyllys 	return (rv);
2446051Swyllys }
2456051Swyllys 
2466051Swyllys static int
2476051Swyllys pk_signcsr_files(KMF_HANDLE_T handle,
2486051Swyllys 	char *signkey,
2496051Swyllys 	char *csrfile,
2506051Swyllys 	KMF_BIGINT *serial,
2516051Swyllys 	char *certfile,
2526051Swyllys 	char *issuer,
2536051Swyllys 	char *subject,
2546051Swyllys 	char *altname,
2556051Swyllys 	KMF_GENERALNAMECHOICES alttype,
2566051Swyllys 	int altcrit,
2576051Swyllys 	uint16_t kubits,
2586051Swyllys 	int kucrit,
2596051Swyllys 	EKU_LIST *ekulist,
2606051Swyllys 	uint32_t ltime,
2616051Swyllys 	KMF_ENCODE_FORMAT fmt)
2626051Swyllys {
2636051Swyllys 	KMF_RETURN rv = KMF_OK;
2646051Swyllys 	KMF_CSR_DATA csrdata;
2656051Swyllys 	KMF_ATTRIBUTE attrlist[16];
2666051Swyllys 	KMF_X509_CERTIFICATE signedCert;
2676051Swyllys 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL;
2686051Swyllys 	KMF_KEY_CLASS keyclass = KMF_ASYM_PRI;
2696051Swyllys 	KMF_KEY_HANDLE cakey;
2706051Swyllys 	KMF_DATA certdata = {NULL, 0};
2716051Swyllys 	int numattr, count;
2726051Swyllys 
2736051Swyllys 	rv = read_csrdata(handle, csrfile, &csrdata);
2746051Swyllys 	if (rv != KMF_OK) {
2756051Swyllys 		cryptoerror(LOG_STDERR,
2766051Swyllys 		    gettext("Error reading CSR data\n"));
2776051Swyllys 		return (rv);
2786051Swyllys 	}
2796051Swyllys 
2806051Swyllys 	/* verify the signature first */
2816051Swyllys 	numattr = 0;
2826051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_CSR_DATA_ATTR,
2836051Swyllys 	    &csrdata, sizeof (csrdata));
2846051Swyllys 	numattr++;
2856051Swyllys 
2866051Swyllys 	rv = kmf_verify_csr(handle, numattr, attrlist);
2876051Swyllys 	if (rv != KMF_OK) {
2886051Swyllys 		cryptoerror(LOG_STDERR, gettext("CSR signature "
2896051Swyllys 		    "verification failed.\n"));
2906051Swyllys 		goto cleanup;
2916051Swyllys 	}
2926051Swyllys 
2936051Swyllys 	rv = build_cert_from_csr(&csrdata, &signedCert, serial, ltime,
2946051Swyllys 	    issuer, subject, altname, alttype, altcrit, kubits,
2956051Swyllys 	    kucrit, ekulist);
2966051Swyllys 
2976051Swyllys 	if (rv != KMF_OK)
2986051Swyllys 		goto cleanup;
2996051Swyllys 
3006051Swyllys 	/*
3016051Swyllys 	 * Find the signing key.
3026051Swyllys 	 */
3036051Swyllys 	(void) memset(&cakey, 0, sizeof (cakey));
3046051Swyllys 
3056051Swyllys 	numattr = 0;
3066051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
3076051Swyllys 	    &kstype, sizeof (kstype));
3086051Swyllys 	numattr++;
3096051Swyllys 
3106051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR,
3116051Swyllys 	    signkey, strlen(signkey));
3126051Swyllys 	numattr++;
3136051Swyllys 
3146051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR,
3156051Swyllys 	    &keyclass, sizeof (keyclass));
3166051Swyllys 	numattr++;
3176051Swyllys 
3186051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR,
3196051Swyllys 	    &cakey, sizeof (cakey));
3206051Swyllys 	numattr++;
3216051Swyllys 
3226051Swyllys 	count = 1;
3236051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR,
3246051Swyllys 	    &count, sizeof (count));
3256051Swyllys 	numattr++;
3266051Swyllys 
3276051Swyllys 	rv = kmf_find_key(handle, numattr, attrlist);
3286051Swyllys 	if (rv != KMF_OK) {
3296051Swyllys 		cryptoerror(LOG_STDERR, gettext(
3306051Swyllys 		    "Error finding CA signing key\n"));
3316051Swyllys 		goto cleanup;
3326051Swyllys 	}
3336051Swyllys 
3346051Swyllys 	rv = pk_sign_cert(handle, &signedCert, &cakey, &certdata);
3356051Swyllys 	if (rv != KMF_OK) {
3366051Swyllys 		cryptoerror(LOG_STDERR, gettext(
3376051Swyllys 		    "Error signing certificate.\n"));
3386051Swyllys 		goto cleanup;
3396051Swyllys 	}
3406051Swyllys 
3416051Swyllys 	rv = kmf_create_cert_file(&certdata, fmt, certfile);
3426051Swyllys 
3436051Swyllys cleanup:
3446051Swyllys 	kmf_free_signed_csr(&csrdata);
3456051Swyllys 	kmf_free_data(&certdata);
3466051Swyllys 	kmf_free_kmf_key(handle, &cakey);
3476051Swyllys 	return (rv);
3486051Swyllys }
3496051Swyllys 
3506051Swyllys static int
3516051Swyllys pk_signcsr_pk11_nss(KMF_HANDLE_T handle,
3526051Swyllys 	KMF_KEYSTORE_TYPE kstype,
3536051Swyllys 	char *dir, char *prefix,
3546051Swyllys 	char *token, KMF_CREDENTIAL *cred,
3556051Swyllys 	char *signkey, char *csrfile,
3566051Swyllys 	KMF_BIGINT *serial, char *certfile, char *issuer, char *subject,
3576051Swyllys 	char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit,
3586051Swyllys 	uint16_t kubits, int kucrit,
3596051Swyllys 	EKU_LIST *ekulist, uint32_t ltime,
3606051Swyllys 	KMF_ENCODE_FORMAT fmt, int store, char *outlabel)
3616051Swyllys {
3626051Swyllys 	KMF_RETURN rv = KMF_OK;
3636051Swyllys 	KMF_DATA outcert = {NULL, 0};
3646051Swyllys 	KMF_CSR_DATA csrdata;
3656051Swyllys 	KMF_KEY_HANDLE casignkey;
3666051Swyllys 	KMF_KEY_CLASS keyclass = KMF_ASYM_PRI;
3676051Swyllys 	int numattr = 0;
3686051Swyllys 	int keys = 1;
3696051Swyllys 	KMF_ATTRIBUTE attrlist[16];
3706051Swyllys 	KMF_X509_CERTIFICATE signedCert;
3716051Swyllys 	boolean_t token_bool = B_TRUE;
3726051Swyllys 	boolean_t private_bool = B_TRUE;
3736051Swyllys 
3746051Swyllys 	rv = read_csrdata(handle, csrfile, &csrdata);
3756051Swyllys 	if (rv != KMF_OK) {
3766051Swyllys 		cryptoerror(LOG_STDERR,
3776051Swyllys 		    gettext("Error reading CSR data\n"));
3786051Swyllys 		return (rv);
3796051Swyllys 	}
3806051Swyllys 
3816051Swyllys 	if (kstype == KMF_KEYSTORE_PK11TOKEN) {
3826051Swyllys 		rv = select_token(handle, token, FALSE);
3836051Swyllys 	} else if (kstype == KMF_KEYSTORE_NSS) {
3846051Swyllys 		rv = configure_nss(handle, dir, prefix);
3856051Swyllys 	}
3866051Swyllys 
3876051Swyllys 	/* verify the signature first */
3886051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_CSR_DATA_ATTR,
3896051Swyllys 	    &csrdata, sizeof (csrdata));
3906051Swyllys 	numattr++;
3916051Swyllys 
3926051Swyllys 	rv = kmf_verify_csr(handle, numattr, attrlist);
3936051Swyllys 	if (rv != KMF_OK) {
3946051Swyllys 		cryptoerror(LOG_STDERR, gettext("CSR signature "
3956051Swyllys 		    "verification failed.\n"));
3966051Swyllys 		goto cleanup;
3976051Swyllys 	}
3986051Swyllys 
3996051Swyllys 	rv = build_cert_from_csr(&csrdata,
4006051Swyllys 	    &signedCert, serial, ltime,
4016051Swyllys 	    issuer, subject, altname,
4026051Swyllys 	    alttype, altcrit, kubits,
4036051Swyllys 	    kucrit, ekulist);
4046051Swyllys 
4056051Swyllys 	if (rv != KMF_OK)
4066051Swyllys 		goto cleanup;
4076051Swyllys 
4086051Swyllys 	/*
4096051Swyllys 	 * Find the signing key.
4106051Swyllys 	 */
4116051Swyllys 	numattr = 0;
4126051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
4136051Swyllys 	    &kstype, sizeof (kstype));
4146051Swyllys 	numattr++;
4156051Swyllys 	if (kstype == KMF_KEYSTORE_NSS) {
4166051Swyllys 		kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR,
4176051Swyllys 		    token, strlen(token));
4186051Swyllys 		numattr++;
4196051Swyllys 	}
4206051Swyllys 
4216051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, signkey,
4226051Swyllys 	    strlen(signkey));
4236051Swyllys 	numattr++;
4246051Swyllys 
4256051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVATE_BOOL_ATTR,
4266051Swyllys 	    &private_bool, sizeof (private_bool));
4276051Swyllys 	numattr++;
4286051Swyllys 
4296051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR,
4306051Swyllys 	    &token_bool, sizeof (token_bool));
4316051Swyllys 	numattr++;
4326051Swyllys 
4336051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR,
4346051Swyllys 	    &keyclass, sizeof (keyclass));
4356051Swyllys 	numattr++;
4366051Swyllys 
4376051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR,
4386051Swyllys 	    cred, sizeof (KMF_CREDENTIAL_ATTR));
4396051Swyllys 	numattr++;
4406051Swyllys 
4416051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR,
4426051Swyllys 	    &keys, sizeof (keys));
4436051Swyllys 	numattr++;
4446051Swyllys 
4456051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR,
4466051Swyllys 	    &casignkey, sizeof (casignkey));
4476051Swyllys 	numattr++;
4486051Swyllys 
4496051Swyllys 	rv = kmf_find_key(handle, numattr, attrlist);
4506051Swyllys 	if (rv != KMF_OK) {
4516051Swyllys 		cryptoerror(LOG_STDERR,
4526051Swyllys 		    gettext("Failed to find signing key\n"));
4536051Swyllys 		goto cleanup;
4546051Swyllys 	}
4556051Swyllys 
4566051Swyllys 	/*
4576051Swyllys 	 * If we found the key, now we can sign the cert.
4586051Swyllys 	 */
4596051Swyllys 	rv = pk_sign_cert(handle, &signedCert, &casignkey, &outcert);
4606051Swyllys 	if (rv != KMF_OK) {
4616051Swyllys 		cryptoerror(LOG_STDERR, gettext(
4626051Swyllys 		    "Error signing certificate.\n"));
4636051Swyllys 		goto cleanup;
4646051Swyllys 	}
4656051Swyllys 
4666051Swyllys 	/*
4676051Swyllys 	 * Store it on the token if the user asked for it.
4686051Swyllys 	 */
4696051Swyllys 	if (store) {
4706051Swyllys 		numattr = 0;
4716051Swyllys 		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
4726051Swyllys 		    &kstype, sizeof (kstype));
4736051Swyllys 		numattr++;
4746051Swyllys 
4756051Swyllys 		kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR,
4766051Swyllys 		    &outcert, sizeof (KMF_DATA));
4776051Swyllys 		numattr++;
4786051Swyllys 
4796051Swyllys 		if (outlabel != NULL) {
4806051Swyllys 			kmf_set_attr_at_index(attrlist, numattr,
4816051Swyllys 			    KMF_CERT_LABEL_ATTR,
4826051Swyllys 			    outlabel, strlen(outlabel));
4836051Swyllys 			numattr++;
4846051Swyllys 		}
4856051Swyllys 
4866051Swyllys 		if (kstype == KMF_KEYSTORE_NSS) {
4876051Swyllys 			if (token != NULL)
4886051Swyllys 				kmf_set_attr_at_index(attrlist, numattr,
4896051Swyllys 				    KMF_TOKEN_LABEL_ATTR,
4906051Swyllys 				    token, strlen(token));
4916051Swyllys 			numattr++;
4926051Swyllys 		}
4936051Swyllys 
4946051Swyllys 		rv = kmf_store_cert(handle, numattr, attrlist);
4956051Swyllys 		if (rv != KMF_OK) {
4966051Swyllys 			display_error(handle, rv,
4976051Swyllys 			    gettext("Failed to store cert "
4986051Swyllys 			    "on PKCS#11 token.\n"));
4996051Swyllys 			rv = KMF_OK;
5006051Swyllys 			/* Not fatal, we can still write it to a file. */
5016051Swyllys 		}
5026051Swyllys 	}
5036051Swyllys 	rv = kmf_create_cert_file(&outcert, fmt, certfile);
5046051Swyllys 
5056051Swyllys cleanup:
5066051Swyllys 	kmf_free_signed_csr(&csrdata);
5076051Swyllys 	kmf_free_data(&outcert);
5086051Swyllys 	kmf_free_kmf_key(handle, &casignkey);
5096051Swyllys 
5106051Swyllys 	return (rv);
5116051Swyllys }
5126051Swyllys 
5136051Swyllys /*
5146051Swyllys  * sign a CSR and generate an x509v3 certificate file.
5156051Swyllys  */
5166051Swyllys int
5176051Swyllys pk_signcsr(int argc, char *argv[])
5186051Swyllys {
5196051Swyllys 	int			opt;
5206051Swyllys 	extern int		optind_av;
5216051Swyllys 	extern char		*optarg_av;
5226051Swyllys 	char			*token_spec = NULL;
5236051Swyllys 	char			*subject = NULL;
5246051Swyllys 	char			*issuer = NULL;
5256051Swyllys 	char			*dir = NULL;
5266051Swyllys 	char			*prefix = NULL;
5276051Swyllys 	char			*csrfile = NULL;
5286051Swyllys 	char			*serstr = NULL;
5296051Swyllys 	char			*ekustr = NULL;
5306051Swyllys 	char			*kustr = NULL;
5316051Swyllys 	char			*format = NULL;
5326051Swyllys 	char			*storestr = NULL;
5336051Swyllys 	char			*altname = NULL;
5346051Swyllys 	char			*certfile = NULL;
5356051Swyllys 	char			*lifetime = NULL;
5366051Swyllys 	char			*signkey = NULL;
5376051Swyllys 	char			*outlabel = NULL;
5386051Swyllys 	uint32_t		ltime = 365 * 24 * 60 * 60; /* 1 Year */
5396051Swyllys 	int			store = 0;
5406051Swyllys 	uint16_t		kubits = 0;
5416051Swyllys 	int			altcrit = 0, kucrit = 0;
5426051Swyllys 	KMF_BIGINT		serial = { NULL, 0 };
5436051Swyllys 	EKU_LIST		*ekulist = NULL;
5446051Swyllys 	KMF_KEYSTORE_TYPE	kstype = 0;
5456051Swyllys 	KMF_RETURN		rv = KMF_OK;
5466051Swyllys 	KMF_HANDLE_T		kmfhandle = NULL;
5476051Swyllys 	KMF_CREDENTIAL		tokencred = {NULL, 0};
5486051Swyllys 	KMF_GENERALNAMECHOICES	alttype = 0;
5496051Swyllys 	KMF_ENCODE_FORMAT	fmt = KMF_FORMAT_PEM;
5506051Swyllys 
5516051Swyllys 	/* Parse command line options.  Do NOT i18n/l10n. */
5526051Swyllys 	while ((opt = getopt_av(argc, argv,
5536051Swyllys 	    "k:(keystore)c:(csr)T:(token)d:(dir)"
5546051Swyllys 	    "p:(prefix)S:(serial)s:(subject)a:(altname)"
5556051Swyllys 	    "t:(store)F:(format)K:(keyusage)l:(signkey)"
5566051Swyllys 	    "L:(lifetime)e:(eku)i:(issuer)"
5576051Swyllys 	    "n:(outlabel)o:(outcert)")) != EOF) {
5586051Swyllys 		if (EMPTYSTRING(optarg_av))
5596051Swyllys 			return (PK_ERR_USAGE);
5606051Swyllys 		switch (opt) {
5616051Swyllys 			case 'k':
5626051Swyllys 				if (kstype != 0)
5636051Swyllys 					return (PK_ERR_USAGE);
5646051Swyllys 				kstype = KS2Int(optarg_av);
5656051Swyllys 				if (kstype == 0)
5666051Swyllys 					return (PK_ERR_USAGE);
5676051Swyllys 				break;
5686051Swyllys 			case 't':
5696051Swyllys 				if (storestr != NULL)
5706051Swyllys 					return (PK_ERR_USAGE);
5716051Swyllys 				storestr = optarg_av;
5726051Swyllys 				store = yn_to_int(optarg_av);
5736051Swyllys 				if (store == -1)
5746051Swyllys 					return (PK_ERR_USAGE);
5756051Swyllys 				break;
5766051Swyllys 			case 'a':
5776051Swyllys 				if (altname)
5786051Swyllys 					return (PK_ERR_USAGE);
5796051Swyllys 				altname = optarg_av;
5806051Swyllys 				break;
5816051Swyllys 			case 's':
5826051Swyllys 				if (subject)
5836051Swyllys 					return (PK_ERR_USAGE);
5846051Swyllys 				subject = optarg_av;
5856051Swyllys 				break;
5866051Swyllys 			case 'i':
5876051Swyllys 				if (issuer)
5886051Swyllys 					return (PK_ERR_USAGE);
5896051Swyllys 				issuer = optarg_av;
5906051Swyllys 				break;
5916051Swyllys 			case 'd':
5926051Swyllys 				if (dir)
5936051Swyllys 					return (PK_ERR_USAGE);
5946051Swyllys 				dir = optarg_av;
5956051Swyllys 				break;
5966051Swyllys 			case 'p':
5976051Swyllys 				if (prefix)
5986051Swyllys 					return (PK_ERR_USAGE);
5996051Swyllys 				prefix = optarg_av;
6006051Swyllys 				break;
6016051Swyllys 			case 'S':
6026051Swyllys 				if (serstr != NULL)
6036051Swyllys 					return (PK_ERR_USAGE);
6046051Swyllys 				serstr = optarg_av;
6056051Swyllys 				break;
6066051Swyllys 			case 'c':
6076051Swyllys 				if (csrfile)
6086051Swyllys 					return (PK_ERR_USAGE);
6096051Swyllys 				csrfile = optarg_av;
6106051Swyllys 				break;
6116051Swyllys 			case 'T':	/* token specifier */
6126051Swyllys 				if (token_spec)
6136051Swyllys 					return (PK_ERR_USAGE);
6146051Swyllys 				token_spec = optarg_av;
6156051Swyllys 				break;
6166051Swyllys 			case 'l':	/* object with specific label */
6176051Swyllys 				if (signkey)
6186051Swyllys 					return (PK_ERR_USAGE);
6196051Swyllys 				signkey = optarg_av;
6206051Swyllys 				break;
6216051Swyllys 			case 'e':
6226051Swyllys 				if (ekustr != NULL)
6236051Swyllys 					return (PK_ERR_USAGE);
6246051Swyllys 				ekustr = optarg_av;
6256051Swyllys 				break;
6266051Swyllys 			case 'K':
6276051Swyllys 				if (kustr != NULL)
6286051Swyllys 					return (PK_ERR_USAGE);
6296051Swyllys 				kustr = optarg_av;
6306051Swyllys 				break;
6316051Swyllys 			case 'F':
6326051Swyllys 				if (format != NULL)
6336051Swyllys 					return (PK_ERR_USAGE);
6346051Swyllys 				format = optarg_av;
6356051Swyllys 				break;
6366051Swyllys 			case 'o':
6376051Swyllys 				if (certfile != NULL)
6386051Swyllys 					return (PK_ERR_USAGE);
6396051Swyllys 				certfile = optarg_av;
6406051Swyllys 				break;
6416051Swyllys 			case 'L':
6426051Swyllys 				if (lifetime != NULL)
6436051Swyllys 					return (PK_ERR_USAGE);
6446051Swyllys 				lifetime = optarg_av;
6456051Swyllys 				break;
6466051Swyllys 			case 'n':
6476051Swyllys 				if (outlabel != NULL)
6486051Swyllys 					return (PK_ERR_USAGE);
6496051Swyllys 				outlabel = optarg_av;
6506051Swyllys 				break;
6516051Swyllys 			default:
6526051Swyllys 				return (PK_ERR_USAGE);
6536051Swyllys 		}
6546051Swyllys 	}
6556051Swyllys 	/* No additional args allowed. */
6566051Swyllys 	argc -= optind_av;
6576051Swyllys 	argv += optind_av;
6586051Swyllys 	if (argc)
6596051Swyllys 		return (PK_ERR_USAGE);
6606051Swyllys 
6616051Swyllys 
6626051Swyllys 	/* Assume keystore = PKCS#11 if not specified. */
6636051Swyllys 	if (kstype == 0)
6646051Swyllys 		kstype = KMF_KEYSTORE_PK11TOKEN;
6656051Swyllys 
666*6884Swyllys 	DIR_OPTION_CHECK(kstype, dir);
667*6884Swyllys 
6686051Swyllys 	if (signkey == NULL) {
6696051Swyllys 		(void) fprintf(stderr, gettext("The signing key label "
6706051Swyllys 		    "or filename was not specified\n"));
6716051Swyllys 		return (PK_ERR_USAGE);
6726051Swyllys 	}
6736051Swyllys 	if (csrfile == NULL) {
6746051Swyllys 		(void) fprintf(stderr, gettext("The CSR filename was not"
6756051Swyllys 		    " specified\n"));
6766051Swyllys 		return (PK_ERR_USAGE);
6776051Swyllys 	}
6786051Swyllys 	if (certfile == NULL) {
6796051Swyllys 		(void) fprintf(stderr, gettext("The output certificate file "
6806051Swyllys 		    "was not specified\n"));
6816051Swyllys 		return (PK_ERR_USAGE);
6826051Swyllys 	}
6836051Swyllys 	if (issuer == NULL) {
6846051Swyllys 		(void) fprintf(stderr, gettext("The issuer DN "
6856051Swyllys 		    "was not specified\n"));
6866051Swyllys 		return (PK_ERR_USAGE);
6876051Swyllys 	}
6886051Swyllys 	if (lifetime != NULL) {
6896051Swyllys 		if (Str2Lifetime(lifetime, &ltime) != 0) {
6906051Swyllys 			cryptoerror(LOG_STDERR,
6916051Swyllys 			    gettext("Error parsing lifetime string\n"));
6926051Swyllys 			return (PK_ERR_USAGE);
6936051Swyllys 		}
6946051Swyllys 	}
6956051Swyllys 	if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) {
6966051Swyllys 		token_spec = PK_DEFAULT_PK11TOKEN;
6976051Swyllys 	} else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) {
6986051Swyllys 		token_spec = DEFAULT_NSS_TOKEN;
6996051Swyllys 	}
7006051Swyllys 
7016051Swyllys 	if (serstr != NULL) {
7026051Swyllys 		uchar_t *bytes = NULL;
7036051Swyllys 		size_t bytelen;
7046051Swyllys 
7056051Swyllys 		rv = kmf_hexstr_to_bytes((uchar_t *)serstr, &bytes, &bytelen);
7066051Swyllys 		if (rv != KMF_OK || bytes == NULL) {
7076051Swyllys 			(void) fprintf(stderr, gettext("Serial number "
7086051Swyllys 			    "must be specified as a hex number "
7096051Swyllys 			    "(ex: 0x0102030405ffeeddee)\n"));
7106051Swyllys 			return (PK_ERR_USAGE);
7116051Swyllys 		}
7126051Swyllys 		serial.val = bytes;
7136051Swyllys 		serial.len = bytelen;
7146051Swyllys 	} else {
7156051Swyllys 		(void) fprintf(stderr, gettext("The serial number was not"
7166051Swyllys 		    " specified\n"));
7176051Swyllys 		return (PK_ERR_USAGE);
7186051Swyllys 	}
7196051Swyllys 
7206051Swyllys 	if ((kstype == KMF_KEYSTORE_PK11TOKEN ||
7216051Swyllys 	    kstype == KMF_KEYSTORE_NSS)) {
7226051Swyllys 		/* Need to get password for private key access */
7236051Swyllys 		(void) get_token_password(kstype, token_spec,
7246051Swyllys 		    &tokencred);
7256051Swyllys 	}
7266669Swyllys 	if (kustr != NULL) {
7276669Swyllys 		rv = verify_keyusage(kustr, &kubits, &kucrit);
7286669Swyllys 		if (rv != KMF_OK) {
7296669Swyllys 			(void) fprintf(stderr, gettext("KeyUsage "
7306669Swyllys 			    "must be specified as a comma-separated list. "
7316669Swyllys 			    "See the man page for details.\n"));
7326669Swyllys 			rv = PK_ERR_USAGE;
7336669Swyllys 			goto end;
7346669Swyllys 		}
7356669Swyllys 	}
7366051Swyllys 	if (ekustr != NULL) {
7376051Swyllys 		rv = verify_ekunames(ekustr, &ekulist);
7386051Swyllys 		if (rv != KMF_OK) {
7396051Swyllys 			(void) fprintf(stderr, gettext("EKUs must "
7406051Swyllys 			    "be specified as a comma-separated list. "
7416051Swyllys 			    "See the man page for details.\n"));
7426051Swyllys 			rv = PK_ERR_USAGE;
7436051Swyllys 			goto end;
7446051Swyllys 		}
7456051Swyllys 	}
7466051Swyllys 	if (altname != NULL) {
7476051Swyllys 		char *p;
7486051Swyllys 		rv = verify_altname(altname, &alttype, &altcrit);
7496051Swyllys 		if (rv != KMF_OK) {
7506051Swyllys 			(void) fprintf(stderr, gettext("Subject AltName "
7516051Swyllys 			    "must be specified as a name=value pair. "
7526051Swyllys 			    "See the man page for details.\n"));
7536051Swyllys 			rv = PK_ERR_USAGE;
7546051Swyllys 			goto end;
7556051Swyllys 		}
7566051Swyllys 		/* advance the altname past the '=' sign */
7576051Swyllys 		p = strchr(altname, '=');
7586051Swyllys 		if (p != NULL)
7596051Swyllys 			altname = p + 1;
7606051Swyllys 	}
7616051Swyllys 	if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) {
7626051Swyllys 		cryptoerror(LOG_STDERR,
7636051Swyllys 		    gettext("Error parsing format string (%s).\n"),
7646051Swyllys 		    format);
7656051Swyllys 		return (PK_ERR_USAGE);
7666051Swyllys 	}
7676051Swyllys 
768*6884Swyllys 	if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
769*6884Swyllys 		return (rv);
770*6884Swyllys 	}
771*6884Swyllys 
7726051Swyllys 	if (kstype == KMF_KEYSTORE_PK11TOKEN) {
7736051Swyllys 		rv = pk_signcsr_pk11_nss(kmfhandle,
7746051Swyllys 		    kstype, dir, prefix, token_spec, &tokencred,
7756051Swyllys 		    signkey, csrfile, &serial, certfile, issuer, subject,
7766051Swyllys 		    altname, alttype, altcrit, kubits, kucrit,
7776051Swyllys 		    ekulist, ltime, fmt, store, outlabel);
7786051Swyllys 
7796051Swyllys 	} else if (kstype == KMF_KEYSTORE_NSS) {
7806051Swyllys 		if (dir == NULL)
7816051Swyllys 			dir = PK_DEFAULT_DIRECTORY;
7826051Swyllys 
7836051Swyllys 		rv = pk_signcsr_pk11_nss(kmfhandle,
7846051Swyllys 		    kstype, dir, prefix, token_spec, &tokencred,
7856051Swyllys 		    signkey, csrfile, &serial, certfile, issuer, subject,
7866051Swyllys 		    altname, alttype, altcrit, kubits, kucrit,
7876051Swyllys 		    ekulist, ltime, fmt, store, outlabel);
7886051Swyllys 
7896051Swyllys 	} else if (kstype == KMF_KEYSTORE_OPENSSL) {
7906051Swyllys 		rv = pk_signcsr_files(kmfhandle,
7916051Swyllys 		    signkey, csrfile, &serial, certfile, issuer, subject,
7926051Swyllys 		    altname, alttype, altcrit, kubits, kucrit,
7936051Swyllys 		    ekulist, ltime, fmt);
7946051Swyllys 	}
7956051Swyllys 
7966051Swyllys end:
7976051Swyllys 	if (rv != KMF_OK) {
7986051Swyllys 		display_error(kmfhandle, rv,
7996051Swyllys 		    gettext("Error listing objects"));
8006051Swyllys 	}
8016051Swyllys 
8026051Swyllys 	if (serial.val != NULL)
8036051Swyllys 		free(serial.val);
8046051Swyllys 
8056051Swyllys 	if (tokencred.cred != NULL)
8066051Swyllys 		free(tokencred.cred);
8076051Swyllys 
8086051Swyllys 	free_eku_list(ekulist);
8096051Swyllys 
8106051Swyllys 	(void) kmf_finalize(kmfhandle);
8116051Swyllys 	return (rv);
8126051Swyllys }
813