xref: /illumos-gate/usr/src/cmd/cmd-crypto/kmfcfg/create.c (revision 269e59f9a28bf47e0f463e64fc5af4a408b73b21)
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 {
144 					KMF_X509_NAME taDN;
145 					/* for syntax checking */
146 					if (kmf_dn_parser(plc.ta_name,
147 					    &taDN) != KMF_OK) {
148 						(void) fprintf(stderr,
149 						    gettext("Error name "
150 						    "input.\n"));
151 						rv = KC_ERR_USAGE;
152 					} else {
153 						kmf_free_dn(&taDN);
154 					}
155 				}
156 				break;
157 			case 's':
158 				plc.ta_serial = get_string(optarg_av, &rv);
159 				if (plc.ta_serial == NULL) {
160 					(void) fprintf(stderr,
161 					    gettext("Error serial input.\n"));
162 				} else {
163 					uchar_t *bytes = NULL;
164 					size_t bytelen;
165 
166 					ret = kmf_hexstr_to_bytes(
167 					    (uchar_t *)plc.ta_serial,
168 					    &bytes, &bytelen);
169 					if (ret != KMF_OK || bytes == NULL) {
170 						(void) fprintf(stderr,
171 						    gettext("serial number "
172 						    "must be specified as a "
173 						    "hex number "
174 						    "(ex: 0x0102030405"
175 						    "ffeeddee)\n"));
176 						rv = KC_ERR_USAGE;
177 					}
178 					if (bytes != NULL)
179 						free(bytes);
180 				}
181 				break;
182 			case 'o':
183 				plc.VAL_OCSP_RESPONDER_URI =
184 				    get_string(optarg_av, &rv);
185 				if (plc.VAL_OCSP_RESPONDER_URI == NULL) {
186 					(void) fprintf(stderr, gettext(
187 					    "Error responder input.\n"));
188 				} else {
189 					ocsp_set_attr++;
190 				}
191 				break;
192 			case 'P':
193 				plc.VAL_OCSP_PROXY =
194 				    get_string(optarg_av, &rv);
195 				if (plc.VAL_OCSP_PROXY == NULL) {
196 					(void) fprintf(stderr,
197 					    gettext("Error proxy input.\n"));
198 				} else {
199 					ocsp_set_attr++;
200 				}
201 				break;
202 			case 'r':
203 				plc.VAL_OCSP_URI_FROM_CERT =
204 				    get_boolean(optarg_av);
205 				if (plc.VAL_OCSP_URI_FROM_CERT == -1) {
206 					(void) fprintf(stderr,
207 					    gettext("Error boolean input.\n"));
208 					rv = KC_ERR_USAGE;
209 				} else {
210 					ocsp_set_attr++;
211 				}
212 				break;
213 			case 'T':
214 				plc.VAL_OCSP_RESP_LIFETIME =
215 				    get_string(optarg_av, &rv);
216 				if (plc.VAL_OCSP_RESP_LIFETIME == NULL) {
217 					(void) fprintf(stderr,
218 					    gettext("Error time input.\n"));
219 				} else {
220 					uint32_t adj;
221 					/* for syntax checking */
222 					if (str2lifetime(
223 					    plc.VAL_OCSP_RESP_LIFETIME,
224 					    &adj) < 0) {
225 						(void) fprintf(stderr,
226 						    gettext("Error time "
227 						    "input.\n"));
228 						rv = KC_ERR_USAGE;
229 					} else {
230 						ocsp_set_attr++;
231 					}
232 				}
233 				break;
234 			case 'R':
235 				plc.VAL_OCSP_IGNORE_RESP_SIGN =
236 				    get_boolean(optarg_av);
237 				if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) {
238 					(void) fprintf(stderr,
239 					    gettext("Error boolean input.\n"));
240 					rv = KC_ERR_USAGE;
241 				} else {
242 					ocsp_set_attr++;
243 				}
244 				break;
245 			case 'n':
246 				plc.VAL_OCSP_RESP_CERT_NAME =
247 				    get_string(optarg_av, &rv);
248 				if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) {
249 					(void) fprintf(stderr,
250 					    gettext("Error name input.\n"));
251 				} else {
252 					KMF_X509_NAME respDN;
253 					/* for syntax checking */
254 					if (kmf_dn_parser(
255 					    plc.VAL_OCSP_RESP_CERT_NAME,
256 					    &respDN) != KMF_OK) {
257 						(void) fprintf(stderr,
258 						    gettext("Error name "
259 						    "input.\n"));
260 						rv = KC_ERR_USAGE;
261 					} else {
262 						kmf_free_dn(&respDN);
263 						ocsp_set_attr++;
264 					}
265 				}
266 				break;
267 			case 'A':
268 				plc.VAL_OCSP_RESP_CERT_SERIAL =
269 				    get_string(optarg_av, &rv);
270 				if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) {
271 					(void) fprintf(stderr,
272 					    gettext("Error serial input.\n"));
273 				} else {
274 					uchar_t *bytes = NULL;
275 					size_t bytelen;
276 
277 					ret = kmf_hexstr_to_bytes((uchar_t *)
278 					    plc.VAL_OCSP_RESP_CERT_SERIAL,
279 					    &bytes, &bytelen);
280 					if (ret != KMF_OK || bytes == NULL) {
281 						(void) fprintf(stderr,
282 						    gettext("serial number "
283 						    "must be specified as a "
284 						    "hex number "
285 						    "(ex: 0x0102030405"
286 						    "ffeeddee)\n"));
287 						rv = KC_ERR_USAGE;
288 						break;
289 					}
290 					if (bytes != NULL)
291 						free(bytes);
292 					ocsp_set_attr++;
293 				}
294 				break;
295 			case 'c':
296 				plc.VAL_CRL_BASEFILENAME =
297 				    get_string(optarg_av, &rv);
298 				if (plc.VAL_CRL_BASEFILENAME == NULL) {
299 					(void) fprintf(stderr,
300 					    gettext("Error boolean input.\n"));
301 				} else {
302 					crl_set_attr++;
303 				}
304 				break;
305 			case 'I':
306 				plc.VAL_CRL_DIRECTORY =
307 				    get_string(optarg_av, &rv);
308 				if (plc.VAL_CRL_DIRECTORY == NULL) {
309 					(void) fprintf(stderr,
310 					    gettext("Error boolean input.\n"));
311 				} else {
312 					crl_set_attr++;
313 				}
314 				break;
315 			case 'g':
316 				plc.VAL_CRL_GET_URI = get_boolean(optarg_av);
317 				if (plc.VAL_CRL_GET_URI == -1) {
318 					(void) fprintf(stderr,
319 					    gettext("Error boolean input.\n"));
320 					rv = KC_ERR_USAGE;
321 				} else {
322 					crl_set_attr++;
323 				}
324 				break;
325 			case 'X':
326 				plc.VAL_CRL_PROXY = get_string(optarg_av, &rv);
327 				if (plc.VAL_CRL_PROXY == NULL) {
328 					(void) fprintf(stderr,
329 					    gettext("Error proxy input.\n"));
330 				} else {
331 					crl_set_attr++;
332 				}
333 				break;
334 			case 'S':
335 				plc.VAL_CRL_IGNORE_SIGN =
336 				    get_boolean(optarg_av);
337 				if (plc.VAL_CRL_IGNORE_SIGN == -1) {
338 					(void) fprintf(stderr,
339 					    gettext("Error boolean input.\n"));
340 					rv = KC_ERR_USAGE;
341 				} else {
342 					crl_set_attr++;
343 				}
344 				break;
345 			case 'D':
346 				plc.VAL_CRL_IGNORE_DATE =
347 				    get_boolean(optarg_av);
348 				if (plc.VAL_CRL_IGNORE_DATE == -1) {
349 					(void) fprintf(stderr,
350 					    gettext("Error boolean input.\n"));
351 					rv = KC_ERR_USAGE;
352 				} else {
353 					crl_set_attr++;
354 				}
355 				break;
356 			case 'u':
357 				plc.ku_bits = parseKUlist(optarg_av);
358 				if (plc.ku_bits == 0) {
359 					(void) fprintf(stderr, gettext(
360 					    "Error keyusage input.\n"));
361 					rv = KC_ERR_USAGE;
362 				}
363 				break;
364 			case 'E':
365 				if (parseEKUNames(optarg_av, &plc) != 0) {
366 					(void) fprintf(stderr,
367 					    gettext("Error EKU input.\n"));
368 					rv = KC_ERR_USAGE;
369 				}
370 				break;
371 			case 'O':
372 				if (parseEKUOIDs(optarg_av, &plc) != 0) {
373 					(void) fprintf(stderr,
374 					    gettext("Error EKU OID input.\n"));
375 					rv = KC_ERR_USAGE;
376 				}
377 				break;
378 			case 'm':
379 				plc.mapper.mapname = get_string(optarg_av, &rv);
380 				if (plc.mapper.mapname == NULL) {
381 					(void) fprintf(stderr,
382 					    gettext("Error mapper-name "
383 					    "input.\n"));
384 				}
385 				break;
386 			case 'M':
387 				plc.mapper.dir = get_string(optarg_av, &rv);
388 				if (plc.mapper.dir == NULL) {
389 					(void) fprintf(stderr,
390 					    gettext("Error mapper-dir "
391 					    "input.\n"));
392 				}
393 				break;
394 			case 'Q':
395 				plc.mapper.pathname = get_string(optarg_av,
396 				    &rv);
397 				if (plc.mapper.pathname == NULL) {
398 					(void) fprintf(stderr,
399 					    gettext("Error mapper-pathname "
400 					    "input.\n"));
401 				}
402 				break;
403 			case 'q':
404 				plc.mapper.options = get_string(optarg_av, &rv);
405 				if (plc.mapper.options == NULL) {
406 					(void) fprintf(stderr,
407 					    gettext("Error mapper-options "
408 					    "input.\n"));
409 				}
410 				break;
411 			default:
412 				(void) fprintf(stderr,
413 				    gettext("Error input option.\n"));
414 				rv = KC_ERR_USAGE;
415 				break;
416 		}
417 
418 		if (rv != KC_OK)
419 			goto out;
420 	}
421 
422 	/* No additional args allowed. */
423 	argc -= optind_av;
424 	if (argc) {
425 		(void) fprintf(stderr,
426 		    gettext("Error input option\n"));
427 		rv = KC_ERR_USAGE;
428 		goto out;
429 	}
430 
431 	if (filename == NULL) {
432 		filename = strdup(KMF_DEFAULT_POLICY_FILE);
433 		if (filename == NULL) {
434 			rv = KC_ERR_MEMORY;
435 			goto out;
436 		}
437 	}
438 
439 	/*
440 	 * Must have a policy name. The policy name can not be default
441 	 * if using the default policy file.
442 	 */
443 	if (plc.name == NULL) {
444 		(void) fprintf(stderr,
445 		    gettext("You must specify a policy name\n"));
446 		rv = KC_ERR_USAGE;
447 		goto out;
448 	} else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 &&
449 	    strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) {
450 		(void) fprintf(stderr,
451 		    gettext("Can not create a default policy in the default "
452 		    "policy file\n"));
453 		rv = KC_ERR_USAGE;
454 		goto out;
455 	}
456 
457 	/*
458 	 * If the policy file exists and the policy is in the policy file
459 	 * already, we will not create it again.
460 	 */
461 	if (access(filename, R_OK) == 0) {
462 		POLICY_LIST *plclist = NULL, *pnode;
463 		int found = 0;
464 
465 		rv = load_policies(filename, &plclist);
466 		if (rv != KMF_OK)
467 			goto out;
468 
469 		pnode = plclist;
470 		while (pnode != NULL && !found) {
471 			if (strcmp(plc.name, pnode->plc.name) == 0)
472 				found++;
473 			pnode = pnode->next;
474 		}
475 		free_policy_list(plclist);
476 
477 		if (found) {
478 			(void) fprintf(stderr,
479 			    gettext("Could not create policy \"%s\" - exists "
480 			    "already\n"), plc.name);
481 			rv = KC_ERR_USAGE;
482 			goto out;
483 		}
484 	}
485 
486 	/*
487 	 * If any OCSP attribute is set, turn on the OCSP checking flag.
488 	 * Also set "has_resp_cert" to be true, if the responder cert
489 	 * is provided.
490 	 */
491 	if (ocsp_set_attr > 0)
492 		plc.revocation |= KMF_REVOCATION_METHOD_OCSP;
493 
494 	if (plc.VAL_OCSP_RESP_CERT.name != NULL &&
495 	    plc.VAL_OCSP_RESP_CERT.serial != NULL) {
496 		plc.VAL_OCSP.has_resp_cert = B_TRUE;
497 	}
498 
499 	/*
500 	 * Setting mapper-name (with optional mapper-dir) and mapper-pathname is
501 	 * mutually exclusive. Also, you cannot set options only, you need the
502 	 * name or pathname, and you can set the directory only with the name,
503 	 * not the pathname.
504 	 */
505 	if ((plc.mapper.mapname != NULL && plc.mapper.pathname != NULL) ||
506 	    (plc.mapper.dir != NULL && plc.mapper.pathname != NULL) ||
507 	    (plc.mapper.dir != NULL && plc.mapper.mapname == NULL) ||
508 	    (plc.mapper.options != NULL && plc.mapper.mapname == NULL &&
509 	    plc.mapper.pathname == NULL)) {
510 		(void) fprintf(stderr,
511 		    gettext("Error in mapper input options\n"));
512 		rv = KC_ERR_USAGE;
513 		goto out;
514 	}
515 
516 	/*
517 	 * If any CRL attribute is set, turn on the CRL checking flag.
518 	 */
519 	if (crl_set_attr > 0)
520 		plc.revocation |= KMF_REVOCATION_METHOD_CRL;
521 
522 	/*
523 	 * Does a sanity check on the new policy.
524 	 */
525 	ret = kmf_verify_policy(&plc);
526 	if (ret != KMF_OK) {
527 		print_sanity_error(ret);
528 		rv = KC_ERR_ADD_POLICY;
529 		goto out;
530 	}
531 
532 	/*
533 	 * Add to the DB.
534 	 */
535 	ret = kmf_add_policy_to_db(&plc, filename, B_FALSE);
536 	if (ret != KMF_OK) {
537 		(void) fprintf(stderr,
538 		    gettext("Error adding policy to database: 0x%04x\n"), ret);
539 		rv = KC_ERR_ADD_POLICY;
540 	}
541 
542 out:
543 	if (filename != NULL)
544 		free(filename);
545 
546 	kmf_free_policy_record(&plc);
547 
548 	return (rv);
549 }
550