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