2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A *
2N/A * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdlib.h>
2N/A#include <ctype.h>
2N/A#include <strings.h>
2N/A#include <unistd.h>
2N/A#include <errno.h>
2N/A#include <libgen.h>
2N/A#include <sys/param.h>
2N/A#include <sys/stat.h>
2N/A
2N/A#include <kmfapiP.h>
2N/A#include <libxml/tree.h>
2N/A#include <libxml/parser.h>
2N/A
2N/Atypedef struct {
2N/A char *ekuname;
2N/A KMF_OID *oid;
2N/A} EKUName2OID;
2N/A
2N/Astatic EKUName2OID EKUList[] = {
2N/A {"serverAuth", (KMF_OID *)&KMFOID_PKIX_KP_ServerAuth},
2N/A {"clientAuth", (KMF_OID *)&KMFOID_PKIX_KP_ClientAuth},
2N/A {"codeSigning", (KMF_OID *)&KMFOID_PKIX_KP_CodeSigning},
2N/A {"emailProtection", (KMF_OID *)&KMFOID_PKIX_KP_EmailProtection},
2N/A {"ipsecEndSystem", (KMF_OID *)&KMFOID_PKIX_KP_IPSecEndSystem},
2N/A {"ipsecTunnel", (KMF_OID *)&KMFOID_PKIX_KP_IPSecTunnel},
2N/A {"ipsecUser", (KMF_OID *)&KMFOID_PKIX_KP_IPSecUser},
2N/A {"timeStamping", (KMF_OID *)&KMFOID_PKIX_KP_TimeStamping},
2N/A {"OCSPSigning", (KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning},
2N/A {"KPClientAuth", (KMF_OID *)&KMFOID_PKINIT_ClientAuth},
2N/A {"KPKdc", (KMF_OID *)&KMFOID_PKINIT_Kdc},
2N/A {"scLogon", (KMF_OID *)&KMFOID_MS_KP_SCLogon}
2N/A};
2N/A
2N/Astatic int num_ekus = sizeof (EKUList) / sizeof (EKUName2OID);
2N/A
2N/Astatic void
2N/AaddFormatting(xmlNodePtr parent, char *text)
2N/A{
2N/A xmlNodePtr snode;
2N/A
2N/A if (parent == NULL || text == NULL)
2N/A return;
2N/A
2N/A snode = xmlNewText((const xmlChar *)text);
2N/A if (snode != NULL) {
2N/A (void) xmlAddChild(parent, snode);
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/AparseOCSPValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo)
2N/A{
2N/A xmlNodePtr n;
2N/A char *c;
2N/A n = node->children;
2N/A while (n != NULL) {
2N/A if (!xmlStrcmp((const xmlChar *)n->name,
2N/A (const xmlChar *)KMF_OCSP_BASIC_ELEMENT)) {
2N/A
2N/A vinfo->ocsp_info.basic.responderURI =
2N/A (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_OCSP_RESPONDER_ATTR);
2N/A
2N/A vinfo->ocsp_info.basic.proxy = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_OCSP_PROXY_ATTR);
2N/A
2N/A c = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_OCSP_URI_ATTR);
2N/A if (c != NULL && !strcasecmp(c, "true")) {
2N/A vinfo->ocsp_info.basic.uri_from_cert = 1;
2N/A xmlFree(c);
2N/A }
2N/A
2N/A vinfo->ocsp_info.basic.response_lifetime =
2N/A (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_OCSP_RESPONSE_LIFETIME_ATTR);
2N/A
2N/A c = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_OCSP_IGNORE_SIGN_ATTR);
2N/A if (c != NULL && !strcasecmp(c, "true")) {
2N/A vinfo->ocsp_info.basic.ignore_response_sign = 1;
2N/A xmlFree(c);
2N/A }
2N/A
2N/A } else if (!xmlStrcmp((const xmlChar *)n->name,
2N/A (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT)) {
2N/A
2N/A vinfo->ocsp_info.resp_cert.name =
2N/A (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CERT_NAME_ATTR);
2N/A vinfo->ocsp_info.resp_cert.serial =
2N/A (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CERT_SERIAL_ATTR);
2N/A vinfo->ocsp_info.has_resp_cert = 1;
2N/A }
2N/A
2N/A n = n->next;
2N/A }
2N/A
2N/A}
2N/A
2N/A/*
2N/A * Parse the "validation-methods" section of the policy.
2N/A */
2N/Astatic void
2N/AparseValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo,
2N/A KMF_POLICY_RECORD *policy)
2N/A{
2N/A xmlNodePtr n;
2N/A char *c;
2N/A n = node->children;
2N/A while (n != NULL) {
2N/A if (!xmlStrcmp((const xmlChar *)n->name,
2N/A (const xmlChar *)KMF_OCSP_ELEMENT)) {
2N/A
2N/A parseOCSPValidation(n, &policy->validation_info);
2N/A policy->revocation |= KMF_REVOCATION_METHOD_OCSP;
2N/A
2N/A
2N/A } else if (!xmlStrcmp((const xmlChar *)n->name,
2N/A (const xmlChar *)KMF_CRL_ELEMENT)) {
2N/A
2N/A vinfo->crl_info.basefilename = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CRL_BASENAME_ATTR);
2N/A
2N/A vinfo->crl_info.directory = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CRL_DIRECTORY_ATTR);
2N/A
2N/A c = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CRL_GET_URI_ATTR);
2N/A if (c != NULL && !strcasecmp(c, "true")) {
2N/A vinfo->crl_info.get_crl_uri = 1;
2N/A } else {
2N/A vinfo->crl_info.get_crl_uri = 0;
2N/A }
2N/A xmlFree(c);
2N/A
2N/A vinfo->crl_info.proxy = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CRL_PROXY_ATTR);
2N/A
2N/A c = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CRL_IGNORE_SIGN_ATTR);
2N/A if (c != NULL && !strcasecmp(c, "true")) {
2N/A vinfo->crl_info.ignore_crl_sign = 1;
2N/A } else {
2N/A vinfo->crl_info.ignore_crl_sign = 0;
2N/A }
2N/A xmlFree(c);
2N/A
2N/A c = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CRL_IGNORE_DATE_ATTR);
2N/A if (c != NULL && !strcasecmp(c, "true")) {
2N/A vinfo->crl_info.ignore_crl_date = 1;
2N/A } else {
2N/A vinfo->crl_info.ignore_crl_date = 0;
2N/A }
2N/A xmlFree(c);
2N/A
2N/A policy->revocation |= KMF_REVOCATION_METHOD_CRL;
2N/A }
2N/A
2N/A n = n->next;
2N/A }
2N/A}
2N/A
2N/Achar *
2N/Akmf_ku_to_string(uint32_t bitfield)
2N/A{
2N/A if (bitfield & KMF_digitalSignature)
2N/A return ("digitalSignature");
2N/A
2N/A if (bitfield & KMF_nonRepudiation)
2N/A return ("nonRepudiation");
2N/A
2N/A if (bitfield & KMF_keyEncipherment)
2N/A return ("keyEncipherment");
2N/A
2N/A if (bitfield & KMF_dataEncipherment)
2N/A return ("dataEncipherment");
2N/A
2N/A if (bitfield & KMF_keyAgreement)
2N/A return ("keyAgreement");
2N/A
2N/A if (bitfield & KMF_keyCertSign)
2N/A return ("keyCertSign");
2N/A
2N/A if (bitfield & KMF_cRLSign)
2N/A return ("cRLSign");
2N/A
2N/A if (bitfield & KMF_encipherOnly)
2N/A return ("encipherOnly");
2N/A
2N/A if (bitfield & KMF_decipherOnly)
2N/A return ("decipherOnly");
2N/A
2N/A return (NULL);
2N/A}
2N/A
2N/Auint32_t
2N/Akmf_string_to_ku(char *kustring)
2N/A{
2N/A if (kustring == NULL || !strlen(kustring))
2N/A return (0);
2N/A if (strcasecmp(kustring, "digitalSignature") == 0)
2N/A return (KMF_digitalSignature);
2N/A if (strcasecmp(kustring, "nonRepudiation") == 0)
2N/A return (KMF_nonRepudiation);
2N/A if (strcasecmp(kustring, "keyEncipherment") == 0)
2N/A return (KMF_keyEncipherment);
2N/A if (strcasecmp(kustring, "dataEncipherment") == 0)
2N/A return (KMF_dataEncipherment);
2N/A if (strcasecmp(kustring, "keyAgreement") == 0)
2N/A return (KMF_keyAgreement);
2N/A if (strcasecmp(kustring, "keyCertSign") == 0)
2N/A return (KMF_keyCertSign);
2N/A if (strcasecmp(kustring, "cRLSign") == 0)
2N/A return (KMF_cRLSign);
2N/A if (strcasecmp(kustring, "encipherOnly") == 0)
2N/A return (KMF_encipherOnly);
2N/A if (strcasecmp(kustring, "decipherOnly") == 0)
2N/A return (KMF_decipherOnly);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic void
2N/AparseKeyUsageSet(xmlNodePtr node, uint32_t *kubits)
2N/A{
2N/A xmlNodePtr n;
2N/A char *c;
2N/A
2N/A n = node->children;
2N/A while (n != NULL) {
2N/A if (!xmlStrcmp((const xmlChar *)n->name,
2N/A (const xmlChar *)KMF_KEY_USAGE_ELEMENT)) {
2N/A c = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_KEY_USAGE_USE_ATTR);
2N/A if (c) {
2N/A *kubits |= kmf_string_to_ku(c);
2N/A xmlFree(c);
2N/A }
2N/A }
2N/A
2N/A n = n->next;
2N/A }
2N/A}
2N/A
2N/Astatic KMF_OID *
2N/Adup_oid(KMF_OID *oldoid)
2N/A{
2N/A KMF_OID *oid;
2N/A
2N/A oid = malloc(sizeof (KMF_OID));
2N/A if (oid == NULL)
2N/A return (NULL);
2N/A
2N/A oid->Length = oldoid->Length;
2N/A oid->Data = malloc(oid->Length);
2N/A if (oid->Data == NULL) {
2N/A free(oid);
2N/A return (NULL);
2N/A }
2N/A (void) memcpy(oid->Data, oldoid->Data, oid->Length);
2N/A
2N/A return (oid);
2N/A}
2N/A
2N/AKMF_OID *
2N/Akmf_ekuname_to_oid(char *ekuname)
2N/A{
2N/A KMF_OID *oid;
2N/A int i;
2N/A
2N/A if (ekuname == NULL)
2N/A return (NULL);
2N/A
2N/A for (i = 0; i < num_ekus; i++) {
2N/A if (strcasecmp(EKUList[i].ekuname, ekuname) == 0) {
2N/A oid = dup_oid(EKUList[i].oid);
2N/A return (oid);
2N/A }
2N/A }
2N/A
2N/A return (NULL);
2N/A}
2N/A
2N/Achar *
2N/Akmf_oid_to_ekuname(KMF_OID *oid)
2N/A{
2N/A int i;
2N/A for (i = 0; i < num_ekus; i++) {
2N/A if (oid->Length == EKUList[i].oid->Length &&
2N/A !memcmp(oid->Data, EKUList[i].oid->Data, oid->Length)) {
2N/A return (EKUList[i].ekuname);
2N/A }
2N/A }
2N/A return (NULL);
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/AparseExtKeyUsage(xmlNodePtr node, KMF_EKU_POLICY *ekus)
2N/A{
2N/A xmlNodePtr n;
2N/A char *c;
2N/A KMF_RETURN ret = KMF_OK;
2N/A boolean_t found = FALSE;
2N/A
2N/A n = node->children;
2N/A while (n != NULL && ret == KMF_OK) {
2N/A KMF_OID newoid, *oidptr;
2N/A
2N/A oidptr = NULL;
2N/A newoid.Data = NULL;
2N/A newoid.Length = 0;
2N/A
2N/A if (!xmlStrcmp((const xmlChar *)n->name,
2N/A (const xmlChar *)KMF_EKU_NAME_ELEMENT)) {
2N/A c = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_EKU_NAME_ATTR);
2N/A if (c != NULL) {
2N/A oidptr = kmf_ekuname_to_oid(c);
2N/A xmlFree(c);
2N/A found = TRUE;
2N/A if (oidptr != NULL)
2N/A newoid = *oidptr;
2N/A }
2N/A } else if (!xmlStrcmp((const xmlChar *)n->name,
2N/A (const xmlChar *)KMF_EKU_OID_ELEMENT)) {
2N/A c = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_EKU_OID_ATTR);
2N/A if (c != NULL) {
2N/A (void) kmf_string_to_oid(c, &newoid);
2N/A xmlFree(c);
2N/A found = TRUE;
2N/A }
2N/A } else {
2N/A n = n->next;
2N/A if ((n == NULL) && (!found))
2N/A ret = KMF_ERR_POLICY_DB_FORMAT;
2N/A continue;
2N/A }
2N/A
2N/A if (newoid.Data != NULL) {
2N/A ekus->eku_count++;
2N/A ekus->ekulist = realloc(ekus->ekulist,
2N/A ekus->eku_count * sizeof (KMF_OID));
2N/A if (ekus->ekulist != NULL) {
2N/A ekus->ekulist[ekus->eku_count-1].Length =
2N/A newoid.Length;
2N/A ekus->ekulist[ekus->eku_count-1].Data =
2N/A newoid.Data;
2N/A } else {
2N/A ret = KMF_ERR_MEMORY;
2N/A }
2N/A } else {
2N/A ret = KMF_ERR_POLICY_DB_FORMAT;
2N/A }
2N/A
2N/A n = n->next;
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/AparseMapper(xmlNodePtr node, KMF_MAPPER_RECORD *mapper)
2N/A{
2N/A xmlNodePtr n;
2N/A
2N/A n = node;
2N/A mapper->mapname = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CERT_MAPPER_NAME_ATTR);
2N/A mapper->dir = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CERT_MAPPER_DIR_ATTR);
2N/A mapper->pathname = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CERT_MAPPER_PATH_ATTR);
2N/A mapper->options = (char *)xmlGetProp(n,
2N/A (const xmlChar *)KMF_CERT_MAPPER_OPTIONS_ATTR);
2N/A
2N/A /*
2N/A * These are set according to whether mapper setting is taken from the
2N/A * database or init function attributes.
2N/A */
2N/A mapper->curpathname = NULL;
2N/A mapper->curoptions = NULL;
2N/A
2N/A return (KMF_OK);
2N/A}
2N/A
2N/Aint
2N/AparsePolicyElement(xmlNodePtr node, KMF_POLICY_RECORD *policy)
2N/A{
2N/A int ret = 0;
2N/A xmlNodePtr n = node->xmlChildrenNode;
2N/A char *c;
2N/A
2N/A if (node->type == XML_ELEMENT_NODE) {
2N/A if (node->properties != NULL) {
2N/A policy->name = (char *)xmlGetProp(node,
2N/A (const xmlChar *)KMF_POLICY_NAME_ATTR);
2N/A
2N/A c = (char *)xmlGetProp(node,
2N/A (const xmlChar *)KMF_OPTIONS_IGNORE_DATE_ATTR);
2N/A if (c && !strcasecmp(c, "true")) {
2N/A policy->ignore_date = 1;
2N/A xmlFree((xmlChar *)c);
2N/A }
2N/A
2N/A c = (char *)xmlGetProp(node,
2N/A (const xmlChar *)KMF_OPTIONS_IGNORE_UNKNOWN_EKUS);
2N/A if (c && !strcasecmp(c, "true")) {
2N/A policy->ignore_unknown_ekus = 1;
2N/A xmlFree(c);
2N/A }
2N/A
2N/A c = (char *)xmlGetProp(node,
2N/A (const xmlChar *)KMF_OPTIONS_IGNORE_TRUST_ANCHOR);
2N/A if (c && !strcasecmp(c, "true")) {
2N/A policy->ignore_trust_anchor = 1;
2N/A xmlFree(c);
2N/A }
2N/A
2N/A c = (char *)xmlGetProp(node,
2N/A (const xmlChar *)KMF_OPTIONS_VALIDITY_ADJUSTTIME);
2N/A if (c) {
2N/A policy->validity_adjusttime = c;
2N/A } else {
2N/A policy->validity_adjusttime = NULL;
2N/A }
2N/A
2N/A policy->ta_name = (char *)xmlGetProp(node,
2N/A (const xmlChar *)KMF_POLICY_TA_NAME_ATTR);
2N/A
2N/A policy->ta_serial = (char *)xmlGetProp(node,
2N/A (const xmlChar *)KMF_POLICY_TA_SERIAL_ATTR);
2N/A }
2N/A
2N/A n = node->children;
2N/A while (n != NULL) {
2N/A if (!xmlStrcmp((const xmlChar *)n->name,
2N/A (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT))
2N/A parseValidation(n, &policy->validation_info,
2N/A policy);
2N/A else if (!xmlStrcmp((const xmlChar *)n->name,
2N/A (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT))
2N/A parseKeyUsageSet(n, &policy->ku_bits);
2N/A else if (!xmlStrcmp((const xmlChar *)n->name,
2N/A (const xmlChar *)KMF_EKU_ELEMENT)) {
2N/A ret = parseExtKeyUsage(n, &policy->eku_set);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A } else if (!xmlStrcmp((const xmlChar *)n->name,
2N/A (const xmlChar *)KMF_CERT_MAPPER_ELEMENT)) {
2N/A ret = parseMapper(n, &policy->mapper);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A }
2N/A
2N/A n = n->next;
2N/A }
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/Astatic int
2N/Anewprop(xmlNodePtr node, char *attrname, char *src)
2N/A{
2N/A xmlAttrPtr newattr;
2N/A
2N/A if (src != NULL && strlen(src)) {
2N/A newattr = xmlNewProp(node, (const xmlChar *)attrname,
2N/A (xmlChar *)src);
2N/A if (newattr == NULL) {
2N/A xmlUnlinkNode(node);
2N/A xmlFreeNode(node);
2N/A return (-1);
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Add CRL policy information to the XML tree.
2N/A * Return non-zero on any failure, else 0 for success.
2N/A *
2N/A * This function is called only when the KMF_REVOCATION_METHOD_CRL flag is on.
2N/A */
2N/Astatic int
2N/AAddCRLNodes(xmlNodePtr node, KMF_CRL_POLICY *crlinfo)
2N/A{
2N/A xmlNodePtr n;
2N/A
2N/A addFormatting(node, "\t\t");
2N/A n = xmlNewChild(node, NULL, (const xmlChar *)"crl", NULL);
2N/A if (n == NULL)
2N/A return (-1);
2N/A
2N/A if (crlinfo->basefilename &&
2N/A newprop(n, KMF_CRL_BASENAME_ATTR, crlinfo->basefilename))
2N/A return (-1);
2N/A
2N/A if (crlinfo->directory &&
2N/A newprop(n, KMF_CRL_DIRECTORY_ATTR, crlinfo->directory))
2N/A return (-1);
2N/A
2N/A if (crlinfo->get_crl_uri &&
2N/A newprop(n, KMF_CRL_GET_URI_ATTR, "TRUE")) {
2N/A return (-1);
2N/A }
2N/A
2N/A if (crlinfo->proxy &&
2N/A newprop(n, KMF_CRL_PROXY_ATTR, crlinfo->proxy))
2N/A return (-1);
2N/A
2N/A if (crlinfo->ignore_crl_sign &&
2N/A newprop(n, KMF_CRL_IGNORE_SIGN_ATTR, "TRUE")) {
2N/A return (-1);
2N/A }
2N/A
2N/A if (crlinfo->ignore_crl_date &&
2N/A newprop(n, KMF_CRL_IGNORE_DATE_ATTR, "TRUE")) {
2N/A return (-1);
2N/A }
2N/A
2N/A addFormatting(node, "\n");
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Add OCSP information to the policy tree.
2N/A * Return non-zero on any failure, else 0 for success.
2N/A *
2N/A * This function is called only when the KMF_REVOCATION_METHOD_OCSP flag is on.
2N/A */
2N/Astatic int
2N/AAddOCSPNodes(xmlNodePtr parent, KMF_OCSP_POLICY *ocsp)
2N/A{
2N/A int ret = 0;
2N/A xmlNodePtr n_ocsp, n_basic, n_resp;
2N/A KMF_OCSP_BASIC_POLICY *basic;
2N/A KMF_RESP_CERT_POLICY *resp_cert;
2N/A
2N/A basic = &(ocsp->basic);
2N/A resp_cert = &(ocsp->resp_cert);
2N/A
2N/A if (basic->responderURI != NULL || basic->uri_from_cert == B_TRUE) {
2N/A
2N/A addFormatting(parent, "\t\t");
2N/A
2N/A /* basic node */
2N/A n_ocsp = xmlNewChild(parent, NULL,
2N/A (const xmlChar *)KMF_OCSP_ELEMENT, NULL);
2N/A if (n_ocsp == NULL)
2N/A return (-1);
2N/A addFormatting(n_ocsp, "\n\t\t\t");
2N/A
2N/A n_basic = xmlNewChild(n_ocsp, NULL,
2N/A (const xmlChar *)KMF_OCSP_BASIC_ELEMENT, NULL);
2N/A if (n_basic == NULL)
2N/A return (-1);
2N/A if (basic->responderURI && newprop(n_basic,
2N/A KMF_OCSP_RESPONDER_ATTR, basic->responderURI))
2N/A return (-1);
2N/A if (basic->proxy &&
2N/A newprop(n_basic, KMF_OCSP_PROXY_ATTR, basic->proxy))
2N/A return (-1);
2N/A if (basic->uri_from_cert &&
2N/A newprop(n_basic, KMF_OCSP_URI_ATTR, "TRUE"))
2N/A return (-1);
2N/A if (basic->response_lifetime &&
2N/A newprop(n_basic, KMF_OCSP_RESPONSE_LIFETIME_ATTR,
2N/A basic->response_lifetime))
2N/A return (-1);
2N/A if (basic->ignore_response_sign &&
2N/A newprop(n_basic, KMF_OCSP_IGNORE_SIGN_ATTR, "TRUE"))
2N/A return (-1);
2N/A
2N/A addFormatting(n_ocsp, "\n\t\t\t");
2N/A
2N/A /* responder cert node */
2N/A if (ocsp->has_resp_cert) {
2N/A n_resp = xmlNewChild(n_ocsp, NULL,
2N/A (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT,
2N/A NULL);
2N/A if (n_resp == NULL)
2N/A return (-1);
2N/A if (newprop(n_resp, KMF_CERT_NAME_ATTR,
2N/A resp_cert->name))
2N/A return (-1);
2N/A if (newprop(n_resp, KMF_CERT_SERIAL_ATTR,
2N/A resp_cert->serial))
2N/A return (-1);
2N/A }
2N/A addFormatting(n_ocsp, "\n\t\t");
2N/A }
2N/A
2N/A addFormatting(parent, "\n");
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Add validation method information to the policy tree.
2N/A * Return non-zero on any failure, else 0 for success.
2N/A */
2N/Astatic int
2N/AAddValidationNodes(xmlNodePtr parent, KMF_POLICY_RECORD *policy)
2N/A{
2N/A xmlNodePtr mnode;
2N/A int ret = 0;
2N/A
2N/A addFormatting(parent, "\t");
2N/A mnode = xmlNewChild(parent, NULL,
2N/A (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT, NULL);
2N/A if (mnode == NULL)
2N/A return (-1);
2N/A
2N/A addFormatting(mnode, "\n");
2N/A
2N/A if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
2N/A ret = AddOCSPNodes(mnode, &(policy->validation_info.ocsp_info));
2N/A if (ret != KMF_OK)
2N/A goto end;
2N/A }
2N/A
2N/A if (policy->revocation & KMF_REVOCATION_METHOD_CRL) {
2N/A ret = AddCRLNodes(mnode, &(policy->validation_info.crl_info));
2N/A if (ret != KMF_OK)
2N/A goto end;
2N/A }
2N/A
2N/A addFormatting(mnode, "\t");
2N/A addFormatting(parent, "\n");
2N/A
2N/Aend:
2N/A if (ret != 0) {
2N/A xmlUnlinkNode(mnode);
2N/A xmlFreeNode(mnode);
2N/A }
2N/A return (ret);
2N/A
2N/A}
2N/A
2N/A/*
2N/A * Add mapper policy info to the policy tree.
2N/A * Return non-zero on any failure, else 0 for success.
2N/A */
2N/Astatic KMF_RETURN
2N/AAddMapperPolicyNodes(xmlNodePtr parent, KMF_MAPPER_RECORD *mapper)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A xmlNodePtr mapper_node;
2N/A
2N/A addFormatting(parent, "\n\t");
2N/A mapper_node = xmlNewChild(parent, NULL,
2N/A (const xmlChar *)KMF_CERT_MAPPER_ELEMENT, NULL);
2N/A if (mapper_node == NULL)
2N/A return (KMF_ERR_POLICY_ENGINE);
2N/A
2N/A if (mapper->mapname != NULL &&
2N/A newprop(mapper_node, KMF_CERT_MAPPER_NAME_ATTR, mapper->mapname)) {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A goto end;
2N/A }
2N/A
2N/A if (mapper->pathname != NULL &&
2N/A newprop(mapper_node, KMF_CERT_MAPPER_PATH_ATTR, mapper->pathname)) {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A goto end;
2N/A }
2N/A
2N/A if (mapper->dir != NULL &&
2N/A newprop(mapper_node, KMF_CERT_MAPPER_DIR_ATTR, mapper->dir)) {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A goto end;
2N/A }
2N/A
2N/A if (mapper->options != NULL &&
2N/A newprop(mapper_node, KMF_CERT_MAPPER_OPTIONS_ATTR, mapper->options))
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A
2N/A if (ret == KMF_OK) {
2N/A addFormatting(mapper_node, "\n\t");
2N/A addFormatting(parent, "\n");
2N/A }
2N/A
2N/Aend:
2N/A if (ret != KMF_OK) {
2N/A xmlUnlinkNode(mapper_node);
2N/A xmlFreeNode(mapper_node);
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Add Key Usage information to the policy tree.
2N/A * Return non-zero on any failure, else 0 for success.
2N/A */
2N/Astatic KMF_RETURN
2N/AAddKeyUsageNodes(xmlNodePtr parent, uint32_t kubits)
2N/A{
2N/A int ret = KMF_OK;
2N/A int i;
2N/A
2N/A xmlNodePtr kuset, kunode;
2N/A
2N/A if (kubits == 0)
2N/A return (0);
2N/A
2N/A addFormatting(parent, "\n\t");
2N/A kuset = xmlNewChild(parent, NULL,
2N/A (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT, NULL);
2N/A if (kuset == NULL)
2N/A return (KMF_ERR_POLICY_ENGINE);
2N/A
2N/A for (i = KULOWBIT; i <= KUHIGHBIT && ret == KMF_OK; i++) {
2N/A char *s = kmf_ku_to_string((kubits & (1<<i)));
2N/A if (s != NULL) {
2N/A addFormatting(kuset, "\n\t\t");
2N/A
2N/A kunode = xmlNewChild(kuset, NULL,
2N/A (const xmlChar *)KMF_KEY_USAGE_ELEMENT, NULL);
2N/A if (kunode == NULL)
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A
2N/A else if (newprop(kunode, KMF_KEY_USAGE_USE_ATTR, s))
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A }
2N/A }
2N/A addFormatting(kuset, "\n\t");
2N/A addFormatting(parent, "\n");
2N/A
2N/A if (ret != KMF_OK) {
2N/A xmlUnlinkNode(kuset);
2N/A xmlFreeNode(kuset);
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Add Extended-Key-Usage information to the policy tree.
2N/A * Return non-zero on any failure, else 0 for success.
2N/A */
2N/Astatic KMF_RETURN
2N/AAddExtKeyUsageNodes(xmlNodePtr parent, KMF_EKU_POLICY *ekus)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A xmlNodePtr n, kunode;
2N/A int i;
2N/A
2N/A if (ekus != NULL && ekus->eku_count > 0) {
2N/A addFormatting(parent, "\n\t");
2N/A n = xmlNewChild(parent, NULL,
2N/A (const xmlChar *)KMF_EKU_ELEMENT, NULL);
2N/A if (n == NULL)
2N/A return (KMF_ERR_POLICY_ENGINE);
2N/A
2N/A for (i = 0; i < ekus->eku_count; i++) {
2N/A char *s = kmf_oid_to_string(&ekus->ekulist[i]);
2N/A if (s != NULL) {
2N/A addFormatting(n, "\n\t\t");
2N/A kunode = xmlNewChild(n, NULL,
2N/A (const xmlChar *)KMF_EKU_OID_ELEMENT,
2N/A NULL);
2N/A if (kunode == NULL)
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A
2N/A else if (newprop(kunode, KMF_EKU_OID_ATTR, s))
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A free(s);
2N/A } else {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A }
2N/A }
2N/A addFormatting(n, "\n\t");
2N/A addFormatting(parent, "\n");
2N/A }
2N/A
2N/A if (ret != KMF_OK) {
2N/A xmlUnlinkNode(n);
2N/A xmlFreeNode(n);
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/Avoid
2N/Akmf_free_eku_policy(KMF_EKU_POLICY *ekus)
2N/A{
2N/A if (ekus->eku_count > 0) {
2N/A int i;
2N/A for (i = 0; i < ekus->eku_count; i++) {
2N/A kmf_free_data(&ekus->ekulist[i]);
2N/A }
2N/A free(ekus->ekulist);
2N/A }
2N/A}
2N/A
2N/A#define FREE_POLICY_STR(s) if (s != NULL) free(s);
2N/A
2N/Avoid
2N/Akmf_free_policy_record(KMF_POLICY_RECORD *policy)
2N/A{
2N/A if (policy == NULL)
2N/A return;
2N/A
2N/A FREE_POLICY_STR(policy->name)
2N/A FREE_POLICY_STR(policy->VAL_OCSP_BASIC.responderURI)
2N/A FREE_POLICY_STR(policy->VAL_OCSP_BASIC.proxy)
2N/A FREE_POLICY_STR(policy->VAL_OCSP_BASIC.response_lifetime)
2N/A FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.name)
2N/A FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.serial)
2N/A FREE_POLICY_STR(policy->validation_info.crl_info.basefilename)
2N/A FREE_POLICY_STR(policy->validation_info.crl_info.directory)
2N/A FREE_POLICY_STR(policy->validation_info.crl_info.proxy)
2N/A FREE_POLICY_STR(policy->validity_adjusttime)
2N/A FREE_POLICY_STR(policy->ta_name)
2N/A FREE_POLICY_STR(policy->ta_serial)
2N/A FREE_POLICY_STR(policy->mapper.mapname)
2N/A FREE_POLICY_STR(policy->mapper.pathname)
2N/A FREE_POLICY_STR(policy->mapper.options)
2N/A FREE_POLICY_STR(policy->mapper.dir)
2N/A
2N/A kmf_free_eku_policy(&policy->eku_set);
2N/A
2N/A (void) memset(policy, 0, sizeof (KMF_POLICY_RECORD));
2N/A}
2N/A
2N/A/*
2N/A * kmf_get_policy
2N/A *
2N/A * Find a policy record in the database.
2N/A */
2N/AKMF_RETURN
2N/Akmf_get_policy(char *filename, char *policy_name, KMF_POLICY_RECORD *plc)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A xmlParserCtxtPtr ctxt;
2N/A xmlDocPtr doc = NULL;
2N/A xmlNodePtr cur, node;
2N/A int found = 0;
2N/A
2N/A if (filename == NULL || policy_name == NULL || plc == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A (void) memset(plc, 0, sizeof (KMF_POLICY_RECORD));
2N/A
2N/A /* Create a parser context */
2N/A ctxt = xmlNewParserCtxt();
2N/A if (ctxt == NULL)
2N/A return (KMF_ERR_POLICY_DB_FORMAT);
2N/A
2N/A /* Read the policy DB and verify it against the schema. */
2N/A doc = xmlCtxtReadFile(ctxt, filename, NULL,
2N/A XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
2N/A if (doc == NULL || ctxt->valid == 0) {
2N/A ret = KMF_ERR_POLICY_DB_FORMAT;
2N/A goto out;
2N/A }
2N/A
2N/A cur = xmlDocGetRootElement(doc);
2N/A if (cur == NULL) {
2N/A ret = KMF_ERR_POLICY_DB_FORMAT;
2N/A goto out;
2N/A }
2N/A
2N/A node = cur->xmlChildrenNode;
2N/A while (node != NULL && !found) {
2N/A char *c;
2N/A /*
2N/A * Search for the policy that matches the given name.
2N/A */
2N/A if (!xmlStrcmp((const xmlChar *)node->name,
2N/A (const xmlChar *)KMF_POLICY_ELEMENT)) {
2N/A /* Check the name attribute */
2N/A c = (char *)xmlGetProp(node,
2N/A (const xmlChar *)KMF_POLICY_NAME_ATTR);
2N/A
2N/A /* If a match, parse the rest of the data */
2N/A if (c != NULL) {
2N/A if (strcmp(c, policy_name) == 0) {
2N/A ret = parsePolicyElement(node, plc);
2N/A found = (ret == KMF_OK);
2N/A }
2N/A xmlFree(c);
2N/A }
2N/A }
2N/A node = node->next;
2N/A }
2N/A
2N/A if (!found) {
2N/A ret = KMF_ERR_POLICY_NOT_FOUND;
2N/A goto out;
2N/A }
2N/A
2N/Aout:
2N/A if (ctxt != NULL)
2N/A xmlFreeParserCtxt(ctxt);
2N/A
2N/A if (doc != NULL)
2N/A xmlFreeDoc(doc);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * kmf_set_policy
2N/A *
2N/A * Set the policy record in the handle. This searches
2N/A * the policy DB for the named policy. If it is not found
2N/A * or an error occurred in processing, the existing policy
2N/A * is kept and an error code is returned.
2N/A */
2N/AKMF_RETURN
2N/Akmf_set_policy(KMF_HANDLE_T handle, char *policyfile, char *policyname)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_POLICY_RECORD *newpolicy = NULL;
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A newpolicy = malloc(sizeof (KMF_POLICY_RECORD));
2N/A if (newpolicy == NULL)
2N/A return (KMF_ERR_MEMORY);
2N/A (void) memset(newpolicy, 0, sizeof (KMF_POLICY_RECORD));
2N/A
2N/A ret = kmf_get_policy(
2N/A policyfile == NULL ? KMF_DEFAULT_POLICY_FILE : policyfile,
2N/A policyname == NULL ? KMF_DEFAULT_POLICY_NAME : policyname,
2N/A newpolicy);
2N/A if (ret != KMF_OK)
2N/A goto out;
2N/A
2N/A ret = kmf_verify_policy(newpolicy);
2N/A if (ret != KMF_OK)
2N/A goto out;
2N/A
2N/A /* release the existing policy data (if any). */
2N/A if (handle->policy != NULL) {
2N/A kmf_free_policy_record(handle->policy);
2N/A free(handle->policy);
2N/A }
2N/A
2N/A handle->policy = newpolicy;
2N/A
2N/Aout:
2N/A /* Cleanup any data allocated before the error occurred */
2N/A if (ret != KMF_OK) {
2N/A kmf_free_policy_record(newpolicy);
2N/A free(newpolicy);
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A
2N/Astatic KMF_RETURN
2N/AdeletePolicyNode(xmlNodePtr node, char *policy_name)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A int found = 0;
2N/A xmlNodePtr dnode = NULL;
2N/A
2N/A while (node != NULL && !found) {
2N/A char *c;
2N/A /*
2N/A * Search for the policy that matches the given name.
2N/A */
2N/A if (!xmlStrcmp((const xmlChar *)node->name,
2N/A (const xmlChar *)KMF_POLICY_ELEMENT)) {
2N/A /* Check the name attribute */
2N/A c = (char *)xmlGetProp(node,
2N/A (const xmlChar *)KMF_POLICY_NAME_ATTR);
2N/A
2N/A /* If a match, parse the rest of the data */
2N/A if (c != NULL) {
2N/A if (strcmp(c, policy_name) == 0) {
2N/A found = 1;
2N/A dnode = node;
2N/A }
2N/A xmlFree(c);
2N/A }
2N/A }
2N/A if (!found)
2N/A node = node->next;
2N/A }
2N/A
2N/A if (found && dnode != NULL) {
2N/A /* Unlink the node */
2N/A xmlUnlinkNode(dnode);
2N/A
2N/A /* Delete it from the document tree */
2N/A xmlFreeNode(dnode);
2N/A } else {
2N/A ret = KMF_ERR_POLICY_NOT_FOUND;
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * update_policyfile
2N/A *
2N/A * Attempt to do a "safe" file update as follows:
2N/A * 1. Lock the original file.
2N/A * 2. Create and write to a temporary file
2N/A * 3. Replace the original file with the temporary file.
2N/A */
2N/Astatic KMF_RETURN
2N/Aupdate_policyfile(xmlDocPtr doc, char *filename)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A FILE *pfile, *tmpfile;
2N/A char tmpfilename[MAXPATHLEN];
2N/A char *p;
2N/A int prefix_len, tmpfd;
2N/A mode_t old_mode;
2N/A
2N/A /*
2N/A * Open and lock the DB file. First try to open an existing file,
2N/A * if that fails, open it as if it were new.
2N/A */
2N/A if ((pfile = fopen(filename, "r+")) == NULL && errno == ENOENT)
2N/A pfile = fopen(filename, "w+");
2N/A
2N/A if (pfile == NULL)
2N/A return (KMF_ERR_POLICY_DB_FILE);
2N/A
2N/A if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
2N/A (void) fclose(pfile);
2N/A return (KMF_ERR_POLICY_DB_FILE);
2N/A }
2N/A
2N/A /*
2N/A * Create a temporary file to hold the new data.
2N/A */
2N/A (void) memset(tmpfilename, 0, sizeof (tmpfilename));
2N/A p = (char *)strrchr(filename, '/');
2N/A if (p == NULL) {
2N/A /*
2N/A * filename contains basename only so we
2N/A * create a temp file in current directory.
2N/A */
2N/A if (strlcpy(tmpfilename, TMPFILE_TEMPLATE,
2N/A sizeof (tmpfilename)) >= sizeof (tmpfilename))
2N/A return (KMF_ERR_INTERNAL);
2N/A } else {
2N/A /*
2N/A * create a temp file in the same directory
2N/A * as the policy file.
2N/A */
2N/A prefix_len = p - filename;
2N/A (void) strncpy(tmpfilename, filename, prefix_len);
2N/A (void) strncat(tmpfilename, "/", 1);
2N/A (void) strncat(tmpfilename, TMPFILE_TEMPLATE,
2N/A sizeof (TMPFILE_TEMPLATE));
2N/A }
2N/A
2N/A old_mode = umask(077);
2N/A tmpfd = mkstemp(tmpfilename);
2N/A (void) umask(old_mode);
2N/A if (tmpfd == -1) {
2N/A return (KMF_ERR_POLICY_DB_FILE);
2N/A }
2N/A
2N/A if ((tmpfile = fdopen(tmpfd, "w")) == NULL) {
2N/A (void) close(tmpfd);
2N/A (void) unlink(tmpfilename);
2N/A (void) fclose(pfile);
2N/A return (KMF_ERR_POLICY_DB_FILE);
2N/A }
2N/A
2N/A /*
2N/A * Write the new info to the temporary file.
2N/A */
2N/A if (xmlDocFormatDump(tmpfile, doc, 1) == -1) {
2N/A (void) fclose(pfile);
2N/A (void) fclose(tmpfile);
2N/A (void) unlink(tmpfilename);
2N/A return (KMF_ERR_POLICY_ENGINE);
2N/A }
2N/A
2N/A (void) fclose(pfile);
2N/A
2N/A if (fchmod(tmpfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
2N/A (void) close(tmpfd);
2N/A (void) unlink(tmpfilename);
2N/A return (KMF_ERR_POLICY_DB_FILE);
2N/A }
2N/A if (fclose(tmpfile) != 0)
2N/A return (KMF_ERR_POLICY_DB_FILE);
2N/A
2N/A /*
2N/A * Replace the original file with the updated tempfile.
2N/A */
2N/A if (rename(tmpfilename, filename) == -1) {
2N/A ret = KMF_ERR_POLICY_DB_FILE;
2N/A }
2N/A
2N/A if (ret != KMF_OK) {
2N/A /* try to remove the tmp file */
2N/A (void) unlink(tmpfilename);
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * kmf_delete_policy_from_db
2N/A *
2N/A * Find a policy by name and remove it from the policy DB file.
2N/A * If the policy is not found, return an error.
2N/A */
2N/AKMF_RETURN
2N/Akmf_delete_policy_from_db(char *policy_name, char *dbfilename)
2N/A{
2N/A KMF_RETURN ret;
2N/A xmlParserCtxtPtr ctxt = NULL;
2N/A xmlDocPtr doc = NULL;
2N/A xmlNodePtr cur, node;
2N/A
2N/A if (policy_name == NULL || dbfilename == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /*
2N/A * Cannot delete the default policy record from the system
2N/A * default policy database (/etc/security/kmfpolicy.xml).
2N/A */
2N/A if (strcmp(dbfilename, KMF_DEFAULT_POLICY_FILE) == 0 &&
2N/A strcmp(policy_name, KMF_DEFAULT_POLICY_NAME) == 0)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /* Make sure the policy file exists */
2N/A if (access(dbfilename, R_OK | W_OK))
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /* Read the policy DB and verify it against the schema. */
2N/A ctxt = xmlNewParserCtxt();
2N/A if (ctxt == NULL)
2N/A return (KMF_ERR_POLICY_DB_FORMAT);
2N/A
2N/A doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
2N/A XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
2N/A if (doc == NULL || ctxt->valid == 0) {
2N/A ret = KMF_ERR_POLICY_DB_FORMAT;
2N/A goto end;
2N/A }
2N/A
2N/A cur = xmlDocGetRootElement(doc);
2N/A if (cur == NULL) {
2N/A xmlFreeDoc(doc);
2N/A return (KMF_ERR_POLICY_DB_FORMAT);
2N/A }
2N/A node = cur->xmlChildrenNode;
2N/A
2N/A ret = deletePolicyNode(node, policy_name);
2N/A
2N/A if (ret == KMF_OK)
2N/A ret = update_policyfile(doc, dbfilename);
2N/A
2N/Aend:
2N/A if (ctxt != NULL)
2N/A xmlFreeParserCtxt(ctxt);
2N/A
2N/A if (doc != NULL)
2N/A xmlFreeDoc(doc);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Add a new policy node to the Policy DB XML tree.
2N/A */
2N/Astatic KMF_RETURN
2N/AaddPolicyNode(xmlNodePtr pnode, KMF_POLICY_RECORD *policy)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A
2N/A if (pnode != NULL && policy != NULL) {
2N/A if (newprop(pnode, KMF_POLICY_NAME_ATTR, policy->name) != 0) {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A goto out;
2N/A }
2N/A if (policy->ignore_date) {
2N/A if (newprop(pnode, KMF_OPTIONS_IGNORE_DATE_ATTR,
2N/A "TRUE")) {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A if (policy->ignore_unknown_ekus) {
2N/A if (newprop(pnode, KMF_OPTIONS_IGNORE_UNKNOWN_EKUS,
2N/A "TRUE")) {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A if (policy->ignore_trust_anchor) {
2N/A if (newprop(pnode, KMF_OPTIONS_IGNORE_TRUST_ANCHOR,
2N/A "TRUE")) {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A if (policy->validity_adjusttime) {
2N/A if (newprop(pnode, KMF_OPTIONS_VALIDITY_ADJUSTTIME,
2N/A policy->validity_adjusttime)) {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A if (newprop(pnode, KMF_POLICY_TA_NAME_ATTR,
2N/A policy->ta_name) != 0) {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A goto out;
2N/A }
2N/A
2N/A if (newprop(pnode, KMF_POLICY_TA_SERIAL_ATTR,
2N/A policy->ta_serial) != 0) {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A goto out;
2N/A }
2N/A
2N/A /* Add a text node for readability */
2N/A addFormatting(pnode, "\n");
2N/A
2N/A if (ret = AddValidationNodes(pnode, policy)) {
2N/A goto out;
2N/A }
2N/A
2N/A if ((ret = AddKeyUsageNodes(pnode, policy->ku_bits))) {
2N/A goto out;
2N/A }
2N/A
2N/A if ((ret = AddExtKeyUsageNodes(pnode, &policy->eku_set))) {
2N/A goto out;
2N/A }
2N/A if ((ret = AddMapperPolicyNodes(pnode, &policy->mapper))) {
2N/A goto out;
2N/A }
2N/A } else {
2N/A ret = KMF_ERR_BAD_PARAMETER;
2N/A }
2N/Aout:
2N/A if (ret != KMF_OK && pnode != NULL) {
2N/A xmlUnlinkNode(pnode);
2N/A xmlFreeNode(pnode);
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/AKMF_RETURN
2N/Akmf_verify_policy(KMF_POLICY_RECORD *policy)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A boolean_t has_ta;
2N/A
2N/A if (policy->name == NULL || !strlen(policy->name))
2N/A return (KMF_ERR_POLICY_NAME);
2N/A
2N/A /* Check the TA related policy */
2N/A if (policy->ta_name != NULL &&
2N/A strcasecmp(policy->ta_name, "search") == 0) {
2N/A has_ta = B_TRUE;
2N/A } else if (policy->ta_name != NULL && policy->ta_serial != NULL) {
2N/A has_ta = B_TRUE;
2N/A } else if (policy->ta_name == NULL && policy->ta_serial == NULL) {
2N/A has_ta = B_FALSE;
2N/A } else {
2N/A /*
2N/A * If the TA cert is set, then both name and serial number
2N/A * need to be specified.
2N/A */
2N/A return (KMF_ERR_TA_POLICY);
2N/A }
2N/A
2N/A if (has_ta == B_FALSE && policy->ignore_trust_anchor == B_FALSE)
2N/A return (KMF_ERR_TA_POLICY);
2N/A
2N/A if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
2N/A /*
2N/A * For OCSP, either use a fixed responder or use the
2N/A * value from the cert, but not both.
2N/A */
2N/A if ((policy->VAL_OCSP_BASIC.responderURI == NULL &&
2N/A policy->VAL_OCSP_BASIC.uri_from_cert == B_FALSE) ||
2N/A (policy->VAL_OCSP_BASIC.responderURI != NULL &&
2N/A policy->VAL_OCSP_BASIC.uri_from_cert == B_TRUE))
2N/A return (KMF_ERR_OCSP_POLICY);
2N/A
2N/A /*
2N/A * If the OCSP responder cert is set, then both name and serial
2N/A * number need to be specified.
2N/A */
2N/A if ((policy->VAL_OCSP_RESP_CERT.name != NULL &&
2N/A policy->VAL_OCSP_RESP_CERT.serial == NULL) ||
2N/A (policy->VAL_OCSP_RESP_CERT.name == NULL &&
2N/A policy->VAL_OCSP_RESP_CERT.serial != NULL))
2N/A return (KMF_ERR_OCSP_POLICY);
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Update the KMF policy file by creating a new XML Policy doc tree
2N/A * from the data in the KMF_POLICY_RECORD structure. If "check_policy"
2N/A * is true, then we check the policy sanity also.
2N/A */
2N/AKMF_RETURN
2N/Akmf_add_policy_to_db(KMF_POLICY_RECORD *policy, char *dbfilename,
2N/A boolean_t check_policy)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A xmlDocPtr doc = NULL;
2N/A xmlNodePtr root, node;
2N/A xmlParserCtxtPtr ctxt = NULL;
2N/A
2N/A if (policy == NULL || dbfilename == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A if (check_policy == B_TRUE) {
2N/A if (ret = kmf_verify_policy(policy))
2N/A return (ret);
2N/A }
2N/A
2N/A /* If the policyDB exists, load it into memory */
2N/A if (!access(dbfilename, R_OK)) {
2N/A
2N/A /* Create a parser context */
2N/A ctxt = xmlNewParserCtxt();
2N/A if (ctxt == NULL)
2N/A return (KMF_ERR_POLICY_DB_FORMAT);
2N/A
2N/A doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
2N/A XML_PARSE_DTDVALID | XML_PARSE_NOERROR |
2N/A XML_PARSE_NOWARNING);
2N/A if (doc == NULL || ctxt->valid == 0) {
2N/A ret = KMF_ERR_POLICY_DB_FORMAT;
2N/A goto out;
2N/A }
2N/A
2N/A root = xmlDocGetRootElement(doc);
2N/A if (root == NULL) {
2N/A ret = KMF_ERR_POLICY_DB_FORMAT;
2N/A goto out;
2N/A }
2N/A
2N/A node = root->xmlChildrenNode;
2N/A /*
2N/A * If the DB has an existing policy of the
2N/A * same name, delete it from the tree.
2N/A */
2N/A ret = deletePolicyNode(node, policy->name);
2N/A if (ret == KMF_ERR_POLICY_NOT_FOUND)
2N/A ret = KMF_OK;
2N/A } else {
2N/A /* Initialize a new DB tree */
2N/A doc = xmlNewDoc((const xmlChar *)"1.0");
2N/A if (doc == NULL)
2N/A return (KMF_ERR_POLICY_ENGINE);
2N/A
2N/A /*
2N/A * Add the DOCTYPE header to the tree so the
2N/A * DTD link is embedded
2N/A */
2N/A doc->intSubset = xmlCreateIntSubset(doc,
2N/A (const xmlChar *)KMF_POLICY_ROOT,
2N/A NULL, (const xmlChar *)KMF_POLICY_DTD);
2N/A
2N/A root = xmlNewDocNode(doc, NULL,
2N/A (const xmlChar *)KMF_POLICY_ROOT, NULL);
2N/A if (root != NULL) {
2N/A (void) xmlDocSetRootElement(doc, root);
2N/A }
2N/A }
2N/A
2N/A /* Append the new policy info to the root node. */
2N/A if (root != NULL) {
2N/A xmlNodePtr pnode;
2N/A
2N/A pnode = xmlNewChild(root, NULL,
2N/A (const xmlChar *)KMF_POLICY_ELEMENT, NULL);
2N/A
2N/A ret = addPolicyNode(pnode, policy);
2N/A /* If that worked, update the DB file. */
2N/A if (ret == KMF_OK)
2N/A ret = update_policyfile(doc, dbfilename);
2N/A } else {
2N/A ret = KMF_ERR_POLICY_ENGINE;
2N/A }
2N/A
2N/A
2N/Aout:
2N/A if (ctxt != NULL)
2N/A xmlFreeParserCtxt(ctxt);
2N/A
2N/A if (doc != NULL)
2N/A xmlFreeDoc(doc);
2N/A
2N/A return (ret);
2N/A}