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