xref: /titanic_41/usr/src/lib/libkmf/libkmf/common/client.c (revision 30a5e8fa1253cb33980ee4514743cf683f584b4e)
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