1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
22 */
23
24#include <stdio.h>
25#include <strings.h>
26#include <ctype.h>
27#include <libgen.h>
28#include <libintl.h>
29#include <errno.h>
30#include <kmfapiP.h>
31#include <cryptoutil.h>
32#include "util.h"
33
34int
35kc_create(int argc, char *argv[])
36{
37	KMF_RETURN	ret;
38	int 		rv = KC_OK;
39	int		opt;
40	extern int	optind_av;
41	extern char	*optarg_av;
42	char		*filename = NULL;
43	int		ocsp_set_attr = 0;
44	boolean_t	crl_set_attr = 0;
45	KMF_POLICY_RECORD plc;
46
47	(void) memset(&plc, 0, sizeof (KMF_POLICY_RECORD));
48
49	while ((opt = getopt_av(argc, argv,
50	    "i:(dbfile)"
51	    "p:(policy)"
52	    "d:(ignore-date)"
53	    "e:(ignore-unknown-eku)"
54	    "a:(ignore-trust-anchor)"
55	    "v:(validity-adjusttime)"
56	    "t:(ta-name)"
57	    "s:(ta-serial)"
58	    "o:(ocsp-responder)"
59	    "P:(ocsp-proxy)"
60	    "r:(ocsp-use-cert-responder)"
61	    "T:(ocsp-response-lifetime)"
62	    "R:(ocsp-ignore-response-sign)"
63	    "n:(ocsp-responder-cert-name)"
64	    "A:(ocsp-responder-cert-serial)"
65	    "c:(crl-basefilename)"
66	    "I:(crl-directory)"
67	    "g:(crl-get-crl-uri)"
68	    "X:(crl-proxy)"
69	    "S:(crl-ignore-crl-sign)"
70	    "D:(crl-ignore-crl-date)"
71	    "m:(mapper-name)"
72	    "M:(mapper-directory)"
73	    "Q:(mapper-pathname)"
74	    "q:(mapper-options)"
75	    "u:(keyusage)"
76	    "E:(ekunames)"
77	    "O:(ekuoids)")) != EOF) {
78		switch (opt) {
79			case 'i':
80				filename = get_string(optarg_av, &rv);
81				if (filename == NULL) {
82					(void) fprintf(stderr,
83					    gettext("Error dbfile input.\n"));
84				}
85				break;
86			case 'p':
87				plc.name = get_string(optarg_av, &rv);
88				if (plc.name == NULL) {
89					(void) fprintf(stderr,
90					    gettext("Error policy name.\n"));
91				}
92				break;
93			case 'd':
94				plc.ignore_date = get_boolean(optarg_av);
95				if (plc.ignore_date == -1) {
96					(void) fprintf(stderr,
97					    gettext("Error boolean input.\n"));
98					rv = KC_ERR_USAGE;
99				}
100				break;
101			case 'e':
102				plc.ignore_unknown_ekus =
103				    get_boolean(optarg_av);
104				if (plc.ignore_unknown_ekus == -1) {
105					(void) fprintf(stderr,
106					    gettext("Error boolean input.\n"));
107					rv = KC_ERR_USAGE;
108				}
109				break;
110			case 'a':
111				plc.ignore_trust_anchor =
112				    get_boolean(optarg_av);
113				if (plc.ignore_trust_anchor == -1) {
114					(void) fprintf(stderr,
115					    gettext("Error boolean input.\n"));
116					rv = KC_ERR_USAGE;
117				}
118				break;
119			case 'v':
120				plc.validity_adjusttime =
121				    get_string(optarg_av, &rv);
122				if (plc.validity_adjusttime == NULL) {
123					(void) fprintf(stderr,
124					    gettext("Error time input.\n"));
125				} else {
126					uint32_t adj;
127					/* for syntax checking */
128					if (str2lifetime(
129					    plc.validity_adjusttime,
130					    &adj) < 0) {
131						(void) fprintf(stderr,
132						    gettext("Error time "
133						    "input.\n"));
134						rv = KC_ERR_USAGE;
135					}
136				}
137				break;
138			case 't':
139				plc.ta_name = get_string(optarg_av, &rv);
140				if (plc.ta_name == NULL) {
141					(void) fprintf(stderr,
142					    gettext("Error name input.\n"));
143				} else if (strcasecmp(plc.ta_name,
144				    "search") != 0) {
145					KMF_X509_NAME taDN;
146					/* for syntax checking */
147					if (kmf_dn_parser(plc.ta_name,
148					    &taDN) != KMF_OK) {
149						(void) fprintf(stderr,
150						    gettext("Error name "
151						    "input.\n"));
152						rv = KC_ERR_USAGE;
153					} else {
154						kmf_free_dn(&taDN);
155					}
156				}
157				break;
158			case 's':
159				plc.ta_serial = get_string(optarg_av, &rv);
160				if (plc.ta_serial == NULL) {
161					(void) fprintf(stderr,
162					    gettext("Error serial input.\n"));
163				} else {
164					uchar_t *bytes = NULL;
165					size_t bytelen;
166
167					ret = kmf_hexstr_to_bytes(
168					    (uchar_t *)plc.ta_serial,
169					    &bytes, &bytelen);
170					if (ret != KMF_OK || bytes == NULL) {
171						(void) fprintf(stderr,
172						    gettext("serial number "
173						    "must be specified as a "
174						    "hex number "
175						    "(ex: 0x0102030405"
176						    "ffeeddee)\n"));
177						rv = KC_ERR_USAGE;
178					}
179					if (bytes != NULL)
180						free(bytes);
181				}
182				break;
183			case 'o':
184				plc.VAL_OCSP_RESPONDER_URI =
185				    get_string(optarg_av, &rv);
186				if (plc.VAL_OCSP_RESPONDER_URI == NULL) {
187					(void) fprintf(stderr, gettext(
188					    "Error responder input.\n"));
189				} else {
190					ocsp_set_attr++;
191				}
192				break;
193			case 'P':
194				plc.VAL_OCSP_PROXY =
195				    get_string(optarg_av, &rv);
196				if (plc.VAL_OCSP_PROXY == NULL) {
197					(void) fprintf(stderr,
198					    gettext("Error proxy input.\n"));
199				} else {
200					ocsp_set_attr++;
201				}
202				break;
203			case 'r':
204				plc.VAL_OCSP_URI_FROM_CERT =
205				    get_boolean(optarg_av);
206				if (plc.VAL_OCSP_URI_FROM_CERT == -1) {
207					(void) fprintf(stderr,
208					    gettext("Error boolean input.\n"));
209					rv = KC_ERR_USAGE;
210				} else {
211					ocsp_set_attr++;
212				}
213				break;
214			case 'T':
215				plc.VAL_OCSP_RESP_LIFETIME =
216				    get_string(optarg_av, &rv);
217				if (plc.VAL_OCSP_RESP_LIFETIME == NULL) {
218					(void) fprintf(stderr,
219					    gettext("Error time input.\n"));
220				} else {
221					uint32_t adj;
222					/* for syntax checking */
223					if (str2lifetime(
224					    plc.VAL_OCSP_RESP_LIFETIME,
225					    &adj) < 0) {
226						(void) fprintf(stderr,
227						    gettext("Error time "
228						    "input.\n"));
229						rv = KC_ERR_USAGE;
230					} else {
231						ocsp_set_attr++;
232					}
233				}
234				break;
235			case 'R':
236				plc.VAL_OCSP_IGNORE_RESP_SIGN =
237				    get_boolean(optarg_av);
238				if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) {
239					(void) fprintf(stderr,
240					    gettext("Error boolean input.\n"));
241					rv = KC_ERR_USAGE;
242				} else {
243					ocsp_set_attr++;
244				}
245				break;
246			case 'n':
247				plc.VAL_OCSP_RESP_CERT_NAME =
248				    get_string(optarg_av, &rv);
249				if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) {
250					(void) fprintf(stderr,
251					    gettext("Error name input.\n"));
252				} else {
253					KMF_X509_NAME respDN;
254					/* for syntax checking */
255					if (kmf_dn_parser(
256					    plc.VAL_OCSP_RESP_CERT_NAME,
257					    &respDN) != KMF_OK) {
258						(void) fprintf(stderr,
259						    gettext("Error name "
260						    "input.\n"));
261						rv = KC_ERR_USAGE;
262					} else {
263						kmf_free_dn(&respDN);
264						ocsp_set_attr++;
265					}
266				}
267				break;
268			case 'A':
269				plc.VAL_OCSP_RESP_CERT_SERIAL =
270				    get_string(optarg_av, &rv);
271				if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) {
272					(void) fprintf(stderr,
273					    gettext("Error serial input.\n"));
274				} else {
275					uchar_t *bytes = NULL;
276					size_t bytelen;
277
278					ret = kmf_hexstr_to_bytes((uchar_t *)
279					    plc.VAL_OCSP_RESP_CERT_SERIAL,
280					    &bytes, &bytelen);
281					if (ret != KMF_OK || bytes == NULL) {
282						(void) fprintf(stderr,
283						    gettext("serial number "
284						    "must be specified as a "
285						    "hex number "
286						    "(ex: 0x0102030405"
287						    "ffeeddee)\n"));
288						rv = KC_ERR_USAGE;
289						break;
290					}
291					if (bytes != NULL)
292						free(bytes);
293					ocsp_set_attr++;
294				}
295				break;
296			case 'c':
297				plc.VAL_CRL_BASEFILENAME =
298				    get_string(optarg_av, &rv);
299				if (plc.VAL_CRL_BASEFILENAME == NULL) {
300					(void) fprintf(stderr,
301					    gettext("Error boolean input.\n"));
302				} else {
303					crl_set_attr++;
304				}
305				break;
306			case 'I':
307				plc.VAL_CRL_DIRECTORY =
308				    get_string(optarg_av, &rv);
309				if (plc.VAL_CRL_DIRECTORY == NULL) {
310					(void) fprintf(stderr,
311					    gettext("Error boolean input.\n"));
312				} else {
313					crl_set_attr++;
314				}
315				break;
316			case 'g':
317				plc.VAL_CRL_GET_URI = get_boolean(optarg_av);
318				if (plc.VAL_CRL_GET_URI == -1) {
319					(void) fprintf(stderr,
320					    gettext("Error boolean input.\n"));
321					rv = KC_ERR_USAGE;
322				} else {
323					crl_set_attr++;
324				}
325				break;
326			case 'X':
327				plc.VAL_CRL_PROXY = get_string(optarg_av, &rv);
328				if (plc.VAL_CRL_PROXY == NULL) {
329					(void) fprintf(stderr,
330					    gettext("Error proxy input.\n"));
331				} else {
332					crl_set_attr++;
333				}
334				break;
335			case 'S':
336				plc.VAL_CRL_IGNORE_SIGN =
337				    get_boolean(optarg_av);
338				if (plc.VAL_CRL_IGNORE_SIGN == -1) {
339					(void) fprintf(stderr,
340					    gettext("Error boolean input.\n"));
341					rv = KC_ERR_USAGE;
342				} else {
343					crl_set_attr++;
344				}
345				break;
346			case 'D':
347				plc.VAL_CRL_IGNORE_DATE =
348				    get_boolean(optarg_av);
349				if (plc.VAL_CRL_IGNORE_DATE == -1) {
350					(void) fprintf(stderr,
351					    gettext("Error boolean input.\n"));
352					rv = KC_ERR_USAGE;
353				} else {
354					crl_set_attr++;
355				}
356				break;
357			case 'u':
358				plc.ku_bits = parseKUlist(optarg_av);
359				if (plc.ku_bits == 0) {
360					(void) fprintf(stderr, gettext(
361					    "Error keyusage input.\n"));
362					rv = KC_ERR_USAGE;
363				}
364				break;
365			case 'E':
366				if (parseEKUNames(optarg_av, &plc) != 0) {
367					(void) fprintf(stderr,
368					    gettext("Error EKU input.\n"));
369					rv = KC_ERR_USAGE;
370				}
371				break;
372			case 'O':
373				if (parseEKUOIDs(optarg_av, &plc) != 0) {
374					(void) fprintf(stderr,
375					    gettext("Error EKU OID input.\n"));
376					rv = KC_ERR_USAGE;
377				}
378				break;
379			case 'm':
380				plc.mapper.mapname = get_string(optarg_av, &rv);
381				if (plc.mapper.mapname == NULL) {
382					(void) fprintf(stderr,
383					    gettext("Error mapper-name "
384					    "input.\n"));
385				}
386				break;
387			case 'M':
388				plc.mapper.dir = get_string(optarg_av, &rv);
389				if (plc.mapper.dir == NULL) {
390					(void) fprintf(stderr,
391					    gettext("Error mapper-dir "
392					    "input.\n"));
393				}
394				break;
395			case 'Q':
396				plc.mapper.pathname = get_string(optarg_av,
397				    &rv);
398				if (plc.mapper.pathname == NULL) {
399					(void) fprintf(stderr,
400					    gettext("Error mapper-pathname "
401					    "input.\n"));
402				}
403				break;
404			case 'q':
405				plc.mapper.options = get_string(optarg_av, &rv);
406				if (plc.mapper.options == NULL) {
407					(void) fprintf(stderr,
408					    gettext("Error mapper-options "
409					    "input.\n"));
410				}
411				break;
412			default:
413				(void) fprintf(stderr,
414				    gettext("Error input option.\n"));
415				rv = KC_ERR_USAGE;
416				break;
417		}
418
419		if (rv != KC_OK)
420			goto out;
421	}
422
423	/* No additional args allowed. */
424	argc -= optind_av;
425	if (argc) {
426		(void) fprintf(stderr,
427		    gettext("Error input option\n"));
428		rv = KC_ERR_USAGE;
429		goto out;
430	}
431
432	if (filename == NULL) {
433		filename = strdup(KMF_DEFAULT_POLICY_FILE);
434		if (filename == NULL) {
435			rv = KC_ERR_MEMORY;
436			goto out;
437		}
438	}
439
440	/*
441	 * Must have a policy name. The policy name can not be default
442	 * if using the default policy file.
443	 */
444	if (plc.name == NULL) {
445		(void) fprintf(stderr,
446		    gettext("You must specify a policy name\n"));
447		rv = KC_ERR_USAGE;
448		goto out;
449	} else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 &&
450	    strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) {
451		(void) fprintf(stderr,
452		    gettext("Can not create a default policy in the default "
453		    "policy file\n"));
454		rv = KC_ERR_USAGE;
455		goto out;
456	}
457
458	/*
459	 * If the policy file exists and the policy is in the policy file
460	 * already, we will not create it again.
461	 */
462	if (access(filename, R_OK) == 0) {
463		POLICY_LIST *plclist = NULL, *pnode;
464		int found = 0;
465
466		rv = load_policies(filename, &plclist);
467		if (rv != KMF_OK)
468			goto out;
469
470		pnode = plclist;
471		while (pnode != NULL && !found) {
472			if (strcmp(plc.name, pnode->plc.name) == 0)
473				found++;
474			pnode = pnode->next;
475		}
476		free_policy_list(plclist);
477
478		if (found) {
479			(void) fprintf(stderr,
480			    gettext("Could not create policy \"%s\" - exists "
481			    "already\n"), plc.name);
482			rv = KC_ERR_USAGE;
483			goto out;
484		}
485	}
486
487	/*
488	 * If any OCSP attribute is set, turn on the OCSP checking flag.
489	 * Also set "has_resp_cert" to be true, if the responder cert
490	 * is provided.
491	 */
492	if (ocsp_set_attr > 0)
493		plc.revocation |= KMF_REVOCATION_METHOD_OCSP;
494
495	if (plc.VAL_OCSP_RESP_CERT.name != NULL &&
496	    plc.VAL_OCSP_RESP_CERT.serial != NULL) {
497		plc.VAL_OCSP.has_resp_cert = B_TRUE;
498	}
499
500	/*
501	 * Setting mapper-name (with optional mapper-dir) and mapper-pathname is
502	 * mutually exclusive. Also, you cannot set options only, you need the
503	 * name or pathname, and you can set the directory only with the name,
504	 * not the pathname.
505	 */
506	if ((plc.mapper.mapname != NULL && plc.mapper.pathname != NULL) ||
507	    (plc.mapper.dir != NULL && plc.mapper.pathname != NULL) ||
508	    (plc.mapper.dir != NULL && plc.mapper.mapname == NULL) ||
509	    (plc.mapper.options != NULL && plc.mapper.mapname == NULL &&
510	    plc.mapper.pathname == NULL)) {
511		(void) fprintf(stderr,
512		    gettext("Error in mapper input options\n"));
513		rv = KC_ERR_USAGE;
514		goto out;
515	}
516
517	/*
518	 * If any CRL attribute is set, turn on the CRL checking flag.
519	 */
520	if (crl_set_attr > 0)
521		plc.revocation |= KMF_REVOCATION_METHOD_CRL;
522
523	/*
524	 * Does a sanity check on the new policy.
525	 */
526	ret = kmf_verify_policy(&plc);
527	if (ret != KMF_OK) {
528		print_sanity_error(ret);
529		rv = KC_ERR_ADD_POLICY;
530		goto out;
531	}
532
533	/*
534	 * Add to the DB.
535	 */
536	ret = kmf_add_policy_to_db(&plc, filename, B_FALSE);
537	if (ret != KMF_OK) {
538		(void) fprintf(stderr,
539		    gettext("Error adding policy to database: 0x%04x\n"), ret);
540		rv = KC_ERR_ADD_POLICY;
541	}
542
543out:
544	if (filename != NULL)
545		free(filename);
546
547	kmf_free_policy_record(&plc);
548
549	return (rv);
550}
551