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