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