File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / pki / commands / issue.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:44 2020 UTC (4 years, 2 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    1: /*
    2:  * Copyright (C) 2009 Martin Willi
    3:  * Copyright (C) 2015-2019 Andreas Steffen
    4:  * HSR Hochschule fuer Technik Rapperswil
    5:  *
    6:  * This program is free software; you can redistribute it and/or modify it
    7:  * under the terms of the GNU General Public License as published by the
    8:  * Free Software Foundation; either version 2 of the License, or (at your
    9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
   10:  *
   11:  * This program is distributed in the hope that it will be useful, but
   12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14:  * for more details.
   15:  */
   16: 
   17: #include <time.h>
   18: #include <errno.h>
   19: 
   20: #include "pki.h"
   21: 
   22: #include <utils/debug.h>
   23: #include <asn1/asn1.h>
   24: #include <collections/linked_list.h>
   25: #include <credentials/certificates/certificate.h>
   26: #include <credentials/certificates/x509.h>
   27: #include <credentials/certificates/pkcs10.h>
   28: 
   29: /**
   30:  * Free cert policy with OID
   31:  */
   32: static void destroy_cert_policy(x509_cert_policy_t *policy)
   33: {
   34: 	free(policy->oid.ptr);
   35: 	free(policy);
   36: }
   37: 
   38: /**
   39:  * Free policy mapping
   40:  */
   41: static void destroy_policy_mapping(x509_policy_mapping_t *mapping)
   42: {
   43: 	free(mapping->issuer.ptr);
   44: 	free(mapping->subject.ptr);
   45: 	free(mapping);
   46: }
   47: 
   48: /**
   49:  * Free a CRL DistributionPoint
   50:  */
   51: static void destroy_cdp(x509_cdp_t *this)
   52: {
   53: 	DESTROY_IF(this->issuer);
   54: 	free(this);
   55: }
   56: 
   57: /**
   58:  * Issue a certificate using a CA certificate and key
   59:  */
   60: static int issue()
   61: {
   62: 	cred_encoding_type_t form = CERT_ASN1_DER;
   63: 	hash_algorithm_t digest = HASH_UNKNOWN;
   64: 	signature_params_t *scheme = NULL;
   65: 	certificate_t *cert_req = NULL, *cert = NULL, *ca =NULL;
   66: 	private_key_t *private = NULL;
   67: 	public_key_t *public = NULL;
   68: 	credential_type_t type = CRED_PUBLIC_KEY;
   69: 	key_type_t subtype = KEY_ANY;
   70: 	bool pkcs10 = FALSE;
   71: 	char *file = NULL, *dn = NULL, *hex = NULL, *cacert = NULL, *cakey = NULL;
   72: 	char *error = NULL, *keyid = NULL;
   73: 	identification_t *id = NULL;
   74: 	linked_list_t *san, *cdps, *ocsp, *permitted, *excluded, *policies, *mappings;
   75: 	linked_list_t *addrblocks;
   76: 	int pathlen = X509_NO_CONSTRAINT, inhibit_any = X509_NO_CONSTRAINT;
   77: 	int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT;
   78: 	chunk_t serial = chunk_empty;
   79: 	chunk_t encoding = chunk_empty;
   80: 	chunk_t critical_extension_oid = chunk_empty;
   81: 	time_t not_before, not_after, lifetime = 1095 * 24 * 60 * 60;
   82: 	char *datenb = NULL, *datena = NULL, *dateform = NULL;
   83: 	x509_flag_t flags = 0;
   84: 	x509_t *x509;
   85: 	x509_cdp_t *cdp = NULL;
   86: 	x509_cert_policy_t *policy = NULL;
   87: 	traffic_selector_t *ts;
   88: 	char *arg;
   89: 	bool pss = lib->settings->get_bool(lib->settings, "%s.rsa_pss", FALSE,
   90: 									   lib->ns);
   91: 
   92: 	san = linked_list_create();
   93: 	cdps = linked_list_create();
   94: 	ocsp = linked_list_create();
   95: 	permitted = linked_list_create();
   96: 	excluded = linked_list_create();
   97: 	policies = linked_list_create();
   98: 	mappings = linked_list_create();
   99: 	addrblocks = linked_list_create();
  100: 
  101: 	while (TRUE)
  102: 	{
  103: 		switch (command_getopt(&arg))
  104: 		{
  105: 			case 'h':
  106: 				goto usage;
  107: 			case 't':
  108: 				if (streq(arg, "pkcs10"))
  109: 				{
  110: 					pkcs10 = TRUE;
  111: 				}
  112: 				else if (streq(arg, "rsa"))
  113: 				{
  114: 					type = CRED_PRIVATE_KEY;
  115: 					subtype = KEY_RSA;
  116: 				}
  117: 				else if (streq(arg, "ecdsa"))
  118: 				{
  119: 					type = CRED_PRIVATE_KEY;
  120: 					subtype = KEY_ECDSA;
  121: 				}
  122: 				else if (streq(arg, "ed25519"))
  123: 				{
  124: 					type = CRED_PRIVATE_KEY;
  125: 					subtype = KEY_ED25519;
  126: 				}
  127: 				else if (streq(arg, "ed448"))
  128: 				{
  129: 					type = CRED_PRIVATE_KEY;
  130: 					subtype = KEY_ED448;
  131: 				}
  132: 				else if (streq(arg, "bliss"))
  133: 				{
  134: 					type = CRED_PRIVATE_KEY;
  135: 					subtype = KEY_BLISS;
  136: 				}
  137: 				else if (streq(arg, "priv"))
  138: 				{
  139: 					type = CRED_PRIVATE_KEY;
  140: 					subtype = KEY_ANY;
  141: 				}
  142: 				else if (!streq(arg, "pub"))
  143: 				{
  144: 					error = "invalid input type";
  145: 					goto usage;
  146: 				}
  147: 				continue;
  148: 			case 'g':
  149: 				if (!enum_from_name(hash_algorithm_short_names, arg, &digest))
  150: 				{
  151: 					error = "invalid --digest type";
  152: 					goto usage;
  153: 				}
  154: 				continue;
  155: 			case 'R':
  156: 				if (streq(arg, "pss"))
  157: 				{
  158: 					pss = TRUE;
  159: 				}
  160: 				else if (!streq(arg, "pkcs1"))
  161: 				{
  162: 					error = "invalid RSA padding";
  163: 					goto usage;
  164: 				}
  165: 				continue;
  166: 			case 'i':
  167: 				file = arg;
  168: 				continue;
  169: 			case 'c':
  170: 				cacert = arg;
  171: 				continue;
  172: 			case 'k':
  173: 				cakey = arg;
  174: 				continue;
  175: 			case 'x':
  176: 				keyid = arg;
  177: 				continue;
  178: 			case 'd':
  179: 				dn = arg;
  180: 				continue;
  181: 			case 'a':
  182: 				san->insert_last(san, identification_create_from_string(arg));
  183: 				continue;
  184: 			case 'l':
  185: 				lifetime = atoi(arg) * 24 * 60 * 60;
  186: 				if (!lifetime)
  187: 				{
  188: 					error = "invalid --lifetime value";
  189: 					goto usage;
  190: 				}
  191: 				continue;
  192: 			case 'D':
  193: 				dateform = arg;
  194: 				continue;
  195: 			case 'F':
  196: 				datenb = arg;
  197: 				continue;
  198: 			case 'T':
  199: 				datena = arg;
  200: 				continue;
  201: 			case 's':
  202: 				hex = arg;
  203: 				continue;
  204: 			case 'b':
  205: 				flags |= X509_CA;
  206: 				continue;
  207: 			case 'p':
  208: 				pathlen = atoi(arg);
  209: 				continue;
  210: 			case 'B':
  211: 				ts = parse_ts(arg);
  212: 				if (!ts)
  213: 				{
  214: 					error = "invalid addressBlock";
  215: 					goto usage;
  216: 				}
  217: 				addrblocks->insert_last(addrblocks, ts);
  218: 				continue;
  219: 			case 'n':
  220: 				permitted->insert_last(permitted,
  221: 									   identification_create_from_string(arg));
  222: 				continue;
  223: 			case 'N':
  224: 				excluded->insert_last(excluded,
  225: 									  identification_create_from_string(arg));
  226: 				continue;
  227: 			case 'P':
  228: 			{
  229: 				chunk_t oid;
  230: 
  231: 				oid = asn1_oid_from_string(arg);
  232: 				if (!oid.len)
  233: 				{
  234: 					error = "--cert-policy OID invalid";
  235: 					goto usage;
  236: 				}
  237: 				INIT(policy,
  238: 					.oid = oid,
  239: 				);
  240: 				policies->insert_last(policies, policy);
  241: 				continue;
  242: 			}
  243: 			case 'C':
  244: 				if (!policy)
  245: 				{
  246: 					error = "--cps-uri must follow a --cert-policy";
  247: 					goto usage;
  248: 				}
  249: 				policy->cps_uri = arg;
  250: 				continue;
  251: 			case 'U':
  252: 				if (!policy)
  253: 				{
  254: 					error = "--user-notice must follow a --cert-policy";
  255: 					goto usage;
  256: 				}
  257: 				policy->unotice_text = arg;
  258: 				continue;
  259: 			case 'M':
  260: 			{
  261: 				char *pos = strchr(arg, ':');
  262: 				x509_policy_mapping_t *mapping;
  263: 				chunk_t subject_oid, issuer_oid;
  264: 
  265: 				if (pos)
  266: 				{
  267: 					*pos++ = '\0';
  268: 					issuer_oid = asn1_oid_from_string(arg);
  269: 					subject_oid = asn1_oid_from_string(pos);
  270: 				}
  271: 				if (!pos || !issuer_oid.len || !subject_oid.len)
  272: 				{
  273: 					error = "--policy-map OIDs invalid";
  274: 					goto usage;
  275: 				}
  276: 				INIT(mapping,
  277: 					.issuer = issuer_oid,
  278: 					.subject = subject_oid,
  279: 				);
  280: 				mappings->insert_last(mappings, mapping);
  281: 				continue;
  282: 			}
  283: 			case 'E':
  284: 				require_explicit = atoi(arg);
  285: 				continue;
  286: 			case 'H':
  287: 				inhibit_mapping = atoi(arg);
  288: 				continue;
  289: 			case 'A':
  290: 				inhibit_any = atoi(arg);
  291: 				continue;
  292: 			case 'e':
  293: 				if (streq(arg, "serverAuth"))
  294: 				{
  295: 					flags |= X509_SERVER_AUTH;
  296: 				}
  297: 				else if (streq(arg, "clientAuth"))
  298: 				{
  299: 					flags |= X509_CLIENT_AUTH;
  300: 				}
  301: 				else if (streq(arg, "ikeIntermediate"))
  302: 				{
  303: 					flags |= X509_IKE_INTERMEDIATE;
  304: 				}
  305: 				else if (streq(arg, "crlSign"))
  306: 				{
  307: 					flags |= X509_CRL_SIGN;
  308: 				}
  309: 				else if (streq(arg, "ocspSigning"))
  310: 				{
  311: 					flags |= X509_OCSP_SIGNER;
  312: 				}
  313: 				else if (streq(arg, "msSmartcardLogon"))
  314: 				{
  315: 					flags |= X509_MS_SMARTCARD_LOGON;
  316: 				}
  317: 				continue;
  318: 			case 'f':
  319: 				if (!get_form(arg, &form, CRED_CERTIFICATE))
  320: 				{
  321: 					error = "invalid output format";
  322: 					goto usage;
  323: 				}
  324: 				continue;
  325: 			case 'u':
  326: 				INIT(cdp,
  327: 					.uri = arg,
  328: 				);
  329: 				cdps->insert_last(cdps, cdp);
  330: 				continue;
  331: 			case 'I':
  332: 				if (!cdp || cdp->issuer)
  333: 				{
  334: 					error = "--crlissuer must follow a --crl";
  335: 					goto usage;
  336: 				}
  337: 				cdp->issuer = identification_create_from_string(arg);
  338: 				continue;
  339: 			case 'o':
  340: 				ocsp->insert_last(ocsp, arg);
  341: 				continue;
  342: 			case 'X':
  343: 				chunk_free(&critical_extension_oid);
  344: 				critical_extension_oid = asn1_oid_from_string(arg);
  345: 				continue;
  346: 			case EOF:
  347: 				break;
  348: 			default:
  349: 				error = "invalid --issue option";
  350: 				goto usage;
  351: 		}
  352: 		break;
  353: 	}
  354: 
  355: 	if (!cacert)
  356: 	{
  357: 		error = "--cacert is required";
  358: 		goto usage;
  359: 	}
  360: 	if (!cakey && !keyid)
  361: 	{
  362: 		error = "--cakey or --keyid is required";
  363: 		goto usage;
  364: 	}
  365: 	if (!calculate_lifetime(dateform, datenb, datena, lifetime,
  366: 							&not_before, &not_after))
  367: 	{
  368: 		error = "invalid --not-before/after datetime";
  369: 		goto usage;
  370: 	}
  371: 	if (dn && *dn)
  372: 	{
  373: 		id = identification_create_from_string(dn);
  374: 		if (id->get_type(id) != ID_DER_ASN1_DN)
  375: 		{
  376: 			error = "supplied --dn is not a distinguished name";
  377: 			goto end;
  378: 		}
  379: 	}
  380: 
  381: 	DBG2(DBG_LIB, "Reading ca certificate:");
  382: 	ca = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
  383: 							BUILD_FROM_FILE, cacert, BUILD_END);
  384: 	if (!ca)
  385: 	{
  386: 		error = "parsing CA certificate failed";
  387: 		goto end;
  388: 	}
  389: 	x509 = (x509_t*)ca;
  390: 	if (!(x509->get_flags(x509) & X509_CA))
  391: 	{
  392: 		error = "CA certificate misses CA basicConstraint";
  393: 		goto end;
  394: 	}
  395: 	public = ca->get_public_key(ca);
  396: 	if (!public)
  397: 	{
  398: 		error = "extracting CA certificate public key failed";
  399: 		goto end;
  400: 	}
  401: 
  402: 	DBG2(DBG_LIB, "Reading ca private key:");
  403: 	if (cakey)
  404: 	{
  405: 		private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
  406: 									 public->get_type(public),
  407: 									 BUILD_FROM_FILE, cakey, BUILD_END);
  408: 	}
  409: 	else
  410: 	{
  411: 		chunk_t chunk;
  412: 
  413: 		chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
  414: 		private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
  415: 									 BUILD_PKCS11_KEYID, chunk, BUILD_END);
  416: 		free(chunk.ptr);
  417: 	}
  418: 	if (!private)
  419: 	{
  420: 		error = "loading CA private key failed";
  421: 		goto end;
  422: 	}
  423: 	if (!private->belongs_to(private, public))
  424: 	{
  425: 		error = "CA private key does not match CA certificate";
  426: 		goto end;
  427: 	}
  428: 	public->destroy(public);
  429: 	public = NULL;
  430: 
  431: 	if (hex)
  432: 	{
  433: 		serial = chunk_from_hex(chunk_create(hex, strlen(hex)), NULL);
  434: 	}
  435: 	else
  436: 	{
  437: 		rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
  438: 
  439: 		if (!rng)
  440: 		{
  441: 			error = "no random number generator found";
  442: 			goto end;
  443: 		}
  444: 		if (!rng_allocate_bytes_not_zero(rng, 8, &serial, FALSE))
  445: 		{
  446: 			error = "failed to generate serial number";
  447: 			rng->destroy(rng);
  448: 			goto end;
  449: 		}
  450: 		serial.ptr[0] &= 0x7F;
  451: 		rng->destroy(rng);
  452: 	}
  453: 
  454: 	if (pkcs10)
  455: 	{
  456: 		enumerator_t *enumerator;
  457: 		identification_t *subjectAltName;
  458: 		pkcs10_t *req;
  459: 
  460: 		DBG2(DBG_LIB, "Reading certificate request");
  461: 		if (file)
  462: 		{
  463: 			cert_req = lib->creds->create(lib->creds, CRED_CERTIFICATE,
  464: 										  CERT_PKCS10_REQUEST,
  465: 										  BUILD_FROM_FILE, file, BUILD_END);
  466: 		}
  467: 		else
  468: 		{
  469: 			chunk_t chunk;
  470: 
  471: 			set_file_mode(stdin, CERT_ASN1_DER);
  472: 			if (!chunk_from_fd(0, &chunk))
  473: 			{
  474: 				fprintf(stderr, "%s: ", strerror(errno));
  475: 				error = "reading certificate request failed";
  476: 				goto end;
  477: 			}
  478: 			cert_req = lib->creds->create(lib->creds, CRED_CERTIFICATE,
  479: 										  CERT_PKCS10_REQUEST,
  480: 										  BUILD_BLOB, chunk, BUILD_END);
  481: 			free(chunk.ptr);
  482: 		}
  483: 		if (!cert_req)
  484: 		{
  485: 			error = "parsing certificate request failed";
  486: 			goto end;
  487: 		}
  488: 
  489: 		/* If not set yet use subject from PKCS#10 certificate request as DN */
  490: 		if (!id)
  491: 		{
  492: 			id = cert_req->get_subject(cert_req);
  493: 			id = id->clone(id);
  494: 		}
  495: 
  496: 		/* Add subjectAltNames from PKCS#10 certificate request */
  497: 		req = (pkcs10_t*)cert_req;
  498: 		enumerator = req->create_subjectAltName_enumerator(req);
  499: 		while (enumerator->enumerate(enumerator, &subjectAltName))
  500: 		{
  501: 			san->insert_last(san, subjectAltName->clone(subjectAltName));
  502: 		}
  503: 		enumerator->destroy(enumerator);
  504: 
  505: 		/* Use public key from PKCS#10 certificate request */
  506: 		public = cert_req->get_public_key(cert_req);
  507: 	}
  508: 	else
  509: 	{
  510: 		DBG2(DBG_LIB, "Reading key:");
  511: 		if (file)
  512: 		{
  513: 			public = lib->creds->create(lib->creds, type, subtype,
  514: 										BUILD_FROM_FILE, file, BUILD_END);
  515: 		}
  516: 		else
  517: 		{
  518: 			chunk_t chunk;
  519: 
  520: 			if (!chunk_from_fd(0, &chunk))
  521: 			{
  522: 				fprintf(stderr, "%s: ", strerror(errno));
  523: 				error = "reading key failed";
  524: 				goto end;
  525: 			}
  526: 			public = lib->creds->create(lib->creds, type, subtype,
  527: 										 BUILD_BLOB, chunk, BUILD_END);
  528: 			free(chunk.ptr);
  529: 		}
  530: 		if (public && type == CRED_PRIVATE_KEY)
  531: 		{
  532: 			private_key_t *priv = (private_key_t*)public;
  533: 			public = priv->get_public_key(priv);
  534: 			priv->destroy(priv);
  535: 		}
  536: 	}
  537: 	if (!public)
  538: 	{
  539: 		error = "parsing public key failed";
  540: 		goto end;
  541: 	}
  542: 
  543: 	if (!id)
  544: 	{
  545: 		id = identification_create_from_encoding(ID_DER_ASN1_DN,
  546: 										chunk_from_chars(ASN1_SEQUENCE, 0));
  547: 	}
  548: 	scheme = get_signature_scheme(private, digest, pss);
  549: 	if (!scheme)
  550: 	{
  551: 		error = "no signature scheme found";
  552: 		goto end;
  553: 	}
  554: 
  555: 	cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
  556: 					BUILD_SIGNING_KEY, private, BUILD_SIGNING_CERT, ca,
  557: 					BUILD_PUBLIC_KEY, public, BUILD_SUBJECT, id,
  558: 					BUILD_NOT_BEFORE_TIME, not_before,
  559: 					BUILD_NOT_AFTER_TIME, not_after, BUILD_SERIAL, serial,
  560: 					BUILD_SUBJECT_ALTNAMES, san, BUILD_X509_FLAG, flags,
  561: 					BUILD_PATHLEN, pathlen, BUILD_ADDRBLOCKS, addrblocks,
  562: 					BUILD_CRL_DISTRIBUTION_POINTS, cdps,
  563: 					BUILD_OCSP_ACCESS_LOCATIONS, ocsp,
  564: 					BUILD_PERMITTED_NAME_CONSTRAINTS, permitted,
  565: 					BUILD_EXCLUDED_NAME_CONSTRAINTS, excluded,
  566: 					BUILD_CERTIFICATE_POLICIES, policies,
  567: 					BUILD_POLICY_MAPPINGS, mappings,
  568: 					BUILD_POLICY_REQUIRE_EXPLICIT, require_explicit,
  569: 					BUILD_POLICY_INHIBIT_MAPPING, inhibit_mapping,
  570: 					BUILD_POLICY_INHIBIT_ANY, inhibit_any,
  571: 					BUILD_CRITICAL_EXTENSION, critical_extension_oid,
  572: 					BUILD_SIGNATURE_SCHEME, scheme,
  573: 					BUILD_END);
  574: 	if (!cert)
  575: 	{
  576: 		error = "generating certificate failed";
  577: 		goto end;
  578: 	}
  579: 	if (!cert->get_encoding(cert, form, &encoding))
  580: 	{
  581: 		error = "encoding certificate failed";
  582: 		goto end;
  583: 	}
  584: 	set_file_mode(stdout, form);
  585: 	if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
  586: 	{
  587: 		error = "writing certificate key failed";
  588: 		goto end;
  589: 	}
  590: 
  591: end:
  592: 	DESTROY_IF(id);
  593: 	DESTROY_IF(cert_req);
  594: 	DESTROY_IF(cert);
  595: 	DESTROY_IF(ca);
  596: 	DESTROY_IF(public);
  597: 	DESTROY_IF(private);
  598: 	san->destroy_offset(san, offsetof(identification_t, destroy));
  599: 	permitted->destroy_offset(permitted, offsetof(identification_t, destroy));
  600: 	excluded->destroy_offset(excluded, offsetof(identification_t, destroy));
  601: 	addrblocks->destroy_offset(addrblocks, offsetof(traffic_selector_t, destroy));
  602: 	policies->destroy_function(policies, (void*)destroy_cert_policy);
  603: 	mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
  604: 	cdps->destroy_function(cdps, (void*)destroy_cdp);
  605: 	ocsp->destroy(ocsp);
  606: 	signature_params_destroy(scheme);
  607: 	free(critical_extension_oid.ptr);
  608: 	free(encoding.ptr);
  609: 	free(serial.ptr);
  610: 
  611: 	if (error)
  612: 	{
  613: 		fprintf(stderr, "%s\n", error);
  614: 		return 1;
  615: 	}
  616: 	return 0;
  617: 
  618: usage:
  619: 	san->destroy_offset(san, offsetof(identification_t, destroy));
  620: 	permitted->destroy_offset(permitted, offsetof(identification_t, destroy));
  621: 	excluded->destroy_offset(excluded, offsetof(identification_t, destroy));
  622: 	addrblocks->destroy_offset(addrblocks, offsetof(traffic_selector_t, destroy));
  623: 	policies->destroy_function(policies, (void*)destroy_cert_policy);
  624: 	mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
  625: 	cdps->destroy_function(cdps, (void*)destroy_cdp);
  626: 	ocsp->destroy(ocsp);
  627: 	free(critical_extension_oid.ptr);
  628: 	return command_usage(error);
  629: }
  630: 
  631: /**
  632:  * Register the command.
  633:  */
  634: static void __attribute__ ((constructor))reg()
  635: {
  636: 	command_register((command_t) {
  637: 		issue, 'i', "issue",
  638: 		"issue a certificate using a CA certificate and key",
  639: 		{"[--in file] [--type pub|pkcs10|priv|rsa|ecdsa|ed25519|ed448|bliss]",
  640: 		 "--cakey file|--cakeyid hex --cacert file [--dn subject-dn]",
  641: 		 "[--san subjectAltName]+ [--lifetime days] [--serial hex]",
  642: 		 "[--ca] [--pathlen len]",
  643: 		 "[--flag serverAuth|clientAuth|crlSign|ocspSigning|msSmartcardLogon]+",
  644: 		 "[--crl uri [--crlissuer i]]+ [--ocsp uri]+ [--nc-permitted name]",
  645: 		 "[--nc-excluded name] [--policy-mapping issuer-oid:subject-oid]",
  646: 		 "[--policy-explicit len] [--policy-inhibit len] [--policy-any len]",
  647: 		 "[--cert-policy oid [--cps-uri uri] [--user-notice text]]+",
  648: 		 "[--digest md5|sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512]",
  649: 		 "[--rsa-padding pkcs1|pss] [--critical oid]",
  650: 		 "[--outform der|pem]"},
  651: 		{
  652: 			{"help",			'h', 0, "show usage information"},
  653: 			{"in",				'i', 1, "key/request file to issue, default: stdin"},
  654: 			{"type",			't', 1, "type of input, default: pub"},
  655: 			{"cacert",			'c', 1, "CA certificate file"},
  656: 			{"cakey",			'k', 1, "CA private key file"},
  657: 			{"cakeyid",			'x', 1, "smartcard or TPM CA private key object handle"},
  658: 			{"dn",				'd', 1, "distinguished name to include as subject"},
  659: 			{"san",				'a', 1, "subjectAltName to include in certificate"},
  660: 			{"lifetime",		'l', 1, "days the certificate is valid, default: 1095"},
  661: 			{"not-before",		'F', 1, "date/time the validity of the cert starts"},
  662: 			{"not-after",		'T', 1, "date/time the validity of the cert ends"},
  663: 			{"dateform",		'D', 1, "strptime(3) input format, default: %d.%m.%y %T"},
  664: 			{"serial",			's', 1, "serial number in hex, default: random"},
  665: 			{"ca",				'b', 0, "include CA basicConstraint, default: no"},
  666: 			{"pathlen",			'p', 1, "set path length constraint"},
  667: 			{"addrblock",		'B', 1, "RFC 3779 addrBlock to include"},
  668: 			{"nc-permitted",	'n', 1, "add permitted NameConstraint"},
  669: 			{"nc-excluded",		'N', 1, "add excluded NameConstraint"},
  670: 			{"cert-policy",		'P', 1, "certificatePolicy OID to include"},
  671: 			{"cps-uri",			'C', 1, "Certification Practice statement URI for certificatePolicy"},
  672: 			{"user-notice",		'U', 1, "user notice for certificatePolicy"},
  673: 			{"policy-mapping",	'M', 1, "policyMapping from issuer to subject OID"},
  674: 			{"policy-explicit",	'E', 1, "requireExplicitPolicy constraint"},
  675: 			{"policy-inhibit",	'H', 1, "inhibitPolicyMapping constraint"},
  676: 			{"policy-any",		'A', 1, "inhibitAnyPolicy constraint"},
  677: 			{"flag",			'e', 1, "include extendedKeyUsage flag"},
  678: 			{"crl",				'u', 1, "CRL distribution point URI to include"},
  679: 			{"crlissuer",		'I', 1, "CRL Issuer for CRL at distribution point"},
  680: 			{"ocsp",			'o', 1, "OCSP AuthorityInfoAccess URI to include"},
  681: 			{"digest",			'g', 1, "digest for signature creation, default: key-specific"},
  682: 			{"rsa-padding",		'R', 1, "padding for RSA signatures, default: pkcs1"},
  683: 			{"critical",		'X', 1, "critical extension OID to include"},
  684: 			{"outform",			'f', 1, "encoding of generated cert, default: der"},
  685: 		}
  686: 	});
  687: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>