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 
37 #define	KC_IGNORE_DATE			0x0000001
38 #define	KC_IGNORE_UNKNOWN_EKUS		0x0000002
39 #define	KC_IGNORE_TRUST_ANCHOR		0x0000004
40 #define	KC_VALIDITY_ADJUSTTIME		0x0000008
41 #define	KC_TA_NAME			0x0000010
42 #define	KC_TA_SERIAL			0x0000020
43 #define	KC_OCSP_RESPONDER_URI		0x0000040
44 #define	KC_OCSP_PROXY			0x0000080
45 #define	KC_OCSP_URI_FROM_CERT		0x0000100
46 #define	KC_OCSP_RESP_LIFETIME		0x0000200
47 #define	KC_OCSP_IGNORE_RESP_SIGN 	0x0000400
48 #define	KC_OCSP_RESP_CERT_NAME		0x0000800
49 #define	KC_OCSP_RESP_CERT_SERIAL	0x0001000
50 #define	KC_OCSP_NONE			0x0002000
51 #define	KC_CRL_BASEFILENAME		0x0004000
52 #define	KC_CRL_DIRECTORY		0x0008000
53 #define	KC_CRL_GET_URI			0x0010000
54 #define	KC_CRL_PROXY			0x0020000
55 #define	KC_CRL_IGNORE_SIGN		0x0040000
56 #define	KC_CRL_IGNORE_DATE		0x0080000
57 #define	KC_CRL_NONE			0x0100000
58 #define	KC_KEYUSAGE			0x0200000
59 #define	KC_KEYUSAGE_NONE		0x0400000
60 #define	KC_EKUS				0x0800000
61 #define	KC_EKUS_NONE			0x1000000
62 
63 int
64 kc_modify(int argc, char *argv[])
65 {
66 	KMF_RETURN	ret;
67 	int 		rv = KC_OK;
68 	int		opt;
69 	extern int	optind_av;
70 	extern char	*optarg_av;
71 	char		*filename = NULL;
72 	uint32_t	flags = 0;
73 	boolean_t	ocsp_none_opt = B_FALSE;
74 	boolean_t	crl_none_opt = B_FALSE;
75 	boolean_t	ku_none_opt = B_FALSE;
76 	boolean_t	eku_none_opt = B_FALSE;
77 	int		ocsp_set_attr = 0;
78 	int		crl_set_attr = 0;
79 	KMF_POLICY_RECORD oplc, plc;
80 
81 	(void) memset(&plc, 0, sizeof (KMF_POLICY_RECORD));
82 	(void) memset(&oplc, 0, sizeof (KMF_POLICY_RECORD));
83 
84 	while ((opt = getopt_av(argc, argv,
85 	    "i:(dbfile)"
86 	    "p:(policy)"
87 	    "d:(ignore-date)"
88 	    "e:(ignore-unknown-eku)"
89 	    "a:(ignore-trust-anchor)"
90 	    "v:(validity-adjusttime)"
91 	    "t:(ta-name)"
92 	    "s:(ta-serial)"
93 	    "o:(ocsp-responder)"
94 	    "P:(ocsp-proxy)"
95 	    "r:(ocsp-use-cert-responder)"
96 	    "T:(ocsp-response-lifetime)"
97 	    "R:(ocsp-ignore-response-sign)"
98 	    "n:(ocsp-responder-cert-name)"
99 	    "A:(ocsp-responder-cert-serial)"
100 	    "y:(ocsp-none)"
101 	    "c:(crl-basefilename)"
102 	    "I:(crl-directory)"
103 	    "g:(crl-get-crl-uri)"
104 	    "X:(crl-proxy)"
105 	    "S:(crl-ignore-crl-sign)"
106 	    "D:(crl-ignore-crl-date)"
107 	    "z:(crl-none)"
108 	    "u:(keyusage)"
109 	    "Y:(keyusage-none)"
110 	    "E:(ekunames)"
111 	    "O:(ekuoids)"
112 	    "Z:(eku-none)")) != EOF) {
113 		switch (opt) {
114 			case 'i':
115 				filename = get_string(optarg_av, &rv);
116 				if (filename == NULL) {
117 					(void) fprintf(stderr,
118 					    gettext("Error dbfile input.\n"));
119 				}
120 				break;
121 			case 'p':
122 				plc.name = get_string(optarg_av, &rv);
123 				if (plc.name == NULL) {
124 					(void) fprintf(stderr,
125 					    gettext("Error policy name.\n"));
126 				}
127 				break;
128 			case 'd':
129 				plc.ignore_date = get_boolean(optarg_av);
130 				if (plc.ignore_date == -1) {
131 					(void) fprintf(stderr,
132 					    gettext("Error boolean input.\n"));
133 					rv = KC_ERR_USAGE;
134 				} else {
135 					flags |= KC_IGNORE_DATE;
136 				}
137 				break;
138 			case 'e':
139 				plc.ignore_unknown_ekus =
140 				    get_boolean(optarg_av);
141 				if (plc.ignore_unknown_ekus == -1) {
142 					(void) fprintf(stderr,
143 					    gettext("Error boolean input.\n"));
144 					rv = KC_ERR_USAGE;
145 				} else {
146 					flags |= KC_IGNORE_UNKNOWN_EKUS;
147 				}
148 				break;
149 			case 'a':
150 				plc.ignore_trust_anchor =
151 				    get_boolean(optarg_av);
152 				if (plc.ignore_trust_anchor == -1) {
153 					(void) fprintf(stderr,
154 					    gettext("Error boolean input.\n"));
155 					rv = KC_ERR_USAGE;
156 				} else {
157 					flags |= KC_IGNORE_TRUST_ANCHOR;
158 				}
159 				break;
160 			case 'v':
161 				plc.validity_adjusttime =
162 				    get_string(optarg_av, &rv);
163 				if (plc.validity_adjusttime == NULL) {
164 					(void) fprintf(stderr,
165 					    gettext("Error time input.\n"));
166 				} else {
167 					uint32_t adj;
168 					/* for syntax checking */
169 					if (str2lifetime(
170 					    plc.validity_adjusttime,
171 					    &adj) < 0) {
172 						(void) fprintf(stderr,
173 						    gettext("Error time "
174 						    "input.\n"));
175 						rv = KC_ERR_USAGE;
176 					} else {
177 						flags |= KC_VALIDITY_ADJUSTTIME;
178 					}
179 				}
180 				break;
181 			case 't':
182 				plc.ta_name = get_string(optarg_av, &rv);
183 				if (plc.ta_name == NULL) {
184 					(void) fprintf(stderr,
185 					    gettext("Error name input.\n"));
186 				} else {
187 					KMF_X509_NAME taDN;
188 					/* for syntax checking */
189 					if (kmf_dn_parser(plc.ta_name,
190 					    &taDN) != KMF_OK) {
191 						(void) fprintf(stderr,
192 						    gettext("Error name "
193 						    "input.\n"));
194 						rv = KC_ERR_USAGE;
195 					} else {
196 						kmf_free_dn(&taDN);
197 						flags |= KC_TA_NAME;
198 					}
199 				}
200 				break;
201 			case 's':
202 				plc.ta_serial = get_string(optarg_av, &rv);
203 				if (plc.ta_serial == NULL) {
204 					(void) fprintf(stderr,
205 					    gettext("Error serial input.\n"));
206 				} else {
207 					uchar_t *bytes = NULL;
208 					size_t bytelen;
209 
210 					ret = kmf_hexstr_to_bytes(
211 					    (uchar_t *)plc.ta_serial,
212 					    &bytes, &bytelen);
213 					if (ret != KMF_OK || bytes == NULL) {
214 						(void) fprintf(stderr,
215 						    gettext("serial number "
216 						    "must be specified as a "
217 						    "hex number "
218 						    "(ex: 0x0102030405"
219 						    "ffeeddee)\n"));
220 						rv = KC_ERR_USAGE;
221 						break;
222 					}
223 					if (bytes != NULL)
224 						free(bytes);
225 					flags |= KC_TA_SERIAL;
226 				}
227 				break;
228 			case 'o':
229 				plc.VAL_OCSP_RESPONDER_URI =
230 				    get_string(optarg_av, &rv);
231 				if (plc.VAL_OCSP_RESPONDER_URI == NULL) {
232 					(void) fprintf(stderr,
233 					    gettext("Error responder "
234 					    "input.\n"));
235 				} else {
236 					flags |= KC_OCSP_RESPONDER_URI;
237 					ocsp_set_attr++;
238 				}
239 				break;
240 			case 'P':
241 				plc.VAL_OCSP_PROXY = get_string(optarg_av, &rv);
242 				if (plc.VAL_OCSP_PROXY == NULL) {
243 					(void) fprintf(stderr,
244 					    gettext("Error proxy input.\n"));
245 				} else {
246 					flags |= KC_OCSP_PROXY;
247 					ocsp_set_attr++;
248 				}
249 				break;
250 			case 'r':
251 				plc.VAL_OCSP_URI_FROM_CERT =
252 				    get_boolean(optarg_av);
253 				if (plc.VAL_OCSP_URI_FROM_CERT == -1) {
254 					(void) fprintf(stderr,
255 					    gettext("Error boolean input.\n"));
256 					rv = KC_ERR_USAGE;
257 				} else {
258 					flags |= KC_OCSP_URI_FROM_CERT;
259 					ocsp_set_attr++;
260 				}
261 				break;
262 			case 'T':
263 				plc.VAL_OCSP_RESP_LIFETIME =
264 				    get_string(optarg_av, &rv);
265 				if (plc.VAL_OCSP_RESP_LIFETIME == NULL) {
266 					(void) fprintf(stderr,
267 					    gettext("Error time input.\n"));
268 				} else {
269 					uint32_t adj;
270 					/* for syntax checking */
271 					if (str2lifetime(
272 					    plc.VAL_OCSP_RESP_LIFETIME,
273 					    &adj) < 0) {
274 						(void) fprintf(stderr,
275 						    gettext("Error time "
276 						    "input.\n"));
277 						rv = KC_ERR_USAGE;
278 					} else {
279 						flags |= KC_OCSP_RESP_LIFETIME;
280 						ocsp_set_attr++;
281 					}
282 				}
283 				break;
284 			case 'R':
285 				plc.VAL_OCSP_IGNORE_RESP_SIGN =
286 				    get_boolean(optarg_av);
287 				if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) {
288 					(void) fprintf(stderr,
289 					    gettext("Error boolean input.\n"));
290 					rv = KC_ERR_USAGE;
291 				} else {
292 					flags |= KC_OCSP_IGNORE_RESP_SIGN;
293 					ocsp_set_attr++;
294 				}
295 				break;
296 			case 'n':
297 				plc.VAL_OCSP_RESP_CERT_NAME =
298 				    get_string(optarg_av, &rv);
299 				if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) {
300 					(void) fprintf(stderr,
301 					    gettext("Error name input.\n"));
302 				} else {
303 					KMF_X509_NAME respDN;
304 					/* for syntax checking */
305 					if (kmf_dn_parser(
306 					    plc.VAL_OCSP_RESP_CERT_NAME,
307 					    &respDN) != KMF_OK) {
308 						(void) fprintf(stderr,
309 						    gettext("Error name "
310 						    "input.\n"));
311 						rv = KC_ERR_USAGE;
312 					} else {
313 						kmf_free_dn(&respDN);
314 						flags |= KC_OCSP_RESP_CERT_NAME;
315 						ocsp_set_attr++;
316 					}
317 				}
318 				break;
319 			case 'A':
320 				plc.VAL_OCSP_RESP_CERT_SERIAL =
321 				    get_string(optarg_av, &rv);
322 				if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) {
323 					(void) fprintf(stderr,
324 					    gettext("Error serial input.\n"));
325 				} else {
326 					uchar_t *bytes = NULL;
327 					size_t bytelen;
328 
329 					ret = kmf_hexstr_to_bytes((uchar_t *)
330 					    plc.VAL_OCSP_RESP_CERT_SERIAL,
331 					    &bytes, &bytelen);
332 					if (ret != KMF_OK || bytes == NULL) {
333 						(void) fprintf(stderr,
334 						    gettext("serial number "
335 						    "must be specified as a "
336 						    "hex number "
337 						    "(ex: 0x0102030405"
338 						    "ffeeddee)\n"));
339 						rv = KC_ERR_USAGE;
340 						break;
341 					}
342 					if (bytes != NULL)
343 						free(bytes);
344 					flags |= KC_OCSP_RESP_CERT_SERIAL;
345 					ocsp_set_attr++;
346 				}
347 				break;
348 			case 'y':
349 				ocsp_none_opt = get_boolean(optarg_av);
350 				if (ocsp_none_opt == -1) {
351 					(void) fprintf(stderr,
352 					    gettext("Error boolean input.\n"));
353 					rv = KC_ERR_USAGE;
354 				} else {
355 					flags |= KC_OCSP_NONE;
356 				}
357 				break;
358 			case 'c':
359 				plc.VAL_CRL_BASEFILENAME =
360 				    get_string(optarg_av, &rv);
361 				if (plc.VAL_CRL_BASEFILENAME == NULL) {
362 					(void) fprintf(stderr, gettext(
363 					    "Error basefilename input.\n"));
364 				} else {
365 					flags |= KC_CRL_BASEFILENAME;
366 					crl_set_attr++;
367 				}
368 				break;
369 			case 'I':
370 				plc.VAL_CRL_DIRECTORY =
371 				    get_string(optarg_av, &rv);
372 				if (plc.VAL_CRL_DIRECTORY == NULL) {
373 					(void) fprintf(stderr,
374 					    gettext("Error boolean input.\n"));
375 				} else {
376 					flags |= KC_CRL_DIRECTORY;
377 					crl_set_attr++;
378 				}
379 				break;
380 			case 'g':
381 				plc.VAL_CRL_GET_URI = get_boolean(optarg_av);
382 				if (plc.VAL_CRL_GET_URI == -1) {
383 					(void) fprintf(stderr,
384 					    gettext("Error boolean input.\n"));
385 					rv = KC_ERR_USAGE;
386 				} else {
387 					flags |= KC_CRL_GET_URI;
388 					crl_set_attr++;
389 				}
390 				break;
391 			case 'X':
392 				plc.VAL_CRL_PROXY = get_string(optarg_av, &rv);
393 				if (plc.VAL_CRL_PROXY == NULL) {
394 					(void) fprintf(stderr,
395 					    gettext("Error proxy input.\n"));
396 				} else {
397 					flags |= KC_CRL_PROXY;
398 					crl_set_attr++;
399 				}
400 				break;
401 			case 'S':
402 				plc.VAL_CRL_IGNORE_SIGN =
403 				    get_boolean(optarg_av);
404 				if (plc.VAL_CRL_IGNORE_SIGN == -1) {
405 					(void) fprintf(stderr,
406 					    gettext("Error boolean input.\n"));
407 					rv = KC_ERR_USAGE;
408 				} else {
409 					flags |= KC_CRL_IGNORE_SIGN;
410 					crl_set_attr++;
411 				}
412 				break;
413 			case 'D':
414 				plc.VAL_CRL_IGNORE_DATE =
415 				    get_boolean(optarg_av);
416 				if (plc.VAL_CRL_IGNORE_DATE == -1) {
417 					(void) fprintf(stderr,
418 					    gettext("Error boolean input.\n"));
419 					rv = KC_ERR_USAGE;
420 				} else {
421 					flags |= KC_CRL_IGNORE_DATE;
422 					crl_set_attr++;
423 				}
424 				break;
425 			case 'z':
426 				crl_none_opt = get_boolean(optarg_av);
427 				if (crl_none_opt == -1) {
428 					(void) fprintf(stderr,
429 					    gettext("Error boolean input.\n"));
430 					rv = KC_ERR_USAGE;
431 				} else {
432 					flags |= KC_CRL_NONE;
433 				}
434 				break;
435 			case 'u':
436 				plc.ku_bits = parseKUlist(optarg_av);
437 				if (plc.ku_bits == 0) {
438 					(void) fprintf(stderr, gettext(
439 					    "Error keyusage input.\n"));
440 					rv = KC_ERR_USAGE;
441 				} else {
442 					flags |= KC_KEYUSAGE;
443 				}
444 				break;
445 			case 'Y':
446 				ku_none_opt = get_boolean(optarg_av);
447 				if (ku_none_opt == -1) {
448 					(void) fprintf(stderr,
449 					    gettext("Error boolean input.\n"));
450 					rv = KC_ERR_USAGE;
451 				} else {
452 					flags |= KC_KEYUSAGE_NONE;
453 				}
454 				break;
455 			case 'E':
456 				if (parseEKUNames(optarg_av, &plc) != 0) {
457 					(void) fprintf(stderr,
458 					    gettext("Error EKU input.\n"));
459 					rv = KC_ERR_USAGE;
460 				} else {
461 					flags |= KC_EKUS;
462 				}
463 				break;
464 			case 'O':
465 				if (parseEKUOIDs(optarg_av, &plc) != 0) {
466 					(void) fprintf(stderr,
467 					    gettext("Error EKU OID input.\n"));
468 					rv = KC_ERR_USAGE;
469 				} else {
470 					flags |= KC_EKUS;
471 				}
472 				break;
473 			case 'Z':
474 				eku_none_opt = get_boolean(optarg_av);
475 				if (eku_none_opt == -1) {
476 					(void) fprintf(stderr,
477 					    gettext("Error boolean input.\n"));
478 					rv = KC_ERR_USAGE;
479 				} else {
480 					flags |= KC_EKUS_NONE;
481 				}
482 				break;
483 			default:
484 				(void) fprintf(stderr,
485 				    gettext("Error input option.\n"));
486 				rv = KC_ERR_USAGE;
487 				break;
488 		}
489 		if (rv != KC_OK)
490 			goto out;
491 	}
492 
493 	/* No additional args allowed. */
494 	argc -= optind_av;
495 	if (argc) {
496 		(void) fprintf(stderr,
497 		    gettext("Error input option\n"));
498 		rv = KC_ERR_USAGE;
499 		goto out;
500 	}
501 
502 	if (filename == NULL) {
503 		filename = strdup(KMF_DEFAULT_POLICY_FILE);
504 		if (filename == NULL) {
505 			rv = KC_ERR_MEMORY;
506 			goto out;
507 		}
508 	}
509 
510 	/*
511 	 * Must have a policy name. The policy name can not be default
512 	 * if using the default policy file.
513 	 */
514 	if (plc.name == NULL) {
515 		(void) fprintf(stderr,
516 		    gettext("You must specify a policy name.\n"));
517 		rv = KC_ERR_USAGE;
518 		goto out;
519 	} else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 &&
520 	    strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) {
521 		(void) fprintf(stderr,
522 		    gettext("Can not modify the default policy in the default "
523 		    "policy file.\n"));
524 		rv = KC_ERR_USAGE;
525 		goto out;
526 	}
527 
528 	/* Check the access permission of the policy DB */
529 	if (access(filename, W_OK) < 0) {
530 		int err = errno;
531 		(void) fprintf(stderr,
532 		    gettext("Cannot access \"%s\" for modify - %s\n"),
533 		    filename, strerror(err));
534 		rv = KC_ERR_ACCESS;
535 		goto out;
536 	}
537 
538 	/* Try to load the named policy from the DB */
539 	ret = kmf_get_policy(filename, plc.name, &oplc);
540 	if (ret != KMF_OK) {
541 		(void) fprintf(stderr,
542 		    gettext("Error loading policy \"%s\" from %s\n"), filename,
543 		    plc.name);
544 		return (KC_ERR_FIND_POLICY);
545 	}
546 
547 	/* Update the general policy attributes. */
548 	if (flags & KC_IGNORE_DATE)
549 		oplc.ignore_date = plc.ignore_date;
550 
551 	if (flags & KC_IGNORE_UNKNOWN_EKUS)
552 		oplc.ignore_unknown_ekus = plc.ignore_unknown_ekus;
553 
554 	if (flags & KC_IGNORE_TRUST_ANCHOR)
555 		oplc.ignore_trust_anchor = plc.ignore_trust_anchor;
556 
557 	if (flags & KC_VALIDITY_ADJUSTTIME) {
558 		if (oplc.validity_adjusttime)
559 			free(oplc.validity_adjusttime);
560 		oplc.validity_adjusttime =
561 		    plc.validity_adjusttime;
562 	}
563 
564 	if (flags & KC_TA_NAME) {
565 		if (oplc.ta_name)
566 			free(oplc.ta_name);
567 		oplc.ta_name = plc.ta_name;
568 	}
569 	if (flags & KC_TA_SERIAL) {
570 		if (oplc.ta_serial)
571 			free(oplc.ta_serial);
572 		oplc.ta_serial = plc.ta_serial;
573 	}
574 
575 	/* Update the OCSP policy */
576 	if (ocsp_none_opt == B_TRUE) {
577 		if (ocsp_set_attr > 0) {
578 			(void) fprintf(stderr,
579 			    gettext("Can not set ocsp-none=true and other "
580 			    "OCSP attributes at the same time.\n"));
581 			rv = KC_ERR_USAGE;
582 			goto out;
583 		}
584 
585 		/*
586 		 * If the original policy does not have OCSP checking,
587 		 * then we do not need to do anything.  If the original
588 		 * policy has the OCSP checking, then we need to release the
589 		 * space of OCSP attributes and turn the OCSP checking off.
590 		 */
591 		if (oplc.revocation & KMF_REVOCATION_METHOD_OCSP) {
592 			if (oplc.VAL_OCSP_BASIC.responderURI) {
593 				free(oplc.VAL_OCSP_BASIC.responderURI);
594 				oplc.VAL_OCSP_BASIC.responderURI = NULL;
595 			}
596 
597 			if (oplc.VAL_OCSP_BASIC.proxy) {
598 				free(oplc.VAL_OCSP_BASIC.proxy);
599 				oplc.VAL_OCSP_BASIC.proxy = NULL;
600 			}
601 
602 			if (oplc.VAL_OCSP_BASIC.response_lifetime) {
603 				free(oplc.VAL_OCSP_BASIC.response_lifetime);
604 				oplc.VAL_OCSP_BASIC.response_lifetime = NULL;
605 			}
606 
607 			if (flags & KC_OCSP_RESP_CERT_NAME) {
608 				free(oplc.VAL_OCSP_RESP_CERT.name);
609 				oplc.VAL_OCSP_RESP_CERT.name = NULL;
610 			}
611 
612 			if (flags & KC_OCSP_RESP_CERT_SERIAL) {
613 				free(oplc.VAL_OCSP_RESP_CERT.serial);
614 				oplc.VAL_OCSP_RESP_CERT.serial = NULL;
615 			}
616 
617 			/* Turn off the OCSP checking */
618 			oplc.revocation &= ~KMF_REVOCATION_METHOD_OCSP;
619 		}
620 
621 	} else {
622 		/*
623 		 * If the "ocsp-none" option is not set or is set to false,
624 		 * then we only need to do the modification if there is at
625 		 * least one OCSP attribute is specified.
626 		 */
627 		if (ocsp_set_attr > 0) {
628 			if (flags & KC_OCSP_RESPONDER_URI) {
629 				if (oplc.VAL_OCSP_RESPONDER_URI)
630 					free(oplc.VAL_OCSP_RESPONDER_URI);
631 				oplc.VAL_OCSP_RESPONDER_URI =
632 				    plc.VAL_OCSP_RESPONDER_URI;
633 			}
634 
635 			if (flags & KC_OCSP_PROXY) {
636 				if (oplc.VAL_OCSP_PROXY)
637 					free(oplc.VAL_OCSP_PROXY);
638 				oplc.VAL_OCSP_PROXY = plc.VAL_OCSP_PROXY;
639 			}
640 
641 			if (flags & KC_OCSP_URI_FROM_CERT)
642 				oplc.VAL_OCSP_URI_FROM_CERT =
643 				    plc.VAL_OCSP_URI_FROM_CERT;
644 
645 			if (flags & KC_OCSP_RESP_LIFETIME) {
646 				if (oplc.VAL_OCSP_RESP_LIFETIME)
647 					free(oplc.VAL_OCSP_RESP_LIFETIME);
648 				oplc.VAL_OCSP_RESP_LIFETIME =
649 				    plc.VAL_OCSP_RESP_LIFETIME;
650 			}
651 
652 			if (flags & KC_OCSP_IGNORE_RESP_SIGN)
653 				oplc.VAL_OCSP_IGNORE_RESP_SIGN =
654 				    plc.VAL_OCSP_IGNORE_RESP_SIGN;
655 
656 			if (flags & KC_OCSP_RESP_CERT_NAME) {
657 				if (oplc.VAL_OCSP_RESP_CERT_NAME)
658 					free(oplc.VAL_OCSP_RESP_CERT_NAME);
659 				oplc.VAL_OCSP_RESP_CERT_NAME =
660 				    plc.VAL_OCSP_RESP_CERT_NAME;
661 			}
662 
663 			if (flags & KC_OCSP_RESP_CERT_SERIAL) {
664 				if (oplc.VAL_OCSP_RESP_CERT_SERIAL)
665 					free(oplc.VAL_OCSP_RESP_CERT_SERIAL);
666 				oplc.VAL_OCSP_RESP_CERT_SERIAL =
667 				    plc.VAL_OCSP_RESP_CERT_SERIAL;
668 			}
669 
670 			if (oplc.VAL_OCSP_RESP_CERT_NAME != NULL &&
671 			    oplc.VAL_OCSP_RESP_CERT_SERIAL != NULL)
672 				oplc.VAL_OCSP.has_resp_cert = B_TRUE;
673 			else
674 				oplc.VAL_OCSP.has_resp_cert = B_FALSE;
675 
676 			/* Turn on the OCSP checking */
677 			oplc.revocation |= KMF_REVOCATION_METHOD_OCSP;
678 		}
679 	}
680 
681 	/* Update the CRL policy */
682 	if (crl_none_opt == B_TRUE) {
683 		if (crl_set_attr > 0) {
684 			(void) fprintf(stderr,
685 			    gettext("Can not set crl-none=true and other CRL "
686 			    "attributes at the same time.\n"));
687 			rv = KC_ERR_USAGE;
688 			goto out;
689 		}
690 
691 		/*
692 		 * If the original policy does not have CRL checking,
693 		 * then we do not need to do anything.  If the original
694 		 * policy has the CRL checking, then we need to release the
695 		 * space of CRL attributes and turn the CRL checking off.
696 		 */
697 		if (oplc.revocation & KMF_REVOCATION_METHOD_CRL) {
698 			if (oplc.VAL_CRL_BASEFILENAME) {
699 				free(oplc.VAL_CRL_BASEFILENAME);
700 				oplc.VAL_CRL_BASEFILENAME = NULL;
701 			}
702 
703 			if (oplc.VAL_CRL_DIRECTORY) {
704 				free(oplc.VAL_CRL_DIRECTORY);
705 				oplc.VAL_CRL_DIRECTORY = NULL;
706 			}
707 
708 			if (oplc.VAL_CRL_PROXY) {
709 				free(oplc.VAL_CRL_PROXY);
710 				oplc.VAL_CRL_PROXY = NULL;
711 			}
712 
713 			/* Turn off the CRL checking */
714 			oplc.revocation &= ~KMF_REVOCATION_METHOD_CRL;
715 		}
716 	} else {
717 		/*
718 		 * If the "ocsp-none" option is not set or is set to false,
719 		 * then we only need to do the modification if there is at
720 		 * least one CRL attribute is specified.
721 		 */
722 		if (crl_set_attr > 0) {
723 			if (flags & KC_CRL_BASEFILENAME) {
724 				if (oplc.VAL_CRL_BASEFILENAME)
725 					free(oplc.VAL_CRL_BASEFILENAME);
726 				oplc.VAL_CRL_BASEFILENAME =
727 				    plc.VAL_CRL_BASEFILENAME;
728 			}
729 
730 			if (flags & KC_CRL_DIRECTORY) {
731 				if (oplc.VAL_CRL_DIRECTORY)
732 					free(oplc.VAL_CRL_DIRECTORY);
733 				oplc.VAL_CRL_DIRECTORY = plc.VAL_CRL_DIRECTORY;
734 			}
735 
736 			if (flags & KC_CRL_GET_URI) {
737 				oplc.VAL_CRL_GET_URI = plc.VAL_CRL_GET_URI;
738 			}
739 
740 			if (flags & KC_CRL_PROXY) {
741 				if (oplc.VAL_CRL_PROXY)
742 					free(oplc.VAL_CRL_PROXY);
743 				oplc.VAL_CRL_PROXY = plc.VAL_CRL_PROXY;
744 			}
745 
746 			if (flags & KC_CRL_IGNORE_SIGN) {
747 				oplc.VAL_CRL_IGNORE_SIGN =
748 				    plc.VAL_CRL_IGNORE_SIGN;
749 			}
750 
751 			if (flags & KC_CRL_IGNORE_DATE) {
752 				oplc.VAL_CRL_IGNORE_DATE =
753 				    plc.VAL_CRL_IGNORE_DATE;
754 			}
755 
756 			/* Turn on the CRL checking */
757 			oplc.revocation |= KMF_REVOCATION_METHOD_CRL;
758 		}
759 	}
760 
761 	/* Update the Key Usage */
762 	if (ku_none_opt == B_TRUE) {
763 		if (flags & KC_KEYUSAGE) {
764 			(void) fprintf(stderr,
765 			    gettext("Can not set keyusage-none=true and "
766 			    "modify the keyusage value at the same time.\n"));
767 			rv = KC_ERR_USAGE;
768 			goto out;
769 		}
770 
771 		oplc.ku_bits = 0;
772 	} else {
773 		/*
774 		 * If the "keyusage-none" option is not set or is set to
775 		 * false, then we only need to do the modification if
776 		 * the keyusage value is specified.
777 		 */
778 		if (flags & KC_KEYUSAGE)
779 			oplc.ku_bits = plc.ku_bits;
780 	}
781 
782 
783 	/* Update the Extended Key Usage */
784 	if (eku_none_opt == B_TRUE) {
785 		if (flags & KC_EKUS) {
786 			(void) fprintf(stderr,
787 			    gettext("Can not set eku-none=true and modify "
788 			    "EKU values at the same time.\n"));
789 			rv = KC_ERR_USAGE;
790 			goto out;
791 		}
792 
793 		/* Release current EKU list (if any) */
794 		if (oplc.eku_set.eku_count > 0) {
795 			kmf_free_eku_policy(&oplc.eku_set);
796 			oplc.eku_set.eku_count = 0;
797 			oplc.eku_set.ekulist = NULL;
798 		}
799 	} else {
800 		/*
801 		 * If the "eku-none" option is not set or is set to false,
802 		 * then we only need to do the modification if either
803 		 * "ekuname" or "ekuoids" is specified.
804 		 */
805 		if (flags & KC_EKUS) {
806 			/* Release current EKU list (if any) */
807 			kmf_free_eku_policy(&oplc.eku_set);
808 			oplc.eku_set = plc.eku_set;
809 		}
810 	}
811 
812 	/* Do a sanity check on the modified policy */
813 	ret = kmf_verify_policy(&oplc);
814 	if (ret != KMF_OK) {
815 		print_sanity_error(ret);
816 		rv = KC_ERR_VERIFY_POLICY;
817 		goto out;
818 	}
819 
820 	/* The modify operation is a delete followed by an add */
821 	ret = kmf_delete_policy_from_db(oplc.name, filename);
822 	if (ret != KMF_OK) {
823 		rv = KC_ERR_DELETE_POLICY;
824 		goto out;
825 	}
826 
827 	/*
828 	 * Now add the modified policy back to the DB.
829 	 */
830 	ret = kmf_add_policy_to_db(&oplc, filename, B_FALSE);
831 	if (ret != KMF_OK) {
832 		(void) fprintf(stderr,
833 		    gettext("Error adding policy to database: 0x%04x\n"), ret);
834 		rv = KC_ERR_ADD_POLICY;
835 		goto out;
836 	}
837 
838 out:
839 	if (filename != NULL)
840 		free(filename);
841 
842 	kmf_free_policy_record(&oplc);
843 
844 	return (rv);
845 }
846