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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * File: CLIENT.C 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <ctype.h> 33 #include <fcntl.h> 34 #include <poll.h> 35 #include <sys/errno.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <sys/socket.h> 39 #include <netdb.h> 40 #include <netinet/in.h> 41 #include <arpa/inet.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include <libgen.h> 45 #include <kmfapi.h> 46 #include <kmfapiP.h> 47 #include <libxml2/libxml/uri.h> 48 49 extern int errno; 50 51 #define OCSP_BUFSIZE 1024 52 53 typedef enum { 54 KMF_RESPONSE_OCSP = 1, 55 KMF_RESPONSE_FILE = 2 56 } KMF_RESPONSE_TYPE; 57 58 #define TEMP_TEMPLATE "temp.XXXXXX" 59 60 /* 61 * This function will establish a socket to the host on the specified port. 62 * If succeed, it return a socket descriptor; otherwise, return -1. 63 */ 64 static int init_socket(char *host, short port) 65 { 66 struct sockaddr_in sin; 67 struct hostent *hp, hrec; 68 int sockfd, opt, herrno; 69 char hostbuf[BUFSIZ]; 70 71 sin.sin_family = PF_INET; 72 sin.sin_port = htons(port); 73 if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) { 74 if ((hp = gethostbyname_r(host, &hrec, hostbuf, 75 sizeof (hostbuf), &herrno)) == NULL) { 76 return (-1); 77 } 78 (void) memcpy((char *)&sin.sin_addr, hp->h_addr, 79 hp->h_length); 80 } 81 82 if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { 83 return (-1); 84 } 85 86 opt = 1; 87 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, 88 sizeof (opt)) < 0) { 89 (void) close(sockfd); 90 return (-1); 91 } 92 93 if (connect(sockfd, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 94 (void) close(sockfd); 95 return (-1); 96 } 97 98 return (sockfd); 99 } 100 101 /* 102 * This function will connect to host on the port. 103 * If succeed, return a socket descriptor; otherwise, return 0. 104 */ 105 static int 106 connect_to_server(char *host, short port) 107 { 108 int retry = 1; 109 int sd = 0; 110 111 while (retry) { 112 if ((sd = init_socket(host, port)) == -1) { 113 if (errno == ECONNREFUSED) { 114 retry = 1; 115 (void) sleep(1); 116 } else { 117 retry = 0; 118 } 119 } else { 120 retry = 0; 121 } 122 } 123 return (sd); 124 } 125 126 static KMF_RETURN 127 send_ocsp_request(int sock, char *reqfile, char *hostname) 128 { 129 KMF_RETURN ret = KMF_OK; 130 int filefd, bytes, n, total = 0; 131 char buf[OCSP_BUFSIZE]; 132 struct stat s; 133 char req_header[256]; 134 static char req_format[] = 135 "POST %s HTTP/1.0\r\n\ 136 Content-Type: application/ocsp-request\r\n\ 137 Content-Length: %d\r\n\r\n"; 138 139 if ((filefd = open(reqfile, O_RDONLY)) == -1) { 140 ret = KMF_ERR_OPEN_FILE; 141 return (ret); 142 } 143 144 /* open the request file */ 145 if (fstat(filefd, &s) < 0) { 146 ret = KMF_ERR_OPEN_FILE; 147 return (ret); 148 } 149 150 151 /* Send http header */ 152 if (hostname != NULL) { 153 (void) snprintf(req_header, 256, req_format, hostname, 154 s.st_size); 155 } else { 156 (void) snprintf(req_header, 256, req_format, "/", s.st_size); 157 } 158 bytes = strlen(req_header); 159 160 if ((n = write(sock, req_header, bytes)) < 0) { 161 ret = KMF_ERR_SEND_REQUEST; 162 goto exit; 163 } 164 165 /* Send the request content */ 166 while ((bytes = read(filefd, buf, OCSP_BUFSIZE)) > 0) { 167 if ((n = write(sock, buf, bytes)) < 0) { 168 ret = KMF_ERR_SEND_REQUEST; 169 goto exit; 170 } 171 total += n; 172 (void) memset(buf, 0, sizeof (buf)); 173 } 174 175 exit: 176 (void) close(filefd); 177 return (ret); 178 } 179 180 181 /* 182 * Perform a write that can handle EINTR. 183 */ 184 static int 185 looping_write(int fd, void *buf, int len) 186 { 187 char *p = buf; 188 int cc, len2 = 0; 189 190 if (len == 0) 191 return (0); 192 do { 193 cc = write(fd, p, len); 194 if (cc < 0) { 195 if (errno == EINTR) 196 continue; 197 return (cc); 198 } else if (cc == 0) { 199 return (len2); 200 } else { 201 p += cc; 202 len2 += cc; 203 len -= cc; 204 } 205 } while (len > 0); 206 207 return (len2); 208 } 209 210 /* 211 * This function will get the response from the server, check the http status 212 * line, and write the response content to a file. If this is a OCSP response, 213 * it will check the content type also. 214 */ 215 static KMF_RETURN 216 get_encoded_response(int sock, KMF_RESPONSE_TYPE resptype, int filefd, 217 unsigned int maxsecs) 218 { 219 int ret = KMF_OK; 220 char *buf = NULL; 221 int buflen = 0; 222 int offset = 0; 223 int search_offset; 224 const int buf_incre = OCSP_BUFSIZE; /* 1 KB at a time */ 225 const int maxBufSize = 8 * buf_incre; /* 8 KB max */ 226 const char *CRLF = "\r\n"; 227 const char *headerEndMark = "\r\n\r\n"; 228 const char *httpprotocol = "HTTP/"; 229 const int CRLFlen = strlen(CRLF); 230 const int marklen = strlen(headerEndMark); 231 const int httplen = strlen(httpprotocol); 232 char *headerEnd = NULL; 233 boolean_t EOS = B_FALSE; 234 const char *httpcode = NULL; 235 const char *contenttype = NULL; 236 int contentlength = 0; 237 int bytes = 0; 238 char *statusLineEnd = NULL; 239 char *space = NULL; 240 char *nextHeader = NULL; 241 struct pollfd pfd; 242 int sock_flag; 243 int poll_ret; 244 boolean_t timeout = B_FALSE; 245 246 /* set O_NONBLOCK flag on socket */ 247 if ((sock_flag = fcntl(sock, F_GETFL, 0)) == -1) { 248 return (KMF_ERR_RECV_RESPONSE); 249 } 250 sock_flag |= O_NONBLOCK; 251 if (fcntl(sock, F_SETFL, sock_flag) == -1) { 252 return (KMF_ERR_RECV_RESPONSE); 253 } 254 255 /* set up poll */ 256 pfd.fd = sock; 257 pfd.events = POLLIN; 258 259 /* 260 * First read HTTP status line and headers. We will read up to at 261 * least the end of the HTTP headers 262 */ 263 do { 264 if ((buflen - offset) < buf_incre) { 265 buflen += buf_incre; 266 buf = realloc(buf, buflen + 1); 267 if (buf == NULL) { 268 ret = KMF_ERR_MEMORY; 269 goto out; 270 } 271 } 272 273 pfd.revents = 0; 274 poll_ret = poll(&pfd, 1, maxsecs * MILLISEC); 275 if (poll_ret == 0) { 276 timeout = B_TRUE; 277 break; 278 } else if (poll_ret < 0) { 279 ret = KMF_ERR_RECV_RESPONSE; 280 goto out; 281 } else { 282 if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { 283 ret = KMF_ERR_RECV_RESPONSE; 284 goto out; 285 } 286 } 287 288 bytes = read(sock, buf + offset, buf_incre); 289 if (bytes < 0) { 290 if (errno == EWOULDBLOCK) { /* no data this time */ 291 continue; 292 } else { 293 ret = KMF_ERR_RECV_RESPONSE; 294 goto out; 295 } 296 } else if (bytes == 0) { /* no more data */ 297 EOS = B_TRUE; 298 } else { /* bytes > 0 */ 299 search_offset = (offset - marklen) > 0 ? 300 offset - marklen : 0; 301 offset += bytes; 302 *(buf + offset) = '\0'; /* NULL termination */ 303 304 headerEnd = strstr((const char *)buf + search_offset, 305 headerEndMark); 306 } 307 308 } while ((!headerEnd) && (EOS == B_FALSE) && (buflen < maxBufSize)); 309 310 if (timeout == B_TRUE) { 311 ret = KMF_ERR_RECV_TIMEOUT; 312 goto out; 313 } else if (headerEnd == NULL) { 314 /* could not find the end of headers */ 315 ret = KMF_ERR_BAD_HTTP_RESPONSE; 316 goto out; 317 } 318 319 /* 320 * Parse the HTTP status line, which will look like this: 321 * "HTTP/1.1 200 OK". 322 */ 323 statusLineEnd = strstr((const char *)buf, CRLF); 324 if (statusLineEnd == NULL) { 325 ret = KMF_ERR_BAD_HTTP_RESPONSE; 326 goto out; 327 } 328 *statusLineEnd = '\0'; 329 330 space = strchr((const char *)buf, ' '); 331 if (space == NULL || 332 (strncasecmp((const char *)buf, httpprotocol, httplen) != 0)) { 333 ret = KMF_ERR_BAD_HTTP_RESPONSE; 334 goto out; 335 } 336 337 /* 338 * Check the HTTP status code. If it is not 200, the HTTP response 339 * is not good. 340 */ 341 httpcode = space + 1; 342 space = strchr(httpcode, ' '); 343 if (space == NULL) { 344 ret = KMF_ERR_BAD_HTTP_RESPONSE; 345 goto out; 346 } 347 348 *space = 0; 349 if (strcmp(httpcode, "200") != 0) { 350 ret = KMF_ERR_BAD_HTTP_RESPONSE; 351 goto out; 352 } 353 354 /* 355 * Parse the HTTP headers in the buffer. Save content-type and 356 * content-length only. 357 */ 358 nextHeader = statusLineEnd + CRLFlen; 359 *headerEnd = '\0'; /* terminate */ 360 do { 361 char *thisHeaderEnd = NULL; 362 char *value = NULL; 363 char *colon = strchr(nextHeader, ':'); 364 365 if (colon == NULL) { 366 ret = KMF_ERR_BAD_HTTP_RESPONSE; 367 goto out; 368 } 369 *colon = '\0'; 370 371 value = colon + 1; 372 if (*value != ' ') { 373 ret = KMF_ERR_BAD_HTTP_RESPONSE; 374 goto out; 375 } 376 value++; 377 378 thisHeaderEnd = strstr(value, CRLF); 379 if (thisHeaderEnd != NULL) 380 *thisHeaderEnd = '\0'; 381 382 if (strcasecmp(nextHeader, "content-type") == 0) { 383 contenttype = value; 384 } else if (strcasecmp(nextHeader, "content-length") == 0) { 385 contentlength = atoi(value); 386 } 387 388 if (thisHeaderEnd != NULL) { 389 nextHeader = thisHeaderEnd + CRLFlen; 390 } else { 391 nextHeader = NULL; 392 } 393 394 } while (nextHeader && (nextHeader < (headerEnd + CRLFlen))); 395 396 /* Check the contenttype if this is an OCSP response */ 397 if (resptype == KMF_RESPONSE_OCSP) { 398 if (contenttype == NULL) { 399 ret = KMF_ERR_BAD_HTTP_RESPONSE; 400 goto out; 401 } else if (strcasecmp(contenttype, 402 "application/ocsp-response") != 0) { 403 ret = KMF_ERR_BAD_HTTP_RESPONSE; 404 goto out; 405 } 406 } 407 408 /* Now we are ready to read the body of the response */ 409 offset = offset - (int)(headerEnd - (const char *)buf) - marklen; 410 if (offset) { 411 /* move all data to the beginning of the buffer */ 412 (void) memmove(buf, headerEnd + marklen, offset); 413 } 414 415 /* resize buffer to only what's needed to hold the current response */ 416 buflen = (1 + (offset-1) / buf_incre) * buf_incre; 417 418 while ((EOS == B_FALSE) && 419 ((contentlength == 0) || (offset < contentlength)) && 420 (buflen < maxBufSize)) { 421 /* we still need to receive more content data */ 422 if ((buflen - offset) < buf_incre) { 423 buflen += buf_incre; 424 buf = realloc(buf, buflen + 1); 425 if (buf == NULL) { 426 ret = KMF_ERR_MEMORY; 427 goto out; 428 } 429 } 430 431 pfd.revents = 0; 432 poll_ret = poll(&pfd, 1, maxsecs * MILLISEC); 433 if (poll_ret == 0) { 434 timeout = B_TRUE; 435 break; 436 } else if (poll_ret < 0) { 437 ret = KMF_ERR_RECV_RESPONSE; 438 goto out; 439 } else { 440 if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { 441 ret = KMF_ERR_RECV_RESPONSE; 442 goto out; 443 } 444 } 445 446 bytes = read(sock, buf + offset, buf_incre); 447 if (bytes < 0) { 448 if (errno == EWOULDBLOCK) { 449 continue; 450 } else { 451 ret = KMF_ERR_RECV_RESPONSE; 452 goto out; 453 } 454 } else if (bytes == 0) { /* no more data */ 455 EOS = B_TRUE; 456 } else { 457 offset += bytes; 458 } 459 } 460 461 if (timeout == B_TRUE) { 462 ret = KMF_ERR_RECV_TIMEOUT; 463 goto out; 464 } else if (((contentlength != 0) && (offset < contentlength)) || 465 offset == 0) { 466 ret = KMF_ERR_BAD_HTTP_RESPONSE; 467 goto out; 468 } 469 470 /* write to the file */ 471 if (looping_write(filefd, buf, offset) != offset) { 472 ret = KMF_ERR_WRITE_FILE; 473 } 474 475 out: 476 free(buf); 477 return (ret); 478 } 479 480 KMF_RETURN 481 KMF_GetEncodedOCSPResponse(KMF_HANDLE_T handle, char *reqfile, char *hostname, 482 int port, char *proxy, int proxy_port, char *respfile, 483 unsigned int maxsecs) 484 { 485 KMF_RETURN ret = KMF_OK; 486 int sock, respfd; 487 char http_hostname[256]; 488 int final_proxy_port, final_port; 489 490 CLEAR_ERROR(handle, ret); 491 if (ret != KMF_OK) 492 return (ret); 493 494 if (hostname == NULL || reqfile == NULL || respfile == NULL) { 495 return (KMF_ERR_BAD_PARAMETER); 496 } 497 498 final_proxy_port = (proxy_port == 0 || proxy_port == -1) ? 499 80 : proxy_port; 500 final_port = (port == 0 || port == -1) ? 80 : port; 501 502 /* Connect to server */ 503 if (proxy != NULL) { 504 sock = connect_to_server(proxy, final_proxy_port); 505 } else { 506 sock = connect_to_server(hostname, final_port); 507 } 508 509 if (sock == -1) { 510 return (KMF_ERR_CONNECT_SERVER); 511 } 512 513 /* Send the OCSP request */ 514 if (proxy != NULL) { 515 (void) snprintf(http_hostname, sizeof (http_hostname), 516 "http://%s:%d", hostname, final_port); 517 ret = send_ocsp_request(sock, reqfile, http_hostname); 518 } else { 519 ret = send_ocsp_request(sock, reqfile, NULL); 520 } 521 522 if (ret != KMF_OK) { 523 goto out; 524 } 525 526 /* Retrieve the OCSP response */ 527 if (maxsecs == 0) { 528 maxsecs = 30; /* default poll time limit is 30 seconds */ 529 } 530 531 if ((respfd = open(respfile, O_CREAT |O_RDWR | O_EXCL, 0600)) == -1) { 532 ret = KMF_ERR_OPEN_FILE; 533 } else { 534 ret = get_encoded_response(sock, KMF_RESPONSE_OCSP, 535 respfd, maxsecs); 536 (void) close(respfd); 537 } 538 539 out: 540 (void) close(sock); 541 return (ret); 542 } 543 544 static KMF_RETURN 545 send_download_request(int sock, char *hostname, int port, boolean_t is_proxy, 546 char *loc) 547 { 548 KMF_RETURN ret = KMF_OK; 549 char url[256]; 550 char req_header[1024]; 551 static char req_format[] = 552 "GET %s HTTP/1.0\r\n\ 553 Host: %s:%d\r\n\ 554 Accept: */*\r\n\r\n"; 555 556 if (is_proxy) { 557 (void) snprintf(url, sizeof (url), "http://%s:%d/%s", 558 hostname, port, loc); 559 } else { 560 (void) snprintf(url, sizeof (url), "/%s", loc); 561 } 562 563 (void) snprintf(req_header, sizeof (req_header), req_format, url, 564 hostname, port); 565 566 if (write(sock, req_header, strlen(req_header)) < 0) { 567 ret = KMF_ERR_SEND_REQUEST; 568 } 569 570 return (ret); 571 } 572 573 static KMF_RETURN 574 download_file(char *uri, char *proxy, int proxy_port, 575 unsigned int maxsecs, int filefd) 576 { 577 KMF_RETURN ret = KMF_OK; 578 xmlURIPtr uriptr; 579 int sock; 580 boolean_t is_proxy; 581 int final_proxy_port; 582 char *hostname = NULL; 583 char *path = NULL; 584 int port; 585 586 if (uri == NULL || filefd == -1) 587 return (KMF_ERR_BAD_PARAMETER); 588 589 /* Parse URI */ 590 uriptr = xmlParseURI(uri); 591 if (uriptr == NULL) { 592 ret = KMF_ERR_BAD_URI; 593 goto out; 594 } 595 596 if (uriptr->scheme == NULL || 597 strncasecmp(uriptr->scheme, "http", 4) != 0) { 598 ret = KMF_ERR_BAD_URI; /* we support http only */ 599 goto out; 600 } 601 602 /* get the host name */ 603 hostname = uriptr->server; 604 if (hostname == NULL) { 605 ret = KMF_ERR_BAD_URI; 606 goto out; 607 } 608 609 /* get the port number */ 610 port = uriptr->port; 611 if (port == 0) { 612 port = 80; 613 } 614 615 /* Get the path */ 616 path = uriptr->path; 617 if (path == NULL) { 618 ret = KMF_ERR_BAD_URI; 619 goto out; 620 } 621 622 /* Connect to server */ 623 if (proxy != NULL) { 624 final_proxy_port = (proxy_port == 0 || proxy_port == -1) ? 625 80 : proxy_port; 626 is_proxy = B_TRUE; 627 sock = connect_to_server(proxy, final_proxy_port); 628 } else { 629 is_proxy = B_FALSE; 630 sock = connect_to_server(hostname, port); 631 } 632 if (sock == -1) { 633 ret = KMF_ERR_CONNECT_SERVER; 634 goto out; 635 } 636 637 /* Send the request */ 638 ret = send_download_request(sock, hostname, port, is_proxy, path); 639 if (ret != KMF_OK) { 640 goto out; 641 } 642 643 /* Retrieve the response */ 644 ret = get_encoded_response(sock, KMF_RESPONSE_FILE, filefd, 645 maxsecs == 0 ? 30 : maxsecs); 646 if (ret != KMF_OK) { 647 goto out; 648 } 649 650 out: 651 if (uriptr != NULL) 652 xmlFreeURI(uriptr); 653 654 if (sock != -1) 655 (void) close(sock); 656 657 return (ret); 658 } 659 660 661 KMF_RETURN 662 KMF_DownloadCRL(KMF_HANDLE_T handle, char *uri, char *proxy, int proxy_port, 663 unsigned int maxsecs, char *crlfile, KMF_ENCODE_FORMAT *pformat) 664 { 665 KMF_RETURN ret = KMF_OK; 666 char *filename = NULL; 667 char tempfn[MAXPATHLEN]; 668 boolean_t temp_created = B_FALSE; 669 mode_t old_mode; 670 int fd = -1, tmpfd = -1; 671 672 CLEAR_ERROR(handle, ret); 673 if (ret != KMF_OK) 674 return (ret); 675 676 if (uri == NULL || crlfile == NULL || pformat == NULL) 677 return (KMF_ERR_BAD_PARAMETER); 678 679 if ((fd = open(crlfile, O_CREAT |O_RDWR | O_EXCL, 0644)) == -1) 680 return (KMF_ERR_OPEN_FILE); 681 682 /* 683 * Download the file and save it to a temp file. To make rename() 684 * happy, the temp file needs to be created in the same directory as 685 * the target file. 686 */ 687 if ((filename = strdup(crlfile)) == NULL) { 688 ret = KMF_ERR_MEMORY; 689 goto out; 690 } 691 (void) snprintf(tempfn, MAXPATHLEN, "%s/%s", dirname(filename), 692 TEMP_TEMPLATE); 693 old_mode = umask(077); 694 tmpfd = mkstemp(tempfn); 695 (void) umask(old_mode); 696 if (tmpfd == -1) { 697 ret = KMF_ERR_INTERNAL; 698 goto out; 699 } else { 700 temp_created = B_TRUE; 701 } 702 703 ret = download_file(uri, proxy, proxy_port, maxsecs, tmpfd); 704 (void) close(tmpfd); 705 if (ret != KMF_OK) { 706 goto out; 707 } 708 709 /* Check if it is a CRL file and get its format */ 710 if (KMF_IsCRLFile(handle, tempfn, pformat) != KMF_OK) { 711 ret = KMF_ERR_BAD_CRLFILE; 712 goto out; 713 } 714 715 /* Finally, change the temp filename to the target crlfile */ 716 if (rename(tempfn, crlfile) == -1) { 717 ret = KMF_ERR_WRITE_FILE; 718 goto out; 719 } 720 721 out: 722 if (filename != NULL) 723 free(filename); 724 725 if (ret != KMF_OK && temp_created == B_TRUE) 726 (void) unlink(tempfn); 727 728 if (fd != -1) 729 (void) close(fd); 730 731 return (ret); 732 } 733 734 735 KMF_RETURN 736 KMF_DownloadCert(KMF_HANDLE_T handle, char *uri, char *proxy, int proxy_port, 737 unsigned int maxsecs, char *certfile, KMF_ENCODE_FORMAT *pformat) 738 { 739 KMF_RETURN ret = KMF_OK; 740 char *filename = NULL; 741 char tempfn[MAXPATHLEN]; 742 boolean_t temp_created = B_FALSE; 743 mode_t old_mode; 744 int fd = -1, tmpfd = -1; 745 746 CLEAR_ERROR(handle, ret); 747 if (ret != KMF_OK) 748 return (ret); 749 750 if (uri == NULL || certfile == NULL || pformat == NULL) 751 return (KMF_ERR_BAD_PARAMETER); 752 753 if ((fd = open(certfile, O_CREAT |O_RDWR | O_EXCL, 0644)) == -1) 754 return (KMF_ERR_OPEN_FILE); 755 756 /* 757 * Download the file and save it to a temp file. To make rename() 758 * happy, the temp file needs to be created in the same directory as 759 * the target file. 760 */ 761 if ((filename = strdup(certfile)) == NULL) { 762 ret = KMF_ERR_MEMORY; 763 goto out; 764 } 765 (void) snprintf(tempfn, MAXPATHLEN, "%s/%s", dirname(filename), 766 TEMP_TEMPLATE); 767 768 old_mode = umask(077); 769 tmpfd = mkstemp(tempfn); 770 (void) umask(old_mode); 771 if (tmpfd == -1) { 772 ret = KMF_ERR_INTERNAL; 773 goto out; 774 } else { 775 temp_created = B_TRUE; 776 } 777 778 ret = download_file(uri, proxy, proxy_port, maxsecs, tmpfd); 779 (void) close(tmpfd); 780 if (ret != KMF_OK) { 781 goto out; 782 } 783 784 /* Check if it is a Cert file and get its format */ 785 if (KMF_IsCertFile(handle, tempfn, pformat) != KMF_OK) { 786 ret = KMF_ERR_BAD_CERTFILE; 787 goto out; 788 } 789 790 /* Finally, change the temp filename to the target filename */ 791 if (rename(tempfn, certfile) == -1) { 792 ret = KMF_ERR_WRITE_FILE; 793 goto out; 794 } 795 796 out: 797 if (filename != NULL) 798 free(filename); 799 800 if (ret != KMF_OK && temp_created == B_TRUE) 801 (void) unlink(tempfn); 802 803 if (fd != -1) 804 (void) close(fd); 805 806 return (ret); 807 } 808 809 KMF_RETURN 810 KMF_GetOCSPForCert(KMF_HANDLE_T handle, 811 KMF_DATA *user_cert, 812 KMF_DATA *ta_cert, 813 KMF_DATA *response) 814 { 815 KMF_POLICY_RECORD *policy; 816 KMF_RETURN ret = KMF_OK; 817 KMF_OCSPREQUEST_PARAMS req_params; 818 char *hostname = NULL, *host_uri = NULL, *proxyname = NULL; 819 char *proxy_port_s = NULL; 820 int host_port = 0, proxy_port = 0; 821 char ocsp_reqname[MAXPATHLEN]; 822 char ocsp_respname[MAXPATHLEN]; 823 KMF_X509EXT_AUTHINFOACCESS aia; 824 int i; 825 boolean_t found = B_FALSE; 826 KMF_X509EXT_ACCESSDESC *access_info; 827 xmlURIPtr uriptr = NULL; 828 829 CLEAR_ERROR(handle, ret); 830 if (ret != KMF_OK) 831 return (ret); 832 833 if (user_cert == NULL || 834 ta_cert == NULL || response == NULL) 835 return (KMF_ERR_BAD_PARAMETER); 836 837 policy = handle->policy; 838 839 /* Create an OCSP request */ 840 req_params.issuer_cert = ta_cert; 841 req_params.user_cert = user_cert; 842 843 /* 844 * Create temporary files to hold the OCSP request & response data. 845 */ 846 (void) strlcpy(ocsp_reqname, OCSPREQ_TEMPNAME, 847 sizeof (ocsp_reqname)); 848 if (mkstemp(ocsp_reqname) == -1) { 849 return (KMF_ERR_INTERNAL); 850 } 851 852 (void) strlcpy(ocsp_respname, OCSPRESP_TEMPNAME, 853 sizeof (ocsp_respname)); 854 if (mkstemp(ocsp_respname) == -1) { 855 return (KMF_ERR_INTERNAL); 856 } 857 858 ret = KMF_CreateOCSPRequest(handle, &req_params, ocsp_reqname); 859 if (ret != KMF_OK) { 860 goto out; 861 } 862 863 if (policy->VAL_OCSP_BASIC.uri_from_cert == 0) { 864 if (policy->VAL_OCSP_BASIC.responderURI == NULL) { 865 ret = KMF_ERR_OCSP_POLICY; 866 goto out; 867 } 868 host_uri = policy->VAL_OCSP_BASIC.responderURI; 869 870 } else { 871 /* 872 * Get the responder URI from certificate 873 * Authority Information Access 874 * thru OID_PKIX_AD_OCSP 875 */ 876 ret = KMF_GetCertAuthInfoAccessExt(user_cert, &aia); 877 if (ret != KMF_OK) { 878 goto out; 879 } 880 881 for (i = 0; i < aia.numberOfAccessDescription; i++) { 882 access_info = &aia.AccessDesc[i]; 883 if (IsEqualOid(&access_info->AccessMethod, 884 (KMF_OID *)&KMFOID_PkixAdOcsp)) { 885 host_uri = 886 (char *)access_info->AccessLocation.Data; 887 found = B_TRUE; 888 break; 889 } 890 } 891 892 if (!found) { 893 ret = KMF_ERR_OCSP_POLICY; 894 goto out; 895 } 896 } 897 898 /* Parse the URI string; get the hostname and port */ 899 uriptr = xmlParseURI(host_uri); 900 if (uriptr == NULL) { 901 ret = KMF_ERR_BAD_URI; 902 goto out; 903 } 904 905 if (strncasecmp(uriptr->scheme, "http", 4) != 0) { 906 ret = KMF_ERR_BAD_URI; /* we support http only */ 907 goto out; 908 } 909 910 hostname = uriptr->server; 911 if (hostname == NULL) { 912 ret = KMF_ERR_BAD_URI; 913 goto out; 914 } 915 916 host_port = uriptr->port; 917 if (host_port == 0) 918 host_port = 80; 919 920 /* get the proxy info */ 921 if (policy->VAL_OCSP_BASIC.proxy != NULL) { 922 char *last; 923 proxyname = 924 strtok_r(policy->VAL_OCSP_BASIC.proxy, ":", &last); 925 proxy_port_s = strtok_r(NULL, "\0", &last); 926 if (proxy_port_s != NULL) { 927 proxy_port = strtol(proxy_port_s, NULL, 0); 928 } else { 929 proxy_port = 8080; /* default */ 930 } 931 } 932 933 /* 934 * Send the request to an OCSP responder and receive an 935 * OCSP response. 936 */ 937 ret = KMF_GetEncodedOCSPResponse(handle, ocsp_reqname, 938 hostname, host_port, proxyname, proxy_port, 939 ocsp_respname, 30); 940 if (ret != KMF_OK) { 941 goto out; 942 } 943 944 ret = KMF_ReadInputFile(handle, ocsp_respname, response); 945 946 out: 947 (void) unlink(ocsp_reqname); 948 (void) unlink(ocsp_respname); 949 950 if (uriptr != NULL) 951 xmlFreeURI(uriptr); 952 953 return (ret); 954 } 955