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