199ebb4caSwyllys /*
299ebb4caSwyllys * CDDL HEADER START
399ebb4caSwyllys *
499ebb4caSwyllys * The contents of this file are subject to the terms of the
599ebb4caSwyllys * Common Development and Distribution License (the "License").
699ebb4caSwyllys * You may not use this file except in compliance with the License.
799ebb4caSwyllys *
899ebb4caSwyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
999ebb4caSwyllys * or http://www.opensolaris.org/os/licensing.
1099ebb4caSwyllys * See the License for the specific language governing permissions
1199ebb4caSwyllys * and limitations under the License.
1299ebb4caSwyllys *
1399ebb4caSwyllys * When distributing Covered Code, include this CDDL HEADER in each
1499ebb4caSwyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1599ebb4caSwyllys * If applicable, add the following below this CDDL HEADER, with the
1699ebb4caSwyllys * fields enclosed by brackets "[]" replaced with your own identifying
1799ebb4caSwyllys * information: Portions Copyright [yyyy] [name of copyright owner]
1899ebb4caSwyllys *
1999ebb4caSwyllys * CDDL HEADER END
2099ebb4caSwyllys */
2199ebb4caSwyllys /*
22*30a5e8faSwyllys * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
2399ebb4caSwyllys * Use is subject to license terms.
2499ebb4caSwyllys *
2599ebb4caSwyllys * File: CLIENT.C
2699ebb4caSwyllys */
2799ebb4caSwyllys
2899ebb4caSwyllys #include <stdio.h>
2999ebb4caSwyllys #include <stdlib.h>
3099ebb4caSwyllys #include <ctype.h>
3199ebb4caSwyllys #include <fcntl.h>
3299ebb4caSwyllys #include <poll.h>
3399ebb4caSwyllys #include <sys/errno.h>
3499ebb4caSwyllys #include <sys/types.h>
3599ebb4caSwyllys #include <sys/stat.h>
3699ebb4caSwyllys #include <sys/socket.h>
3799ebb4caSwyllys #include <netdb.h>
3899ebb4caSwyllys #include <netinet/in.h>
3999ebb4caSwyllys #include <arpa/inet.h>
4099ebb4caSwyllys #include <string.h>
4199ebb4caSwyllys #include <unistd.h>
4299ebb4caSwyllys #include <libgen.h>
4399ebb4caSwyllys #include <kmfapi.h>
4499ebb4caSwyllys #include <kmfapiP.h>
4599ebb4caSwyllys #include <libxml2/libxml/uri.h>
4699ebb4caSwyllys
4799ebb4caSwyllys extern int errno;
4899ebb4caSwyllys
4999ebb4caSwyllys #define OCSP_BUFSIZE 1024
5099ebb4caSwyllys
5199ebb4caSwyllys typedef enum {
5299ebb4caSwyllys KMF_RESPONSE_OCSP = 1,
5399ebb4caSwyllys KMF_RESPONSE_FILE = 2
5499ebb4caSwyllys } KMF_RESPONSE_TYPE;
5599ebb4caSwyllys
5699ebb4caSwyllys #define TEMP_TEMPLATE "temp.XXXXXX"
5799ebb4caSwyllys
5899ebb4caSwyllys /*
5999ebb4caSwyllys * This function will establish a socket to the host on the specified port.
6099ebb4caSwyllys * If succeed, it return a socket descriptor; otherwise, return -1.
6199ebb4caSwyllys */
init_socket(char * host,short port)6299ebb4caSwyllys static int init_socket(char *host, short port)
6399ebb4caSwyllys {
6499ebb4caSwyllys struct sockaddr_in sin;
6599ebb4caSwyllys struct hostent *hp, hrec;
6699ebb4caSwyllys int sockfd, opt, herrno;
6799ebb4caSwyllys char hostbuf[BUFSIZ];
6899ebb4caSwyllys
6999ebb4caSwyllys sin.sin_family = PF_INET;
7099ebb4caSwyllys sin.sin_port = htons(port);
7199ebb4caSwyllys if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
7299ebb4caSwyllys if ((hp = gethostbyname_r(host, &hrec, hostbuf,
73*30a5e8faSwyllys sizeof (hostbuf), &herrno)) == NULL) {
7499ebb4caSwyllys return (-1);
7599ebb4caSwyllys }
7699ebb4caSwyllys (void) memcpy((char *)&sin.sin_addr, hp->h_addr,
7799ebb4caSwyllys hp->h_length);
7899ebb4caSwyllys }
7999ebb4caSwyllys
8099ebb4caSwyllys if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
8199ebb4caSwyllys return (-1);
8299ebb4caSwyllys }
8399ebb4caSwyllys
8499ebb4caSwyllys opt = 1;
8599ebb4caSwyllys if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
8699ebb4caSwyllys sizeof (opt)) < 0) {
8799ebb4caSwyllys (void) close(sockfd);
8899ebb4caSwyllys return (-1);
8999ebb4caSwyllys }
9099ebb4caSwyllys
9199ebb4caSwyllys if (connect(sockfd, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
9299ebb4caSwyllys (void) close(sockfd);
9399ebb4caSwyllys return (-1);
9499ebb4caSwyllys }
9599ebb4caSwyllys
9699ebb4caSwyllys return (sockfd);
9799ebb4caSwyllys }
9899ebb4caSwyllys
9999ebb4caSwyllys /*
10099ebb4caSwyllys * This function will connect to host on the port.
10199ebb4caSwyllys * If succeed, return a socket descriptor; otherwise, return 0.
10299ebb4caSwyllys */
10399ebb4caSwyllys static int
connect_to_server(char * host,short port)10499ebb4caSwyllys connect_to_server(char *host, short port)
10599ebb4caSwyllys {
10699ebb4caSwyllys int retry = 1;
10799ebb4caSwyllys int sd = 0;
10899ebb4caSwyllys
10999ebb4caSwyllys while (retry) {
11099ebb4caSwyllys if ((sd = init_socket(host, port)) == -1) {
11199ebb4caSwyllys if (errno == ECONNREFUSED) {
11299ebb4caSwyllys retry = 1;
11399ebb4caSwyllys (void) sleep(1);
11499ebb4caSwyllys } else {
11599ebb4caSwyllys retry = 0;
11699ebb4caSwyllys }
11799ebb4caSwyllys } else {
11899ebb4caSwyllys retry = 0;
11999ebb4caSwyllys }
12099ebb4caSwyllys }
12199ebb4caSwyllys return (sd);
12299ebb4caSwyllys }
12399ebb4caSwyllys
12499ebb4caSwyllys static KMF_RETURN
send_ocsp_request(int sock,char * reqfile,char * hostname)12599ebb4caSwyllys send_ocsp_request(int sock, char *reqfile, char *hostname)
12699ebb4caSwyllys {
12799ebb4caSwyllys KMF_RETURN ret = KMF_OK;
12899ebb4caSwyllys int filefd, bytes, n, total = 0;
12999ebb4caSwyllys char buf[OCSP_BUFSIZE];
13099ebb4caSwyllys struct stat s;
13199ebb4caSwyllys char req_header[256];
13299ebb4caSwyllys static char req_format[] =
13399ebb4caSwyllys "POST %s HTTP/1.0\r\n\
13499ebb4caSwyllys Content-Type: application/ocsp-request\r\n\
13599ebb4caSwyllys Content-Length: %d\r\n\r\n";
13699ebb4caSwyllys
13799ebb4caSwyllys if ((filefd = open(reqfile, O_RDONLY)) == -1) {
13899ebb4caSwyllys ret = KMF_ERR_OPEN_FILE;
13999ebb4caSwyllys return (ret);
14099ebb4caSwyllys }
14199ebb4caSwyllys
14299ebb4caSwyllys /* open the request file */
14399ebb4caSwyllys if (fstat(filefd, &s) < 0) {
14499ebb4caSwyllys ret = KMF_ERR_OPEN_FILE;
14599ebb4caSwyllys return (ret);
14699ebb4caSwyllys }
14799ebb4caSwyllys
14899ebb4caSwyllys
14999ebb4caSwyllys /* Send http header */
15099ebb4caSwyllys if (hostname != NULL) {
15199ebb4caSwyllys (void) snprintf(req_header, 256, req_format, hostname,
15299ebb4caSwyllys s.st_size);
15399ebb4caSwyllys } else {
15499ebb4caSwyllys (void) snprintf(req_header, 256, req_format, "/", s.st_size);
15599ebb4caSwyllys }
15699ebb4caSwyllys bytes = strlen(req_header);
15799ebb4caSwyllys
15899ebb4caSwyllys if ((n = write(sock, req_header, bytes)) < 0) {
15999ebb4caSwyllys ret = KMF_ERR_SEND_REQUEST;
16099ebb4caSwyllys goto exit;
16199ebb4caSwyllys }
16299ebb4caSwyllys
16399ebb4caSwyllys /* Send the request content */
16499ebb4caSwyllys while ((bytes = read(filefd, buf, OCSP_BUFSIZE)) > 0) {
16599ebb4caSwyllys if ((n = write(sock, buf, bytes)) < 0) {
16699ebb4caSwyllys ret = KMF_ERR_SEND_REQUEST;
16799ebb4caSwyllys goto exit;
16899ebb4caSwyllys }
16999ebb4caSwyllys total += n;
17099ebb4caSwyllys (void) memset(buf, 0, sizeof (buf));
17199ebb4caSwyllys }
17299ebb4caSwyllys
17399ebb4caSwyllys exit:
17499ebb4caSwyllys (void) close(filefd);
17599ebb4caSwyllys return (ret);
17699ebb4caSwyllys }
17799ebb4caSwyllys
17899ebb4caSwyllys
17999ebb4caSwyllys /*
18099ebb4caSwyllys * Perform a write that can handle EINTR.
18199ebb4caSwyllys */
18299ebb4caSwyllys static int
looping_write(int fd,void * buf,int len)18399ebb4caSwyllys looping_write(int fd, void *buf, int len)
18499ebb4caSwyllys {
18599ebb4caSwyllys char *p = buf;
18699ebb4caSwyllys int cc, len2 = 0;
18799ebb4caSwyllys
18899ebb4caSwyllys if (len == 0)
18999ebb4caSwyllys return (0);
19099ebb4caSwyllys do {
19199ebb4caSwyllys cc = write(fd, p, len);
19299ebb4caSwyllys if (cc < 0) {
19399ebb4caSwyllys if (errno == EINTR)
19499ebb4caSwyllys continue;
19599ebb4caSwyllys return (cc);
19699ebb4caSwyllys } else if (cc == 0) {
19799ebb4caSwyllys return (len2);
19899ebb4caSwyllys } else {
19999ebb4caSwyllys p += cc;
20099ebb4caSwyllys len2 += cc;
20199ebb4caSwyllys len -= cc;
20299ebb4caSwyllys }
20399ebb4caSwyllys } while (len > 0);
20499ebb4caSwyllys
20599ebb4caSwyllys return (len2);
20699ebb4caSwyllys }
20799ebb4caSwyllys
20899ebb4caSwyllys /*
20999ebb4caSwyllys * This function will get the response from the server, check the http status
21099ebb4caSwyllys * line, and write the response content to a file. If this is a OCSP response,
21199ebb4caSwyllys * it will check the content type also.
21299ebb4caSwyllys */
21399ebb4caSwyllys static KMF_RETURN
get_encoded_response(int sock,KMF_RESPONSE_TYPE resptype,int filefd,unsigned int maxsecs)21499ebb4caSwyllys get_encoded_response(int sock, KMF_RESPONSE_TYPE resptype, int filefd,
21599ebb4caSwyllys unsigned int maxsecs)
21699ebb4caSwyllys {
21799ebb4caSwyllys int ret = KMF_OK;
21899ebb4caSwyllys char *buf = NULL;
21999ebb4caSwyllys int buflen = 0;
22099ebb4caSwyllys int offset = 0;
22199ebb4caSwyllys int search_offset;
22299ebb4caSwyllys const int buf_incre = OCSP_BUFSIZE; /* 1 KB at a time */
22399ebb4caSwyllys const int maxBufSize = 8 * buf_incre; /* 8 KB max */
22499ebb4caSwyllys const char *CRLF = "\r\n";
22599ebb4caSwyllys const char *headerEndMark = "\r\n\r\n";
22699ebb4caSwyllys const char *httpprotocol = "HTTP/";
22799ebb4caSwyllys const int CRLFlen = strlen(CRLF);
22899ebb4caSwyllys const int marklen = strlen(headerEndMark);
22999ebb4caSwyllys const int httplen = strlen(httpprotocol);
23099ebb4caSwyllys char *headerEnd = NULL;
23199ebb4caSwyllys boolean_t EOS = B_FALSE;
23299ebb4caSwyllys const char *httpcode = NULL;
23399ebb4caSwyllys const char *contenttype = NULL;
23499ebb4caSwyllys int contentlength = 0;
23599ebb4caSwyllys int bytes = 0;
23699ebb4caSwyllys char *statusLineEnd = NULL;
23799ebb4caSwyllys char *space = NULL;
23899ebb4caSwyllys char *nextHeader = NULL;
23999ebb4caSwyllys struct pollfd pfd;
24099ebb4caSwyllys int sock_flag;
24199ebb4caSwyllys int poll_ret;
24299ebb4caSwyllys boolean_t timeout = B_FALSE;
24399ebb4caSwyllys
24499ebb4caSwyllys /* set O_NONBLOCK flag on socket */
24599ebb4caSwyllys if ((sock_flag = fcntl(sock, F_GETFL, 0)) == -1) {
24699ebb4caSwyllys return (KMF_ERR_RECV_RESPONSE);
24799ebb4caSwyllys }
24899ebb4caSwyllys sock_flag |= O_NONBLOCK;
24999ebb4caSwyllys if (fcntl(sock, F_SETFL, sock_flag) == -1) {
25099ebb4caSwyllys return (KMF_ERR_RECV_RESPONSE);
25199ebb4caSwyllys }
25299ebb4caSwyllys
25399ebb4caSwyllys /* set up poll */
25499ebb4caSwyllys pfd.fd = sock;
25599ebb4caSwyllys pfd.events = POLLIN;
25699ebb4caSwyllys
25799ebb4caSwyllys /*
25899ebb4caSwyllys * First read HTTP status line and headers. We will read up to at
25999ebb4caSwyllys * least the end of the HTTP headers
26099ebb4caSwyllys */
26199ebb4caSwyllys do {
26299ebb4caSwyllys if ((buflen - offset) < buf_incre) {
26399ebb4caSwyllys buflen += buf_incre;
26499ebb4caSwyllys buf = realloc(buf, buflen + 1);
26599ebb4caSwyllys if (buf == NULL) {
26699ebb4caSwyllys ret = KMF_ERR_MEMORY;
26799ebb4caSwyllys goto out;
26899ebb4caSwyllys }
26999ebb4caSwyllys }
27099ebb4caSwyllys
27199ebb4caSwyllys pfd.revents = 0;
27299ebb4caSwyllys poll_ret = poll(&pfd, 1, maxsecs * MILLISEC);
27399ebb4caSwyllys if (poll_ret == 0) {
27499ebb4caSwyllys timeout = B_TRUE;
27599ebb4caSwyllys break;
27699ebb4caSwyllys } else if (poll_ret < 0) {
27799ebb4caSwyllys ret = KMF_ERR_RECV_RESPONSE;
27899ebb4caSwyllys goto out;
27999ebb4caSwyllys } else {
28099ebb4caSwyllys if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
28199ebb4caSwyllys ret = KMF_ERR_RECV_RESPONSE;
28299ebb4caSwyllys goto out;
28399ebb4caSwyllys }
28499ebb4caSwyllys }
28599ebb4caSwyllys
28699ebb4caSwyllys bytes = read(sock, buf + offset, buf_incre);
28799ebb4caSwyllys if (bytes < 0) {
28899ebb4caSwyllys if (errno == EWOULDBLOCK) { /* no data this time */
28999ebb4caSwyllys continue;
29099ebb4caSwyllys } else {
29199ebb4caSwyllys ret = KMF_ERR_RECV_RESPONSE;
29299ebb4caSwyllys goto out;
29399ebb4caSwyllys }
29499ebb4caSwyllys } else if (bytes == 0) { /* no more data */
29599ebb4caSwyllys EOS = B_TRUE;
29699ebb4caSwyllys } else { /* bytes > 0 */
29799ebb4caSwyllys search_offset = (offset - marklen) > 0 ?
29899ebb4caSwyllys offset - marklen : 0;
29999ebb4caSwyllys offset += bytes;
30099ebb4caSwyllys *(buf + offset) = '\0'; /* NULL termination */
30199ebb4caSwyllys
30299ebb4caSwyllys headerEnd = strstr((const char *)buf + search_offset,
30399ebb4caSwyllys headerEndMark);
30499ebb4caSwyllys }
30599ebb4caSwyllys
30699ebb4caSwyllys } while ((!headerEnd) && (EOS == B_FALSE) && (buflen < maxBufSize));
30799ebb4caSwyllys
30899ebb4caSwyllys if (timeout == B_TRUE) {
30999ebb4caSwyllys ret = KMF_ERR_RECV_TIMEOUT;
31099ebb4caSwyllys goto out;
31199ebb4caSwyllys } else if (headerEnd == NULL) {
31299ebb4caSwyllys /* could not find the end of headers */
31399ebb4caSwyllys ret = KMF_ERR_BAD_HTTP_RESPONSE;
31499ebb4caSwyllys goto out;
31599ebb4caSwyllys }
31699ebb4caSwyllys
31799ebb4caSwyllys /*
31899ebb4caSwyllys * Parse the HTTP status line, which will look like this:
31999ebb4caSwyllys * "HTTP/1.1 200 OK".
32099ebb4caSwyllys */
32199ebb4caSwyllys statusLineEnd = strstr((const char *)buf, CRLF);
32299ebb4caSwyllys if (statusLineEnd == NULL) {
32399ebb4caSwyllys ret = KMF_ERR_BAD_HTTP_RESPONSE;
32499ebb4caSwyllys goto out;
32599ebb4caSwyllys }
32699ebb4caSwyllys *statusLineEnd = '\0';
32799ebb4caSwyllys
32899ebb4caSwyllys space = strchr((const char *)buf, ' ');
32999ebb4caSwyllys if (space == NULL ||
33099ebb4caSwyllys (strncasecmp((const char *)buf, httpprotocol, httplen) != 0)) {
33199ebb4caSwyllys ret = KMF_ERR_BAD_HTTP_RESPONSE;
33299ebb4caSwyllys goto out;
33399ebb4caSwyllys }
33499ebb4caSwyllys
33599ebb4caSwyllys /*
33699ebb4caSwyllys * Check the HTTP status code. If it is not 200, the HTTP response
33799ebb4caSwyllys * is not good.
33899ebb4caSwyllys */
33999ebb4caSwyllys httpcode = space + 1;
34099ebb4caSwyllys space = strchr(httpcode, ' ');
34199ebb4caSwyllys if (space == NULL) {
34299ebb4caSwyllys ret = KMF_ERR_BAD_HTTP_RESPONSE;
34399ebb4caSwyllys goto out;
34499ebb4caSwyllys }
34599ebb4caSwyllys
34699ebb4caSwyllys *space = 0;
34799ebb4caSwyllys if (strcmp(httpcode, "200") != 0) {
34899ebb4caSwyllys ret = KMF_ERR_BAD_HTTP_RESPONSE;
34999ebb4caSwyllys goto out;
35099ebb4caSwyllys }
35199ebb4caSwyllys
35299ebb4caSwyllys /*
35399ebb4caSwyllys * Parse the HTTP headers in the buffer. Save content-type and
35499ebb4caSwyllys * content-length only.
35599ebb4caSwyllys */
35699ebb4caSwyllys nextHeader = statusLineEnd + CRLFlen;
35799ebb4caSwyllys *headerEnd = '\0'; /* terminate */
35899ebb4caSwyllys do {
35999ebb4caSwyllys char *thisHeaderEnd = NULL;
36099ebb4caSwyllys char *value = NULL;
36199ebb4caSwyllys char *colon = strchr(nextHeader, ':');
36299ebb4caSwyllys
36399ebb4caSwyllys if (colon == NULL) {
36499ebb4caSwyllys ret = KMF_ERR_BAD_HTTP_RESPONSE;
36599ebb4caSwyllys goto out;
36699ebb4caSwyllys }
36799ebb4caSwyllys *colon = '\0';
36899ebb4caSwyllys
36999ebb4caSwyllys value = colon + 1;
37099ebb4caSwyllys if (*value != ' ') {
37199ebb4caSwyllys ret = KMF_ERR_BAD_HTTP_RESPONSE;
37299ebb4caSwyllys goto out;
37399ebb4caSwyllys }
37499ebb4caSwyllys value++;
37599ebb4caSwyllys
37699ebb4caSwyllys thisHeaderEnd = strstr(value, CRLF);
37799ebb4caSwyllys if (thisHeaderEnd != NULL)
37899ebb4caSwyllys *thisHeaderEnd = '\0';
37999ebb4caSwyllys
38099ebb4caSwyllys if (strcasecmp(nextHeader, "content-type") == 0) {
38199ebb4caSwyllys contenttype = value;
38299ebb4caSwyllys } else if (strcasecmp(nextHeader, "content-length") == 0) {
38399ebb4caSwyllys contentlength = atoi(value);
38499ebb4caSwyllys }
38599ebb4caSwyllys
38699ebb4caSwyllys if (thisHeaderEnd != NULL) {
38799ebb4caSwyllys nextHeader = thisHeaderEnd + CRLFlen;
38899ebb4caSwyllys } else {
38999ebb4caSwyllys nextHeader = NULL;
39099ebb4caSwyllys }
39199ebb4caSwyllys
39299ebb4caSwyllys } while (nextHeader && (nextHeader < (headerEnd + CRLFlen)));
39399ebb4caSwyllys
39499ebb4caSwyllys /* Check the contenttype if this is an OCSP response */
39599ebb4caSwyllys if (resptype == KMF_RESPONSE_OCSP) {
39699ebb4caSwyllys if (contenttype == NULL) {
39799ebb4caSwyllys ret = KMF_ERR_BAD_HTTP_RESPONSE;
39899ebb4caSwyllys goto out;
39999ebb4caSwyllys } else if (strcasecmp(contenttype,
40099ebb4caSwyllys "application/ocsp-response") != 0) {
40199ebb4caSwyllys ret = KMF_ERR_BAD_HTTP_RESPONSE;
40299ebb4caSwyllys goto out;
40399ebb4caSwyllys }
40499ebb4caSwyllys }
40599ebb4caSwyllys
40699ebb4caSwyllys /* Now we are ready to read the body of the response */
40799ebb4caSwyllys offset = offset - (int)(headerEnd - (const char *)buf) - marklen;
40899ebb4caSwyllys if (offset) {
40999ebb4caSwyllys /* move all data to the beginning of the buffer */
41099ebb4caSwyllys (void) memmove(buf, headerEnd + marklen, offset);
41199ebb4caSwyllys }
41299ebb4caSwyllys
41399ebb4caSwyllys /* resize buffer to only what's needed to hold the current response */
41499ebb4caSwyllys buflen = (1 + (offset-1) / buf_incre) * buf_incre;
41599ebb4caSwyllys
41699ebb4caSwyllys while ((EOS == B_FALSE) &&
41799ebb4caSwyllys ((contentlength == 0) || (offset < contentlength)) &&
41899ebb4caSwyllys (buflen < maxBufSize)) {
41999ebb4caSwyllys /* we still need to receive more content data */
42099ebb4caSwyllys if ((buflen - offset) < buf_incre) {
42199ebb4caSwyllys buflen += buf_incre;
42299ebb4caSwyllys buf = realloc(buf, buflen + 1);
42399ebb4caSwyllys if (buf == NULL) {
42499ebb4caSwyllys ret = KMF_ERR_MEMORY;
42599ebb4caSwyllys goto out;
42699ebb4caSwyllys }
42799ebb4caSwyllys }
42899ebb4caSwyllys
42999ebb4caSwyllys pfd.revents = 0;
43099ebb4caSwyllys poll_ret = poll(&pfd, 1, maxsecs * MILLISEC);
43199ebb4caSwyllys if (poll_ret == 0) {
43299ebb4caSwyllys timeout = B_TRUE;
43399ebb4caSwyllys break;
43499ebb4caSwyllys } else if (poll_ret < 0) {
43599ebb4caSwyllys ret = KMF_ERR_RECV_RESPONSE;
43699ebb4caSwyllys goto out;
43799ebb4caSwyllys } else {
43899ebb4caSwyllys if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
43999ebb4caSwyllys ret = KMF_ERR_RECV_RESPONSE;
44099ebb4caSwyllys goto out;
44199ebb4caSwyllys }
44299ebb4caSwyllys }
44399ebb4caSwyllys
44499ebb4caSwyllys bytes = read(sock, buf + offset, buf_incre);
44599ebb4caSwyllys if (bytes < 0) {
44699ebb4caSwyllys if (errno == EWOULDBLOCK) {
44799ebb4caSwyllys continue;
44899ebb4caSwyllys } else {
44999ebb4caSwyllys ret = KMF_ERR_RECV_RESPONSE;
45099ebb4caSwyllys goto out;
45199ebb4caSwyllys }
45299ebb4caSwyllys } else if (bytes == 0) { /* no more data */
45399ebb4caSwyllys EOS = B_TRUE;
45499ebb4caSwyllys } else {
45599ebb4caSwyllys offset += bytes;
45699ebb4caSwyllys }
45799ebb4caSwyllys }
45899ebb4caSwyllys
45999ebb4caSwyllys if (timeout == B_TRUE) {
46099ebb4caSwyllys ret = KMF_ERR_RECV_TIMEOUT;
46199ebb4caSwyllys goto out;
46299ebb4caSwyllys } else if (((contentlength != 0) && (offset < contentlength)) ||
46399ebb4caSwyllys offset == 0) {
46499ebb4caSwyllys ret = KMF_ERR_BAD_HTTP_RESPONSE;
46599ebb4caSwyllys goto out;
46699ebb4caSwyllys }
46799ebb4caSwyllys
46899ebb4caSwyllys /* write to the file */
46999ebb4caSwyllys if (looping_write(filefd, buf, offset) != offset) {
47099ebb4caSwyllys ret = KMF_ERR_WRITE_FILE;
47199ebb4caSwyllys }
47299ebb4caSwyllys
47399ebb4caSwyllys out:
47499ebb4caSwyllys free(buf);
47599ebb4caSwyllys return (ret);
47699ebb4caSwyllys }
47799ebb4caSwyllys
47899ebb4caSwyllys KMF_RETURN
kmf_get_encoded_ocsp_response(KMF_HANDLE_T handle,char * reqfile,char * hostname,int port,char * proxy,int proxy_port,char * respfile,unsigned int maxsecs)479*30a5e8faSwyllys kmf_get_encoded_ocsp_response(KMF_HANDLE_T handle,
480*30a5e8faSwyllys char *reqfile, char *hostname,
48199ebb4caSwyllys int port, char *proxy, int proxy_port, char *respfile,
48299ebb4caSwyllys unsigned int maxsecs)
48399ebb4caSwyllys {
48499ebb4caSwyllys KMF_RETURN ret = KMF_OK;
48599ebb4caSwyllys int sock, respfd;
48699ebb4caSwyllys char http_hostname[256];
48799ebb4caSwyllys int final_proxy_port, final_port;
48899ebb4caSwyllys
48999ebb4caSwyllys CLEAR_ERROR(handle, ret);
49099ebb4caSwyllys if (ret != KMF_OK)
49199ebb4caSwyllys return (ret);
49299ebb4caSwyllys
49399ebb4caSwyllys if (hostname == NULL || reqfile == NULL || respfile == NULL) {
49499ebb4caSwyllys return (KMF_ERR_BAD_PARAMETER);
49599ebb4caSwyllys }
49699ebb4caSwyllys
49799ebb4caSwyllys final_proxy_port = (proxy_port == 0 || proxy_port == -1) ?
49899ebb4caSwyllys 80 : proxy_port;
49999ebb4caSwyllys final_port = (port == 0 || port == -1) ? 80 : port;
50099ebb4caSwyllys
50199ebb4caSwyllys /* Connect to server */
50299ebb4caSwyllys if (proxy != NULL) {
50399ebb4caSwyllys sock = connect_to_server(proxy, final_proxy_port);
50499ebb4caSwyllys } else {
50599ebb4caSwyllys sock = connect_to_server(hostname, final_port);
50699ebb4caSwyllys }
50799ebb4caSwyllys
50899ebb4caSwyllys if (sock == -1) {
50999ebb4caSwyllys return (KMF_ERR_CONNECT_SERVER);
51099ebb4caSwyllys }
51199ebb4caSwyllys
51299ebb4caSwyllys /* Send the OCSP request */
51399ebb4caSwyllys if (proxy != NULL) {
51499ebb4caSwyllys (void) snprintf(http_hostname, sizeof (http_hostname),
51599ebb4caSwyllys "http://%s:%d", hostname, final_port);
51699ebb4caSwyllys ret = send_ocsp_request(sock, reqfile, http_hostname);
51799ebb4caSwyllys } else {
51899ebb4caSwyllys ret = send_ocsp_request(sock, reqfile, NULL);
51999ebb4caSwyllys }
52099ebb4caSwyllys
52199ebb4caSwyllys if (ret != KMF_OK) {
52299ebb4caSwyllys goto out;
52399ebb4caSwyllys }
52499ebb4caSwyllys
52599ebb4caSwyllys /* Retrieve the OCSP response */
52699ebb4caSwyllys if (maxsecs == 0) {
52799ebb4caSwyllys maxsecs = 30; /* default poll time limit is 30 seconds */
52899ebb4caSwyllys }
52999ebb4caSwyllys
53099ebb4caSwyllys if ((respfd = open(respfile, O_CREAT |O_RDWR | O_EXCL, 0600)) == -1) {
53199ebb4caSwyllys ret = KMF_ERR_OPEN_FILE;
53299ebb4caSwyllys } else {
53399ebb4caSwyllys ret = get_encoded_response(sock, KMF_RESPONSE_OCSP,
534*30a5e8faSwyllys respfd, maxsecs);
53599ebb4caSwyllys (void) close(respfd);
53699ebb4caSwyllys }
53799ebb4caSwyllys
53899ebb4caSwyllys out:
53999ebb4caSwyllys (void) close(sock);
54099ebb4caSwyllys return (ret);
54199ebb4caSwyllys }
54299ebb4caSwyllys
54399ebb4caSwyllys static KMF_RETURN
send_download_request(int sock,char * hostname,int port,boolean_t is_proxy,char * loc)54499ebb4caSwyllys send_download_request(int sock, char *hostname, int port, boolean_t is_proxy,
54599ebb4caSwyllys char *loc)
54699ebb4caSwyllys {
54799ebb4caSwyllys KMF_RETURN ret = KMF_OK;
54899ebb4caSwyllys char url[256];
54999ebb4caSwyllys char req_header[1024];
55099ebb4caSwyllys static char req_format[] =
55199ebb4caSwyllys "GET %s HTTP/1.0\r\n\
55299ebb4caSwyllys Host: %s:%d\r\n\
55399ebb4caSwyllys Accept: */*\r\n\r\n";
55499ebb4caSwyllys
55599ebb4caSwyllys if (is_proxy) {
55699ebb4caSwyllys (void) snprintf(url, sizeof (url), "http://%s:%d/%s",
55799ebb4caSwyllys hostname, port, loc);
55899ebb4caSwyllys } else {
55999ebb4caSwyllys (void) snprintf(url, sizeof (url), "/%s", loc);
56099ebb4caSwyllys }
56199ebb4caSwyllys
56299ebb4caSwyllys (void) snprintf(req_header, sizeof (req_header), req_format, url,
56399ebb4caSwyllys hostname, port);
56499ebb4caSwyllys
56599ebb4caSwyllys if (write(sock, req_header, strlen(req_header)) < 0) {
56699ebb4caSwyllys ret = KMF_ERR_SEND_REQUEST;
56799ebb4caSwyllys }
56899ebb4caSwyllys
56999ebb4caSwyllys return (ret);
57099ebb4caSwyllys }
57199ebb4caSwyllys
57299ebb4caSwyllys static KMF_RETURN
download_file(char * uri,char * proxy,int proxy_port,unsigned int maxsecs,int filefd)57399ebb4caSwyllys download_file(char *uri, char *proxy, int proxy_port,
57499ebb4caSwyllys unsigned int maxsecs, int filefd)
57599ebb4caSwyllys {
57699ebb4caSwyllys KMF_RETURN ret = KMF_OK;
57799ebb4caSwyllys xmlURIPtr uriptr;
57899ebb4caSwyllys int sock;
57999ebb4caSwyllys boolean_t is_proxy;
58099ebb4caSwyllys int final_proxy_port;
58199ebb4caSwyllys char *hostname = NULL;
58299ebb4caSwyllys char *path = NULL;
58399ebb4caSwyllys int port;
58499ebb4caSwyllys
58599ebb4caSwyllys if (uri == NULL || filefd == -1)
58699ebb4caSwyllys return (KMF_ERR_BAD_PARAMETER);
58799ebb4caSwyllys
58899ebb4caSwyllys /* Parse URI */
58999ebb4caSwyllys uriptr = xmlParseURI(uri);
59099ebb4caSwyllys if (uriptr == NULL) {
59199ebb4caSwyllys ret = KMF_ERR_BAD_URI;
59299ebb4caSwyllys goto out;
59399ebb4caSwyllys }
59499ebb4caSwyllys
59599ebb4caSwyllys if (uriptr->scheme == NULL ||
59699ebb4caSwyllys strncasecmp(uriptr->scheme, "http", 4) != 0) {
59799ebb4caSwyllys ret = KMF_ERR_BAD_URI; /* we support http only */
59899ebb4caSwyllys goto out;
59999ebb4caSwyllys }
60099ebb4caSwyllys
60199ebb4caSwyllys /* get the host name */
60299ebb4caSwyllys hostname = uriptr->server;
60399ebb4caSwyllys if (hostname == NULL) {
60499ebb4caSwyllys ret = KMF_ERR_BAD_URI;
60599ebb4caSwyllys goto out;
60699ebb4caSwyllys }
60799ebb4caSwyllys
60899ebb4caSwyllys /* get the port number */
60999ebb4caSwyllys port = uriptr->port;
61099ebb4caSwyllys if (port == 0) {
61199ebb4caSwyllys port = 80;
61299ebb4caSwyllys }
61399ebb4caSwyllys
61499ebb4caSwyllys /* Get the path */
61599ebb4caSwyllys path = uriptr->path;
61699ebb4caSwyllys if (path == NULL) {
61799ebb4caSwyllys ret = KMF_ERR_BAD_URI;
61899ebb4caSwyllys goto out;
61999ebb4caSwyllys }
62099ebb4caSwyllys
62199ebb4caSwyllys /* Connect to server */
62299ebb4caSwyllys if (proxy != NULL) {
62399ebb4caSwyllys final_proxy_port = (proxy_port == 0 || proxy_port == -1) ?
624*30a5e8faSwyllys 80 : proxy_port;
62599ebb4caSwyllys is_proxy = B_TRUE;
62699ebb4caSwyllys sock = connect_to_server(proxy, final_proxy_port);
62799ebb4caSwyllys } else {
62899ebb4caSwyllys is_proxy = B_FALSE;
62999ebb4caSwyllys sock = connect_to_server(hostname, port);
63099ebb4caSwyllys }
63199ebb4caSwyllys if (sock == -1) {
63299ebb4caSwyllys ret = KMF_ERR_CONNECT_SERVER;
63399ebb4caSwyllys goto out;
63499ebb4caSwyllys }
63599ebb4caSwyllys
63699ebb4caSwyllys /* Send the request */
63799ebb4caSwyllys ret = send_download_request(sock, hostname, port, is_proxy, path);
63899ebb4caSwyllys if (ret != KMF_OK) {
63999ebb4caSwyllys goto out;
64099ebb4caSwyllys }
64199ebb4caSwyllys
64299ebb4caSwyllys /* Retrieve the response */
64399ebb4caSwyllys ret = get_encoded_response(sock, KMF_RESPONSE_FILE, filefd,
64499ebb4caSwyllys maxsecs == 0 ? 30 : maxsecs);
64599ebb4caSwyllys if (ret != KMF_OK) {
64699ebb4caSwyllys goto out;
64799ebb4caSwyllys }
64899ebb4caSwyllys
64999ebb4caSwyllys out:
65099ebb4caSwyllys if (uriptr != NULL)
65199ebb4caSwyllys xmlFreeURI(uriptr);
65299ebb4caSwyllys
65399ebb4caSwyllys if (sock != -1)
65499ebb4caSwyllys (void) close(sock);
65599ebb4caSwyllys
65699ebb4caSwyllys return (ret);
65799ebb4caSwyllys }
65899ebb4caSwyllys
65999ebb4caSwyllys
66099ebb4caSwyllys KMF_RETURN
kmf_download_crl(KMF_HANDLE_T handle,char * uri,char * proxy,int proxy_port,unsigned int maxsecs,char * crlfile,KMF_ENCODE_FORMAT * pformat)661*30a5e8faSwyllys kmf_download_crl(KMF_HANDLE_T handle, char *uri, char *proxy, int proxy_port,
66299ebb4caSwyllys unsigned int maxsecs, char *crlfile, KMF_ENCODE_FORMAT *pformat)
66399ebb4caSwyllys {
66499ebb4caSwyllys KMF_RETURN ret = KMF_OK;
66599ebb4caSwyllys char *filename = NULL;
66699ebb4caSwyllys char tempfn[MAXPATHLEN];
66799ebb4caSwyllys boolean_t temp_created = B_FALSE;
66899ebb4caSwyllys mode_t old_mode;
66999ebb4caSwyllys int fd = -1, tmpfd = -1;
67099ebb4caSwyllys
67199ebb4caSwyllys CLEAR_ERROR(handle, ret);
67299ebb4caSwyllys if (ret != KMF_OK)
67399ebb4caSwyllys return (ret);
67499ebb4caSwyllys
67599ebb4caSwyllys if (uri == NULL || crlfile == NULL || pformat == NULL)
67699ebb4caSwyllys return (KMF_ERR_BAD_PARAMETER);
67799ebb4caSwyllys
67899ebb4caSwyllys if ((fd = open(crlfile, O_CREAT |O_RDWR | O_EXCL, 0644)) == -1)
67999ebb4caSwyllys return (KMF_ERR_OPEN_FILE);
68099ebb4caSwyllys
68199ebb4caSwyllys /*
68299ebb4caSwyllys * Download the file and save it to a temp file. To make rename()
68399ebb4caSwyllys * happy, the temp file needs to be created in the same directory as
68499ebb4caSwyllys * the target file.
68599ebb4caSwyllys */
68699ebb4caSwyllys if ((filename = strdup(crlfile)) == NULL) {
68799ebb4caSwyllys ret = KMF_ERR_MEMORY;
68899ebb4caSwyllys goto out;
68999ebb4caSwyllys }
69099ebb4caSwyllys (void) snprintf(tempfn, MAXPATHLEN, "%s/%s", dirname(filename),
69199ebb4caSwyllys TEMP_TEMPLATE);
69299ebb4caSwyllys old_mode = umask(077);
69399ebb4caSwyllys tmpfd = mkstemp(tempfn);
69499ebb4caSwyllys (void) umask(old_mode);
69599ebb4caSwyllys if (tmpfd == -1) {
69699ebb4caSwyllys ret = KMF_ERR_INTERNAL;
69799ebb4caSwyllys goto out;
69899ebb4caSwyllys } else {
69999ebb4caSwyllys temp_created = B_TRUE;
70099ebb4caSwyllys }
70199ebb4caSwyllys
70299ebb4caSwyllys ret = download_file(uri, proxy, proxy_port, maxsecs, tmpfd);
70399ebb4caSwyllys (void) close(tmpfd);
70499ebb4caSwyllys if (ret != KMF_OK) {
70599ebb4caSwyllys goto out;
70699ebb4caSwyllys }
70799ebb4caSwyllys
70899ebb4caSwyllys /* Check if it is a CRL file and get its format */
709*30a5e8faSwyllys if (kmf_is_crl_file(handle, tempfn, pformat) != KMF_OK) {
71099ebb4caSwyllys ret = KMF_ERR_BAD_CRLFILE;
71199ebb4caSwyllys goto out;
71299ebb4caSwyllys }
71399ebb4caSwyllys
71499ebb4caSwyllys /* Finally, change the temp filename to the target crlfile */
71599ebb4caSwyllys if (rename(tempfn, crlfile) == -1) {
71699ebb4caSwyllys ret = KMF_ERR_WRITE_FILE;
71799ebb4caSwyllys goto out;
71899ebb4caSwyllys }
71999ebb4caSwyllys
72099ebb4caSwyllys out:
72199ebb4caSwyllys if (filename != NULL)
72299ebb4caSwyllys free(filename);
72399ebb4caSwyllys
72499ebb4caSwyllys if (ret != KMF_OK && temp_created == B_TRUE)
72599ebb4caSwyllys (void) unlink(tempfn);
72699ebb4caSwyllys
72799ebb4caSwyllys if (fd != -1)
72899ebb4caSwyllys (void) close(fd);
72999ebb4caSwyllys
73099ebb4caSwyllys return (ret);
73199ebb4caSwyllys }
73299ebb4caSwyllys
73399ebb4caSwyllys
73499ebb4caSwyllys KMF_RETURN
kmf_download_cert(KMF_HANDLE_T handle,char * uri,char * proxy,int proxy_port,unsigned int maxsecs,char * certfile,KMF_ENCODE_FORMAT * pformat)735*30a5e8faSwyllys kmf_download_cert(KMF_HANDLE_T handle, char *uri, char *proxy, int proxy_port,
73699ebb4caSwyllys unsigned int maxsecs, char *certfile, KMF_ENCODE_FORMAT *pformat)
73799ebb4caSwyllys {
73899ebb4caSwyllys KMF_RETURN ret = KMF_OK;
73999ebb4caSwyllys char *filename = NULL;
74099ebb4caSwyllys char tempfn[MAXPATHLEN];
74199ebb4caSwyllys boolean_t temp_created = B_FALSE;
74299ebb4caSwyllys mode_t old_mode;
74399ebb4caSwyllys int fd = -1, tmpfd = -1;
74499ebb4caSwyllys
74599ebb4caSwyllys CLEAR_ERROR(handle, ret);
74699ebb4caSwyllys if (ret != KMF_OK)
74799ebb4caSwyllys return (ret);
74899ebb4caSwyllys
74999ebb4caSwyllys if (uri == NULL || certfile == NULL || pformat == NULL)
75099ebb4caSwyllys return (KMF_ERR_BAD_PARAMETER);
75199ebb4caSwyllys
75299ebb4caSwyllys if ((fd = open(certfile, O_CREAT |O_RDWR | O_EXCL, 0644)) == -1)
75399ebb4caSwyllys return (KMF_ERR_OPEN_FILE);
75499ebb4caSwyllys
75599ebb4caSwyllys /*
75699ebb4caSwyllys * Download the file and save it to a temp file. To make rename()
75799ebb4caSwyllys * happy, the temp file needs to be created in the same directory as
75899ebb4caSwyllys * the target file.
75999ebb4caSwyllys */
76099ebb4caSwyllys if ((filename = strdup(certfile)) == NULL) {
76199ebb4caSwyllys ret = KMF_ERR_MEMORY;
76299ebb4caSwyllys goto out;
76399ebb4caSwyllys }
76499ebb4caSwyllys (void) snprintf(tempfn, MAXPATHLEN, "%s/%s", dirname(filename),
76599ebb4caSwyllys TEMP_TEMPLATE);
76699ebb4caSwyllys
76799ebb4caSwyllys old_mode = umask(077);
76899ebb4caSwyllys tmpfd = mkstemp(tempfn);
76999ebb4caSwyllys (void) umask(old_mode);
77099ebb4caSwyllys if (tmpfd == -1) {
77199ebb4caSwyllys ret = KMF_ERR_INTERNAL;
77299ebb4caSwyllys goto out;
77399ebb4caSwyllys } else {
77499ebb4caSwyllys temp_created = B_TRUE;
77599ebb4caSwyllys }
77699ebb4caSwyllys
77799ebb4caSwyllys ret = download_file(uri, proxy, proxy_port, maxsecs, tmpfd);
77899ebb4caSwyllys (void) close(tmpfd);
77999ebb4caSwyllys if (ret != KMF_OK) {
78099ebb4caSwyllys goto out;
78199ebb4caSwyllys }
78299ebb4caSwyllys
78399ebb4caSwyllys /* Check if it is a Cert file and get its format */
784*30a5e8faSwyllys if (kmf_is_cert_file(handle, tempfn, pformat) != KMF_OK) {
78599ebb4caSwyllys ret = KMF_ERR_BAD_CERTFILE;
78699ebb4caSwyllys goto out;
78799ebb4caSwyllys }
78899ebb4caSwyllys
78999ebb4caSwyllys /* Finally, change the temp filename to the target filename */
79099ebb4caSwyllys if (rename(tempfn, certfile) == -1) {
79199ebb4caSwyllys ret = KMF_ERR_WRITE_FILE;
79299ebb4caSwyllys goto out;
79399ebb4caSwyllys }
79499ebb4caSwyllys
79599ebb4caSwyllys out:
79699ebb4caSwyllys if (filename != NULL)
79799ebb4caSwyllys free(filename);
79899ebb4caSwyllys
79999ebb4caSwyllys if (ret != KMF_OK && temp_created == B_TRUE)
80099ebb4caSwyllys (void) unlink(tempfn);
80199ebb4caSwyllys
80299ebb4caSwyllys if (fd != -1)
80399ebb4caSwyllys (void) close(fd);
80499ebb4caSwyllys
80599ebb4caSwyllys return (ret);
80699ebb4caSwyllys }
80799ebb4caSwyllys
80899ebb4caSwyllys KMF_RETURN
kmf_get_ocsp_for_cert(KMF_HANDLE_T handle,KMF_DATA * user_cert,KMF_DATA * ta_cert,KMF_DATA * response)809*30a5e8faSwyllys kmf_get_ocsp_for_cert(KMF_HANDLE_T handle,
81099ebb4caSwyllys KMF_DATA *user_cert,
81199ebb4caSwyllys KMF_DATA *ta_cert,
81299ebb4caSwyllys KMF_DATA *response)
81399ebb4caSwyllys {
81499ebb4caSwyllys KMF_POLICY_RECORD *policy;
81599ebb4caSwyllys KMF_RETURN ret = KMF_OK;
81699ebb4caSwyllys char *hostname = NULL, *host_uri = NULL, *proxyname = NULL;
81799ebb4caSwyllys char *proxy_port_s = NULL;
81899ebb4caSwyllys int host_port = 0, proxy_port = 0;
81999ebb4caSwyllys char ocsp_reqname[MAXPATHLEN];
82099ebb4caSwyllys char ocsp_respname[MAXPATHLEN];
82199ebb4caSwyllys KMF_X509EXT_AUTHINFOACCESS aia;
82299ebb4caSwyllys int i;
82399ebb4caSwyllys boolean_t found = B_FALSE;
82499ebb4caSwyllys KMF_X509EXT_ACCESSDESC *access_info;
82599ebb4caSwyllys xmlURIPtr uriptr = NULL;
826*30a5e8faSwyllys KMF_ATTRIBUTE attrlist[10];
827*30a5e8faSwyllys int numattr = 0;
82899ebb4caSwyllys
82999ebb4caSwyllys CLEAR_ERROR(handle, ret);
83099ebb4caSwyllys if (ret != KMF_OK)
83199ebb4caSwyllys return (ret);
83299ebb4caSwyllys
833*30a5e8faSwyllys if (user_cert == NULL || ta_cert == NULL || response == NULL)
83499ebb4caSwyllys return (KMF_ERR_BAD_PARAMETER);
83599ebb4caSwyllys
83699ebb4caSwyllys policy = handle->policy;
83799ebb4caSwyllys
83899ebb4caSwyllys /* Create an OCSP request */
839*30a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr,
840*30a5e8faSwyllys KMF_ISSUER_CERT_DATA_ATTR, ta_cert,
841*30a5e8faSwyllys sizeof (KMF_DATA));
842*30a5e8faSwyllys numattr++;
843*30a5e8faSwyllys
844*30a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr,
845*30a5e8faSwyllys KMF_USER_CERT_DATA_ATTR, user_cert,
846*30a5e8faSwyllys sizeof (KMF_DATA));
847*30a5e8faSwyllys numattr++;
84899ebb4caSwyllys
84999ebb4caSwyllys /*
85099ebb4caSwyllys * Create temporary files to hold the OCSP request & response data.
85199ebb4caSwyllys */
85299ebb4caSwyllys (void) strlcpy(ocsp_reqname, OCSPREQ_TEMPNAME,
85399ebb4caSwyllys sizeof (ocsp_reqname));
85499ebb4caSwyllys if (mkstemp(ocsp_reqname) == -1) {
85599ebb4caSwyllys return (KMF_ERR_INTERNAL);
85699ebb4caSwyllys }
85799ebb4caSwyllys
85899ebb4caSwyllys (void) strlcpy(ocsp_respname, OCSPRESP_TEMPNAME,
85999ebb4caSwyllys sizeof (ocsp_respname));
86099ebb4caSwyllys if (mkstemp(ocsp_respname) == -1) {
86199ebb4caSwyllys return (KMF_ERR_INTERNAL);
86299ebb4caSwyllys }
86399ebb4caSwyllys
864*30a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr,
865*30a5e8faSwyllys KMF_OCSP_REQUEST_FILENAME_ATTR, ocsp_respname,
866*30a5e8faSwyllys strlen(ocsp_respname));
867*30a5e8faSwyllys numattr++;
868*30a5e8faSwyllys
869*30a5e8faSwyllys ret = kmf_create_ocsp_request(handle, numattr, attrlist);
87099ebb4caSwyllys if (ret != KMF_OK) {
87199ebb4caSwyllys goto out;
87299ebb4caSwyllys }
87399ebb4caSwyllys
87499ebb4caSwyllys if (policy->VAL_OCSP_BASIC.uri_from_cert == 0) {
87599ebb4caSwyllys if (policy->VAL_OCSP_BASIC.responderURI == NULL) {
87699ebb4caSwyllys ret = KMF_ERR_OCSP_POLICY;
87799ebb4caSwyllys goto out;
87899ebb4caSwyllys }
87999ebb4caSwyllys host_uri = policy->VAL_OCSP_BASIC.responderURI;
88099ebb4caSwyllys
88199ebb4caSwyllys } else {
88299ebb4caSwyllys /*
88399ebb4caSwyllys * Get the responder URI from certificate
88499ebb4caSwyllys * Authority Information Access
88599ebb4caSwyllys * thru OID_PKIX_AD_OCSP
88699ebb4caSwyllys */
887*30a5e8faSwyllys ret = kmf_get_cert_auth_info_access(user_cert, &aia);
88899ebb4caSwyllys if (ret != KMF_OK) {
88999ebb4caSwyllys goto out;
89099ebb4caSwyllys }
89199ebb4caSwyllys
89299ebb4caSwyllys for (i = 0; i < aia.numberOfAccessDescription; i++) {
89399ebb4caSwyllys access_info = &aia.AccessDesc[i];
89499ebb4caSwyllys if (IsEqualOid(&access_info->AccessMethod,
89599ebb4caSwyllys (KMF_OID *)&KMFOID_PkixAdOcsp)) {
89699ebb4caSwyllys host_uri =
89799ebb4caSwyllys (char *)access_info->AccessLocation.Data;
89899ebb4caSwyllys found = B_TRUE;
89999ebb4caSwyllys break;
90099ebb4caSwyllys }
90199ebb4caSwyllys }
90299ebb4caSwyllys
90399ebb4caSwyllys if (!found) {
90499ebb4caSwyllys ret = KMF_ERR_OCSP_POLICY;
90599ebb4caSwyllys goto out;
90699ebb4caSwyllys }
90799ebb4caSwyllys }
90899ebb4caSwyllys
90999ebb4caSwyllys /* Parse the URI string; get the hostname and port */
91099ebb4caSwyllys uriptr = xmlParseURI(host_uri);
91199ebb4caSwyllys if (uriptr == NULL) {
91299ebb4caSwyllys ret = KMF_ERR_BAD_URI;
91399ebb4caSwyllys goto out;
91499ebb4caSwyllys }
91599ebb4caSwyllys
91699ebb4caSwyllys if (strncasecmp(uriptr->scheme, "http", 4) != 0) {
91799ebb4caSwyllys ret = KMF_ERR_BAD_URI; /* we support http only */
91899ebb4caSwyllys goto out;
91999ebb4caSwyllys }
92099ebb4caSwyllys
92199ebb4caSwyllys hostname = uriptr->server;
92299ebb4caSwyllys if (hostname == NULL) {
92399ebb4caSwyllys ret = KMF_ERR_BAD_URI;
92499ebb4caSwyllys goto out;
92599ebb4caSwyllys }
92699ebb4caSwyllys
92799ebb4caSwyllys host_port = uriptr->port;
92899ebb4caSwyllys if (host_port == 0)
92999ebb4caSwyllys host_port = 80;
93099ebb4caSwyllys
93199ebb4caSwyllys /* get the proxy info */
93299ebb4caSwyllys if (policy->VAL_OCSP_BASIC.proxy != NULL) {
93399ebb4caSwyllys char *last;
93499ebb4caSwyllys proxyname =
93599ebb4caSwyllys strtok_r(policy->VAL_OCSP_BASIC.proxy, ":", &last);
93699ebb4caSwyllys proxy_port_s = strtok_r(NULL, "\0", &last);
93799ebb4caSwyllys if (proxy_port_s != NULL) {
93899ebb4caSwyllys proxy_port = strtol(proxy_port_s, NULL, 0);
93999ebb4caSwyllys } else {
94099ebb4caSwyllys proxy_port = 8080; /* default */
94199ebb4caSwyllys }
94299ebb4caSwyllys }
94399ebb4caSwyllys
94499ebb4caSwyllys /*
94599ebb4caSwyllys * Send the request to an OCSP responder and receive an
94699ebb4caSwyllys * OCSP response.
94799ebb4caSwyllys */
948*30a5e8faSwyllys ret = kmf_get_encoded_ocsp_response(handle, ocsp_reqname,
94999ebb4caSwyllys hostname, host_port, proxyname, proxy_port,
95099ebb4caSwyllys ocsp_respname, 30);
95199ebb4caSwyllys if (ret != KMF_OK) {
95299ebb4caSwyllys goto out;
95399ebb4caSwyllys }
95499ebb4caSwyllys
955*30a5e8faSwyllys ret = kmf_read_input_file(handle, ocsp_respname, response);
95699ebb4caSwyllys
95799ebb4caSwyllys out:
95899ebb4caSwyllys (void) unlink(ocsp_reqname);
95999ebb4caSwyllys (void) unlink(ocsp_respname);
96099ebb4caSwyllys
96199ebb4caSwyllys if (uriptr != NULL)
96299ebb4caSwyllys xmlFreeURI(uriptr);
96399ebb4caSwyllys
96499ebb4caSwyllys return (ret);
96599ebb4caSwyllys }
966