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