xref: /illumos-gate/usr/src/lib/libkmf/libkmf/common/policy.c (revision 99ebb4ca412cb0a19d77a3899a87c055b9c30fa8)
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 2006 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 <stdlib.h>
28 #include <ctype.h>
29 #include <strings.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <sys/param.h>
33 #include <sys/stat.h>
34 
35 #include <kmfapiP.h>
36 #include <libxml/tree.h>
37 #include <libxml/parser.h>
38 
39 typedef struct {
40 	char	*ekuname;
41 	KMF_OID	*oid;
42 } EKUName2OID;
43 
44 static EKUName2OID EKUList[] = {
45 	{"serverAuth",		(KMF_OID *)&KMFOID_PKIX_KP_ServerAuth},
46 	{"clientAuth",		(KMF_OID *)&KMFOID_PKIX_KP_ClientAuth},
47 	{"codeSigning",		(KMF_OID *)&KMFOID_PKIX_KP_CodeSigning},
48 	{"emailProtection",	(KMF_OID *)&KMFOID_PKIX_KP_EmailProtection},
49 	{"ipsecEndSystem",	(KMF_OID *)&KMFOID_PKIX_KP_IPSecEndSystem},
50 	{"ipsecTunnel",		(KMF_OID *)&KMFOID_PKIX_KP_IPSecTunnel},
51 	{"ipsecUser",		(KMF_OID *)&KMFOID_PKIX_KP_IPSecUser},
52 	{"timeStamping",	(KMF_OID *)&KMFOID_PKIX_KP_TimeStamping},
53 	{"OCSPSigning", 	(KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning}
54 };
55 
56 static int num_ekus = sizeof (EKUList) / sizeof (EKUName2OID);
57 
58 static void
59 addFormatting(xmlNodePtr parent, char *text)
60 {
61 	xmlNodePtr snode;
62 
63 	if (parent == NULL || text == NULL)
64 		return;
65 
66 	snode = xmlNewText((const xmlChar *)text);
67 	if (snode != NULL) {
68 		xmlAddChild(parent, snode);
69 	}
70 }
71 
72 static void
73 parseOCSPValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo)
74 {
75 	xmlNodePtr n;
76 	char *c;
77 	n = node->children;
78 	while (n != NULL) {
79 		if (!xmlStrcmp((const xmlChar *)n->name,
80 			(const xmlChar *)KMF_OCSP_BASIC_ELEMENT)) {
81 
82 			vinfo->ocsp_info.basic.responderURI =
83 			    (char *)xmlGetProp(n,
84 			    (const xmlChar *)KMF_OCSP_RESPONDER_ATTR);
85 
86 			vinfo->ocsp_info.basic.proxy = (char *)xmlGetProp(n,
87 			    (const xmlChar *)KMF_OCSP_PROXY_ATTR);
88 
89 			c = (char *)xmlGetProp(n,
90 			    (const xmlChar *)KMF_OCSP_URI_ATTR);
91 			if (c != NULL && !strcasecmp(c, "true")) {
92 				vinfo->ocsp_info.basic.uri_from_cert = 1;
93 				xmlFree(c);
94 			}
95 
96 			vinfo->ocsp_info.basic.response_lifetime =
97 			    (char *)xmlGetProp(n,
98 			    (const xmlChar *)KMF_OCSP_RESPONSE_LIFETIME_ATTR);
99 
100 			c = (char *)xmlGetProp(n,
101 			    (const xmlChar *)KMF_OCSP_IGNORE_SIGN_ATTR);
102 			if (c != NULL && !strcasecmp(c, "true")) {
103 				vinfo->ocsp_info.basic.ignore_response_sign = 1;
104 				xmlFree(c);
105 			}
106 
107 		} else if (!xmlStrcmp((const xmlChar *)n->name,
108 		    (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT)) {
109 
110 			vinfo->ocsp_info.resp_cert.name =
111 			    (char *)xmlGetProp(n,
112 			    (const xmlChar *)KMF_CERT_NAME_ATTR);
113 			vinfo->ocsp_info.resp_cert.serial =
114 				(char *)xmlGetProp(n,
115 				(const xmlChar *)KMF_CERT_SERIAL_ATTR);
116 			vinfo->ocsp_info.has_resp_cert = 1;
117 		}
118 
119 		n = n->next;
120 	}
121 
122 }
123 
124 /*
125  * Parse the "validation-methods" section of the policy.
126  */
127 static void
128 parseValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo,
129 	KMF_POLICY_RECORD *policy)
130 {
131 	xmlNodePtr n;
132 	char *c;
133 	n = node->children;
134 	while (n != NULL) {
135 		if (!xmlStrcmp((const xmlChar *)n->name,
136 			(const xmlChar *)KMF_OCSP_ELEMENT)) {
137 
138 			parseOCSPValidation(n, &policy->validation_info);
139 			policy->revocation |= KMF_REVOCATION_METHOD_OCSP;
140 
141 
142 		} else if (!xmlStrcmp((const xmlChar *)n->name,
143 				(const xmlChar *)KMF_CRL_ELEMENT)) {
144 
145 			vinfo->crl_info.basefilename = (char *)xmlGetProp(n,
146 				(const xmlChar *)KMF_CRL_BASENAME_ATTR);
147 
148 			vinfo->crl_info.directory = (char *)xmlGetProp(n,
149 				(const xmlChar *)KMF_CRL_DIRECTORY_ATTR);
150 
151 			c = (char *)xmlGetProp(n,
152 				(const xmlChar *)KMF_CRL_GET_URI_ATTR);
153 			if (c != NULL && !strcasecmp(c, "true")) {
154 				vinfo->crl_info.get_crl_uri = 1;
155 			} else {
156 				vinfo->crl_info.get_crl_uri = 0;
157 			}
158 			xmlFree(c);
159 
160 			vinfo->crl_info.proxy = (char *)xmlGetProp(n,
161 			    (const xmlChar *)KMF_CRL_PROXY_ATTR);
162 
163 			c = (char *)xmlGetProp(n,
164 				(const xmlChar *)KMF_CRL_IGNORE_SIGN_ATTR);
165 			if (c != NULL && !strcasecmp(c, "true")) {
166 				vinfo->crl_info.ignore_crl_sign = 1;
167 			} else {
168 				vinfo->crl_info.ignore_crl_sign = 0;
169 			}
170 			xmlFree(c);
171 
172 			c = (char *)xmlGetProp(n,
173 				(const xmlChar *)KMF_CRL_IGNORE_DATE_ATTR);
174 			if (c != NULL && !strcasecmp(c, "true")) {
175 				vinfo->crl_info.ignore_crl_date = 1;
176 			} else {
177 				vinfo->crl_info.ignore_crl_date = 0;
178 			}
179 			xmlFree(c);
180 
181 			policy->revocation |= KMF_REVOCATION_METHOD_CRL;
182 		}
183 
184 		n = n->next;
185 	}
186 }
187 
188 char *
189 ku2str(uint32_t bitfield)
190 {
191 	if (bitfield & KMF_digitalSignature)
192 		return ("digitalSignature");
193 
194 	if (bitfield & KMF_nonRepudiation)
195 		return ("nonRepudiation");
196 
197 	if (bitfield & KMF_keyEncipherment)
198 		return ("keyEncipherment");
199 
200 	if (bitfield & KMF_dataEncipherment)
201 		return ("dataEncipherment");
202 
203 	if (bitfield & KMF_keyAgreement)
204 		return ("keyAgreement");
205 
206 	if (bitfield & KMF_keyCertSign)
207 		return ("keyCertSign");
208 
209 	if (bitfield & KMF_cRLSign)
210 		return ("cRLSign");
211 
212 	if (bitfield & KMF_encipherOnly)
213 		return ("encipherOnly");
214 
215 	if (bitfield & KMF_decipherOnly)
216 		return ("decipherOnly");
217 
218 	return (NULL);
219 }
220 
221 uint16_t
222 KMF_StringToKeyUsage(char *kustring)
223 {
224 	if (kustring == NULL || !strlen(kustring))
225 		return (0);
226 	if (strcasecmp(kustring, "digitalSignature") == 0)
227 		return (KMF_digitalSignature);
228 	if (strcasecmp(kustring, "nonRepudiation") == 0)
229 		return (KMF_nonRepudiation);
230 	if (strcasecmp(kustring, "keyEncipherment") == 0)
231 		return (KMF_keyEncipherment);
232 	if (strcasecmp(kustring, "dataEncipherment") == 0)
233 		return (KMF_dataEncipherment);
234 	if (strcasecmp(kustring, "keyAgreement") == 0)
235 		return (KMF_keyAgreement);
236 	if (strcasecmp(kustring, "keyCertSign") == 0)
237 		return (KMF_keyCertSign);
238 	if (strcasecmp(kustring, "cRLSign") == 0)
239 		return (KMF_cRLSign);
240 	if (strcasecmp(kustring, "encipherOnly") == 0)
241 		return (KMF_encipherOnly);
242 	if (strcasecmp(kustring, "decipherOnly") == 0)
243 		return (KMF_decipherOnly);
244 
245 	return (0);
246 }
247 
248 static void
249 parseKeyUsageSet(xmlNodePtr node, uint32_t *kubits)
250 {
251 	xmlNodePtr n;
252 	char *c;
253 
254 	n = node->children;
255 	while (n != NULL) {
256 		if (!xmlStrcmp((const xmlChar *)n->name,
257 			(const xmlChar *)KMF_KEY_USAGE_ELEMENT)) {
258 			c = (char *)xmlGetProp(n,
259 				(const xmlChar *)KMF_KEY_USAGE_USE_ATTR);
260 			if (c) {
261 				*kubits |= KMF_StringToKeyUsage(c);
262 				xmlFree(c);
263 			}
264 		}
265 
266 		n = n->next;
267 	}
268 }
269 
270 static KMF_OID *
271 dup_oid(KMF_OID *oldoid)
272 {
273 	KMF_OID *oid;
274 
275 	oid = malloc(sizeof (KMF_OID));
276 	if (oid == NULL)
277 		return (NULL);
278 
279 	oid->Length = oldoid->Length;
280 	oid->Data = malloc(oid->Length);
281 	if (oid->Data == NULL) {
282 		free(oid);
283 		return (NULL);
284 	}
285 	(void) memcpy(oid->Data, oldoid->Data, oid->Length);
286 
287 	return (oid);
288 }
289 
290 KMF_OID *
291 kmf_ekuname2oid(char *ekuname)
292 {
293 	KMF_OID *oid;
294 	int i;
295 
296 	if (ekuname == NULL)
297 		return (NULL);
298 
299 	for (i = 0; i < num_ekus; i++) {
300 		if (strcasecmp(EKUList[i].ekuname, ekuname) == 0) {
301 			oid = dup_oid(EKUList[i].oid);
302 			return (oid);
303 		}
304 	}
305 
306 	return (NULL);
307 }
308 
309 char *
310 KMF_OID2EKUString(KMF_OID *oid)
311 {
312 	int i;
313 	for (i = 0; i < num_ekus; i++) {
314 		if (oid->Length == EKUList[i].oid->Length &&
315 			!memcmp(oid->Data, EKUList[i].oid->Data, oid->Length)) {
316 			return (EKUList[i].ekuname);
317 		}
318 	}
319 	return (NULL);
320 }
321 
322 /*
323  * Convert a human-readable OID string of the form "1.2.3.4" or
324  * "1 2 3 4" into a KMF_OID value.
325  */
326 KMF_OID *
327 kmf_string2oid(char *oidstring)
328 {
329 	KMF_OID *oid = NULL;
330 	char *cp, *bp, *startp;
331 	int numbuf;
332 	int onumbuf;
333 	int nbytes, index;
334 	int len;
335 	unsigned char *op;
336 
337 	if (oidstring == NULL)
338 		return (NULL);
339 
340 	len = strlen(oidstring);
341 
342 	bp = oidstring;
343 	cp = bp;
344 	/* Skip over leading space */
345 	while ((bp < &cp[len]) && isspace(*bp))
346 		bp++;
347 
348 	startp = bp;
349 	nbytes = 0;
350 
351 	/*
352 	 * The first two numbers are chewed up by the first octet.
353 	 */
354 	if (sscanf(bp, "%d", &numbuf) != 1)
355 		return (NULL);
356 	while ((bp < &cp[len]) && isdigit(*bp))
357 		bp++;
358 	while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.'))
359 		bp++;
360 	if (sscanf(bp, "%d", &numbuf) != 1)
361 		return (NULL);
362 	while ((bp < &cp[len]) && isdigit(*bp))
363 		bp++;
364 	while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.'))
365 		bp++;
366 	nbytes++;
367 
368 	while (isdigit(*bp)) {
369 		if (sscanf(bp, "%d", &numbuf) != 1)
370 			return (NULL);
371 		while (numbuf) {
372 			nbytes++;
373 			numbuf >>= 7;
374 		}
375 		while ((bp < &cp[len]) && isdigit(*bp))
376 			bp++;
377 		while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.'))
378 			bp++;
379 	}
380 
381 	oid = malloc(sizeof (KMF_OID));
382 	if (oid == NULL)
383 		return (NULL);
384 
385 	oid->Length = nbytes;
386 	oid->Data = malloc(oid->Length);
387 	if (oid->Data == NULL) {
388 		free(oid);
389 		return (NULL);
390 	}
391 	(void) memset(oid->Data, 0, oid->Length);
392 
393 	op = oid->Data;
394 
395 	bp = startp;
396 	(void) sscanf(bp, "%d", &numbuf);
397 
398 	while (isdigit(*bp)) bp++;
399 	while (isspace(*bp) || *bp == '.') bp++;
400 
401 	onumbuf = 40 * numbuf;
402 	(void) sscanf(bp, "%d", &numbuf);
403 	onumbuf += numbuf;
404 	*op = (unsigned char) onumbuf;
405 	op++;
406 
407 	while (isdigit(*bp)) bp++;
408 	while (isspace(*bp) || *bp == '.') bp++;
409 	while (isdigit(*bp)) {
410 		(void) sscanf(bp, "%d", &numbuf);
411 		nbytes = 0;
412 		/* Have to fill in the bytes msb-first */
413 		onumbuf = numbuf;
414 		while (numbuf) {
415 			nbytes++;
416 			numbuf >>= 7;
417 		}
418 		numbuf = onumbuf;
419 		op += nbytes;
420 		index = -1;
421 		while (numbuf) {
422 			op[index] = (unsigned char)numbuf & 0x7f;
423 			if (index != -1)
424 				op[index] |= 0x80;
425 			index--;
426 			numbuf >>= 7;
427 		}
428 		while (isdigit(*bp)) bp++;
429 		while (isspace(*bp) || *bp == '.') bp++;
430 	}
431 
432 	return (oid);
433 }
434 
435 static KMF_RETURN
436 parseExtKeyUsage(xmlNodePtr node, KMF_EKU_POLICY *ekus)
437 {
438 	xmlNodePtr n;
439 	char *c;
440 	KMF_RETURN ret = KMF_OK;
441 	boolean_t found = FALSE;
442 
443 	n = node->children;
444 	while (n != NULL && ret == KMF_OK) {
445 		KMF_OID *newoid = NULL;
446 
447 		if (!xmlStrcmp((const xmlChar *)n->name,
448 			(const xmlChar *)KMF_EKU_NAME_ELEMENT)) {
449 			c = (char *)xmlGetProp(n,
450 				(const xmlChar *)KMF_EKU_NAME_ATTR);
451 			if (c != NULL) {
452 				newoid = kmf_ekuname2oid(c);
453 				xmlFree(c);
454 				found = TRUE;
455 			}
456 		} else if (!xmlStrcmp((const xmlChar *)n->name,
457 			(const xmlChar *)KMF_EKU_OID_ELEMENT)) {
458 			c = (char *)xmlGetProp(n,
459 				(const xmlChar *)KMF_EKU_OID_ATTR);
460 			if (c != NULL) {
461 				newoid = kmf_string2oid(c);
462 				xmlFree(c);
463 				found = TRUE;
464 			}
465 		} else {
466 			n = n->next;
467 			if ((n == NULL) && (!found))
468 				ret = KMF_ERR_POLICY_DB_FORMAT;
469 			continue;
470 		}
471 
472 		if (newoid != NULL) {
473 			ekus->eku_count++;
474 			ekus->ekulist = realloc(ekus->ekulist,
475 					ekus->eku_count * sizeof (KMF_OID));
476 			if (ekus->ekulist != NULL) {
477 				ekus->ekulist[ekus->eku_count-1].Length =
478 				    newoid->Length;
479 				ekus->ekulist[ekus->eku_count-1].Data =
480 				    malloc(newoid->Length);
481 				if (ekus->ekulist[ekus->eku_count-1].Data ==
482 				    NULL) {
483 					ret = KMF_ERR_MEMORY;
484 				} else {
485 					(void) memcpy(
486 					    ekus->ekulist[ekus->eku_count-1].
487 					    Data,
488 					    newoid->Data, newoid->Length);
489 				}
490 			} else {
491 				ret = KMF_ERR_MEMORY;
492 			}
493 			KMF_FreeData(newoid);
494 			free(newoid);
495 		} else {
496 			ret = KMF_ERR_POLICY_DB_FORMAT;
497 		}
498 
499 		n = n->next;
500 	}
501 
502 	return (ret);
503 }
504 
505 int
506 parsePolicyElement(xmlNodePtr node, KMF_POLICY_RECORD *policy)
507 {
508 	int ret = 0;
509 	xmlNodePtr n = node->xmlChildrenNode;
510 	char *c;
511 
512 	if (node->type == XML_ELEMENT_NODE) {
513 		if (node->properties != NULL) {
514 			policy->name = (char *)xmlGetProp(node,
515 				(const xmlChar *)KMF_POLICY_NAME_ATTR);
516 
517 			c = (char *)xmlGetProp(node,
518 				(const xmlChar *)KMF_OPTIONS_IGNORE_DATE_ATTR);
519 			if (c && !strcasecmp(c, "true")) {
520 				policy->ignore_date = 1;
521 				xmlFree((xmlChar *)c);
522 			}
523 
524 			c = (char *)xmlGetProp(node,
525 			    (const xmlChar *)KMF_OPTIONS_IGNORE_UNKNOWN_EKUS);
526 			if (c && !strcasecmp(c, "true")) {
527 				policy->ignore_unknown_ekus = 1;
528 				xmlFree(c);
529 			}
530 
531 			c = (char *)xmlGetProp(node,
532 			    (const xmlChar *)KMF_OPTIONS_IGNORE_TRUST_ANCHOR);
533 			if (c && !strcasecmp(c, "true")) {
534 				policy->ignore_trust_anchor = 1;
535 				xmlFree(c);
536 			}
537 
538 			c = (char *)xmlGetProp(node,
539 			    (const xmlChar *)KMF_OPTIONS_VALIDITY_ADJUSTTIME);
540 			if (c) {
541 				policy->validity_adjusttime = c;
542 			} else {
543 				policy->validity_adjusttime = NULL;
544 			}
545 
546 			policy->ta_name = (char *)xmlGetProp(node,
547 				(const xmlChar *)KMF_POLICY_TA_NAME_ATTR);
548 
549 			policy->ta_serial = (char *)xmlGetProp(node,
550 				(const xmlChar *)KMF_POLICY_TA_SERIAL_ATTR);
551 		}
552 
553 		n = node->children;
554 		while (n != NULL) {
555 			if (!xmlStrcmp((const xmlChar *)n->name,
556 			(const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT))
557 				parseValidation(n, &policy->validation_info,
558 				    policy);
559 			else if (!xmlStrcmp((const xmlChar *)n->name,
560 			(const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT))
561 				parseKeyUsageSet(n, &policy->ku_bits);
562 			else if (!xmlStrcmp((const xmlChar *)n->name,
563 			    (const xmlChar *)KMF_EKU_ELEMENT)) {
564 				ret = parseExtKeyUsage(n, &policy->eku_set);
565 				if (ret != KMF_OK)
566 					return (ret);
567 			}
568 
569 			n = n->next;
570 		}
571 	}
572 
573 	return (ret);
574 }
575 
576 static int
577 newprop(xmlNodePtr node, char *attrname, char *src)
578 {
579 	xmlAttrPtr newattr;
580 
581 	if (src != NULL && strlen(src)) {
582 		newattr = xmlNewProp(node, (const xmlChar *)attrname,
583 			(xmlChar *)src);
584 		if (newattr == NULL) {
585 			xmlUnlinkNode(node);
586 			xmlFreeNode(node);
587 			return (-1);
588 		}
589 	}
590 	return (0);
591 }
592 
593 /*
594  * Add CRL policy information to the XML tree.
595  * Return non-zero on any failure, else 0 for success.
596  *
597  * This function is called only when the KMF_REVOCATION_METHOD_CRL flag is on.
598  */
599 static int
600 AddCRLNodes(xmlNodePtr node, KMF_CRL_POLICY *crlinfo)
601 {
602 	xmlNodePtr n;
603 
604 	addFormatting(node, "\t\t");
605 	n = xmlNewChild(node, NULL, (const xmlChar *)"crl", NULL);
606 	if (n == NULL)
607 		return (-1);
608 
609 	if (crlinfo->basefilename &&
610 	    newprop(n, KMF_CRL_BASENAME_ATTR, crlinfo->basefilename))
611 		return (-1);
612 
613 	if (crlinfo->directory &&
614 	    newprop(n, KMF_CRL_DIRECTORY_ATTR, crlinfo->directory))
615 		return (-1);
616 
617 	if (crlinfo->get_crl_uri &&
618 	    newprop(n, KMF_CRL_GET_URI_ATTR, "TRUE")) {
619 		return (-1);
620 	}
621 
622 	if (crlinfo->proxy &&
623 	    newprop(n, KMF_CRL_PROXY_ATTR, crlinfo->proxy))
624 		return (-1);
625 
626 	if (crlinfo->ignore_crl_sign &&
627 	    newprop(n, KMF_CRL_IGNORE_SIGN_ATTR, "TRUE")) {
628 		return (-1);
629 	}
630 
631 	if (crlinfo->ignore_crl_date &&
632 	    newprop(n, KMF_CRL_IGNORE_DATE_ATTR, "TRUE")) {
633 		return (-1);
634 	}
635 
636 	addFormatting(node, "\n");
637 	return (0);
638 }
639 
640 /*
641  * Add OCSP information to the policy tree.
642  * Return non-zero on any failure, else 0 for success.
643  *
644  * This function is called only when the KMF_REVOCATION_METHOD_OCSP flag is on.
645  */
646 static int
647 AddOCSPNodes(xmlNodePtr parent, KMF_OCSP_POLICY *ocsp)
648 {
649 	int ret = 0;
650 	xmlNodePtr n_ocsp, n_basic, n_resp;
651 	KMF_OCSP_BASIC_POLICY *basic;
652 	KMF_RESP_CERT_POLICY *resp_cert;
653 
654 	basic = &(ocsp->basic);
655 	resp_cert = &(ocsp->resp_cert);
656 
657 	if (basic->responderURI != NULL || basic->uri_from_cert == B_TRUE) {
658 
659 		addFormatting(parent, "\t\t");
660 
661 		/* basic node */
662 		n_ocsp = xmlNewChild(parent, NULL,
663 			(const xmlChar *)KMF_OCSP_ELEMENT, NULL);
664 		if (n_ocsp == NULL)
665 			return (-1);
666 		addFormatting(n_ocsp, "\n\t\t\t");
667 
668 		n_basic = xmlNewChild(n_ocsp, NULL,
669 		    (const xmlChar *)KMF_OCSP_BASIC_ELEMENT, NULL);
670 		if (n_basic == NULL)
671 			return (-1);
672 		if (basic->responderURI && newprop(n_basic,
673 		    KMF_OCSP_RESPONDER_ATTR, basic->responderURI))
674 			return (-1);
675 		if (basic->proxy &&
676 		    newprop(n_basic, KMF_OCSP_PROXY_ATTR, basic->proxy))
677 			return (-1);
678 		if (basic->uri_from_cert &&
679 		    newprop(n_basic, KMF_OCSP_URI_ATTR, "TRUE"))
680 			return (-1);
681 		if (basic->response_lifetime &&
682 		    newprop(n_basic, KMF_OCSP_RESPONSE_LIFETIME_ATTR,
683 			basic->response_lifetime))
684 			return (-1);
685 		if (basic->ignore_response_sign &&
686 		    newprop(n_basic, KMF_OCSP_IGNORE_SIGN_ATTR, "TRUE"))
687 			return (-1);
688 
689 		addFormatting(n_ocsp, "\n\t\t\t");
690 
691 		/* responder cert node */
692 		if (ocsp->has_resp_cert) {
693 			n_resp = xmlNewChild(n_ocsp, NULL,
694 			    (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT,
695 			    NULL);
696 			if (n_resp == NULL)
697 				return (-1);
698 			if (newprop(n_resp, KMF_CERT_NAME_ATTR,
699 			    resp_cert->name))
700 				return (-1);
701 			if (newprop(n_resp, KMF_CERT_SERIAL_ATTR,
702 			    resp_cert->serial))
703 				return (-1);
704 		}
705 		addFormatting(n_ocsp, "\n\t\t");
706 	}
707 
708 	addFormatting(parent, "\n");
709 	return (ret);
710 }
711 
712 /*
713  * Add validation method information to the policy tree.
714  * Return non-zero on any failure, else 0 for success.
715  */
716 static int
717 AddValidationNodes(xmlNodePtr parent, KMF_POLICY_RECORD *policy)
718 {
719 	xmlNodePtr mnode;
720 	int ret = 0;
721 
722 	addFormatting(parent, "\t");
723 	mnode = xmlNewChild(parent, NULL,
724 		(const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT, NULL);
725 	if (mnode == NULL)
726 		return (-1);
727 
728 	addFormatting(mnode, "\n");
729 
730 	if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
731 		ret = AddOCSPNodes(mnode, &(policy->validation_info.ocsp_info));
732 		if (ret != KMF_OK)
733 			goto end;
734 	}
735 
736 	if (policy->revocation & KMF_REVOCATION_METHOD_CRL) {
737 		ret = AddCRLNodes(mnode, &(policy->validation_info.crl_info));
738 		if (ret != KMF_OK)
739 			goto end;
740 	}
741 
742 	addFormatting(mnode, "\t");
743 	addFormatting(parent, "\n");
744 
745 end:
746 	if (ret != 0) {
747 		xmlUnlinkNode(mnode);
748 		xmlFreeNode(mnode);
749 	}
750 	return (ret);
751 
752 }
753 
754 /*
755  * Add Key Usage information to the policy tree.
756  * Return non-zero on any failure, else 0 for success.
757  */
758 static KMF_RETURN
759 AddKeyUsageNodes(xmlNodePtr parent, uint32_t kubits)
760 {
761 	int ret = KMF_OK;
762 	int i;
763 
764 	xmlNodePtr kuset, kunode;
765 
766 	if (kubits == 0)
767 		return (0);
768 
769 	addFormatting(parent, "\n\t");
770 	kuset = xmlNewChild(parent, NULL,
771 		(const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT, NULL);
772 	if (kuset == NULL)
773 		return (KMF_ERR_POLICY_ENGINE);
774 
775 	for (i = KULOWBIT; i <= KUHIGHBIT && ret == KMF_OK; i++) {
776 		char *s = ku2str((kubits & (1<<i)));
777 		if (s != NULL) {
778 			addFormatting(kuset, "\n\t\t");
779 
780 			kunode = xmlNewChild(kuset, NULL,
781 				(const xmlChar *)KMF_KEY_USAGE_ELEMENT, NULL);
782 			if (kunode == NULL)
783 				ret = KMF_ERR_POLICY_ENGINE;
784 
785 			else if (newprop(kunode, KMF_KEY_USAGE_USE_ATTR, s))
786 				ret = KMF_ERR_POLICY_ENGINE;
787 		}
788 	}
789 	addFormatting(kuset, "\n\t");
790 	addFormatting(parent, "\n");
791 
792 	if (ret != KMF_OK) {
793 		xmlUnlinkNode(kuset);
794 		xmlFreeNode(kuset);
795 	}
796 
797 	return (ret);
798 }
799 
800 /*
801  * Add Extended-Key-Usage information to the policy tree.
802  * Return non-zero on any failure, else 0 for success.
803  */
804 static KMF_RETURN
805 AddExtKeyUsageNodes(xmlNodePtr parent, KMF_EKU_POLICY *ekus)
806 {
807 	KMF_RETURN ret = KMF_OK;
808 	xmlNodePtr n, kunode;
809 	int i;
810 
811 	if (ekus != NULL && ekus->eku_count > 0) {
812 		addFormatting(parent, "\n\t");
813 		n = xmlNewChild(parent, NULL,
814 			(const xmlChar *)KMF_EKU_ELEMENT, NULL);
815 		if (n == NULL)
816 			return (KMF_ERR_POLICY_ENGINE);
817 
818 		for (i = 0; i < ekus->eku_count; i++) {
819 			char *s = KMF_OID2String(&ekus->ekulist[i]);
820 			if (s != NULL) {
821 				addFormatting(n, "\n\t\t");
822 				kunode = xmlNewChild(n, NULL,
823 					(const xmlChar *)KMF_EKU_OID_ELEMENT,
824 					NULL);
825 				if (kunode == NULL)
826 					ret = KMF_ERR_POLICY_ENGINE;
827 
828 				else if (newprop(kunode, KMF_EKU_OID_ATTR, s))
829 					ret = KMF_ERR_POLICY_ENGINE;
830 				free(s);
831 			} else {
832 				ret = KMF_ERR_POLICY_ENGINE;
833 			}
834 		}
835 		addFormatting(n, "\n\t");
836 		addFormatting(parent, "\n");
837 	}
838 
839 	if (ret != KMF_OK) {
840 		xmlUnlinkNode(n);
841 		xmlFreeNode(n);
842 	}
843 	return (ret);
844 }
845 
846 void
847 KMF_FreeEKUPolicy(KMF_EKU_POLICY *ekus)
848 {
849 	if (ekus->eku_count > 0) {
850 		int i;
851 		for (i = 0; i < ekus->eku_count; i++) {
852 			KMF_FreeData(&ekus->ekulist[i]);
853 		}
854 		free(ekus->ekulist);
855 	}
856 }
857 
858 #define	FREE_POLICY_STR(s) if (s != NULL) free(s);
859 
860 void
861 KMF_FreePolicyRecord(KMF_POLICY_RECORD *policy)
862 {
863 	if (policy == NULL)
864 		return;
865 
866 	FREE_POLICY_STR(policy->name)
867 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.responderURI)
868 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.proxy)
869 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.response_lifetime)
870 	FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.name)
871 	FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.serial)
872 	FREE_POLICY_STR(policy->validation_info.crl_info.basefilename)
873 	FREE_POLICY_STR(policy->validation_info.crl_info.directory)
874 	FREE_POLICY_STR(policy->validation_info.crl_info.proxy)
875 	FREE_POLICY_STR(policy->validity_adjusttime)
876 	FREE_POLICY_STR(policy->ta_name)
877 	FREE_POLICY_STR(policy->ta_serial)
878 
879 	KMF_FreeEKUPolicy(&policy->eku_set);
880 
881 	(void) memset(policy, 0, sizeof (KMF_POLICY_RECORD));
882 }
883 
884 /*
885  * KMF_GetPolicy
886  *
887  * Find a policy record in the database.
888  */
889 KMF_RETURN
890 KMF_GetPolicy(char *filename, char *policy_name, KMF_POLICY_RECORD *plc)
891 {
892 	KMF_RETURN ret = KMF_OK;
893 	xmlParserCtxtPtr ctxt;
894 	xmlDocPtr doc = NULL;
895 	xmlNodePtr cur, node;
896 	int found = 0;
897 
898 	if (filename == NULL || policy_name == NULL || plc == NULL)
899 		return (KMF_ERR_BAD_PARAMETER);
900 
901 	(void) memset(plc, 0, sizeof (KMF_POLICY_RECORD));
902 
903 	/* Create a parser context */
904 	ctxt = xmlNewParserCtxt();
905 	if (ctxt == NULL)
906 		return (KMF_ERR_POLICY_DB_FORMAT);
907 
908 	/* Read the policy DB and verify it against the schema. */
909 	doc = xmlCtxtReadFile(ctxt, filename, NULL,
910 	    XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
911 	if (doc == NULL || ctxt->valid == 0) {
912 		ret = KMF_ERR_POLICY_DB_FORMAT;
913 		goto out;
914 	}
915 
916 	cur = xmlDocGetRootElement(doc);
917 	if (cur == NULL) {
918 		ret = KMF_ERR_POLICY_DB_FORMAT;
919 		goto out;
920 	}
921 
922 	node = cur->xmlChildrenNode;
923 	while (node != NULL && !found) {
924 		char *c;
925 		/*
926 		 * Search for the policy that matches the given name.
927 		 */
928 		if (!xmlStrcmp((const xmlChar *)node->name,
929 			(const xmlChar *)KMF_POLICY_ELEMENT)) {
930 			/* Check the name attribute */
931 			c = (char *)xmlGetProp(node,
932 				(const xmlChar *)KMF_POLICY_NAME_ATTR);
933 
934 			/* If a match, parse the rest of the data */
935 			if (c != NULL) {
936 				if (strcmp(c, policy_name) == 0) {
937 					ret = parsePolicyElement(node, plc);
938 					found = (ret == KMF_OK);
939 				}
940 				xmlFree(c);
941 			}
942 		}
943 		node = node->next;
944 	}
945 
946 	if (!found) {
947 		ret = KMF_ERR_POLICY_NOT_FOUND;
948 		goto out;
949 	}
950 
951 out:
952 	if (ctxt != NULL)
953 		xmlFreeParserCtxt(ctxt);
954 
955 	if (doc != NULL)
956 		xmlFreeDoc(doc);
957 
958 	return (ret);
959 }
960 
961 /*
962  * KMF_SetPolicy
963  *
964  * Set the policy record in the handle.  This searches
965  * the policy DB for the named policy.  If it is not found
966  * or an error occurred in processing, the existing policy
967  * is kept and an error code is returned.
968  */
969 KMF_RETURN
970 KMF_SetPolicy(KMF_HANDLE_T handle, char *policyfile, char *policyname)
971 {
972 	KMF_RETURN ret = KMF_OK;
973 	KMF_POLICY_RECORD *newpolicy = NULL;
974 
975 	CLEAR_ERROR(handle, ret);
976 	if (ret != KMF_OK)
977 		return (ret);
978 
979 	newpolicy = malloc(sizeof (KMF_POLICY_RECORD));
980 	if (newpolicy == NULL)
981 		return (KMF_ERR_MEMORY);
982 	(void) memset(newpolicy, 0, sizeof (KMF_POLICY_RECORD));
983 
984 	ret = KMF_GetPolicy(
985 	    policyfile == NULL ? KMF_DEFAULT_POLICY_FILE : policyfile,
986 	    policyname == NULL ? KMF_DEFAULT_POLICY_NAME : policyname,
987 	    newpolicy);
988 	if (ret != KMF_OK)
989 		goto out;
990 
991 	ret = KMF_VerifyPolicy(newpolicy);
992 	if (ret != KMF_OK)
993 		goto out;
994 
995 	/* release the existing policy data (if any). */
996 	if (handle->policy != NULL) {
997 		KMF_FreePolicyRecord(handle->policy);
998 		free(handle->policy);
999 	}
1000 
1001 	handle->policy = newpolicy;
1002 
1003 out:
1004 	/* Cleanup any data allocated before the error occurred */
1005 	if (ret != KMF_OK) {
1006 		KMF_FreePolicyRecord(newpolicy);
1007 		free(newpolicy);
1008 	}
1009 
1010 	return (ret);
1011 }
1012 
1013 
1014 static KMF_RETURN
1015 deletePolicyNode(xmlNodePtr node, char *policy_name)
1016 {
1017 	KMF_RETURN ret = KMF_OK;
1018 	int found = 0;
1019 	xmlNodePtr dnode = NULL;
1020 
1021 	while (node != NULL && !found) {
1022 		char *c;
1023 		/*
1024 		 * Search for the policy that matches the given name.
1025 		 */
1026 		if (!xmlStrcmp((const xmlChar *)node->name,
1027 			(const xmlChar *)KMF_POLICY_ELEMENT)) {
1028 			/* Check the name attribute */
1029 			c = (char *)xmlGetProp(node,
1030 				(const xmlChar *)KMF_POLICY_NAME_ATTR);
1031 
1032 			/* If a match, parse the rest of the data */
1033 			if (c != NULL) {
1034 				if (strcmp(c, policy_name) == 0) {
1035 					found = 1;
1036 					dnode = node;
1037 				}
1038 				xmlFree(c);
1039 			}
1040 		}
1041 		if (!found)
1042 			node = node->next;
1043 	}
1044 
1045 	if (found && dnode != NULL) {
1046 		/* Unlink the node */
1047 		xmlUnlinkNode(dnode);
1048 
1049 		/* Delete it from the document tree */
1050 		xmlFreeNode(dnode);
1051 	} else {
1052 		ret = KMF_ERR_POLICY_NOT_FOUND;
1053 	}
1054 
1055 	return (ret);
1056 }
1057 
1058 /*
1059  * update_policyfile
1060  *
1061  * Attempt to do a "safe" file update as follows:
1062  *  1. Lock the original file.
1063  *  2. Create and write to a temporary file
1064  *  3. Replace the original file with the temporary file.
1065  */
1066 static KMF_RETURN
1067 update_policyfile(xmlDocPtr doc, char *filename)
1068 {
1069 	KMF_RETURN ret = KMF_OK;
1070 	FILE *pfile, *tmpfile;
1071 	char tmpfilename[MAXPATHLEN];
1072 	char *p;
1073 	int prefix_len, tmpfd;
1074 	mode_t old_mode;
1075 
1076 	/*
1077 	 * Open and lock the DB file. First try to open an existing file,
1078 	 * if that fails, open it as if it were new.
1079 	 */
1080 	if ((pfile = fopen(filename, "r+")) == NULL && errno == ENOENT)
1081 		pfile = fopen(filename, "w+");
1082 
1083 	if (pfile == NULL)
1084 		return (KMF_ERR_POLICY_DB_FILE);
1085 
1086 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
1087 		(void) fclose(pfile);
1088 		return (KMF_ERR_POLICY_DB_FILE);
1089 	}
1090 
1091 	/*
1092 	 * Create a temporary file to hold the new data.
1093 	 */
1094 	(void) memset(tmpfilename, 0, sizeof (tmpfilename));
1095 	p = (char *)strrchr(filename, '/');
1096 	if (p == NULL) {
1097 		/*
1098 		 * filename contains basename only so we
1099 		 * create a temp file in current directory.
1100 		 */
1101 		if (strlcpy(tmpfilename, TMPFILE_TEMPLATE,
1102 		    sizeof (tmpfilename)) >= sizeof (tmpfilename))
1103 			return (KMF_ERR_INTERNAL);
1104 	} else {
1105 		/*
1106 		 * create a temp file in the same directory
1107 		 * as the policy file.
1108 		 */
1109 		prefix_len = p - filename;
1110 		(void) strncpy(tmpfilename, filename, prefix_len);
1111 		(void) strncat(tmpfilename, "/", 1);
1112 		(void) strncat(tmpfilename, TMPFILE_TEMPLATE,
1113 		    sizeof (TMPFILE_TEMPLATE));
1114 	}
1115 
1116 	old_mode = umask(077);
1117 	tmpfd = mkstemp(tmpfilename);
1118 	(void) umask(old_mode);
1119 	if (tmpfd == -1) {
1120 		return (KMF_ERR_POLICY_DB_FILE);
1121 	}
1122 
1123 	if ((tmpfile = fdopen(tmpfd, "w")) == NULL) {
1124 		(void) close(tmpfd);
1125 		(void) unlink(tmpfilename);
1126 		(void) fclose(pfile);
1127 		return (KMF_ERR_POLICY_DB_FILE);
1128 	}
1129 
1130 	/*
1131 	 * Write the new info to the temporary file.
1132 	 */
1133 	if (xmlDocFormatDump(tmpfile, doc, 1) == -1) {
1134 		(void) fclose(pfile);
1135 		(void) fclose(tmpfile);
1136 		(void) unlink(tmpfilename);
1137 		return (KMF_ERR_POLICY_ENGINE);
1138 	}
1139 
1140 	(void) fclose(pfile);
1141 
1142 	if (fchmod(tmpfd,
1143 		S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1144 		(void) close(tmpfd);
1145 		(void) unlink(tmpfilename);
1146 		return (KMF_ERR_POLICY_DB_FILE);
1147 	}
1148 	if (fclose(tmpfile) != 0)
1149 		return (KMF_ERR_POLICY_DB_FILE);
1150 
1151 	/*
1152 	 * Replace the original file with the updated tempfile.
1153 	 */
1154 	if (rename(tmpfilename, filename) == -1) {
1155 		ret = KMF_ERR_POLICY_DB_FILE;
1156 	}
1157 
1158 	if (ret != KMF_OK) {
1159 		/* try to remove the tmp file */
1160 		(void) unlink(tmpfilename);
1161 	}
1162 
1163 	return (ret);
1164 }
1165 
1166 /*
1167  * DeletePolicyFromDB
1168  *
1169  * Find a policy by name and remove it from the policy DB file.
1170  * If the policy is not found, return an error.
1171  */
1172 KMF_RETURN
1173 KMF_DeletePolicyFromDB(char *policy_name, char *dbfilename)
1174 {
1175 	KMF_RETURN ret;
1176 	xmlParserCtxtPtr ctxt = NULL;
1177 	xmlDocPtr doc = NULL;
1178 	xmlNodePtr cur, node;
1179 
1180 	if (policy_name == NULL || dbfilename == NULL)
1181 		return (KMF_ERR_BAD_PARAMETER);
1182 
1183 	/*
1184 	 * Cannot delete the default policy record from the system
1185 	 * default policy database (/etc/security/kmfpolicy.xml).
1186 	 */
1187 	if (strcmp(dbfilename, KMF_DEFAULT_POLICY_FILE) == 0 &&
1188 	    strcmp(policy_name, KMF_DEFAULT_POLICY_NAME) == 0)
1189 		return (KMF_ERR_BAD_PARAMETER);
1190 
1191 	/* Make sure the policy file exists */
1192 	if (access(dbfilename, R_OK | W_OK))
1193 		return (KMF_ERR_BAD_PARAMETER);
1194 
1195 	/* Read the policy DB and verify it against the schema. */
1196 	ctxt = xmlNewParserCtxt();
1197 	if (ctxt == NULL)
1198 		return (KMF_ERR_POLICY_DB_FORMAT);
1199 
1200 	doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
1201 	    XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
1202 	if (doc == NULL || ctxt->valid == 0) {
1203 		ret = KMF_ERR_POLICY_DB_FORMAT;
1204 		goto end;
1205 	}
1206 
1207 	cur = xmlDocGetRootElement(doc);
1208 	if (cur == NULL) {
1209 		xmlFreeDoc(doc);
1210 		return (KMF_ERR_POLICY_DB_FORMAT);
1211 	}
1212 	node = cur->xmlChildrenNode;
1213 
1214 	ret = deletePolicyNode(node, policy_name);
1215 
1216 	if (ret == KMF_OK)
1217 		ret = update_policyfile(doc, dbfilename);
1218 
1219 end:
1220 	if (ctxt != NULL)
1221 		xmlFreeParserCtxt(ctxt);
1222 
1223 	if (doc != NULL)
1224 		xmlFreeDoc(doc);
1225 
1226 	return (ret);
1227 }
1228 
1229 /*
1230  * Add a new policy node to the Policy DB XML tree.
1231  */
1232 static KMF_RETURN
1233 addPolicyNode(xmlNodePtr pnode, KMF_POLICY_RECORD *policy)
1234 {
1235 	KMF_RETURN ret = KMF_OK;
1236 
1237 	if (pnode != NULL && policy != NULL) {
1238 		if (newprop(pnode, KMF_POLICY_NAME_ATTR, policy->name) != 0) {
1239 			ret = KMF_ERR_POLICY_ENGINE;
1240 			goto out;
1241 		}
1242 		if (policy->ignore_date) {
1243 			if (newprop(pnode, KMF_OPTIONS_IGNORE_DATE_ATTR,
1244 				"TRUE")) {
1245 				ret = KMF_ERR_POLICY_ENGINE;
1246 				goto out;
1247 			}
1248 		}
1249 
1250 		if (policy->ignore_unknown_ekus) {
1251 			if (newprop(pnode, KMF_OPTIONS_IGNORE_UNKNOWN_EKUS,
1252 				"TRUE")) {
1253 				ret = KMF_ERR_POLICY_ENGINE;
1254 				goto out;
1255 			}
1256 		}
1257 
1258 		if (policy->ignore_trust_anchor) {
1259 			if (newprop(pnode, KMF_OPTIONS_IGNORE_TRUST_ANCHOR,
1260 				"TRUE")) {
1261 				ret = KMF_ERR_POLICY_ENGINE;
1262 				goto out;
1263 			}
1264 		}
1265 
1266 		if (policy->validity_adjusttime) {
1267 			if (newprop(pnode, KMF_OPTIONS_VALIDITY_ADJUSTTIME,
1268 				policy->validity_adjusttime)) {
1269 				ret = KMF_ERR_POLICY_ENGINE;
1270 				goto out;
1271 			}
1272 		}
1273 
1274 		if (newprop(pnode, KMF_POLICY_TA_NAME_ATTR,
1275 		    policy->ta_name) != 0) {
1276 			ret = KMF_ERR_POLICY_ENGINE;
1277 			goto out;
1278 		}
1279 
1280 		if (newprop(pnode, KMF_POLICY_TA_SERIAL_ATTR,
1281 		    policy->ta_serial) != 0) {
1282 			ret = KMF_ERR_POLICY_ENGINE;
1283 			goto out;
1284 		}
1285 
1286 		/* Add a text node for readability */
1287 		addFormatting(pnode, "\n");
1288 
1289 		if (ret = AddValidationNodes(pnode, policy)) {
1290 			goto out;
1291 		}
1292 
1293 		if ((ret = AddKeyUsageNodes(pnode, policy->ku_bits))) {
1294 			goto out;
1295 		}
1296 
1297 		if ((ret = AddExtKeyUsageNodes(pnode, &policy->eku_set))) {
1298 			goto out;
1299 		}
1300 	} else {
1301 		ret = KMF_ERR_BAD_PARAMETER;
1302 	}
1303 out:
1304 	if (ret != KMF_OK && pnode != NULL) {
1305 		xmlUnlinkNode(pnode);
1306 		xmlFreeNode(pnode);
1307 	}
1308 
1309 	return (ret);
1310 }
1311 
1312 
1313 KMF_RETURN
1314 KMF_VerifyPolicy(KMF_POLICY_RECORD *policy)
1315 {
1316 	KMF_RETURN ret = KMF_OK;
1317 	boolean_t has_ta;
1318 
1319 	if (policy->name == NULL || !strlen(policy->name))
1320 		return (KMF_ERR_POLICY_NAME);
1321 
1322 	/* Check the TA related policy */
1323 	if (policy->ta_name != NULL && policy->ta_serial != NULL) {
1324 		has_ta = B_TRUE;
1325 	} else if (policy->ta_name == NULL && policy->ta_serial == NULL) {
1326 		has_ta = B_FALSE;
1327 	} else {
1328 		/*
1329 		 * If the TA cert is set, then both name and serial number
1330 		 * need to be specified.
1331 		 */
1332 		return (KMF_ERR_TA_POLICY);
1333 	}
1334 
1335 	if (has_ta == B_FALSE && policy->ignore_trust_anchor == B_FALSE)
1336 		return (KMF_ERR_TA_POLICY);
1337 
1338 	if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
1339 		/*
1340 		 * For OCSP, either use a fixed responder or use the
1341 		 * value from the cert, but not both.
1342 		 */
1343 		if ((policy->VAL_OCSP_BASIC.responderURI == NULL &&
1344 		    policy->VAL_OCSP_BASIC.uri_from_cert == B_FALSE) ||
1345 		    (policy->VAL_OCSP_BASIC.responderURI != NULL &&
1346 		    policy->VAL_OCSP_BASIC.uri_from_cert == B_TRUE))
1347 			return (KMF_ERR_OCSP_POLICY);
1348 
1349 		/*
1350 		 * If the OCSP responder cert is set, then both name and serial
1351 		 * number need to be specified.
1352 		 */
1353 		if ((policy->VAL_OCSP_RESP_CERT.name != NULL &&
1354 		    policy->VAL_OCSP_RESP_CERT.serial == NULL) ||
1355 		    (policy->VAL_OCSP_RESP_CERT.name == NULL &&
1356 		    policy->VAL_OCSP_RESP_CERT.serial != NULL))
1357 			return (KMF_ERR_OCSP_POLICY);
1358 	}
1359 
1360 	return (ret);
1361 }
1362 
1363 /*
1364  * Update the KMF policy file by creating a new XML Policy doc tree
1365  * from the data in the KMF_POLICY_RECORD structure. If "check_policy"
1366  * is true, then we check the policy sanity also.
1367  */
1368 KMF_RETURN
1369 KMF_AddPolicyToDB(KMF_POLICY_RECORD *policy, char *dbfilename,
1370     boolean_t check_policy)
1371 {
1372 	KMF_RETURN ret = KMF_OK;
1373 	xmlDocPtr doc = NULL;
1374 	xmlNodePtr root, node;
1375 	xmlParserCtxtPtr ctxt = NULL;
1376 
1377 	if (policy == NULL || dbfilename == NULL)
1378 		return (KMF_ERR_BAD_PARAMETER);
1379 
1380 	if (check_policy == B_TRUE) {
1381 		if (ret = KMF_VerifyPolicy(policy))
1382 		    return (ret);
1383 	}
1384 
1385 	/* If the policyDB exists, load it into memory */
1386 	if (!access(dbfilename, R_OK)) {
1387 
1388 		/* Create a parser context */
1389 		ctxt = xmlNewParserCtxt();
1390 		if (ctxt == NULL)
1391 			return (KMF_ERR_POLICY_DB_FORMAT);
1392 
1393 		doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
1394 		    XML_PARSE_DTDVALID | XML_PARSE_NOERROR |
1395 		    XML_PARSE_NOWARNING);
1396 		if (doc == NULL || ctxt->valid == 0) {
1397 			ret = KMF_ERR_POLICY_DB_FORMAT;
1398 			goto out;
1399 		}
1400 
1401 		root = xmlDocGetRootElement(doc);
1402 		if (root == NULL) {
1403 			ret = KMF_ERR_POLICY_DB_FORMAT;
1404 			goto out;
1405 		}
1406 
1407 		node = root->xmlChildrenNode;
1408 		/*
1409 		 * If the DB has an existing policy of the
1410 		 * same name, delete it from the tree.
1411 		 */
1412 		ret = deletePolicyNode(node, policy->name);
1413 		if (ret == KMF_ERR_POLICY_NOT_FOUND)
1414 			ret = KMF_OK;
1415 	} else {
1416 		/* Initialize a new DB tree */
1417 		doc = xmlNewDoc((const xmlChar *)"1.0");
1418 		if (doc == NULL)
1419 			return (KMF_ERR_POLICY_ENGINE);
1420 
1421 		/*
1422 		 * Add the DOCTYPE header to the tree so the
1423 		 * DTD link is embedded
1424 		 */
1425 		doc->intSubset = xmlCreateIntSubset(doc,
1426 			(const xmlChar *)KMF_POLICY_ROOT,
1427 			NULL, (const xmlChar *)KMF_POLICY_DTD);
1428 
1429 		root = xmlNewDocNode(doc, NULL,
1430 			(const xmlChar *)KMF_POLICY_ROOT, NULL);
1431 		if (root != NULL) {
1432 			xmlDocSetRootElement(doc, root);
1433 		}
1434 	}
1435 
1436 	/* Append the new policy info to the root node. */
1437 	if (root != NULL) {
1438 		xmlNodePtr pnode;
1439 
1440 		pnode = xmlNewChild(root, NULL,
1441 			(const xmlChar *)KMF_POLICY_ELEMENT, NULL);
1442 
1443 		ret = addPolicyNode(pnode, policy);
1444 		/* If that worked, update the DB file. */
1445 		if (ret == KMF_OK)
1446 			ret = update_policyfile(doc, dbfilename);
1447 	} else {
1448 		ret = KMF_ERR_POLICY_ENGINE;
1449 	}
1450 
1451 
1452 out:
1453 	if (ctxt != NULL)
1454 		xmlFreeParserCtxt(ctxt);
1455 
1456 	if (doc != NULL)
1457 		xmlFreeDoc(doc);
1458 
1459 	return (ret);
1460 }
1461