xref: /illumos-gate/usr/src/cmd/cmd-crypto/kmfcfg/create.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
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 
34 int
35 kc_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 
543 out:
544 	if (filename != NULL)
545 		free(filename);
546 
547 	kmf_free_policy_record(&plc);
548 
549 	return (rv);
550 }
551