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