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