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