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