199ebb4caSwyllys /*
299ebb4caSwyllys  * CDDL HEADER START
399ebb4caSwyllys  *
499ebb4caSwyllys  * The contents of this file are subject to the terms of the
599ebb4caSwyllys  * Common Development and Distribution License (the "License").
699ebb4caSwyllys  * You may not use this file except in compliance with the License.
799ebb4caSwyllys  *
899ebb4caSwyllys  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
999ebb4caSwyllys  * or http://www.opensolaris.org/os/licensing.
1099ebb4caSwyllys  * See the License for the specific language governing permissions
1199ebb4caSwyllys  * and limitations under the License.
1299ebb4caSwyllys  *
1399ebb4caSwyllys  * When distributing Covered Code, include this CDDL HEADER in each
1499ebb4caSwyllys  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1599ebb4caSwyllys  * If applicable, add the following below this CDDL HEADER, with the
1699ebb4caSwyllys  * fields enclosed by brackets "[]" replaced with your own identifying
1799ebb4caSwyllys  * information: Portions Copyright [yyyy] [name of copyright owner]
1899ebb4caSwyllys  *
1999ebb4caSwyllys  * CDDL HEADER END
20269e59f9SJan Pechanec  *
21269e59f9SJan Pechanec  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
2299ebb4caSwyllys  */
2399ebb4caSwyllys 
2499ebb4caSwyllys #include <stdlib.h>
2599ebb4caSwyllys #include <ctype.h>
2699ebb4caSwyllys #include <strings.h>
2799ebb4caSwyllys #include <unistd.h>
2899ebb4caSwyllys #include <errno.h>
29269e59f9SJan Pechanec #include <libgen.h>
3099ebb4caSwyllys #include <sys/param.h>
3199ebb4caSwyllys #include <sys/stat.h>
3299ebb4caSwyllys 
3399ebb4caSwyllys #include <kmfapiP.h>
3499ebb4caSwyllys #include <libxml/tree.h>
3599ebb4caSwyllys #include <libxml/parser.h>
3699ebb4caSwyllys 
3799ebb4caSwyllys typedef struct {
3899ebb4caSwyllys 	char	*ekuname;
3999ebb4caSwyllys 	KMF_OID	*oid;
4099ebb4caSwyllys } EKUName2OID;
4199ebb4caSwyllys 
4299ebb4caSwyllys static EKUName2OID EKUList[] = {
4399ebb4caSwyllys 	{"serverAuth",		(KMF_OID *)&KMFOID_PKIX_KP_ServerAuth},
4499ebb4caSwyllys 	{"clientAuth",		(KMF_OID *)&KMFOID_PKIX_KP_ClientAuth},
4599ebb4caSwyllys 	{"codeSigning",		(KMF_OID *)&KMFOID_PKIX_KP_CodeSigning},
4699ebb4caSwyllys 	{"emailProtection",	(KMF_OID *)&KMFOID_PKIX_KP_EmailProtection},
4799ebb4caSwyllys 	{"ipsecEndSystem",	(KMF_OID *)&KMFOID_PKIX_KP_IPSecEndSystem},
4899ebb4caSwyllys 	{"ipsecTunnel",		(KMF_OID *)&KMFOID_PKIX_KP_IPSecTunnel},
4999ebb4caSwyllys 	{"ipsecUser",		(KMF_OID *)&KMFOID_PKIX_KP_IPSecUser},
5099ebb4caSwyllys 	{"timeStamping",	(KMF_OID *)&KMFOID_PKIX_KP_TimeStamping},
5172ca8cc9SWyllys Ingersoll 	{"OCSPSigning", 	(KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning},
5272ca8cc9SWyllys Ingersoll 	{"KPClientAuth", 	(KMF_OID *)&KMFOID_PKINIT_ClientAuth},
5372ca8cc9SWyllys Ingersoll 	{"KPKdc", 		(KMF_OID *)&KMFOID_PKINIT_Kdc},
5472ca8cc9SWyllys Ingersoll 	{"scLogon", 		(KMF_OID *)&KMFOID_MS_KP_SCLogon}
5599ebb4caSwyllys };
5699ebb4caSwyllys 
5799ebb4caSwyllys static int num_ekus = sizeof (EKUList) / sizeof (EKUName2OID);
5899ebb4caSwyllys 
5999ebb4caSwyllys static void
addFormatting(xmlNodePtr parent,char * text)6099ebb4caSwyllys addFormatting(xmlNodePtr parent, char *text)
6199ebb4caSwyllys {
6299ebb4caSwyllys 	xmlNodePtr snode;
6399ebb4caSwyllys 
6499ebb4caSwyllys 	if (parent == NULL || text == NULL)
6599ebb4caSwyllys 		return;
6699ebb4caSwyllys 
6799ebb4caSwyllys 	snode = xmlNewText((const xmlChar *)text);
6899ebb4caSwyllys 	if (snode != NULL) {
695ad42b1bSSurya Prakki 		(void) xmlAddChild(parent, snode);
7099ebb4caSwyllys 	}
7199ebb4caSwyllys }
7299ebb4caSwyllys 
7399ebb4caSwyllys static void
parseOCSPValidation(xmlNodePtr node,KMF_VALIDATION_POLICY * vinfo)7499ebb4caSwyllys parseOCSPValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo)
7599ebb4caSwyllys {
7699ebb4caSwyllys 	xmlNodePtr n;
7799ebb4caSwyllys 	char *c;
7899ebb4caSwyllys 	n = node->children;
7999ebb4caSwyllys 	while (n != NULL) {
8099ebb4caSwyllys 		if (!xmlStrcmp((const xmlChar *)n->name,
8130a5e8faSwyllys 		    (const xmlChar *)KMF_OCSP_BASIC_ELEMENT)) {
8299ebb4caSwyllys 
8399ebb4caSwyllys 			vinfo->ocsp_info.basic.responderURI =
8499ebb4caSwyllys 			    (char *)xmlGetProp(n,
8599ebb4caSwyllys 			    (const xmlChar *)KMF_OCSP_RESPONDER_ATTR);
8699ebb4caSwyllys 
8799ebb4caSwyllys 			vinfo->ocsp_info.basic.proxy = (char *)xmlGetProp(n,
8899ebb4caSwyllys 			    (const xmlChar *)KMF_OCSP_PROXY_ATTR);
8999ebb4caSwyllys 
9099ebb4caSwyllys 			c = (char *)xmlGetProp(n,
9199ebb4caSwyllys 			    (const xmlChar *)KMF_OCSP_URI_ATTR);
9299ebb4caSwyllys 			if (c != NULL && !strcasecmp(c, "true")) {
9399ebb4caSwyllys 				vinfo->ocsp_info.basic.uri_from_cert = 1;
9499ebb4caSwyllys 				xmlFree(c);
9599ebb4caSwyllys 			}
9699ebb4caSwyllys 
9799ebb4caSwyllys 			vinfo->ocsp_info.basic.response_lifetime =
9899ebb4caSwyllys 			    (char *)xmlGetProp(n,
9999ebb4caSwyllys 			    (const xmlChar *)KMF_OCSP_RESPONSE_LIFETIME_ATTR);
10099ebb4caSwyllys 
10199ebb4caSwyllys 			c = (char *)xmlGetProp(n,
10299ebb4caSwyllys 			    (const xmlChar *)KMF_OCSP_IGNORE_SIGN_ATTR);
10399ebb4caSwyllys 			if (c != NULL && !strcasecmp(c, "true")) {
10499ebb4caSwyllys 				vinfo->ocsp_info.basic.ignore_response_sign = 1;
10599ebb4caSwyllys 				xmlFree(c);
10699ebb4caSwyllys 			}
10799ebb4caSwyllys 
10899ebb4caSwyllys 		} else if (!xmlStrcmp((const xmlChar *)n->name,
10999ebb4caSwyllys 		    (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT)) {
11099ebb4caSwyllys 
11199ebb4caSwyllys 			vinfo->ocsp_info.resp_cert.name =
11299ebb4caSwyllys 			    (char *)xmlGetProp(n,
11399ebb4caSwyllys 			    (const xmlChar *)KMF_CERT_NAME_ATTR);
11499ebb4caSwyllys 			vinfo->ocsp_info.resp_cert.serial =
11530a5e8faSwyllys 			    (char *)xmlGetProp(n,
11630a5e8faSwyllys 			    (const xmlChar *)KMF_CERT_SERIAL_ATTR);
11799ebb4caSwyllys 			vinfo->ocsp_info.has_resp_cert = 1;
11899ebb4caSwyllys 		}
11999ebb4caSwyllys 
12099ebb4caSwyllys 		n = n->next;
12199ebb4caSwyllys 	}
12299ebb4caSwyllys 
12399ebb4caSwyllys }
12499ebb4caSwyllys 
12599ebb4caSwyllys /*
12699ebb4caSwyllys  * Parse the "validation-methods" section of the policy.
12799ebb4caSwyllys  */
12899ebb4caSwyllys static void
parseValidation(xmlNodePtr node,KMF_VALIDATION_POLICY * vinfo,KMF_POLICY_RECORD * policy)12999ebb4caSwyllys parseValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo,
13099ebb4caSwyllys 	KMF_POLICY_RECORD *policy)
13199ebb4caSwyllys {
13299ebb4caSwyllys 	xmlNodePtr n;
13399ebb4caSwyllys 	char *c;
13499ebb4caSwyllys 	n = node->children;
13599ebb4caSwyllys 	while (n != NULL) {
13699ebb4caSwyllys 		if (!xmlStrcmp((const xmlChar *)n->name,
13730a5e8faSwyllys 		    (const xmlChar *)KMF_OCSP_ELEMENT)) {
13899ebb4caSwyllys 
13999ebb4caSwyllys 			parseOCSPValidation(n, &policy->validation_info);
14099ebb4caSwyllys 			policy->revocation |= KMF_REVOCATION_METHOD_OCSP;
14199ebb4caSwyllys 
14299ebb4caSwyllys 
14399ebb4caSwyllys 		} else if (!xmlStrcmp((const xmlChar *)n->name,
14430a5e8faSwyllys 		    (const xmlChar *)KMF_CRL_ELEMENT)) {
14599ebb4caSwyllys 
14699ebb4caSwyllys 			vinfo->crl_info.basefilename = (char *)xmlGetProp(n,
14730a5e8faSwyllys 			    (const xmlChar *)KMF_CRL_BASENAME_ATTR);
14899ebb4caSwyllys 
14999ebb4caSwyllys 			vinfo->crl_info.directory = (char *)xmlGetProp(n,
15030a5e8faSwyllys 			    (const xmlChar *)KMF_CRL_DIRECTORY_ATTR);
15199ebb4caSwyllys 
15299ebb4caSwyllys 			c = (char *)xmlGetProp(n,
15330a5e8faSwyllys 			    (const xmlChar *)KMF_CRL_GET_URI_ATTR);
15499ebb4caSwyllys 			if (c != NULL && !strcasecmp(c, "true")) {
15599ebb4caSwyllys 				vinfo->crl_info.get_crl_uri = 1;
15699ebb4caSwyllys 			} else {
15799ebb4caSwyllys 				vinfo->crl_info.get_crl_uri = 0;
15899ebb4caSwyllys 			}
15999ebb4caSwyllys 			xmlFree(c);
16099ebb4caSwyllys 
16199ebb4caSwyllys 			vinfo->crl_info.proxy = (char *)xmlGetProp(n,
16299ebb4caSwyllys 			    (const xmlChar *)KMF_CRL_PROXY_ATTR);
16399ebb4caSwyllys 
16499ebb4caSwyllys 			c = (char *)xmlGetProp(n,
16530a5e8faSwyllys 			    (const xmlChar *)KMF_CRL_IGNORE_SIGN_ATTR);
16699ebb4caSwyllys 			if (c != NULL && !strcasecmp(c, "true")) {
16799ebb4caSwyllys 				vinfo->crl_info.ignore_crl_sign = 1;
16899ebb4caSwyllys 			} else {
16999ebb4caSwyllys 				vinfo->crl_info.ignore_crl_sign = 0;
17099ebb4caSwyllys 			}
17199ebb4caSwyllys 			xmlFree(c);
17299ebb4caSwyllys 
17399ebb4caSwyllys 			c = (char *)xmlGetProp(n,
17430a5e8faSwyllys 			    (const xmlChar *)KMF_CRL_IGNORE_DATE_ATTR);
17599ebb4caSwyllys 			if (c != NULL && !strcasecmp(c, "true")) {
17699ebb4caSwyllys 				vinfo->crl_info.ignore_crl_date = 1;
17799ebb4caSwyllys 			} else {
17899ebb4caSwyllys 				vinfo->crl_info.ignore_crl_date = 0;
17999ebb4caSwyllys 			}
18099ebb4caSwyllys 			xmlFree(c);
18199ebb4caSwyllys 
18299ebb4caSwyllys 			policy->revocation |= KMF_REVOCATION_METHOD_CRL;
18399ebb4caSwyllys 		}
18499ebb4caSwyllys 
18599ebb4caSwyllys 		n = n->next;
18699ebb4caSwyllys 	}
18799ebb4caSwyllys }
18899ebb4caSwyllys 
18999ebb4caSwyllys char *
kmf_ku_to_string(uint32_t bitfield)19030a5e8faSwyllys kmf_ku_to_string(uint32_t bitfield)
19199ebb4caSwyllys {
19299ebb4caSwyllys 	if (bitfield & KMF_digitalSignature)
19399ebb4caSwyllys 		return ("digitalSignature");
19499ebb4caSwyllys 
19599ebb4caSwyllys 	if (bitfield & KMF_nonRepudiation)
19699ebb4caSwyllys 		return ("nonRepudiation");
19799ebb4caSwyllys 
19899ebb4caSwyllys 	if (bitfield & KMF_keyEncipherment)
19999ebb4caSwyllys 		return ("keyEncipherment");
20099ebb4caSwyllys 
20199ebb4caSwyllys 	if (bitfield & KMF_dataEncipherment)
20299ebb4caSwyllys 		return ("dataEncipherment");
20399ebb4caSwyllys 
20499ebb4caSwyllys 	if (bitfield & KMF_keyAgreement)
20599ebb4caSwyllys 		return ("keyAgreement");
20699ebb4caSwyllys 
20799ebb4caSwyllys 	if (bitfield & KMF_keyCertSign)
20899ebb4caSwyllys 		return ("keyCertSign");
20999ebb4caSwyllys 
21099ebb4caSwyllys 	if (bitfield & KMF_cRLSign)
21199ebb4caSwyllys 		return ("cRLSign");
21299ebb4caSwyllys 
21399ebb4caSwyllys 	if (bitfield & KMF_encipherOnly)
21499ebb4caSwyllys 		return ("encipherOnly");
21599ebb4caSwyllys 
21699ebb4caSwyllys 	if (bitfield & KMF_decipherOnly)
21799ebb4caSwyllys 		return ("decipherOnly");
21899ebb4caSwyllys 
21999ebb4caSwyllys 	return (NULL);
22099ebb4caSwyllys }
22199ebb4caSwyllys 
22230a5e8faSwyllys uint32_t
kmf_string_to_ku(char * kustring)22330a5e8faSwyllys kmf_string_to_ku(char *kustring)
22499ebb4caSwyllys {
22599ebb4caSwyllys 	if (kustring == NULL || !strlen(kustring))
22699ebb4caSwyllys 		return (0);
22799ebb4caSwyllys 	if (strcasecmp(kustring, "digitalSignature") == 0)
22899ebb4caSwyllys 		return (KMF_digitalSignature);
22999ebb4caSwyllys 	if (strcasecmp(kustring, "nonRepudiation") == 0)
23099ebb4caSwyllys 		return (KMF_nonRepudiation);
23199ebb4caSwyllys 	if (strcasecmp(kustring, "keyEncipherment") == 0)
23299ebb4caSwyllys 		return (KMF_keyEncipherment);
23399ebb4caSwyllys 	if (strcasecmp(kustring, "dataEncipherment") == 0)
23499ebb4caSwyllys 		return (KMF_dataEncipherment);
23599ebb4caSwyllys 	if (strcasecmp(kustring, "keyAgreement") == 0)
23699ebb4caSwyllys 		return (KMF_keyAgreement);
23799ebb4caSwyllys 	if (strcasecmp(kustring, "keyCertSign") == 0)
23899ebb4caSwyllys 		return (KMF_keyCertSign);
23999ebb4caSwyllys 	if (strcasecmp(kustring, "cRLSign") == 0)
24099ebb4caSwyllys 		return (KMF_cRLSign);
24199ebb4caSwyllys 	if (strcasecmp(kustring, "encipherOnly") == 0)
24299ebb4caSwyllys 		return (KMF_encipherOnly);
24399ebb4caSwyllys 	if (strcasecmp(kustring, "decipherOnly") == 0)
24499ebb4caSwyllys 		return (KMF_decipherOnly);
24599ebb4caSwyllys 
24699ebb4caSwyllys 	return (0);
24799ebb4caSwyllys }
24899ebb4caSwyllys 
24999ebb4caSwyllys static void
parseKeyUsageSet(xmlNodePtr node,uint32_t * kubits)25099ebb4caSwyllys parseKeyUsageSet(xmlNodePtr node, uint32_t *kubits)
25199ebb4caSwyllys {
25299ebb4caSwyllys 	xmlNodePtr n;
25399ebb4caSwyllys 	char *c;
25499ebb4caSwyllys 
25599ebb4caSwyllys 	n = node->children;
25699ebb4caSwyllys 	while (n != NULL) {
25799ebb4caSwyllys 		if (!xmlStrcmp((const xmlChar *)n->name,
25830a5e8faSwyllys 		    (const xmlChar *)KMF_KEY_USAGE_ELEMENT)) {
25999ebb4caSwyllys 			c = (char *)xmlGetProp(n,
26030a5e8faSwyllys 			    (const xmlChar *)KMF_KEY_USAGE_USE_ATTR);
26199ebb4caSwyllys 			if (c) {
26230a5e8faSwyllys 				*kubits |= kmf_string_to_ku(c);
26399ebb4caSwyllys 				xmlFree(c);
26499ebb4caSwyllys 			}
26599ebb4caSwyllys 		}
26699ebb4caSwyllys 
26799ebb4caSwyllys 		n = n->next;
26899ebb4caSwyllys 	}
26999ebb4caSwyllys }
27099ebb4caSwyllys 
27199ebb4caSwyllys static KMF_OID *
dup_oid(KMF_OID * oldoid)27299ebb4caSwyllys dup_oid(KMF_OID *oldoid)
27399ebb4caSwyllys {
27499ebb4caSwyllys 	KMF_OID *oid;
27599ebb4caSwyllys 
27699ebb4caSwyllys 	oid = malloc(sizeof (KMF_OID));
27799ebb4caSwyllys 	if (oid == NULL)
27899ebb4caSwyllys 		return (NULL);
27999ebb4caSwyllys 
28099ebb4caSwyllys 	oid->Length = oldoid->Length;
28199ebb4caSwyllys 	oid->Data = malloc(oid->Length);
28299ebb4caSwyllys 	if (oid->Data == NULL) {
28399ebb4caSwyllys 		free(oid);
28499ebb4caSwyllys 		return (NULL);
28599ebb4caSwyllys 	}
28699ebb4caSwyllys 	(void) memcpy(oid->Data, oldoid->Data, oid->Length);
28799ebb4caSwyllys 
28899ebb4caSwyllys 	return (oid);
28999ebb4caSwyllys }
29099ebb4caSwyllys 
29199ebb4caSwyllys KMF_OID *
kmf_ekuname_to_oid(char * ekuname)29230a5e8faSwyllys kmf_ekuname_to_oid(char *ekuname)
29399ebb4caSwyllys {
29499ebb4caSwyllys 	KMF_OID *oid;
29599ebb4caSwyllys 	int i;
29699ebb4caSwyllys 
29799ebb4caSwyllys 	if (ekuname == NULL)
29899ebb4caSwyllys 		return (NULL);
29999ebb4caSwyllys 
30099ebb4caSwyllys 	for (i = 0; i < num_ekus; i++) {
30199ebb4caSwyllys 		if (strcasecmp(EKUList[i].ekuname, ekuname) == 0) {
30299ebb4caSwyllys 			oid = dup_oid(EKUList[i].oid);
30399ebb4caSwyllys 			return (oid);
30499ebb4caSwyllys 		}
30599ebb4caSwyllys 	}
30699ebb4caSwyllys 
30799ebb4caSwyllys 	return (NULL);
30899ebb4caSwyllys }
30999ebb4caSwyllys 
31099ebb4caSwyllys char *
kmf_oid_to_ekuname(KMF_OID * oid)311d00756ccSwyllys kmf_oid_to_ekuname(KMF_OID *oid)
31299ebb4caSwyllys {
31399ebb4caSwyllys 	int i;
31499ebb4caSwyllys 	for (i = 0; i < num_ekus; i++) {
31599ebb4caSwyllys 		if (oid->Length == EKUList[i].oid->Length &&
31630a5e8faSwyllys 		    !memcmp(oid->Data, EKUList[i].oid->Data, oid->Length)) {
31799ebb4caSwyllys 			return (EKUList[i].ekuname);
31899ebb4caSwyllys 		}
31999ebb4caSwyllys 	}
32099ebb4caSwyllys 	return (NULL);
32199ebb4caSwyllys }
32299ebb4caSwyllys 
32399ebb4caSwyllys static KMF_RETURN
parseExtKeyUsage(xmlNodePtr node,KMF_EKU_POLICY * ekus)32499ebb4caSwyllys parseExtKeyUsage(xmlNodePtr node, KMF_EKU_POLICY *ekus)
32599ebb4caSwyllys {
32699ebb4caSwyllys 	xmlNodePtr n;
32799ebb4caSwyllys 	char *c;
32899ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
32999ebb4caSwyllys 	boolean_t found = FALSE;
33099ebb4caSwyllys 
33199ebb4caSwyllys 	n = node->children;
33299ebb4caSwyllys 	while (n != NULL && ret == KMF_OK) {
33330a5e8faSwyllys 		KMF_OID newoid, *oidptr;
33430a5e8faSwyllys 
33530a5e8faSwyllys 		oidptr = NULL;
33630a5e8faSwyllys 		newoid.Data = NULL;
33730a5e8faSwyllys 		newoid.Length = 0;
33899ebb4caSwyllys 
33999ebb4caSwyllys 		if (!xmlStrcmp((const xmlChar *)n->name,
34030a5e8faSwyllys 		    (const xmlChar *)KMF_EKU_NAME_ELEMENT)) {
34199ebb4caSwyllys 			c = (char *)xmlGetProp(n,
34230a5e8faSwyllys 			    (const xmlChar *)KMF_EKU_NAME_ATTR);
34399ebb4caSwyllys 			if (c != NULL) {
34430a5e8faSwyllys 				oidptr = kmf_ekuname_to_oid(c);
34599ebb4caSwyllys 				xmlFree(c);
34699ebb4caSwyllys 				found = TRUE;
34730a5e8faSwyllys 				if (oidptr != NULL)
34830a5e8faSwyllys 					newoid = *oidptr;
34999ebb4caSwyllys 			}
35099ebb4caSwyllys 		} else if (!xmlStrcmp((const xmlChar *)n->name,
35130a5e8faSwyllys 		    (const xmlChar *)KMF_EKU_OID_ELEMENT)) {
35299ebb4caSwyllys 			c = (char *)xmlGetProp(n,
35330a5e8faSwyllys 			    (const xmlChar *)KMF_EKU_OID_ATTR);
35499ebb4caSwyllys 			if (c != NULL) {
35530a5e8faSwyllys 				(void) kmf_string_to_oid(c, &newoid);
35699ebb4caSwyllys 				xmlFree(c);
35799ebb4caSwyllys 				found = TRUE;
35899ebb4caSwyllys 			}
35999ebb4caSwyllys 		} else {
36099ebb4caSwyllys 			n = n->next;
36199ebb4caSwyllys 			if ((n == NULL) && (!found))
36299ebb4caSwyllys 				ret = KMF_ERR_POLICY_DB_FORMAT;
36399ebb4caSwyllys 			continue;
36499ebb4caSwyllys 		}
36599ebb4caSwyllys 
36630a5e8faSwyllys 		if (newoid.Data != NULL) {
36799ebb4caSwyllys 			ekus->eku_count++;
36899ebb4caSwyllys 			ekus->ekulist = realloc(ekus->ekulist,
36930a5e8faSwyllys 			    ekus->eku_count * sizeof (KMF_OID));
37099ebb4caSwyllys 			if (ekus->ekulist != NULL) {
37199ebb4caSwyllys 				ekus->ekulist[ekus->eku_count-1].Length =
37230a5e8faSwyllys 				    newoid.Length;
37399ebb4caSwyllys 				ekus->ekulist[ekus->eku_count-1].Data =
37430a5e8faSwyllys 				    newoid.Data;
37599ebb4caSwyllys 			} else {
37699ebb4caSwyllys 				ret = KMF_ERR_MEMORY;
37799ebb4caSwyllys 			}
37899ebb4caSwyllys 		} else {
37999ebb4caSwyllys 			ret = KMF_ERR_POLICY_DB_FORMAT;
38099ebb4caSwyllys 		}
38199ebb4caSwyllys 
38299ebb4caSwyllys 		n = n->next;
38399ebb4caSwyllys 	}
38499ebb4caSwyllys 
38599ebb4caSwyllys 	return (ret);
38699ebb4caSwyllys }
38799ebb4caSwyllys 
388269e59f9SJan Pechanec static KMF_RETURN
parseMapper(xmlNodePtr node,KMF_MAPPER_RECORD * mapper)389269e59f9SJan Pechanec parseMapper(xmlNodePtr node, KMF_MAPPER_RECORD *mapper)
390269e59f9SJan Pechanec {
391269e59f9SJan Pechanec 	xmlNodePtr n;
392269e59f9SJan Pechanec 
393269e59f9SJan Pechanec 	n = node;
394269e59f9SJan Pechanec 	mapper->mapname = (char *)xmlGetProp(n,
395269e59f9SJan Pechanec 	    (const xmlChar *)KMF_CERT_MAPPER_NAME_ATTR);
396269e59f9SJan Pechanec 	mapper->dir = (char *)xmlGetProp(n,
397269e59f9SJan Pechanec 	    (const xmlChar *)KMF_CERT_MAPPER_DIR_ATTR);
398269e59f9SJan Pechanec 	mapper->pathname = (char *)xmlGetProp(n,
399269e59f9SJan Pechanec 	    (const xmlChar *)KMF_CERT_MAPPER_PATH_ATTR);
400269e59f9SJan Pechanec 	mapper->options = (char *)xmlGetProp(n,
401269e59f9SJan Pechanec 	    (const xmlChar *)KMF_CERT_MAPPER_OPTIONS_ATTR);
402269e59f9SJan Pechanec 
403269e59f9SJan Pechanec 	/*
404269e59f9SJan Pechanec 	 * These are set according to whether mapper setting is taken from the
405269e59f9SJan Pechanec 	 * database or init function attributes.
406269e59f9SJan Pechanec 	 */
407269e59f9SJan Pechanec 	mapper->curpathname = NULL;
408269e59f9SJan Pechanec 	mapper->curoptions = NULL;
409269e59f9SJan Pechanec 
410269e59f9SJan Pechanec 	return (KMF_OK);
411269e59f9SJan Pechanec }
412269e59f9SJan Pechanec 
41399ebb4caSwyllys int
parsePolicyElement(xmlNodePtr node,KMF_POLICY_RECORD * policy)41499ebb4caSwyllys parsePolicyElement(xmlNodePtr node, KMF_POLICY_RECORD *policy)
41599ebb4caSwyllys {
41699ebb4caSwyllys 	int ret = 0;
41799ebb4caSwyllys 	xmlNodePtr n = node->xmlChildrenNode;
41899ebb4caSwyllys 	char *c;
41999ebb4caSwyllys 
42099ebb4caSwyllys 	if (node->type == XML_ELEMENT_NODE) {
42199ebb4caSwyllys 		if (node->properties != NULL) {
42299ebb4caSwyllys 			policy->name = (char *)xmlGetProp(node,
42330a5e8faSwyllys 			    (const xmlChar *)KMF_POLICY_NAME_ATTR);
42499ebb4caSwyllys 
42599ebb4caSwyllys 			c = (char *)xmlGetProp(node,
42630a5e8faSwyllys 			    (const xmlChar *)KMF_OPTIONS_IGNORE_DATE_ATTR);
42799ebb4caSwyllys 			if (c && !strcasecmp(c, "true")) {
42899ebb4caSwyllys 				policy->ignore_date = 1;
42999ebb4caSwyllys 				xmlFree((xmlChar *)c);
43099ebb4caSwyllys 			}
43199ebb4caSwyllys 
43299ebb4caSwyllys 			c = (char *)xmlGetProp(node,
43399ebb4caSwyllys 			    (const xmlChar *)KMF_OPTIONS_IGNORE_UNKNOWN_EKUS);
43499ebb4caSwyllys 			if (c && !strcasecmp(c, "true")) {
43599ebb4caSwyllys 				policy->ignore_unknown_ekus = 1;
43699ebb4caSwyllys 				xmlFree(c);
43799ebb4caSwyllys 			}
43899ebb4caSwyllys 
43999ebb4caSwyllys 			c = (char *)xmlGetProp(node,
44099ebb4caSwyllys 			    (const xmlChar *)KMF_OPTIONS_IGNORE_TRUST_ANCHOR);
44199ebb4caSwyllys 			if (c && !strcasecmp(c, "true")) {
44299ebb4caSwyllys 				policy->ignore_trust_anchor = 1;
44399ebb4caSwyllys 				xmlFree(c);
44499ebb4caSwyllys 			}
44599ebb4caSwyllys 
44699ebb4caSwyllys 			c = (char *)xmlGetProp(node,
44799ebb4caSwyllys 			    (const xmlChar *)KMF_OPTIONS_VALIDITY_ADJUSTTIME);
44899ebb4caSwyllys 			if (c) {
44999ebb4caSwyllys 				policy->validity_adjusttime = c;
45099ebb4caSwyllys 			} else {
45199ebb4caSwyllys 				policy->validity_adjusttime = NULL;
45299ebb4caSwyllys 			}
45399ebb4caSwyllys 
45499ebb4caSwyllys 			policy->ta_name = (char *)xmlGetProp(node,
45530a5e8faSwyllys 			    (const xmlChar *)KMF_POLICY_TA_NAME_ATTR);
45699ebb4caSwyllys 
45799ebb4caSwyllys 			policy->ta_serial = (char *)xmlGetProp(node,
45830a5e8faSwyllys 			    (const xmlChar *)KMF_POLICY_TA_SERIAL_ATTR);
45999ebb4caSwyllys 		}
46099ebb4caSwyllys 
46199ebb4caSwyllys 		n = node->children;
46299ebb4caSwyllys 		while (n != NULL) {
46399ebb4caSwyllys 			if (!xmlStrcmp((const xmlChar *)n->name,
46430a5e8faSwyllys 			    (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT))
46599ebb4caSwyllys 				parseValidation(n, &policy->validation_info,
46699ebb4caSwyllys 				    policy);
46799ebb4caSwyllys 			else if (!xmlStrcmp((const xmlChar *)n->name,
46830a5e8faSwyllys 			    (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT))
46999ebb4caSwyllys 				parseKeyUsageSet(n, &policy->ku_bits);
47099ebb4caSwyllys 			else if (!xmlStrcmp((const xmlChar *)n->name,
47199ebb4caSwyllys 			    (const xmlChar *)KMF_EKU_ELEMENT)) {
47299ebb4caSwyllys 				ret = parseExtKeyUsage(n, &policy->eku_set);
47399ebb4caSwyllys 				if (ret != KMF_OK)
47499ebb4caSwyllys 					return (ret);
475269e59f9SJan Pechanec 			} else if (!xmlStrcmp((const xmlChar *)n->name,
476269e59f9SJan Pechanec 			    (const xmlChar *)KMF_CERT_MAPPER_ELEMENT)) {
477269e59f9SJan Pechanec 				ret = parseMapper(n, &policy->mapper);
478269e59f9SJan Pechanec 				if (ret != KMF_OK)
479269e59f9SJan Pechanec 					return (ret);
48099ebb4caSwyllys 			}
48199ebb4caSwyllys 
48299ebb4caSwyllys 			n = n->next;
48399ebb4caSwyllys 		}
48499ebb4caSwyllys 	}
48599ebb4caSwyllys 
48699ebb4caSwyllys 	return (ret);
48799ebb4caSwyllys }
48899ebb4caSwyllys 
48999ebb4caSwyllys static int
newprop(xmlNodePtr node,char * attrname,char * src)49099ebb4caSwyllys newprop(xmlNodePtr node, char *attrname, char *src)
49199ebb4caSwyllys {
49299ebb4caSwyllys 	xmlAttrPtr newattr;
49399ebb4caSwyllys 
49499ebb4caSwyllys 	if (src != NULL && strlen(src)) {
49599ebb4caSwyllys 		newattr = xmlNewProp(node, (const xmlChar *)attrname,
49630a5e8faSwyllys 		    (xmlChar *)src);
49799ebb4caSwyllys 		if (newattr == NULL) {
49899ebb4caSwyllys 			xmlUnlinkNode(node);
49999ebb4caSwyllys 			xmlFreeNode(node);
50099ebb4caSwyllys 			return (-1);
50199ebb4caSwyllys 		}
50299ebb4caSwyllys 	}
50399ebb4caSwyllys 	return (0);
50499ebb4caSwyllys }
50599ebb4caSwyllys 
50699ebb4caSwyllys /*
50799ebb4caSwyllys  * Add CRL policy information to the XML tree.
50899ebb4caSwyllys  * Return non-zero on any failure, else 0 for success.
50999ebb4caSwyllys  *
51099ebb4caSwyllys  * This function is called only when the KMF_REVOCATION_METHOD_CRL flag is on.
51199ebb4caSwyllys  */
51299ebb4caSwyllys static int
AddCRLNodes(xmlNodePtr node,KMF_CRL_POLICY * crlinfo)51399ebb4caSwyllys AddCRLNodes(xmlNodePtr node, KMF_CRL_POLICY *crlinfo)
51499ebb4caSwyllys {
51599ebb4caSwyllys 	xmlNodePtr n;
51699ebb4caSwyllys 
51799ebb4caSwyllys 	addFormatting(node, "\t\t");
51899ebb4caSwyllys 	n = xmlNewChild(node, NULL, (const xmlChar *)"crl", NULL);
51999ebb4caSwyllys 	if (n == NULL)
52099ebb4caSwyllys 		return (-1);
52199ebb4caSwyllys 
52299ebb4caSwyllys 	if (crlinfo->basefilename &&
52399ebb4caSwyllys 	    newprop(n, KMF_CRL_BASENAME_ATTR, crlinfo->basefilename))
52499ebb4caSwyllys 		return (-1);
52599ebb4caSwyllys 
52699ebb4caSwyllys 	if (crlinfo->directory &&
52799ebb4caSwyllys 	    newprop(n, KMF_CRL_DIRECTORY_ATTR, crlinfo->directory))
52899ebb4caSwyllys 		return (-1);
52999ebb4caSwyllys 
53099ebb4caSwyllys 	if (crlinfo->get_crl_uri &&
53199ebb4caSwyllys 	    newprop(n, KMF_CRL_GET_URI_ATTR, "TRUE")) {
53299ebb4caSwyllys 		return (-1);
53399ebb4caSwyllys 	}
53499ebb4caSwyllys 
53599ebb4caSwyllys 	if (crlinfo->proxy &&
53699ebb4caSwyllys 	    newprop(n, KMF_CRL_PROXY_ATTR, crlinfo->proxy))
53799ebb4caSwyllys 		return (-1);
53899ebb4caSwyllys 
53999ebb4caSwyllys 	if (crlinfo->ignore_crl_sign &&
54099ebb4caSwyllys 	    newprop(n, KMF_CRL_IGNORE_SIGN_ATTR, "TRUE")) {
54199ebb4caSwyllys 		return (-1);
54299ebb4caSwyllys 	}
54399ebb4caSwyllys 
54499ebb4caSwyllys 	if (crlinfo->ignore_crl_date &&
54599ebb4caSwyllys 	    newprop(n, KMF_CRL_IGNORE_DATE_ATTR, "TRUE")) {
54699ebb4caSwyllys 		return (-1);
54799ebb4caSwyllys 	}
54899ebb4caSwyllys 
54999ebb4caSwyllys 	addFormatting(node, "\n");
55099ebb4caSwyllys 	return (0);
55199ebb4caSwyllys }
55299ebb4caSwyllys 
55399ebb4caSwyllys /*
55499ebb4caSwyllys  * Add OCSP information to the policy tree.
55599ebb4caSwyllys  * Return non-zero on any failure, else 0 for success.
55699ebb4caSwyllys  *
55799ebb4caSwyllys  * This function is called only when the KMF_REVOCATION_METHOD_OCSP flag is on.
55899ebb4caSwyllys  */
55999ebb4caSwyllys static int
AddOCSPNodes(xmlNodePtr parent,KMF_OCSP_POLICY * ocsp)56099ebb4caSwyllys AddOCSPNodes(xmlNodePtr parent, KMF_OCSP_POLICY *ocsp)
56199ebb4caSwyllys {
56299ebb4caSwyllys 	int ret = 0;
56399ebb4caSwyllys 	xmlNodePtr n_ocsp, n_basic, n_resp;
56499ebb4caSwyllys 	KMF_OCSP_BASIC_POLICY *basic;
56599ebb4caSwyllys 	KMF_RESP_CERT_POLICY *resp_cert;
56699ebb4caSwyllys 
56799ebb4caSwyllys 	basic = &(ocsp->basic);
56899ebb4caSwyllys 	resp_cert = &(ocsp->resp_cert);
56999ebb4caSwyllys 
57099ebb4caSwyllys 	if (basic->responderURI != NULL || basic->uri_from_cert == B_TRUE) {
57199ebb4caSwyllys 
57299ebb4caSwyllys 		addFormatting(parent, "\t\t");
57399ebb4caSwyllys 
57499ebb4caSwyllys 		/* basic node */
57599ebb4caSwyllys 		n_ocsp = xmlNewChild(parent, NULL,
57630a5e8faSwyllys 		    (const xmlChar *)KMF_OCSP_ELEMENT, NULL);
57799ebb4caSwyllys 		if (n_ocsp == NULL)
57899ebb4caSwyllys 			return (-1);
57999ebb4caSwyllys 		addFormatting(n_ocsp, "\n\t\t\t");
58099ebb4caSwyllys 
58199ebb4caSwyllys 		n_basic = xmlNewChild(n_ocsp, NULL,
58299ebb4caSwyllys 		    (const xmlChar *)KMF_OCSP_BASIC_ELEMENT, NULL);
58399ebb4caSwyllys 		if (n_basic == NULL)
58499ebb4caSwyllys 			return (-1);
58599ebb4caSwyllys 		if (basic->responderURI && newprop(n_basic,
58699ebb4caSwyllys 		    KMF_OCSP_RESPONDER_ATTR, basic->responderURI))
58799ebb4caSwyllys 			return (-1);
58899ebb4caSwyllys 		if (basic->proxy &&
58999ebb4caSwyllys 		    newprop(n_basic, KMF_OCSP_PROXY_ATTR, basic->proxy))
59099ebb4caSwyllys 			return (-1);
59199ebb4caSwyllys 		if (basic->uri_from_cert &&
59299ebb4caSwyllys 		    newprop(n_basic, KMF_OCSP_URI_ATTR, "TRUE"))
59399ebb4caSwyllys 			return (-1);
59499ebb4caSwyllys 		if (basic->response_lifetime &&
59599ebb4caSwyllys 		    newprop(n_basic, KMF_OCSP_RESPONSE_LIFETIME_ATTR,
59630a5e8faSwyllys 		    basic->response_lifetime))
59799ebb4caSwyllys 			return (-1);
59899ebb4caSwyllys 		if (basic->ignore_response_sign &&
59999ebb4caSwyllys 		    newprop(n_basic, KMF_OCSP_IGNORE_SIGN_ATTR, "TRUE"))
60099ebb4caSwyllys 			return (-1);
60199ebb4caSwyllys 
60299ebb4caSwyllys 		addFormatting(n_ocsp, "\n\t\t\t");
60399ebb4caSwyllys 
60499ebb4caSwyllys 		/* responder cert node */
60599ebb4caSwyllys 		if (ocsp->has_resp_cert) {
60699ebb4caSwyllys 			n_resp = xmlNewChild(n_ocsp, NULL,
60799ebb4caSwyllys 			    (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT,
60899ebb4caSwyllys 			    NULL);
60999ebb4caSwyllys 			if (n_resp == NULL)
61099ebb4caSwyllys 				return (-1);
61199ebb4caSwyllys 			if (newprop(n_resp, KMF_CERT_NAME_ATTR,
61299ebb4caSwyllys 			    resp_cert->name))
61399ebb4caSwyllys 				return (-1);
61499ebb4caSwyllys 			if (newprop(n_resp, KMF_CERT_SERIAL_ATTR,
61599ebb4caSwyllys 			    resp_cert->serial))
61699ebb4caSwyllys 				return (-1);
61799ebb4caSwyllys 		}
61899ebb4caSwyllys 		addFormatting(n_ocsp, "\n\t\t");
61999ebb4caSwyllys 	}
62099ebb4caSwyllys 
62199ebb4caSwyllys 	addFormatting(parent, "\n");
62299ebb4caSwyllys 	return (ret);
62399ebb4caSwyllys }
62499ebb4caSwyllys 
62599ebb4caSwyllys /*
62699ebb4caSwyllys  * Add validation method information to the policy tree.
62799ebb4caSwyllys  * Return non-zero on any failure, else 0 for success.
62899ebb4caSwyllys  */
62999ebb4caSwyllys static int
AddValidationNodes(xmlNodePtr parent,KMF_POLICY_RECORD * policy)63099ebb4caSwyllys AddValidationNodes(xmlNodePtr parent, KMF_POLICY_RECORD *policy)
63199ebb4caSwyllys {
63299ebb4caSwyllys 	xmlNodePtr mnode;
63399ebb4caSwyllys 	int ret = 0;
63499ebb4caSwyllys 
63599ebb4caSwyllys 	addFormatting(parent, "\t");
63699ebb4caSwyllys 	mnode = xmlNewChild(parent, NULL,
63730a5e8faSwyllys 	    (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT, NULL);
63899ebb4caSwyllys 	if (mnode == NULL)
63999ebb4caSwyllys 		return (-1);
64099ebb4caSwyllys 
64199ebb4caSwyllys 	addFormatting(mnode, "\n");
64299ebb4caSwyllys 
64399ebb4caSwyllys 	if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
64499ebb4caSwyllys 		ret = AddOCSPNodes(mnode, &(policy->validation_info.ocsp_info));
64599ebb4caSwyllys 		if (ret != KMF_OK)
64699ebb4caSwyllys 			goto end;
64799ebb4caSwyllys 	}
64899ebb4caSwyllys 
64999ebb4caSwyllys 	if (policy->revocation & KMF_REVOCATION_METHOD_CRL) {
65099ebb4caSwyllys 		ret = AddCRLNodes(mnode, &(policy->validation_info.crl_info));
65199ebb4caSwyllys 		if (ret != KMF_OK)
65299ebb4caSwyllys 			goto end;
65399ebb4caSwyllys 	}
65499ebb4caSwyllys 
65599ebb4caSwyllys 	addFormatting(mnode, "\t");
65699ebb4caSwyllys 	addFormatting(parent, "\n");
65799ebb4caSwyllys 
65899ebb4caSwyllys end:
65999ebb4caSwyllys 	if (ret != 0) {
66099ebb4caSwyllys 		xmlUnlinkNode(mnode);
66199ebb4caSwyllys 		xmlFreeNode(mnode);
66299ebb4caSwyllys 	}
66399ebb4caSwyllys 	return (ret);
66499ebb4caSwyllys 
66599ebb4caSwyllys }
66699ebb4caSwyllys 
667269e59f9SJan Pechanec /*
668269e59f9SJan Pechanec  * Add mapper policy info to the policy tree.
669269e59f9SJan Pechanec  * Return non-zero on any failure, else 0 for success.
670269e59f9SJan Pechanec  */
671269e59f9SJan Pechanec static KMF_RETURN
AddMapperPolicyNodes(xmlNodePtr parent,KMF_MAPPER_RECORD * mapper)672269e59f9SJan Pechanec AddMapperPolicyNodes(xmlNodePtr parent, KMF_MAPPER_RECORD  *mapper)
673269e59f9SJan Pechanec {
674269e59f9SJan Pechanec 	KMF_RETURN ret = KMF_OK;
675269e59f9SJan Pechanec 	xmlNodePtr mapper_node;
676269e59f9SJan Pechanec 
677269e59f9SJan Pechanec 	addFormatting(parent, "\n\t");
678269e59f9SJan Pechanec 	mapper_node = xmlNewChild(parent, NULL,
679269e59f9SJan Pechanec 	    (const xmlChar *)KMF_CERT_MAPPER_ELEMENT, NULL);
680269e59f9SJan Pechanec 	if (mapper_node == NULL)
681269e59f9SJan Pechanec 		return (KMF_ERR_POLICY_ENGINE);
682269e59f9SJan Pechanec 
683269e59f9SJan Pechanec 	if (mapper->mapname != NULL &&
684269e59f9SJan Pechanec 	    newprop(mapper_node, KMF_CERT_MAPPER_NAME_ATTR, mapper->mapname)) {
685269e59f9SJan Pechanec 		ret = KMF_ERR_POLICY_ENGINE;
686269e59f9SJan Pechanec 		goto end;
687269e59f9SJan Pechanec 	}
688269e59f9SJan Pechanec 
689269e59f9SJan Pechanec 	if (mapper->pathname != NULL &&
690269e59f9SJan Pechanec 	    newprop(mapper_node, KMF_CERT_MAPPER_PATH_ATTR, mapper->pathname)) {
691269e59f9SJan Pechanec 		ret = KMF_ERR_POLICY_ENGINE;
692269e59f9SJan Pechanec 		goto end;
693269e59f9SJan Pechanec 	}
694269e59f9SJan Pechanec 
695269e59f9SJan Pechanec 	if (mapper->dir != NULL &&
696269e59f9SJan Pechanec 	    newprop(mapper_node, KMF_CERT_MAPPER_DIR_ATTR, mapper->dir)) {
697269e59f9SJan Pechanec 		ret = KMF_ERR_POLICY_ENGINE;
698269e59f9SJan Pechanec 		goto end;
699269e59f9SJan Pechanec 	}
700269e59f9SJan Pechanec 
701269e59f9SJan Pechanec 	if (mapper->options != NULL &&
702269e59f9SJan Pechanec 	    newprop(mapper_node, KMF_CERT_MAPPER_OPTIONS_ATTR, mapper->options))
703269e59f9SJan Pechanec 		ret = KMF_ERR_POLICY_ENGINE;
704269e59f9SJan Pechanec 
705269e59f9SJan Pechanec 	if (ret == KMF_OK) {
706269e59f9SJan Pechanec 		addFormatting(mapper_node, "\n\t");
707269e59f9SJan Pechanec 		addFormatting(parent, "\n");
708269e59f9SJan Pechanec 	}
709269e59f9SJan Pechanec 
710269e59f9SJan Pechanec end:
711269e59f9SJan Pechanec 	if (ret != KMF_OK) {
712269e59f9SJan Pechanec 		xmlUnlinkNode(mapper_node);
713269e59f9SJan Pechanec 		xmlFreeNode(mapper_node);
714269e59f9SJan Pechanec 	}
715269e59f9SJan Pechanec 	return (ret);
716269e59f9SJan Pechanec }
717269e59f9SJan Pechanec 
71899ebb4caSwyllys /*
71999ebb4caSwyllys  * Add Key Usage information to the policy tree.
72099ebb4caSwyllys  * Return non-zero on any failure, else 0 for success.
72199ebb4caSwyllys  */
72299ebb4caSwyllys static KMF_RETURN
AddKeyUsageNodes(xmlNodePtr parent,uint32_t kubits)72399ebb4caSwyllys AddKeyUsageNodes(xmlNodePtr parent, uint32_t kubits)
72499ebb4caSwyllys {
72599ebb4caSwyllys 	int ret = KMF_OK;
72699ebb4caSwyllys 	int i;
72799ebb4caSwyllys 
72899ebb4caSwyllys 	xmlNodePtr kuset, kunode;
72999ebb4caSwyllys 
73099ebb4caSwyllys 	if (kubits == 0)
73199ebb4caSwyllys 		return (0);
73299ebb4caSwyllys 
73399ebb4caSwyllys 	addFormatting(parent, "\n\t");
73499ebb4caSwyllys 	kuset = xmlNewChild(parent, NULL,
73530a5e8faSwyllys 	    (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT, NULL);
73699ebb4caSwyllys 	if (kuset == NULL)
73799ebb4caSwyllys 		return (KMF_ERR_POLICY_ENGINE);
73899ebb4caSwyllys 
73999ebb4caSwyllys 	for (i = KULOWBIT; i <= KUHIGHBIT && ret == KMF_OK; i++) {
74030a5e8faSwyllys 		char *s = kmf_ku_to_string((kubits & (1<<i)));
74199ebb4caSwyllys 		if (s != NULL) {
74299ebb4caSwyllys 			addFormatting(kuset, "\n\t\t");
74399ebb4caSwyllys 
74499ebb4caSwyllys 			kunode = xmlNewChild(kuset, NULL,
74530a5e8faSwyllys 			    (const xmlChar *)KMF_KEY_USAGE_ELEMENT, NULL);
74699ebb4caSwyllys 			if (kunode == NULL)
74799ebb4caSwyllys 				ret = KMF_ERR_POLICY_ENGINE;
74899ebb4caSwyllys 
74999ebb4caSwyllys 			else if (newprop(kunode, KMF_KEY_USAGE_USE_ATTR, s))
75099ebb4caSwyllys 				ret = KMF_ERR_POLICY_ENGINE;
75199ebb4caSwyllys 		}
75299ebb4caSwyllys 	}
75399ebb4caSwyllys 	addFormatting(kuset, "\n\t");
75499ebb4caSwyllys 	addFormatting(parent, "\n");
75599ebb4caSwyllys 
75699ebb4caSwyllys 	if (ret != KMF_OK) {
75799ebb4caSwyllys 		xmlUnlinkNode(kuset);
75899ebb4caSwyllys 		xmlFreeNode(kuset);
75999ebb4caSwyllys 	}
76099ebb4caSwyllys 
76199ebb4caSwyllys 	return (ret);
76299ebb4caSwyllys }
76399ebb4caSwyllys 
76499ebb4caSwyllys /*
76599ebb4caSwyllys  * Add Extended-Key-Usage information to the policy tree.
76699ebb4caSwyllys  * Return non-zero on any failure, else 0 for success.
76799ebb4caSwyllys  */
76899ebb4caSwyllys static KMF_RETURN
AddExtKeyUsageNodes(xmlNodePtr parent,KMF_EKU_POLICY * ekus)76999ebb4caSwyllys AddExtKeyUsageNodes(xmlNodePtr parent, KMF_EKU_POLICY *ekus)
77099ebb4caSwyllys {
77199ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
77299ebb4caSwyllys 	xmlNodePtr n, kunode;
77399ebb4caSwyllys 	int i;
77499ebb4caSwyllys 
77599ebb4caSwyllys 	if (ekus != NULL && ekus->eku_count > 0) {
77699ebb4caSwyllys 		addFormatting(parent, "\n\t");
77799ebb4caSwyllys 		n = xmlNewChild(parent, NULL,
77830a5e8faSwyllys 		    (const xmlChar *)KMF_EKU_ELEMENT, NULL);
77999ebb4caSwyllys 		if (n == NULL)
78099ebb4caSwyllys 			return (KMF_ERR_POLICY_ENGINE);
78199ebb4caSwyllys 
78299ebb4caSwyllys 		for (i = 0; i < ekus->eku_count; i++) {
78330a5e8faSwyllys 			char *s = kmf_oid_to_string(&ekus->ekulist[i]);
78499ebb4caSwyllys 			if (s != NULL) {
78599ebb4caSwyllys 				addFormatting(n, "\n\t\t");
78699ebb4caSwyllys 				kunode = xmlNewChild(n, NULL,
78730a5e8faSwyllys 				    (const xmlChar *)KMF_EKU_OID_ELEMENT,
78830a5e8faSwyllys 				    NULL);
78999ebb4caSwyllys 				if (kunode == NULL)
79099ebb4caSwyllys 					ret = KMF_ERR_POLICY_ENGINE;
79199ebb4caSwyllys 
79299ebb4caSwyllys 				else if (newprop(kunode, KMF_EKU_OID_ATTR, s))
79399ebb4caSwyllys 					ret = KMF_ERR_POLICY_ENGINE;
79499ebb4caSwyllys 				free(s);
79599ebb4caSwyllys 			} else {
79699ebb4caSwyllys 				ret = KMF_ERR_POLICY_ENGINE;
79799ebb4caSwyllys 			}
79899ebb4caSwyllys 		}
79999ebb4caSwyllys 		addFormatting(n, "\n\t");
80099ebb4caSwyllys 		addFormatting(parent, "\n");
80199ebb4caSwyllys 	}
80299ebb4caSwyllys 
80399ebb4caSwyllys 	if (ret != KMF_OK) {
80499ebb4caSwyllys 		xmlUnlinkNode(n);
80599ebb4caSwyllys 		xmlFreeNode(n);
80699ebb4caSwyllys 	}
80799ebb4caSwyllys 	return (ret);
80899ebb4caSwyllys }
80999ebb4caSwyllys 
81099ebb4caSwyllys void
kmf_free_eku_policy(KMF_EKU_POLICY * ekus)81130a5e8faSwyllys kmf_free_eku_policy(KMF_EKU_POLICY *ekus)
81299ebb4caSwyllys {
81399ebb4caSwyllys 	if (ekus->eku_count > 0) {
81499ebb4caSwyllys 		int i;
81599ebb4caSwyllys 		for (i = 0; i < ekus->eku_count; i++) {
81630a5e8faSwyllys 			kmf_free_data(&ekus->ekulist[i]);
81799ebb4caSwyllys 		}
81899ebb4caSwyllys 		free(ekus->ekulist);
81999ebb4caSwyllys 	}
82099ebb4caSwyllys }
82199ebb4caSwyllys 
82299ebb4caSwyllys #define	FREE_POLICY_STR(s) if (s != NULL) free(s);
82399ebb4caSwyllys 
82499ebb4caSwyllys void
kmf_free_policy_record(KMF_POLICY_RECORD * policy)82530a5e8faSwyllys kmf_free_policy_record(KMF_POLICY_RECORD *policy)
82699ebb4caSwyllys {
82799ebb4caSwyllys 	if (policy == NULL)
82899ebb4caSwyllys 		return;
82999ebb4caSwyllys 
83099ebb4caSwyllys 	FREE_POLICY_STR(policy->name)
83199ebb4caSwyllys 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.responderURI)
83299ebb4caSwyllys 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.proxy)
83399ebb4caSwyllys 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.response_lifetime)
83499ebb4caSwyllys 	FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.name)
83599ebb4caSwyllys 	FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.serial)
83699ebb4caSwyllys 	FREE_POLICY_STR(policy->validation_info.crl_info.basefilename)
83799ebb4caSwyllys 	FREE_POLICY_STR(policy->validation_info.crl_info.directory)
83899ebb4caSwyllys 	FREE_POLICY_STR(policy->validation_info.crl_info.proxy)
83999ebb4caSwyllys 	FREE_POLICY_STR(policy->validity_adjusttime)
84099ebb4caSwyllys 	FREE_POLICY_STR(policy->ta_name)
84199ebb4caSwyllys 	FREE_POLICY_STR(policy->ta_serial)
842269e59f9SJan Pechanec 	FREE_POLICY_STR(policy->mapper.mapname)
843269e59f9SJan Pechanec 	FREE_POLICY_STR(policy->mapper.pathname)
844269e59f9SJan Pechanec 	FREE_POLICY_STR(policy->mapper.options)
845269e59f9SJan Pechanec 	FREE_POLICY_STR(policy->mapper.dir)
84699ebb4caSwyllys 
84730a5e8faSwyllys 	kmf_free_eku_policy(&policy->eku_set);
84899ebb4caSwyllys 
84999ebb4caSwyllys 	(void) memset(policy, 0, sizeof (KMF_POLICY_RECORD));
85099ebb4caSwyllys }
85199ebb4caSwyllys 
85299ebb4caSwyllys /*
85330a5e8faSwyllys  * kmf_get_policy
85499ebb4caSwyllys  *
85599ebb4caSwyllys  * Find a policy record in the database.
85699ebb4caSwyllys  */
85799ebb4caSwyllys KMF_RETURN
kmf_get_policy(char * filename,char * policy_name,KMF_POLICY_RECORD * plc)85830a5e8faSwyllys kmf_get_policy(char *filename, char *policy_name, KMF_POLICY_RECORD *plc)
85999ebb4caSwyllys {
86099ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
86199ebb4caSwyllys 	xmlParserCtxtPtr ctxt;
86299ebb4caSwyllys 	xmlDocPtr doc = NULL;
86399ebb4caSwyllys 	xmlNodePtr cur, node;
86499ebb4caSwyllys 	int found = 0;
86599ebb4caSwyllys 
86699ebb4caSwyllys 	if (filename == NULL || policy_name == NULL || plc == NULL)
86799ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
86899ebb4caSwyllys 
86999ebb4caSwyllys 	(void) memset(plc, 0, sizeof (KMF_POLICY_RECORD));
87099ebb4caSwyllys 
87199ebb4caSwyllys 	/* Create a parser context */
87299ebb4caSwyllys 	ctxt = xmlNewParserCtxt();
87399ebb4caSwyllys 	if (ctxt == NULL)
87499ebb4caSwyllys 		return (KMF_ERR_POLICY_DB_FORMAT);
87599ebb4caSwyllys 
87699ebb4caSwyllys 	/* Read the policy DB and verify it against the schema. */
87799ebb4caSwyllys 	doc = xmlCtxtReadFile(ctxt, filename, NULL,
87899ebb4caSwyllys 	    XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
87999ebb4caSwyllys 	if (doc == NULL || ctxt->valid == 0) {
88099ebb4caSwyllys 		ret = KMF_ERR_POLICY_DB_FORMAT;
88199ebb4caSwyllys 		goto out;
88299ebb4caSwyllys 	}
88399ebb4caSwyllys 
88499ebb4caSwyllys 	cur = xmlDocGetRootElement(doc);
88599ebb4caSwyllys 	if (cur == NULL) {
88699ebb4caSwyllys 		ret = KMF_ERR_POLICY_DB_FORMAT;
88799ebb4caSwyllys 		goto out;
88899ebb4caSwyllys 	}
88999ebb4caSwyllys 
89099ebb4caSwyllys 	node = cur->xmlChildrenNode;
89199ebb4caSwyllys 	while (node != NULL && !found) {
89299ebb4caSwyllys 		char *c;
89399ebb4caSwyllys 		/*
89499ebb4caSwyllys 		 * Search for the policy that matches the given name.
89599ebb4caSwyllys 		 */
89699ebb4caSwyllys 		if (!xmlStrcmp((const xmlChar *)node->name,
89730a5e8faSwyllys 		    (const xmlChar *)KMF_POLICY_ELEMENT)) {
89899ebb4caSwyllys 			/* Check the name attribute */
89999ebb4caSwyllys 			c = (char *)xmlGetProp(node,
90030a5e8faSwyllys 			    (const xmlChar *)KMF_POLICY_NAME_ATTR);
90199ebb4caSwyllys 
90299ebb4caSwyllys 			/* If a match, parse the rest of the data */
90399ebb4caSwyllys 			if (c != NULL) {
90499ebb4caSwyllys 				if (strcmp(c, policy_name) == 0) {
90599ebb4caSwyllys 					ret = parsePolicyElement(node, plc);
90699ebb4caSwyllys 					found = (ret == KMF_OK);
90799ebb4caSwyllys 				}
90899ebb4caSwyllys 				xmlFree(c);
90999ebb4caSwyllys 			}
91099ebb4caSwyllys 		}
91199ebb4caSwyllys 		node = node->next;
91299ebb4caSwyllys 	}
91399ebb4caSwyllys 
91499ebb4caSwyllys 	if (!found) {
91599ebb4caSwyllys 		ret = KMF_ERR_POLICY_NOT_FOUND;
91699ebb4caSwyllys 		goto out;
91799ebb4caSwyllys 	}
91899ebb4caSwyllys 
91999ebb4caSwyllys out:
92099ebb4caSwyllys 	if (ctxt != NULL)
92199ebb4caSwyllys 		xmlFreeParserCtxt(ctxt);
92299ebb4caSwyllys 
92399ebb4caSwyllys 	if (doc != NULL)
92499ebb4caSwyllys 		xmlFreeDoc(doc);
92599ebb4caSwyllys 
92699ebb4caSwyllys 	return (ret);
92799ebb4caSwyllys }
92899ebb4caSwyllys 
92999ebb4caSwyllys /*
93030a5e8faSwyllys  * kmf_set_policy
93199ebb4caSwyllys  *
93299ebb4caSwyllys  * Set the policy record in the handle.  This searches
93399ebb4caSwyllys  * the policy DB for the named policy.  If it is not found
93499ebb4caSwyllys  * or an error occurred in processing, the existing policy
93599ebb4caSwyllys  * is kept and an error code is returned.
93699ebb4caSwyllys  */
93799ebb4caSwyllys KMF_RETURN
kmf_set_policy(KMF_HANDLE_T handle,char * policyfile,char * policyname)93830a5e8faSwyllys kmf_set_policy(KMF_HANDLE_T handle, char *policyfile, char *policyname)
93999ebb4caSwyllys {
94099ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
94199ebb4caSwyllys 	KMF_POLICY_RECORD *newpolicy = NULL;
94299ebb4caSwyllys 
94399ebb4caSwyllys 	CLEAR_ERROR(handle, ret);
94499ebb4caSwyllys 	if (ret != KMF_OK)
94599ebb4caSwyllys 		return (ret);
94699ebb4caSwyllys 
94799ebb4caSwyllys 	newpolicy = malloc(sizeof (KMF_POLICY_RECORD));
94899ebb4caSwyllys 	if (newpolicy == NULL)
94999ebb4caSwyllys 		return (KMF_ERR_MEMORY);
95099ebb4caSwyllys 	(void) memset(newpolicy, 0, sizeof (KMF_POLICY_RECORD));
95199ebb4caSwyllys 
95230a5e8faSwyllys 	ret = kmf_get_policy(
95399ebb4caSwyllys 	    policyfile == NULL ? KMF_DEFAULT_POLICY_FILE : policyfile,
95499ebb4caSwyllys 	    policyname == NULL ? KMF_DEFAULT_POLICY_NAME : policyname,
95599ebb4caSwyllys 	    newpolicy);
95699ebb4caSwyllys 	if (ret != KMF_OK)
95799ebb4caSwyllys 		goto out;
95899ebb4caSwyllys 
95930a5e8faSwyllys 	ret = kmf_verify_policy(newpolicy);
96099ebb4caSwyllys 	if (ret != KMF_OK)
96199ebb4caSwyllys 		goto out;
96299ebb4caSwyllys 
96399ebb4caSwyllys 	/* release the existing policy data (if any). */
96499ebb4caSwyllys 	if (handle->policy != NULL) {
96530a5e8faSwyllys 		kmf_free_policy_record(handle->policy);
96699ebb4caSwyllys 		free(handle->policy);
96799ebb4caSwyllys 	}
96899ebb4caSwyllys 
96999ebb4caSwyllys 	handle->policy = newpolicy;
97099ebb4caSwyllys 
97199ebb4caSwyllys out:
97299ebb4caSwyllys 	/* Cleanup any data allocated before the error occurred */
97399ebb4caSwyllys 	if (ret != KMF_OK) {
97430a5e8faSwyllys 		kmf_free_policy_record(newpolicy);
97599ebb4caSwyllys 		free(newpolicy);
97699ebb4caSwyllys 	}
97799ebb4caSwyllys 
97899ebb4caSwyllys 	return (ret);
97999ebb4caSwyllys }
98099ebb4caSwyllys 
98199ebb4caSwyllys 
98299ebb4caSwyllys static KMF_RETURN
deletePolicyNode(xmlNodePtr node,char * policy_name)98399ebb4caSwyllys deletePolicyNode(xmlNodePtr node, char *policy_name)
98499ebb4caSwyllys {
98599ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
98699ebb4caSwyllys 	int found = 0;
98799ebb4caSwyllys 	xmlNodePtr dnode = NULL;
98899ebb4caSwyllys 
98999ebb4caSwyllys 	while (node != NULL && !found) {
99099ebb4caSwyllys 		char *c;
99199ebb4caSwyllys 		/*
99299ebb4caSwyllys 		 * Search for the policy that matches the given name.
99399ebb4caSwyllys 		 */
99499ebb4caSwyllys 		if (!xmlStrcmp((const xmlChar *)node->name,
99530a5e8faSwyllys 		    (const xmlChar *)KMF_POLICY_ELEMENT)) {
99699ebb4caSwyllys 			/* Check the name attribute */
99799ebb4caSwyllys 			c = (char *)xmlGetProp(node,
99830a5e8faSwyllys 			    (const xmlChar *)KMF_POLICY_NAME_ATTR);
99999ebb4caSwyllys 
100099ebb4caSwyllys 			/* If a match, parse the rest of the data */
100199ebb4caSwyllys 			if (c != NULL) {
100299ebb4caSwyllys 				if (strcmp(c, policy_name) == 0) {
100399ebb4caSwyllys 					found = 1;
100499ebb4caSwyllys 					dnode = node;
100599ebb4caSwyllys 				}
100699ebb4caSwyllys 				xmlFree(c);
100799ebb4caSwyllys 			}
100899ebb4caSwyllys 		}
100999ebb4caSwyllys 		if (!found)
101099ebb4caSwyllys 			node = node->next;
101199ebb4caSwyllys 	}
101299ebb4caSwyllys 
101399ebb4caSwyllys 	if (found && dnode != NULL) {
101499ebb4caSwyllys 		/* Unlink the node */
101599ebb4caSwyllys 		xmlUnlinkNode(dnode);
101699ebb4caSwyllys 
101799ebb4caSwyllys 		/* Delete it from the document tree */
101899ebb4caSwyllys 		xmlFreeNode(dnode);
101999ebb4caSwyllys 	} else {
102099ebb4caSwyllys 		ret = KMF_ERR_POLICY_NOT_FOUND;
102199ebb4caSwyllys 	}
102299ebb4caSwyllys 
102399ebb4caSwyllys 	return (ret);
102499ebb4caSwyllys }
102599ebb4caSwyllys 
102699ebb4caSwyllys /*
102799ebb4caSwyllys  * update_policyfile
102899ebb4caSwyllys  *
102999ebb4caSwyllys  * Attempt to do a "safe" file update as follows:
103099ebb4caSwyllys  *  1. Lock the original file.
103199ebb4caSwyllys  *  2. Create and write to a temporary file
103299ebb4caSwyllys  *  3. Replace the original file with the temporary file.
103399ebb4caSwyllys  */
103499ebb4caSwyllys static KMF_RETURN
update_policyfile(xmlDocPtr doc,char * filename)103599ebb4caSwyllys update_policyfile(xmlDocPtr doc, char *filename)
103699ebb4caSwyllys {
103799ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
103899ebb4caSwyllys 	FILE *pfile, *tmpfile;
103999ebb4caSwyllys 	char tmpfilename[MAXPATHLEN];
104099ebb4caSwyllys 	char *p;
104199ebb4caSwyllys 	int prefix_len, tmpfd;
104299ebb4caSwyllys 	mode_t old_mode;
104399ebb4caSwyllys 
104499ebb4caSwyllys 	/*
104599ebb4caSwyllys 	 * Open and lock the DB file. First try to open an existing file,
104699ebb4caSwyllys 	 * if that fails, open it as if it were new.
104799ebb4caSwyllys 	 */
104899ebb4caSwyllys 	if ((pfile = fopen(filename, "r+")) == NULL && errno == ENOENT)
104999ebb4caSwyllys 		pfile = fopen(filename, "w+");
105099ebb4caSwyllys 
105199ebb4caSwyllys 	if (pfile == NULL)
105299ebb4caSwyllys 		return (KMF_ERR_POLICY_DB_FILE);
105399ebb4caSwyllys 
105499ebb4caSwyllys 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
105599ebb4caSwyllys 		(void) fclose(pfile);
105699ebb4caSwyllys 		return (KMF_ERR_POLICY_DB_FILE);
105799ebb4caSwyllys 	}
105899ebb4caSwyllys 
105999ebb4caSwyllys 	/*
106099ebb4caSwyllys 	 * Create a temporary file to hold the new data.
106199ebb4caSwyllys 	 */
106299ebb4caSwyllys 	(void) memset(tmpfilename, 0, sizeof (tmpfilename));
106399ebb4caSwyllys 	p = (char *)strrchr(filename, '/');
106499ebb4caSwyllys 	if (p == NULL) {
106599ebb4caSwyllys 		/*
106699ebb4caSwyllys 		 * filename contains basename only so we
106799ebb4caSwyllys 		 * create a temp file in current directory.
106899ebb4caSwyllys 		 */
106999ebb4caSwyllys 		if (strlcpy(tmpfilename, TMPFILE_TEMPLATE,
107099ebb4caSwyllys 		    sizeof (tmpfilename)) >= sizeof (tmpfilename))
107199ebb4caSwyllys 			return (KMF_ERR_INTERNAL);
107299ebb4caSwyllys 	} else {
107399ebb4caSwyllys 		/*
107499ebb4caSwyllys 		 * create a temp file in the same directory
107599ebb4caSwyllys 		 * as the policy file.
107699ebb4caSwyllys 		 */
107799ebb4caSwyllys 		prefix_len = p - filename;
107899ebb4caSwyllys 		(void) strncpy(tmpfilename, filename, prefix_len);
107999ebb4caSwyllys 		(void) strncat(tmpfilename, "/", 1);
108099ebb4caSwyllys 		(void) strncat(tmpfilename, TMPFILE_TEMPLATE,
108199ebb4caSwyllys 		    sizeof (TMPFILE_TEMPLATE));
108299ebb4caSwyllys 	}
108399ebb4caSwyllys 
108499ebb4caSwyllys 	old_mode = umask(077);
108599ebb4caSwyllys 	tmpfd = mkstemp(tmpfilename);
108699ebb4caSwyllys 	(void) umask(old_mode);
108799ebb4caSwyllys 	if (tmpfd == -1) {
108899ebb4caSwyllys 		return (KMF_ERR_POLICY_DB_FILE);
108999ebb4caSwyllys 	}
109099ebb4caSwyllys 
109199ebb4caSwyllys 	if ((tmpfile = fdopen(tmpfd, "w")) == NULL) {
109299ebb4caSwyllys 		(void) close(tmpfd);
109399ebb4caSwyllys 		(void) unlink(tmpfilename);
109499ebb4caSwyllys 		(void) fclose(pfile);
109599ebb4caSwyllys 		return (KMF_ERR_POLICY_DB_FILE);
109699ebb4caSwyllys 	}
109799ebb4caSwyllys 
109899ebb4caSwyllys 	/*
109999ebb4caSwyllys 	 * Write the new info to the temporary file.
110099ebb4caSwyllys 	 */
110199ebb4caSwyllys 	if (xmlDocFormatDump(tmpfile, doc, 1) == -1) {
110299ebb4caSwyllys 		(void) fclose(pfile);
110399ebb4caSwyllys 		(void) fclose(tmpfile);
110499ebb4caSwyllys 		(void) unlink(tmpfilename);
110599ebb4caSwyllys 		return (KMF_ERR_POLICY_ENGINE);
110699ebb4caSwyllys 	}
110799ebb4caSwyllys 
110899ebb4caSwyllys 	(void) fclose(pfile);
110999ebb4caSwyllys 
111030a5e8faSwyllys 	if (fchmod(tmpfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
111199ebb4caSwyllys 		(void) close(tmpfd);
111299ebb4caSwyllys 		(void) unlink(tmpfilename);
111399ebb4caSwyllys 		return (KMF_ERR_POLICY_DB_FILE);
111499ebb4caSwyllys 	}
111599ebb4caSwyllys 	if (fclose(tmpfile) != 0)
111699ebb4caSwyllys 		return (KMF_ERR_POLICY_DB_FILE);
111799ebb4caSwyllys 
111899ebb4caSwyllys 	/*
111999ebb4caSwyllys 	 * Replace the original file with the updated tempfile.
112099ebb4caSwyllys 	 */
112199ebb4caSwyllys 	if (rename(tmpfilename, filename) == -1) {
112299ebb4caSwyllys 		ret = KMF_ERR_POLICY_DB_FILE;
112399ebb4caSwyllys 	}
112499ebb4caSwyllys 
112599ebb4caSwyllys 	if (ret != KMF_OK) {
112699ebb4caSwyllys 		/* try to remove the tmp file */
112799ebb4caSwyllys 		(void) unlink(tmpfilename);
112899ebb4caSwyllys 	}
112999ebb4caSwyllys 
113099ebb4caSwyllys 	return (ret);
113199ebb4caSwyllys }
113299ebb4caSwyllys 
113399ebb4caSwyllys /*
113430a5e8faSwyllys  * kmf_delete_policy_from_db
113599ebb4caSwyllys  *
113699ebb4caSwyllys  * Find a policy by name and remove it from the policy DB file.
113799ebb4caSwyllys  * If the policy is not found, return an error.
113899ebb4caSwyllys  */
113999ebb4caSwyllys KMF_RETURN
kmf_delete_policy_from_db(char * policy_name,char * dbfilename)114030a5e8faSwyllys kmf_delete_policy_from_db(char *policy_name, char *dbfilename)
114199ebb4caSwyllys {
114299ebb4caSwyllys 	KMF_RETURN ret;
114399ebb4caSwyllys 	xmlParserCtxtPtr ctxt = NULL;
114499ebb4caSwyllys 	xmlDocPtr doc = NULL;
114599ebb4caSwyllys 	xmlNodePtr cur, node;
114699ebb4caSwyllys 
114799ebb4caSwyllys 	if (policy_name == NULL || dbfilename == NULL)
114899ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
114999ebb4caSwyllys 
115099ebb4caSwyllys 	/*
115199ebb4caSwyllys 	 * Cannot delete the default policy record from the system
115299ebb4caSwyllys 	 * default policy database (/etc/security/kmfpolicy.xml).
115399ebb4caSwyllys 	 */
115499ebb4caSwyllys 	if (strcmp(dbfilename, KMF_DEFAULT_POLICY_FILE) == 0 &&
115599ebb4caSwyllys 	    strcmp(policy_name, KMF_DEFAULT_POLICY_NAME) == 0)
115699ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
115799ebb4caSwyllys 
115899ebb4caSwyllys 	/* Make sure the policy file exists */
115999ebb4caSwyllys 	if (access(dbfilename, R_OK | W_OK))
116099ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
116199ebb4caSwyllys 
116299ebb4caSwyllys 	/* Read the policy DB and verify it against the schema. */
116399ebb4caSwyllys 	ctxt = xmlNewParserCtxt();
116499ebb4caSwyllys 	if (ctxt == NULL)
116599ebb4caSwyllys 		return (KMF_ERR_POLICY_DB_FORMAT);
116699ebb4caSwyllys 
116799ebb4caSwyllys 	doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
116899ebb4caSwyllys 	    XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
116999ebb4caSwyllys 	if (doc == NULL || ctxt->valid == 0) {
117099ebb4caSwyllys 		ret = KMF_ERR_POLICY_DB_FORMAT;
117199ebb4caSwyllys 		goto end;
117299ebb4caSwyllys 	}
117399ebb4caSwyllys 
117499ebb4caSwyllys 	cur = xmlDocGetRootElement(doc);
117599ebb4caSwyllys 	if (cur == NULL) {
117699ebb4caSwyllys 		xmlFreeDoc(doc);
117799ebb4caSwyllys 		return (KMF_ERR_POLICY_DB_FORMAT);
117899ebb4caSwyllys 	}
117999ebb4caSwyllys 	node = cur->xmlChildrenNode;
118099ebb4caSwyllys 
118199ebb4caSwyllys 	ret = deletePolicyNode(node, policy_name);
118299ebb4caSwyllys 
118399ebb4caSwyllys 	if (ret == KMF_OK)
118499ebb4caSwyllys 		ret = update_policyfile(doc, dbfilename);
118599ebb4caSwyllys 
118699ebb4caSwyllys end:
118799ebb4caSwyllys 	if (ctxt != NULL)
118899ebb4caSwyllys 		xmlFreeParserCtxt(ctxt);
118999ebb4caSwyllys 
119099ebb4caSwyllys 	if (doc != NULL)
119199ebb4caSwyllys 		xmlFreeDoc(doc);
119299ebb4caSwyllys 
119399ebb4caSwyllys 	return (ret);
119499ebb4caSwyllys }
119599ebb4caSwyllys 
119699ebb4caSwyllys /*
119799ebb4caSwyllys  * Add a new policy node to the Policy DB XML tree.
119899ebb4caSwyllys  */
119999ebb4caSwyllys static KMF_RETURN
addPolicyNode(xmlNodePtr pnode,KMF_POLICY_RECORD * policy)120099ebb4caSwyllys addPolicyNode(xmlNodePtr pnode, KMF_POLICY_RECORD *policy)
120199ebb4caSwyllys {
120299ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
120399ebb4caSwyllys 
120499ebb4caSwyllys 	if (pnode != NULL && policy != NULL) {
120599ebb4caSwyllys 		if (newprop(pnode, KMF_POLICY_NAME_ATTR, policy->name) != 0) {
120699ebb4caSwyllys 			ret = KMF_ERR_POLICY_ENGINE;
120799ebb4caSwyllys 			goto out;
120899ebb4caSwyllys 		}
120999ebb4caSwyllys 		if (policy->ignore_date) {
121099ebb4caSwyllys 			if (newprop(pnode, KMF_OPTIONS_IGNORE_DATE_ATTR,
121130a5e8faSwyllys 			    "TRUE")) {
121299ebb4caSwyllys 				ret = KMF_ERR_POLICY_ENGINE;
121399ebb4caSwyllys 				goto out;
121499ebb4caSwyllys 			}
121599ebb4caSwyllys 		}
121699ebb4caSwyllys 
121799ebb4caSwyllys 		if (policy->ignore_unknown_ekus) {
121899ebb4caSwyllys 			if (newprop(pnode, KMF_OPTIONS_IGNORE_UNKNOWN_EKUS,
121930a5e8faSwyllys 			    "TRUE")) {
122099ebb4caSwyllys 				ret = KMF_ERR_POLICY_ENGINE;
122199ebb4caSwyllys 				goto out;
122299ebb4caSwyllys 			}
122399ebb4caSwyllys 		}
122499ebb4caSwyllys 
122599ebb4caSwyllys 		if (policy->ignore_trust_anchor) {
122699ebb4caSwyllys 			if (newprop(pnode, KMF_OPTIONS_IGNORE_TRUST_ANCHOR,
122730a5e8faSwyllys 			    "TRUE")) {
122899ebb4caSwyllys 				ret = KMF_ERR_POLICY_ENGINE;
122999ebb4caSwyllys 				goto out;
123099ebb4caSwyllys 			}
123199ebb4caSwyllys 		}
123299ebb4caSwyllys 
123399ebb4caSwyllys 		if (policy->validity_adjusttime) {
123499ebb4caSwyllys 			if (newprop(pnode, KMF_OPTIONS_VALIDITY_ADJUSTTIME,
123530a5e8faSwyllys 			    policy->validity_adjusttime)) {
123699ebb4caSwyllys 				ret = KMF_ERR_POLICY_ENGINE;
123799ebb4caSwyllys 				goto out;
123899ebb4caSwyllys 			}
123999ebb4caSwyllys 		}
124099ebb4caSwyllys 
124199ebb4caSwyllys 		if (newprop(pnode, KMF_POLICY_TA_NAME_ATTR,
124299ebb4caSwyllys 		    policy->ta_name) != 0) {
124399ebb4caSwyllys 			ret = KMF_ERR_POLICY_ENGINE;
124499ebb4caSwyllys 			goto out;
124599ebb4caSwyllys 		}
124699ebb4caSwyllys 
124799ebb4caSwyllys 		if (newprop(pnode, KMF_POLICY_TA_SERIAL_ATTR,
124899ebb4caSwyllys 		    policy->ta_serial) != 0) {
124999ebb4caSwyllys 			ret = KMF_ERR_POLICY_ENGINE;
125099ebb4caSwyllys 			goto out;
125199ebb4caSwyllys 		}
125299ebb4caSwyllys 
125399ebb4caSwyllys 		/* Add a text node for readability */
125499ebb4caSwyllys 		addFormatting(pnode, "\n");
125599ebb4caSwyllys 
125699ebb4caSwyllys 		if (ret = AddValidationNodes(pnode, policy)) {
125799ebb4caSwyllys 			goto out;
125899ebb4caSwyllys 		}
125999ebb4caSwyllys 
126099ebb4caSwyllys 		if ((ret = AddKeyUsageNodes(pnode, policy->ku_bits))) {
126199ebb4caSwyllys 			goto out;
126299ebb4caSwyllys 		}
126399ebb4caSwyllys 
126499ebb4caSwyllys 		if ((ret = AddExtKeyUsageNodes(pnode, &policy->eku_set))) {
126599ebb4caSwyllys 			goto out;
126699ebb4caSwyllys 		}
1267269e59f9SJan Pechanec 		if ((ret = AddMapperPolicyNodes(pnode, &policy->mapper))) {
1268269e59f9SJan Pechanec 			goto out;
1269269e59f9SJan Pechanec 		}
127099ebb4caSwyllys 	} else {
127199ebb4caSwyllys 		ret = KMF_ERR_BAD_PARAMETER;
127299ebb4caSwyllys 	}
127399ebb4caSwyllys out:
127499ebb4caSwyllys 	if (ret != KMF_OK && pnode != NULL) {
127599ebb4caSwyllys 		xmlUnlinkNode(pnode);
127699ebb4caSwyllys 		xmlFreeNode(pnode);
127799ebb4caSwyllys 	}
127899ebb4caSwyllys 
127999ebb4caSwyllys 	return (ret);
128099ebb4caSwyllys }
128199ebb4caSwyllys 
128299ebb4caSwyllys KMF_RETURN
kmf_verify_policy(KMF_POLICY_RECORD * policy)128330a5e8faSwyllys kmf_verify_policy(KMF_POLICY_RECORD *policy)
128499ebb4caSwyllys {
128599ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
128699ebb4caSwyllys 	boolean_t has_ta;
128799ebb4caSwyllys 
128899ebb4caSwyllys 	if (policy->name == NULL || !strlen(policy->name))
128999ebb4caSwyllys 		return (KMF_ERR_POLICY_NAME);
129099ebb4caSwyllys 
129199ebb4caSwyllys 	/* Check the TA related policy */
1292*fc2613b0SWyllys Ingersoll 	if (policy->ta_name != NULL &&
1293*fc2613b0SWyllys Ingersoll 	    strcasecmp(policy->ta_name, "search") == 0) {
1294*fc2613b0SWyllys Ingersoll 		has_ta = B_TRUE;
1295*fc2613b0SWyllys Ingersoll 	} else if (policy->ta_name != NULL && policy->ta_serial != NULL) {
129699ebb4caSwyllys 		has_ta = B_TRUE;
129799ebb4caSwyllys 	} else if (policy->ta_name == NULL && policy->ta_serial == NULL) {
129899ebb4caSwyllys 		has_ta = B_FALSE;
129999ebb4caSwyllys 	} else {
130099ebb4caSwyllys 		/*
130199ebb4caSwyllys 		 * If the TA cert is set, then both name and serial number
130299ebb4caSwyllys 		 * need to be specified.
130399ebb4caSwyllys 		 */
130499ebb4caSwyllys 		return (KMF_ERR_TA_POLICY);
130599ebb4caSwyllys 	}
130699ebb4caSwyllys 
130799ebb4caSwyllys 	if (has_ta == B_FALSE && policy->ignore_trust_anchor == B_FALSE)
130899ebb4caSwyllys 		return (KMF_ERR_TA_POLICY);
130999ebb4caSwyllys 
131099ebb4caSwyllys 	if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
131199ebb4caSwyllys 		/*
131299ebb4caSwyllys 		 * For OCSP, either use a fixed responder or use the
131399ebb4caSwyllys 		 * value from the cert, but not both.
131499ebb4caSwyllys 		 */
131599ebb4caSwyllys 		if ((policy->VAL_OCSP_BASIC.responderURI == NULL &&
131699ebb4caSwyllys 		    policy->VAL_OCSP_BASIC.uri_from_cert == B_FALSE) ||
131799ebb4caSwyllys 		    (policy->VAL_OCSP_BASIC.responderURI != NULL &&
131899ebb4caSwyllys 		    policy->VAL_OCSP_BASIC.uri_from_cert == B_TRUE))
131999ebb4caSwyllys 			return (KMF_ERR_OCSP_POLICY);
132099ebb4caSwyllys 
132199ebb4caSwyllys 		/*
132299ebb4caSwyllys 		 * If the OCSP responder cert is set, then both name and serial
132399ebb4caSwyllys 		 * number need to be specified.
132499ebb4caSwyllys 		 */
132599ebb4caSwyllys 		if ((policy->VAL_OCSP_RESP_CERT.name != NULL &&
132699ebb4caSwyllys 		    policy->VAL_OCSP_RESP_CERT.serial == NULL) ||
132799ebb4caSwyllys 		    (policy->VAL_OCSP_RESP_CERT.name == NULL &&
132899ebb4caSwyllys 		    policy->VAL_OCSP_RESP_CERT.serial != NULL))
132999ebb4caSwyllys 			return (KMF_ERR_OCSP_POLICY);
133099ebb4caSwyllys 	}
133199ebb4caSwyllys 
133299ebb4caSwyllys 	return (ret);
133399ebb4caSwyllys }
133499ebb4caSwyllys 
133599ebb4caSwyllys /*
133699ebb4caSwyllys  * Update the KMF policy file by creating a new XML Policy doc tree
133799ebb4caSwyllys  * from the data in the KMF_POLICY_RECORD structure. If "check_policy"
133899ebb4caSwyllys  * is true, then we check the policy sanity also.
133999ebb4caSwyllys  */
134099ebb4caSwyllys KMF_RETURN
kmf_add_policy_to_db(KMF_POLICY_RECORD * policy,char * dbfilename,boolean_t check_policy)134130a5e8faSwyllys kmf_add_policy_to_db(KMF_POLICY_RECORD *policy, char *dbfilename,
134299ebb4caSwyllys     boolean_t check_policy)
134399ebb4caSwyllys {
134499ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
134599ebb4caSwyllys 	xmlDocPtr doc = NULL;
134699ebb4caSwyllys 	xmlNodePtr root, node;
134799ebb4caSwyllys 	xmlParserCtxtPtr ctxt = NULL;
134899ebb4caSwyllys 
134999ebb4caSwyllys 	if (policy == NULL || dbfilename == NULL)
135099ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
135199ebb4caSwyllys 
135299ebb4caSwyllys 	if (check_policy == B_TRUE) {
135330a5e8faSwyllys 		if (ret = kmf_verify_policy(policy))
135430a5e8faSwyllys 			return (ret);
135599ebb4caSwyllys 	}
135699ebb4caSwyllys 
135799ebb4caSwyllys 	/* If the policyDB exists, load it into memory */
135899ebb4caSwyllys 	if (!access(dbfilename, R_OK)) {
135999ebb4caSwyllys 
136099ebb4caSwyllys 		/* Create a parser context */
136199ebb4caSwyllys 		ctxt = xmlNewParserCtxt();
136299ebb4caSwyllys 		if (ctxt == NULL)
136399ebb4caSwyllys 			return (KMF_ERR_POLICY_DB_FORMAT);
136499ebb4caSwyllys 
136599ebb4caSwyllys 		doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
136699ebb4caSwyllys 		    XML_PARSE_DTDVALID | XML_PARSE_NOERROR |
136799ebb4caSwyllys 		    XML_PARSE_NOWARNING);
136899ebb4caSwyllys 		if (doc == NULL || ctxt->valid == 0) {
136999ebb4caSwyllys 			ret = KMF_ERR_POLICY_DB_FORMAT;
137099ebb4caSwyllys 			goto out;
137199ebb4caSwyllys 		}
137299ebb4caSwyllys 
137399ebb4caSwyllys 		root = xmlDocGetRootElement(doc);
137499ebb4caSwyllys 		if (root == NULL) {
137599ebb4caSwyllys 			ret = KMF_ERR_POLICY_DB_FORMAT;
137699ebb4caSwyllys 			goto out;
137799ebb4caSwyllys 		}
137899ebb4caSwyllys 
137999ebb4caSwyllys 		node = root->xmlChildrenNode;
138099ebb4caSwyllys 		/*
138199ebb4caSwyllys 		 * If the DB has an existing policy of the
138299ebb4caSwyllys 		 * same name, delete it from the tree.
138399ebb4caSwyllys 		 */
138499ebb4caSwyllys 		ret = deletePolicyNode(node, policy->name);
138599ebb4caSwyllys 		if (ret == KMF_ERR_POLICY_NOT_FOUND)
138699ebb4caSwyllys 			ret = KMF_OK;
138799ebb4caSwyllys 	} else {
138899ebb4caSwyllys 		/* Initialize a new DB tree */
138999ebb4caSwyllys 		doc = xmlNewDoc((const xmlChar *)"1.0");
139099ebb4caSwyllys 		if (doc == NULL)
139199ebb4caSwyllys 			return (KMF_ERR_POLICY_ENGINE);
139299ebb4caSwyllys 
139399ebb4caSwyllys 		/*
139499ebb4caSwyllys 		 * Add the DOCTYPE header to the tree so the
139599ebb4caSwyllys 		 * DTD link is embedded
139699ebb4caSwyllys 		 */
139799ebb4caSwyllys 		doc->intSubset = xmlCreateIntSubset(doc,
139830a5e8faSwyllys 		    (const xmlChar *)KMF_POLICY_ROOT,
139930a5e8faSwyllys 		    NULL, (const xmlChar *)KMF_POLICY_DTD);
140099ebb4caSwyllys 
140199ebb4caSwyllys 		root = xmlNewDocNode(doc, NULL,
140230a5e8faSwyllys 		    (const xmlChar *)KMF_POLICY_ROOT, NULL);
140399ebb4caSwyllys 		if (root != NULL) {
14045ad42b1bSSurya Prakki 			(void) xmlDocSetRootElement(doc, root);
140599ebb4caSwyllys 		}
140699ebb4caSwyllys 	}
140799ebb4caSwyllys 
140899ebb4caSwyllys 	/* Append the new policy info to the root node. */
140999ebb4caSwyllys 	if (root != NULL) {
141099ebb4caSwyllys 		xmlNodePtr pnode;
141199ebb4caSwyllys 
141299ebb4caSwyllys 		pnode = xmlNewChild(root, NULL,
141330a5e8faSwyllys 		    (const xmlChar *)KMF_POLICY_ELEMENT, NULL);
141499ebb4caSwyllys 
141599ebb4caSwyllys 		ret = addPolicyNode(pnode, policy);
141699ebb4caSwyllys 		/* If that worked, update the DB file. */
141799ebb4caSwyllys 		if (ret == KMF_OK)
141899ebb4caSwyllys 			ret = update_policyfile(doc, dbfilename);
141999ebb4caSwyllys 	} else {
142099ebb4caSwyllys 		ret = KMF_ERR_POLICY_ENGINE;
142199ebb4caSwyllys 	}
142299ebb4caSwyllys 
142399ebb4caSwyllys 
142499ebb4caSwyllys out:
142599ebb4caSwyllys 	if (ctxt != NULL)
142699ebb4caSwyllys 		xmlFreeParserCtxt(ctxt);
142799ebb4caSwyllys 
142899ebb4caSwyllys 	if (doc != NULL)
142999ebb4caSwyllys 		xmlFreeDoc(doc);
143099ebb4caSwyllys 
143199ebb4caSwyllys 	return (ret);
143299ebb4caSwyllys }
1433