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