xref: /illumos-gate/usr/src/lib/libkmf/libkmf/common/policy.c (revision 30a5e8fa1253cb33980ee4514743cf683f584b4e)
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 <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 kmf_ku_to_string(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 uint32_t
222 kmf_string_to_ku(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_string_to_ku(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_ekuname_to_oid(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_oid_to_eku_string(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 static KMF_RETURN
323 parseExtKeyUsage(xmlNodePtr node, KMF_EKU_POLICY *ekus)
324 {
325 	xmlNodePtr n;
326 	char *c;
327 	KMF_RETURN ret = KMF_OK;
328 	boolean_t found = FALSE;
329 
330 	n = node->children;
331 	while (n != NULL && ret == KMF_OK) {
332 		KMF_OID newoid, *oidptr;
333 
334 		oidptr = NULL;
335 		newoid.Data = NULL;
336 		newoid.Length = 0;
337 
338 		if (!xmlStrcmp((const xmlChar *)n->name,
339 		    (const xmlChar *)KMF_EKU_NAME_ELEMENT)) {
340 			c = (char *)xmlGetProp(n,
341 			    (const xmlChar *)KMF_EKU_NAME_ATTR);
342 			if (c != NULL) {
343 				oidptr = kmf_ekuname_to_oid(c);
344 				xmlFree(c);
345 				found = TRUE;
346 				if (oidptr != NULL)
347 					newoid = *oidptr;
348 			}
349 		} else if (!xmlStrcmp((const xmlChar *)n->name,
350 		    (const xmlChar *)KMF_EKU_OID_ELEMENT)) {
351 			c = (char *)xmlGetProp(n,
352 			    (const xmlChar *)KMF_EKU_OID_ATTR);
353 			if (c != NULL) {
354 				(void) kmf_string_to_oid(c, &newoid);
355 				xmlFree(c);
356 				found = TRUE;
357 			}
358 		} else {
359 			n = n->next;
360 			if ((n == NULL) && (!found))
361 				ret = KMF_ERR_POLICY_DB_FORMAT;
362 			continue;
363 		}
364 
365 		if (newoid.Data != NULL) {
366 			ekus->eku_count++;
367 			ekus->ekulist = realloc(ekus->ekulist,
368 			    ekus->eku_count * sizeof (KMF_OID));
369 			if (ekus->ekulist != NULL) {
370 				ekus->ekulist[ekus->eku_count-1].Length =
371 				    newoid.Length;
372 				ekus->ekulist[ekus->eku_count-1].Data =
373 				    newoid.Data;
374 			} else {
375 				ret = KMF_ERR_MEMORY;
376 			}
377 		} else {
378 			ret = KMF_ERR_POLICY_DB_FORMAT;
379 		}
380 
381 		n = n->next;
382 	}
383 
384 	return (ret);
385 }
386 
387 int
388 parsePolicyElement(xmlNodePtr node, KMF_POLICY_RECORD *policy)
389 {
390 	int ret = 0;
391 	xmlNodePtr n = node->xmlChildrenNode;
392 	char *c;
393 
394 	if (node->type == XML_ELEMENT_NODE) {
395 		if (node->properties != NULL) {
396 			policy->name = (char *)xmlGetProp(node,
397 			    (const xmlChar *)KMF_POLICY_NAME_ATTR);
398 
399 			c = (char *)xmlGetProp(node,
400 			    (const xmlChar *)KMF_OPTIONS_IGNORE_DATE_ATTR);
401 			if (c && !strcasecmp(c, "true")) {
402 				policy->ignore_date = 1;
403 				xmlFree((xmlChar *)c);
404 			}
405 
406 			c = (char *)xmlGetProp(node,
407 			    (const xmlChar *)KMF_OPTIONS_IGNORE_UNKNOWN_EKUS);
408 			if (c && !strcasecmp(c, "true")) {
409 				policy->ignore_unknown_ekus = 1;
410 				xmlFree(c);
411 			}
412 
413 			c = (char *)xmlGetProp(node,
414 			    (const xmlChar *)KMF_OPTIONS_IGNORE_TRUST_ANCHOR);
415 			if (c && !strcasecmp(c, "true")) {
416 				policy->ignore_trust_anchor = 1;
417 				xmlFree(c);
418 			}
419 
420 			c = (char *)xmlGetProp(node,
421 			    (const xmlChar *)KMF_OPTIONS_VALIDITY_ADJUSTTIME);
422 			if (c) {
423 				policy->validity_adjusttime = c;
424 			} else {
425 				policy->validity_adjusttime = NULL;
426 			}
427 
428 			policy->ta_name = (char *)xmlGetProp(node,
429 			    (const xmlChar *)KMF_POLICY_TA_NAME_ATTR);
430 
431 			policy->ta_serial = (char *)xmlGetProp(node,
432 			    (const xmlChar *)KMF_POLICY_TA_SERIAL_ATTR);
433 		}
434 
435 		n = node->children;
436 		while (n != NULL) {
437 			if (!xmlStrcmp((const xmlChar *)n->name,
438 			    (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT))
439 				parseValidation(n, &policy->validation_info,
440 				    policy);
441 			else if (!xmlStrcmp((const xmlChar *)n->name,
442 			    (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT))
443 				parseKeyUsageSet(n, &policy->ku_bits);
444 			else if (!xmlStrcmp((const xmlChar *)n->name,
445 			    (const xmlChar *)KMF_EKU_ELEMENT)) {
446 				ret = parseExtKeyUsage(n, &policy->eku_set);
447 				if (ret != KMF_OK)
448 					return (ret);
449 			}
450 
451 			n = n->next;
452 		}
453 	}
454 
455 	return (ret);
456 }
457 
458 static int
459 newprop(xmlNodePtr node, char *attrname, char *src)
460 {
461 	xmlAttrPtr newattr;
462 
463 	if (src != NULL && strlen(src)) {
464 		newattr = xmlNewProp(node, (const xmlChar *)attrname,
465 		    (xmlChar *)src);
466 		if (newattr == NULL) {
467 			xmlUnlinkNode(node);
468 			xmlFreeNode(node);
469 			return (-1);
470 		}
471 	}
472 	return (0);
473 }
474 
475 /*
476  * Add CRL policy information to the XML tree.
477  * Return non-zero on any failure, else 0 for success.
478  *
479  * This function is called only when the KMF_REVOCATION_METHOD_CRL flag is on.
480  */
481 static int
482 AddCRLNodes(xmlNodePtr node, KMF_CRL_POLICY *crlinfo)
483 {
484 	xmlNodePtr n;
485 
486 	addFormatting(node, "\t\t");
487 	n = xmlNewChild(node, NULL, (const xmlChar *)"crl", NULL);
488 	if (n == NULL)
489 		return (-1);
490 
491 	if (crlinfo->basefilename &&
492 	    newprop(n, KMF_CRL_BASENAME_ATTR, crlinfo->basefilename))
493 		return (-1);
494 
495 	if (crlinfo->directory &&
496 	    newprop(n, KMF_CRL_DIRECTORY_ATTR, crlinfo->directory))
497 		return (-1);
498 
499 	if (crlinfo->get_crl_uri &&
500 	    newprop(n, KMF_CRL_GET_URI_ATTR, "TRUE")) {
501 		return (-1);
502 	}
503 
504 	if (crlinfo->proxy &&
505 	    newprop(n, KMF_CRL_PROXY_ATTR, crlinfo->proxy))
506 		return (-1);
507 
508 	if (crlinfo->ignore_crl_sign &&
509 	    newprop(n, KMF_CRL_IGNORE_SIGN_ATTR, "TRUE")) {
510 		return (-1);
511 	}
512 
513 	if (crlinfo->ignore_crl_date &&
514 	    newprop(n, KMF_CRL_IGNORE_DATE_ATTR, "TRUE")) {
515 		return (-1);
516 	}
517 
518 	addFormatting(node, "\n");
519 	return (0);
520 }
521 
522 /*
523  * Add OCSP information to the policy tree.
524  * Return non-zero on any failure, else 0 for success.
525  *
526  * This function is called only when the KMF_REVOCATION_METHOD_OCSP flag is on.
527  */
528 static int
529 AddOCSPNodes(xmlNodePtr parent, KMF_OCSP_POLICY *ocsp)
530 {
531 	int ret = 0;
532 	xmlNodePtr n_ocsp, n_basic, n_resp;
533 	KMF_OCSP_BASIC_POLICY *basic;
534 	KMF_RESP_CERT_POLICY *resp_cert;
535 
536 	basic = &(ocsp->basic);
537 	resp_cert = &(ocsp->resp_cert);
538 
539 	if (basic->responderURI != NULL || basic->uri_from_cert == B_TRUE) {
540 
541 		addFormatting(parent, "\t\t");
542 
543 		/* basic node */
544 		n_ocsp = xmlNewChild(parent, NULL,
545 		    (const xmlChar *)KMF_OCSP_ELEMENT, NULL);
546 		if (n_ocsp == NULL)
547 			return (-1);
548 		addFormatting(n_ocsp, "\n\t\t\t");
549 
550 		n_basic = xmlNewChild(n_ocsp, NULL,
551 		    (const xmlChar *)KMF_OCSP_BASIC_ELEMENT, NULL);
552 		if (n_basic == NULL)
553 			return (-1);
554 		if (basic->responderURI && newprop(n_basic,
555 		    KMF_OCSP_RESPONDER_ATTR, basic->responderURI))
556 			return (-1);
557 		if (basic->proxy &&
558 		    newprop(n_basic, KMF_OCSP_PROXY_ATTR, basic->proxy))
559 			return (-1);
560 		if (basic->uri_from_cert &&
561 		    newprop(n_basic, KMF_OCSP_URI_ATTR, "TRUE"))
562 			return (-1);
563 		if (basic->response_lifetime &&
564 		    newprop(n_basic, KMF_OCSP_RESPONSE_LIFETIME_ATTR,
565 		    basic->response_lifetime))
566 			return (-1);
567 		if (basic->ignore_response_sign &&
568 		    newprop(n_basic, KMF_OCSP_IGNORE_SIGN_ATTR, "TRUE"))
569 			return (-1);
570 
571 		addFormatting(n_ocsp, "\n\t\t\t");
572 
573 		/* responder cert node */
574 		if (ocsp->has_resp_cert) {
575 			n_resp = xmlNewChild(n_ocsp, NULL,
576 			    (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT,
577 			    NULL);
578 			if (n_resp == NULL)
579 				return (-1);
580 			if (newprop(n_resp, KMF_CERT_NAME_ATTR,
581 			    resp_cert->name))
582 				return (-1);
583 			if (newprop(n_resp, KMF_CERT_SERIAL_ATTR,
584 			    resp_cert->serial))
585 				return (-1);
586 		}
587 		addFormatting(n_ocsp, "\n\t\t");
588 	}
589 
590 	addFormatting(parent, "\n");
591 	return (ret);
592 }
593 
594 /*
595  * Add validation method information to the policy tree.
596  * Return non-zero on any failure, else 0 for success.
597  */
598 static int
599 AddValidationNodes(xmlNodePtr parent, KMF_POLICY_RECORD *policy)
600 {
601 	xmlNodePtr mnode;
602 	int ret = 0;
603 
604 	addFormatting(parent, "\t");
605 	mnode = xmlNewChild(parent, NULL,
606 	    (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT, NULL);
607 	if (mnode == NULL)
608 		return (-1);
609 
610 	addFormatting(mnode, "\n");
611 
612 	if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
613 		ret = AddOCSPNodes(mnode, &(policy->validation_info.ocsp_info));
614 		if (ret != KMF_OK)
615 			goto end;
616 	}
617 
618 	if (policy->revocation & KMF_REVOCATION_METHOD_CRL) {
619 		ret = AddCRLNodes(mnode, &(policy->validation_info.crl_info));
620 		if (ret != KMF_OK)
621 			goto end;
622 	}
623 
624 	addFormatting(mnode, "\t");
625 	addFormatting(parent, "\n");
626 
627 end:
628 	if (ret != 0) {
629 		xmlUnlinkNode(mnode);
630 		xmlFreeNode(mnode);
631 	}
632 	return (ret);
633 
634 }
635 
636 /*
637  * Add Key Usage information to the policy tree.
638  * Return non-zero on any failure, else 0 for success.
639  */
640 static KMF_RETURN
641 AddKeyUsageNodes(xmlNodePtr parent, uint32_t kubits)
642 {
643 	int ret = KMF_OK;
644 	int i;
645 
646 	xmlNodePtr kuset, kunode;
647 
648 	if (kubits == 0)
649 		return (0);
650 
651 	addFormatting(parent, "\n\t");
652 	kuset = xmlNewChild(parent, NULL,
653 	    (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT, NULL);
654 	if (kuset == NULL)
655 		return (KMF_ERR_POLICY_ENGINE);
656 
657 	for (i = KULOWBIT; i <= KUHIGHBIT && ret == KMF_OK; i++) {
658 		char *s = kmf_ku_to_string((kubits & (1<<i)));
659 		if (s != NULL) {
660 			addFormatting(kuset, "\n\t\t");
661 
662 			kunode = xmlNewChild(kuset, NULL,
663 			    (const xmlChar *)KMF_KEY_USAGE_ELEMENT, NULL);
664 			if (kunode == NULL)
665 				ret = KMF_ERR_POLICY_ENGINE;
666 
667 			else if (newprop(kunode, KMF_KEY_USAGE_USE_ATTR, s))
668 				ret = KMF_ERR_POLICY_ENGINE;
669 		}
670 	}
671 	addFormatting(kuset, "\n\t");
672 	addFormatting(parent, "\n");
673 
674 	if (ret != KMF_OK) {
675 		xmlUnlinkNode(kuset);
676 		xmlFreeNode(kuset);
677 	}
678 
679 	return (ret);
680 }
681 
682 /*
683  * Add Extended-Key-Usage information to the policy tree.
684  * Return non-zero on any failure, else 0 for success.
685  */
686 static KMF_RETURN
687 AddExtKeyUsageNodes(xmlNodePtr parent, KMF_EKU_POLICY *ekus)
688 {
689 	KMF_RETURN ret = KMF_OK;
690 	xmlNodePtr n, kunode;
691 	int i;
692 
693 	if (ekus != NULL && ekus->eku_count > 0) {
694 		addFormatting(parent, "\n\t");
695 		n = xmlNewChild(parent, NULL,
696 		    (const xmlChar *)KMF_EKU_ELEMENT, NULL);
697 		if (n == NULL)
698 			return (KMF_ERR_POLICY_ENGINE);
699 
700 		for (i = 0; i < ekus->eku_count; i++) {
701 			char *s = kmf_oid_to_string(&ekus->ekulist[i]);
702 			if (s != NULL) {
703 				addFormatting(n, "\n\t\t");
704 				kunode = xmlNewChild(n, NULL,
705 				    (const xmlChar *)KMF_EKU_OID_ELEMENT,
706 				    NULL);
707 				if (kunode == NULL)
708 					ret = KMF_ERR_POLICY_ENGINE;
709 
710 				else if (newprop(kunode, KMF_EKU_OID_ATTR, s))
711 					ret = KMF_ERR_POLICY_ENGINE;
712 				free(s);
713 			} else {
714 				ret = KMF_ERR_POLICY_ENGINE;
715 			}
716 		}
717 		addFormatting(n, "\n\t");
718 		addFormatting(parent, "\n");
719 	}
720 
721 	if (ret != KMF_OK) {
722 		xmlUnlinkNode(n);
723 		xmlFreeNode(n);
724 	}
725 	return (ret);
726 }
727 
728 void
729 kmf_free_eku_policy(KMF_EKU_POLICY *ekus)
730 {
731 	if (ekus->eku_count > 0) {
732 		int i;
733 		for (i = 0; i < ekus->eku_count; i++) {
734 			kmf_free_data(&ekus->ekulist[i]);
735 		}
736 		free(ekus->ekulist);
737 	}
738 }
739 
740 #define	FREE_POLICY_STR(s) if (s != NULL) free(s);
741 
742 void
743 kmf_free_policy_record(KMF_POLICY_RECORD *policy)
744 {
745 	if (policy == NULL)
746 		return;
747 
748 	FREE_POLICY_STR(policy->name)
749 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.responderURI)
750 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.proxy)
751 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.response_lifetime)
752 	FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.name)
753 	FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.serial)
754 	FREE_POLICY_STR(policy->validation_info.crl_info.basefilename)
755 	FREE_POLICY_STR(policy->validation_info.crl_info.directory)
756 	FREE_POLICY_STR(policy->validation_info.crl_info.proxy)
757 	FREE_POLICY_STR(policy->validity_adjusttime)
758 	FREE_POLICY_STR(policy->ta_name)
759 	FREE_POLICY_STR(policy->ta_serial)
760 
761 	kmf_free_eku_policy(&policy->eku_set);
762 
763 	(void) memset(policy, 0, sizeof (KMF_POLICY_RECORD));
764 }
765 
766 /*
767  * kmf_get_policy
768  *
769  * Find a policy record in the database.
770  */
771 KMF_RETURN
772 kmf_get_policy(char *filename, char *policy_name, KMF_POLICY_RECORD *plc)
773 {
774 	KMF_RETURN ret = KMF_OK;
775 	xmlParserCtxtPtr ctxt;
776 	xmlDocPtr doc = NULL;
777 	xmlNodePtr cur, node;
778 	int found = 0;
779 
780 	if (filename == NULL || policy_name == NULL || plc == NULL)
781 		return (KMF_ERR_BAD_PARAMETER);
782 
783 	(void) memset(plc, 0, sizeof (KMF_POLICY_RECORD));
784 
785 	/* Create a parser context */
786 	ctxt = xmlNewParserCtxt();
787 	if (ctxt == NULL)
788 		return (KMF_ERR_POLICY_DB_FORMAT);
789 
790 	/* Read the policy DB and verify it against the schema. */
791 	doc = xmlCtxtReadFile(ctxt, filename, NULL,
792 	    XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
793 	if (doc == NULL || ctxt->valid == 0) {
794 		ret = KMF_ERR_POLICY_DB_FORMAT;
795 		goto out;
796 	}
797 
798 	cur = xmlDocGetRootElement(doc);
799 	if (cur == NULL) {
800 		ret = KMF_ERR_POLICY_DB_FORMAT;
801 		goto out;
802 	}
803 
804 	node = cur->xmlChildrenNode;
805 	while (node != NULL && !found) {
806 		char *c;
807 		/*
808 		 * Search for the policy that matches the given name.
809 		 */
810 		if (!xmlStrcmp((const xmlChar *)node->name,
811 		    (const xmlChar *)KMF_POLICY_ELEMENT)) {
812 			/* Check the name attribute */
813 			c = (char *)xmlGetProp(node,
814 			    (const xmlChar *)KMF_POLICY_NAME_ATTR);
815 
816 			/* If a match, parse the rest of the data */
817 			if (c != NULL) {
818 				if (strcmp(c, policy_name) == 0) {
819 					ret = parsePolicyElement(node, plc);
820 					found = (ret == KMF_OK);
821 				}
822 				xmlFree(c);
823 			}
824 		}
825 		node = node->next;
826 	}
827 
828 	if (!found) {
829 		ret = KMF_ERR_POLICY_NOT_FOUND;
830 		goto out;
831 	}
832 
833 out:
834 	if (ctxt != NULL)
835 		xmlFreeParserCtxt(ctxt);
836 
837 	if (doc != NULL)
838 		xmlFreeDoc(doc);
839 
840 	return (ret);
841 }
842 
843 /*
844  * kmf_set_policy
845  *
846  * Set the policy record in the handle.  This searches
847  * the policy DB for the named policy.  If it is not found
848  * or an error occurred in processing, the existing policy
849  * is kept and an error code is returned.
850  */
851 KMF_RETURN
852 kmf_set_policy(KMF_HANDLE_T handle, char *policyfile, char *policyname)
853 {
854 	KMF_RETURN ret = KMF_OK;
855 	KMF_POLICY_RECORD *newpolicy = NULL;
856 
857 	CLEAR_ERROR(handle, ret);
858 	if (ret != KMF_OK)
859 		return (ret);
860 
861 	newpolicy = malloc(sizeof (KMF_POLICY_RECORD));
862 	if (newpolicy == NULL)
863 		return (KMF_ERR_MEMORY);
864 	(void) memset(newpolicy, 0, sizeof (KMF_POLICY_RECORD));
865 
866 	ret = kmf_get_policy(
867 	    policyfile == NULL ? KMF_DEFAULT_POLICY_FILE : policyfile,
868 	    policyname == NULL ? KMF_DEFAULT_POLICY_NAME : policyname,
869 	    newpolicy);
870 	if (ret != KMF_OK)
871 		goto out;
872 
873 	ret = kmf_verify_policy(newpolicy);
874 	if (ret != KMF_OK)
875 		goto out;
876 
877 	/* release the existing policy data (if any). */
878 	if (handle->policy != NULL) {
879 		kmf_free_policy_record(handle->policy);
880 		free(handle->policy);
881 	}
882 
883 	handle->policy = newpolicy;
884 
885 out:
886 	/* Cleanup any data allocated before the error occurred */
887 	if (ret != KMF_OK) {
888 		kmf_free_policy_record(newpolicy);
889 		free(newpolicy);
890 	}
891 
892 	return (ret);
893 }
894 
895 
896 static KMF_RETURN
897 deletePolicyNode(xmlNodePtr node, char *policy_name)
898 {
899 	KMF_RETURN ret = KMF_OK;
900 	int found = 0;
901 	xmlNodePtr dnode = NULL;
902 
903 	while (node != NULL && !found) {
904 		char *c;
905 		/*
906 		 * Search for the policy that matches the given name.
907 		 */
908 		if (!xmlStrcmp((const xmlChar *)node->name,
909 		    (const xmlChar *)KMF_POLICY_ELEMENT)) {
910 			/* Check the name attribute */
911 			c = (char *)xmlGetProp(node,
912 			    (const xmlChar *)KMF_POLICY_NAME_ATTR);
913 
914 			/* If a match, parse the rest of the data */
915 			if (c != NULL) {
916 				if (strcmp(c, policy_name) == 0) {
917 					found = 1;
918 					dnode = node;
919 				}
920 				xmlFree(c);
921 			}
922 		}
923 		if (!found)
924 			node = node->next;
925 	}
926 
927 	if (found && dnode != NULL) {
928 		/* Unlink the node */
929 		xmlUnlinkNode(dnode);
930 
931 		/* Delete it from the document tree */
932 		xmlFreeNode(dnode);
933 	} else {
934 		ret = KMF_ERR_POLICY_NOT_FOUND;
935 	}
936 
937 	return (ret);
938 }
939 
940 /*
941  * update_policyfile
942  *
943  * Attempt to do a "safe" file update as follows:
944  *  1. Lock the original file.
945  *  2. Create and write to a temporary file
946  *  3. Replace the original file with the temporary file.
947  */
948 static KMF_RETURN
949 update_policyfile(xmlDocPtr doc, char *filename)
950 {
951 	KMF_RETURN ret = KMF_OK;
952 	FILE *pfile, *tmpfile;
953 	char tmpfilename[MAXPATHLEN];
954 	char *p;
955 	int prefix_len, tmpfd;
956 	mode_t old_mode;
957 
958 	/*
959 	 * Open and lock the DB file. First try to open an existing file,
960 	 * if that fails, open it as if it were new.
961 	 */
962 	if ((pfile = fopen(filename, "r+")) == NULL && errno == ENOENT)
963 		pfile = fopen(filename, "w+");
964 
965 	if (pfile == NULL)
966 		return (KMF_ERR_POLICY_DB_FILE);
967 
968 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
969 		(void) fclose(pfile);
970 		return (KMF_ERR_POLICY_DB_FILE);
971 	}
972 
973 	/*
974 	 * Create a temporary file to hold the new data.
975 	 */
976 	(void) memset(tmpfilename, 0, sizeof (tmpfilename));
977 	p = (char *)strrchr(filename, '/');
978 	if (p == NULL) {
979 		/*
980 		 * filename contains basename only so we
981 		 * create a temp file in current directory.
982 		 */
983 		if (strlcpy(tmpfilename, TMPFILE_TEMPLATE,
984 		    sizeof (tmpfilename)) >= sizeof (tmpfilename))
985 			return (KMF_ERR_INTERNAL);
986 	} else {
987 		/*
988 		 * create a temp file in the same directory
989 		 * as the policy file.
990 		 */
991 		prefix_len = p - filename;
992 		(void) strncpy(tmpfilename, filename, prefix_len);
993 		(void) strncat(tmpfilename, "/", 1);
994 		(void) strncat(tmpfilename, TMPFILE_TEMPLATE,
995 		    sizeof (TMPFILE_TEMPLATE));
996 	}
997 
998 	old_mode = umask(077);
999 	tmpfd = mkstemp(tmpfilename);
1000 	(void) umask(old_mode);
1001 	if (tmpfd == -1) {
1002 		return (KMF_ERR_POLICY_DB_FILE);
1003 	}
1004 
1005 	if ((tmpfile = fdopen(tmpfd, "w")) == NULL) {
1006 		(void) close(tmpfd);
1007 		(void) unlink(tmpfilename);
1008 		(void) fclose(pfile);
1009 		return (KMF_ERR_POLICY_DB_FILE);
1010 	}
1011 
1012 	/*
1013 	 * Write the new info to the temporary file.
1014 	 */
1015 	if (xmlDocFormatDump(tmpfile, doc, 1) == -1) {
1016 		(void) fclose(pfile);
1017 		(void) fclose(tmpfile);
1018 		(void) unlink(tmpfilename);
1019 		return (KMF_ERR_POLICY_ENGINE);
1020 	}
1021 
1022 	(void) fclose(pfile);
1023 
1024 	if (fchmod(tmpfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1025 		(void) close(tmpfd);
1026 		(void) unlink(tmpfilename);
1027 		return (KMF_ERR_POLICY_DB_FILE);
1028 	}
1029 	if (fclose(tmpfile) != 0)
1030 		return (KMF_ERR_POLICY_DB_FILE);
1031 
1032 	/*
1033 	 * Replace the original file with the updated tempfile.
1034 	 */
1035 	if (rename(tmpfilename, filename) == -1) {
1036 		ret = KMF_ERR_POLICY_DB_FILE;
1037 	}
1038 
1039 	if (ret != KMF_OK) {
1040 		/* try to remove the tmp file */
1041 		(void) unlink(tmpfilename);
1042 	}
1043 
1044 	return (ret);
1045 }
1046 
1047 /*
1048  * kmf_delete_policy_from_db
1049  *
1050  * Find a policy by name and remove it from the policy DB file.
1051  * If the policy is not found, return an error.
1052  */
1053 KMF_RETURN
1054 kmf_delete_policy_from_db(char *policy_name, char *dbfilename)
1055 {
1056 	KMF_RETURN ret;
1057 	xmlParserCtxtPtr ctxt = NULL;
1058 	xmlDocPtr doc = NULL;
1059 	xmlNodePtr cur, node;
1060 
1061 	if (policy_name == NULL || dbfilename == NULL)
1062 		return (KMF_ERR_BAD_PARAMETER);
1063 
1064 	/*
1065 	 * Cannot delete the default policy record from the system
1066 	 * default policy database (/etc/security/kmfpolicy.xml).
1067 	 */
1068 	if (strcmp(dbfilename, KMF_DEFAULT_POLICY_FILE) == 0 &&
1069 	    strcmp(policy_name, KMF_DEFAULT_POLICY_NAME) == 0)
1070 		return (KMF_ERR_BAD_PARAMETER);
1071 
1072 	/* Make sure the policy file exists */
1073 	if (access(dbfilename, R_OK | W_OK))
1074 		return (KMF_ERR_BAD_PARAMETER);
1075 
1076 	/* Read the policy DB and verify it against the schema. */
1077 	ctxt = xmlNewParserCtxt();
1078 	if (ctxt == NULL)
1079 		return (KMF_ERR_POLICY_DB_FORMAT);
1080 
1081 	doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
1082 	    XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
1083 	if (doc == NULL || ctxt->valid == 0) {
1084 		ret = KMF_ERR_POLICY_DB_FORMAT;
1085 		goto end;
1086 	}
1087 
1088 	cur = xmlDocGetRootElement(doc);
1089 	if (cur == NULL) {
1090 		xmlFreeDoc(doc);
1091 		return (KMF_ERR_POLICY_DB_FORMAT);
1092 	}
1093 	node = cur->xmlChildrenNode;
1094 
1095 	ret = deletePolicyNode(node, policy_name);
1096 
1097 	if (ret == KMF_OK)
1098 		ret = update_policyfile(doc, dbfilename);
1099 
1100 end:
1101 	if (ctxt != NULL)
1102 		xmlFreeParserCtxt(ctxt);
1103 
1104 	if (doc != NULL)
1105 		xmlFreeDoc(doc);
1106 
1107 	return (ret);
1108 }
1109 
1110 /*
1111  * Add a new policy node to the Policy DB XML tree.
1112  */
1113 static KMF_RETURN
1114 addPolicyNode(xmlNodePtr pnode, KMF_POLICY_RECORD *policy)
1115 {
1116 	KMF_RETURN ret = KMF_OK;
1117 
1118 	if (pnode != NULL && policy != NULL) {
1119 		if (newprop(pnode, KMF_POLICY_NAME_ATTR, policy->name) != 0) {
1120 			ret = KMF_ERR_POLICY_ENGINE;
1121 			goto out;
1122 		}
1123 		if (policy->ignore_date) {
1124 			if (newprop(pnode, KMF_OPTIONS_IGNORE_DATE_ATTR,
1125 			    "TRUE")) {
1126 				ret = KMF_ERR_POLICY_ENGINE;
1127 				goto out;
1128 			}
1129 		}
1130 
1131 		if (policy->ignore_unknown_ekus) {
1132 			if (newprop(pnode, KMF_OPTIONS_IGNORE_UNKNOWN_EKUS,
1133 			    "TRUE")) {
1134 				ret = KMF_ERR_POLICY_ENGINE;
1135 				goto out;
1136 			}
1137 		}
1138 
1139 		if (policy->ignore_trust_anchor) {
1140 			if (newprop(pnode, KMF_OPTIONS_IGNORE_TRUST_ANCHOR,
1141 			    "TRUE")) {
1142 				ret = KMF_ERR_POLICY_ENGINE;
1143 				goto out;
1144 			}
1145 		}
1146 
1147 		if (policy->validity_adjusttime) {
1148 			if (newprop(pnode, KMF_OPTIONS_VALIDITY_ADJUSTTIME,
1149 			    policy->validity_adjusttime)) {
1150 				ret = KMF_ERR_POLICY_ENGINE;
1151 				goto out;
1152 			}
1153 		}
1154 
1155 		if (newprop(pnode, KMF_POLICY_TA_NAME_ATTR,
1156 		    policy->ta_name) != 0) {
1157 			ret = KMF_ERR_POLICY_ENGINE;
1158 			goto out;
1159 		}
1160 
1161 		if (newprop(pnode, KMF_POLICY_TA_SERIAL_ATTR,
1162 		    policy->ta_serial) != 0) {
1163 			ret = KMF_ERR_POLICY_ENGINE;
1164 			goto out;
1165 		}
1166 
1167 		/* Add a text node for readability */
1168 		addFormatting(pnode, "\n");
1169 
1170 		if (ret = AddValidationNodes(pnode, policy)) {
1171 			goto out;
1172 		}
1173 
1174 		if ((ret = AddKeyUsageNodes(pnode, policy->ku_bits))) {
1175 			goto out;
1176 		}
1177 
1178 		if ((ret = AddExtKeyUsageNodes(pnode, &policy->eku_set))) {
1179 			goto out;
1180 		}
1181 	} else {
1182 		ret = KMF_ERR_BAD_PARAMETER;
1183 	}
1184 out:
1185 	if (ret != KMF_OK && pnode != NULL) {
1186 		xmlUnlinkNode(pnode);
1187 		xmlFreeNode(pnode);
1188 	}
1189 
1190 	return (ret);
1191 }
1192 
1193 
1194 KMF_RETURN
1195 kmf_verify_policy(KMF_POLICY_RECORD *policy)
1196 {
1197 	KMF_RETURN ret = KMF_OK;
1198 	boolean_t has_ta;
1199 
1200 	if (policy->name == NULL || !strlen(policy->name))
1201 		return (KMF_ERR_POLICY_NAME);
1202 
1203 	/* Check the TA related policy */
1204 	if (policy->ta_name != NULL && policy->ta_serial != NULL) {
1205 		has_ta = B_TRUE;
1206 	} else if (policy->ta_name == NULL && policy->ta_serial == NULL) {
1207 		has_ta = B_FALSE;
1208 	} else {
1209 		/*
1210 		 * If the TA cert is set, then both name and serial number
1211 		 * need to be specified.
1212 		 */
1213 		return (KMF_ERR_TA_POLICY);
1214 	}
1215 
1216 	if (has_ta == B_FALSE && policy->ignore_trust_anchor == B_FALSE)
1217 		return (KMF_ERR_TA_POLICY);
1218 
1219 	if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
1220 		/*
1221 		 * For OCSP, either use a fixed responder or use the
1222 		 * value from the cert, but not both.
1223 		 */
1224 		if ((policy->VAL_OCSP_BASIC.responderURI == NULL &&
1225 		    policy->VAL_OCSP_BASIC.uri_from_cert == B_FALSE) ||
1226 		    (policy->VAL_OCSP_BASIC.responderURI != NULL &&
1227 		    policy->VAL_OCSP_BASIC.uri_from_cert == B_TRUE))
1228 			return (KMF_ERR_OCSP_POLICY);
1229 
1230 		/*
1231 		 * If the OCSP responder cert is set, then both name and serial
1232 		 * number need to be specified.
1233 		 */
1234 		if ((policy->VAL_OCSP_RESP_CERT.name != NULL &&
1235 		    policy->VAL_OCSP_RESP_CERT.serial == NULL) ||
1236 		    (policy->VAL_OCSP_RESP_CERT.name == NULL &&
1237 		    policy->VAL_OCSP_RESP_CERT.serial != NULL))
1238 			return (KMF_ERR_OCSP_POLICY);
1239 	}
1240 
1241 	return (ret);
1242 }
1243 
1244 /*
1245  * Update the KMF policy file by creating a new XML Policy doc tree
1246  * from the data in the KMF_POLICY_RECORD structure. If "check_policy"
1247  * is true, then we check the policy sanity also.
1248  */
1249 KMF_RETURN
1250 kmf_add_policy_to_db(KMF_POLICY_RECORD *policy, char *dbfilename,
1251     boolean_t check_policy)
1252 {
1253 	KMF_RETURN ret = KMF_OK;
1254 	xmlDocPtr doc = NULL;
1255 	xmlNodePtr root, node;
1256 	xmlParserCtxtPtr ctxt = NULL;
1257 
1258 	if (policy == NULL || dbfilename == NULL)
1259 		return (KMF_ERR_BAD_PARAMETER);
1260 
1261 	if (check_policy == B_TRUE) {
1262 		if (ret = kmf_verify_policy(policy))
1263 			return (ret);
1264 	}
1265 
1266 	/* If the policyDB exists, load it into memory */
1267 	if (!access(dbfilename, R_OK)) {
1268 
1269 		/* Create a parser context */
1270 		ctxt = xmlNewParserCtxt();
1271 		if (ctxt == NULL)
1272 			return (KMF_ERR_POLICY_DB_FORMAT);
1273 
1274 		doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
1275 		    XML_PARSE_DTDVALID | XML_PARSE_NOERROR |
1276 		    XML_PARSE_NOWARNING);
1277 		if (doc == NULL || ctxt->valid == 0) {
1278 			ret = KMF_ERR_POLICY_DB_FORMAT;
1279 			goto out;
1280 		}
1281 
1282 		root = xmlDocGetRootElement(doc);
1283 		if (root == NULL) {
1284 			ret = KMF_ERR_POLICY_DB_FORMAT;
1285 			goto out;
1286 		}
1287 
1288 		node = root->xmlChildrenNode;
1289 		/*
1290 		 * If the DB has an existing policy of the
1291 		 * same name, delete it from the tree.
1292 		 */
1293 		ret = deletePolicyNode(node, policy->name);
1294 		if (ret == KMF_ERR_POLICY_NOT_FOUND)
1295 			ret = KMF_OK;
1296 	} else {
1297 		/* Initialize a new DB tree */
1298 		doc = xmlNewDoc((const xmlChar *)"1.0");
1299 		if (doc == NULL)
1300 			return (KMF_ERR_POLICY_ENGINE);
1301 
1302 		/*
1303 		 * Add the DOCTYPE header to the tree so the
1304 		 * DTD link is embedded
1305 		 */
1306 		doc->intSubset = xmlCreateIntSubset(doc,
1307 		    (const xmlChar *)KMF_POLICY_ROOT,
1308 		    NULL, (const xmlChar *)KMF_POLICY_DTD);
1309 
1310 		root = xmlNewDocNode(doc, NULL,
1311 		    (const xmlChar *)KMF_POLICY_ROOT, NULL);
1312 		if (root != NULL) {
1313 			xmlDocSetRootElement(doc, root);
1314 		}
1315 	}
1316 
1317 	/* Append the new policy info to the root node. */
1318 	if (root != NULL) {
1319 		xmlNodePtr pnode;
1320 
1321 		pnode = xmlNewChild(root, NULL,
1322 		    (const xmlChar *)KMF_POLICY_ELEMENT, NULL);
1323 
1324 		ret = addPolicyNode(pnode, policy);
1325 		/* If that worked, update the DB file. */
1326 		if (ret == KMF_OK)
1327 			ret = update_policyfile(doc, dbfilename);
1328 	} else {
1329 		ret = KMF_ERR_POLICY_ENGINE;
1330 	}
1331 
1332 
1333 out:
1334 	if (ctxt != NULL)
1335 		xmlFreeParserCtxt(ctxt);
1336 
1337 	if (doc != NULL)
1338 		xmlFreeDoc(doc);
1339 
1340 	return (ret);
1341 }
1342