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
39typedef struct {
40	char	*ekuname;
41	KMF_OID	*oid;
42} EKUName2OID;
43
44static 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
56static int num_ekus = sizeof (EKUList) / sizeof (EKUName2OID);
57
58static void
59addFormatting(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
72static void
73parseOCSPValidation(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 */
127static void
128parseValidation(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
188char *
189ku2str(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
221uint16_t
222KMF_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
248static void
249parseKeyUsageSet(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
270static KMF_OID *
271dup_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
290KMF_OID *
291kmf_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
309char *
310KMF_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 */
326KMF_OID *
327kmf_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
435static KMF_RETURN
436parseExtKeyUsage(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
505int
506parsePolicyElement(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
576static int
577newprop(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 */
599static int
600AddCRLNodes(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 */
646static int
647AddOCSPNodes(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 */
716static int
717AddValidationNodes(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
745end:
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 */
758static KMF_RETURN
759AddKeyUsageNodes(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 */
804static KMF_RETURN
805AddExtKeyUsageNodes(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
846void
847KMF_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
860void
861KMF_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 */
889KMF_RETURN
890KMF_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
951out:
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 */
969KMF_RETURN
970KMF_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
1003out:
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
1014static KMF_RETURN
1015deletePolicyNode(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 */
1066static KMF_RETURN
1067update_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 */
1172KMF_RETURN
1173KMF_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
1219end:
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 */
1232static KMF_RETURN
1233addPolicyNode(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	}
1303out:
1304	if (ret != KMF_OK && pnode != NULL) {
1305		xmlUnlinkNode(pnode);
1306		xmlFreeNode(pnode);
1307	}
1308
1309	return (ret);
1310}
1311
1312
1313KMF_RETURN
1314KMF_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 */
1368KMF_RETURN
1369KMF_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
1452out:
1453	if (ctxt != NULL)
1454		xmlFreeParserCtxt(ctxt);
1455
1456	if (doc != NULL)
1457		xmlFreeDoc(doc);
1458
1459	return (ret);
1460}
1461