xref: /titanic_44/usr/src/common/net/wanboot/boot_http.c (revision b8afd3a780ce850ff107bb3be330465bf47f84bd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <strings.h>
34 #include <stdlib.h>
35 #include <netdb.h>
36 
37 #include <openssl/ssl.h>
38 #include <openssl/err.h>
39 #include <openssl/rand.h>
40 #include <openssl/pkcs12.h>
41 
42 /* this must be included after ssl.h to avoid re-defining 'offsetof' */
43 #include <sys/sysmacros.h>
44 
45 #include <boot_http.h>
46 #include <socket_inet.h>
47 #include <p12access.h>
48 
49 #include "bootlog.h"
50 
51 #define	BOOT_HTTP_MAJOR_VERSION	1
52 #define	BOOT_HTTP_MINOR_VERSION	0
53 #define	BOOT_HTTP_MICRO_VERSION	0
54 
55 static boot_http_ver_t boot_http_ver = {
56 	BOOT_HTTP_MAJOR_VERSION,
57 	BOOT_HTTP_MINOR_VERSION,
58 	BOOT_HTTP_MICRO_VERSION
59 };
60 
61 static int	early_err;	/* Error from before error occurred */
62 
63 static boolean_t verbosemode = B_FALSE;
64 static char	*cipher_list = NULL; /* Ciphers supported (if not default) */
65 
66 typedef struct {
67 	int	i;		/* current position in buffer */
68 	int	n;		/* number of bytes in buffer */
69 	char	buf[512];	/* buffer */
70 } buf_struct_t;
71 
72 typedef struct {
73 	uint_t	errsrc;		/* Source of this error */
74 	ulong_t	error;		/* Which error? */
75 } errent_t;
76 
77 
78 typedef enum {
79 	HTTP_REQ_TYPE_HEAD = 1,
80 	HTTP_REQ_TYPE_GET
81 } http_req_t;
82 
83 #define	FAILSAFE 20		/* Max # empty lines to accept */
84 #define	DEFAULT_TIMEOUT	10	/* Default socket read timeout value */
85 #define	HTTP_CONN_INFO 0x90919293 /* Identifies a http_conn_t struct */
86 #define	ESTACK_SIZE	20	/* Size of the stack */
87 
88 typedef struct http_conn_t {
89 	uint_t	signature;	/* Cookie indicating this is a handle */
90 	int	fd;		/* Connection's fd... */
91 	SSL_CTX *ctx;
92 	void	*ssl;		/* Handle to ssl data structure */
93 	int	read_timeout;	/* Timeout to use on read requests in sec */
94 	char    *basic_auth_userid;   /* Basic authentication user ID */
95 	char   	*basic_auth_password; /* and password */
96 	char	is_multipart;	/* B_TRUE if doing multipart/mixed download */
97 	char	is_firstpart;	/* B_TRUE if first part in a multipart xfer */
98 	char	is_firstchunk;	/* B_TRUE if first chunk in chunked xfer */
99 	char	is_chunked;	/* B_TRUE if message body is chunked */
100 	boolean_t keepalive;
101 	struct	sockaddr_in  host_addr; /* Address of host */
102 	url_t		uri;   		/* The current URI */
103 	url_hport_t	proxy;		/* The proxy info */
104 	boolean_t 	proxied;	/* Connection is proxied */
105 	char	*random_file;	/* File with seed info for pseudo random  */
106 				/* number generator */
107 	char	*client_cert_file;	/* File holding client's certificate */
108 	char	*private_key_file;	/* File with the private key */
109 	char	*file_password;	/* file with password to key or pkcs12 file. */
110 	http_respinfo_t resp;	/* Response summary info */
111 	char	**resphdr;	/* Array of header response lines */
112 	buf_struct_t inbuf;
113 	char	*boundary;	/* Boundary text (multipart downloads only) */
114 	uint_t	boundary_len;	/* Length of boundary string */
115 	uint_t	numerrs;
116 	uint_t	nexterr;	/* Next error to return */
117 	ssize_t	body_size;	/* Size of message body or chunk */
118 	ssize_t	body_read;	/* # of bytes of body_size processed */
119 	ssize_t	body_size_tot;	/* Total message body size */
120 	ssize_t	body_read_tot;	/* # of bytes of body_size_tot processed */
121 	errent_t errs[ESTACK_SIZE]; /* stack of errors on the last request */
122 				/* (libssl can return multiple errors on one */
123 				/* operation) */
124 } http_conn_t;
125 
126 /*
127  * Convenient macros for accessing fields in connection structure.
128  */
129 #define	CONN_HOSTNAME		c_id->uri.hport.hostname
130 #define	CONN_PORT		c_id->uri.hport.port
131 #define	CONN_ABSPATH		c_id->uri.abspath
132 #define	CONN_HTTPS		c_id->uri.https
133 #define	CONN_PROXY_HOSTNAME	c_id->proxy.hostname
134 #define	CONN_PROXY_PORT		c_id->proxy.port
135 
136 #define	RESET_ERR(c_id)	(c_id)->numerrs = 0, (c_id)->nexterr = 0
137 #define	SET_ERR(c_id, src, err)	if ((c_id)->numerrs < ESTACK_SIZE) \
138 		(c_id)->errs[(c_id)->numerrs].errsrc = (src), \
139 		(c_id)->errs[(c_id)->numerrs ++].error = (err)
140 
141 #define	GET_ERR(c_id, e_src, e_code) \
142 		if ((c_id)->nexterr < (c_id)->numerrs) \
143 			(e_src) = (c_id)->errs[((c_id)->nexterr)].errsrc, \
144 			(e_code) = (c_id)->errs[((c_id)->nexterr)++].error; \
145 		else \
146 			(e_src) = 0, (e_code) = 0
147 
148 /*
149  * Macro used to increment message body read counters
150  */
151 #define	INC_BREAD_CNT(bool, bcnt) \
152 	if (bool) { \
153 		bcnt--; \
154 		c_id->body_read++;\
155 		c_id->body_read_tot++; \
156 	}
157 
158 static int	ssl_init = 0;		/* 1 when ssl has been initialized */
159 static char	*ca_verify_file;	/* List of trusted CA's  */
160 static int	verify_depth = 16;	/* Certificate chain depth to verify */
161 static int	p12_format = 0;		/* Default to PEM format */
162 
163 
164 /* prototypes for local functions */
165 static int	http_req(http_handle_t, const char *, http_req_t, offset_t,
166     offset_t);
167 static boolean_t http_check_conn(http_conn_t *);
168 static SSL_CTX *initialize_ctx(http_conn_t *);
169 static int	tcp_connect(http_conn_t *, const char *, uint16_t);
170 static int	readline(http_conn_t *, int, char *, int);
171 static int	proxy_connect(http_conn_t *);
172 static int	check_cert_chain(http_conn_t *, char *);
173 static void	print_ciphers(SSL *);
174 static int	read_headerlines(http_conn_t *, boolean_t);
175 static void	free_response(http_conn_t *, int);
176 static int	free_ctx_ssl(http_conn_t *);
177 static int	get_chunk_header(http_conn_t *);
178 static int	init_bread(http_conn_t *);
179 static int	get_msgcnt(http_conn_t *, ssize_t *);
180 static int	getaline(http_conn_t *, char *, int, boolean_t);
181 static int	getbytes(http_conn_t *, char *, int);
182 static int	http_srv_send(http_conn_t *, const void *, size_t);
183 static int	http_srv_recv(http_conn_t *, void *, size_t);
184 static void	handle_ssl_error(http_conn_t *, int);
185 static int	count_digits(int);
186 static int	hexdigit(char);
187 static char	*eat_ws(const char *);
188 static boolean_t startswith(const char **strp, const char *starts);
189 
190 /* ---------------------- public functions ----------------------- */
191 
192 /*
193  * http_set_p12_format - Set flag indicating that certs & keys will be in
194  *                    pkcs12 format.
195  *
196  * Default is PEM certs.  When this is called, the default can be changed to
197  * pcs12 format.
198  */
199 void
200 http_set_p12_format(int on_off)
201 {
202 	p12_format = on_off;
203 }
204 
205 /*
206  * http_get_version - Get current boot http support version
207  *
208  *     pVer = http_get_version();
209  *
210  * Arguments:
211  *	None.
212  *
213  * Returns:
214  *	Pointer to struct with version information.
215  *
216  * Returns the version of the http support in the current library.  This
217  * is a struct with unsigned integsrs for <major>, <minor> and
218  * <micro> version numbers.  <major> changes when an incompatible change
219  * is made.  <minor> changes when an upwardly-compatible API change is
220  * made.  <micro> consists of bug fixes, etc.
221  */
222 boot_http_ver_t const *
223 http_get_version(void)
224 {
225 	return (&boot_http_ver);
226 }
227 
228 /*
229  * http_set_verbose - Turn verbose on/off
230  *
231  *     http_set_verbose(on_off);
232  *
233  * Arguments:
234  *	on_off	- When TRUE, turn verbose mode one.  When FALSE, turn
235  *		  verbose off.
236  *
237  * Returns:
238  *	None.
239  *
240  * When enabled, information is logged to bootlog (or the Solaris equivalent).
241  */
242 void
243 http_set_verbose(boolean_t on_off)
244 {
245 	verbosemode = on_off;
246 }
247 
248 /*
249  * http_set_cipher_list - Change the list of ciphers that can be used.
250  *
251  *     ret = http_set_cipher_list(handle, list);
252  *
253  * Arguments:
254  *	list	- List of ciphers that can be used.
255  *
256  * Returns:
257  *	0	- Success
258  *	-1	- An error occurred.  Check http_get_lasterr().
259  */
260 int
261 http_set_cipher_list(const char *list)
262 {
263 	early_err = 0;
264 
265 	if (list != NULL) {
266 		list = strdup(list);
267 		if (list == NULL) {
268 			early_err = EHTTP_NOMEM;
269 			return (-1);
270 		}
271 	}
272 
273 	free(cipher_list);
274 	cipher_list = (char *)list;
275 	return (0);
276 }
277 
278 /*
279  * http_srv_init - Set up a structure for a connection.
280  *
281  *     handle = http_srv_init(url);
282  *
283  * Arguments:
284  *	url - the structure that contains the URI.
285  *
286  * Returns:
287  *	!= NULL	- A handle for referring to this connection.
288  *	== NULL - An error occurred.  Get the exact error from
289  *                http_get_lasterr().
290  */
291 http_handle_t
292 http_srv_init(const url_t *url)
293 {
294 	http_conn_t	*c_id;
295 
296 	early_err = 0;
297 	if (url == NULL) {
298 		early_err = EHTTP_BADARG;
299 		return (NULL);
300 	}
301 
302 	if ((c_id = malloc(sizeof (*c_id))) == NULL) {
303 		early_err = EHTTP_NOMEM;
304 		return (NULL);
305 	}
306 
307 	bzero(c_id, sizeof (*c_id));
308 	c_id->uri = *url;
309 	c_id->proxied = B_FALSE;
310 	c_id->read_timeout = DEFAULT_TIMEOUT;
311 	c_id->keepalive = B_TRUE;
312 	c_id->fd = -1;
313 
314 	/* Do this at the end, just in case.... */
315 	c_id->signature = HTTP_CONN_INFO;
316 
317 	return (c_id);
318 }
319 
320 /*
321  * http_conn_is_https - Determine whether the scheme is http or https.
322  *
323  *	B_TRUE	- Connection is an SSL connection.
324  *	B_FALSE - Connection isn't SSL.
325  *
326  *     ret = http_conn_is_https(handle, boolean_t *bool);
327  *
328  * Arguments:
329  *	handle	- Handle associated with the desired connection
330  *	bool	- Ptr to boolean in which to place result
331  *
332  * Returns:
333  *	0	- Success
334  *	-1	- Some error occurred.
335  */
336 int
337 http_conn_is_https(http_handle_t handle, boolean_t *bool)
338 {
339 	http_conn_t	*c_id = handle;
340 
341 	if (!http_check_conn(c_id))
342 		return (-1);
343 
344 	*bool = CONN_HTTPS;
345 	return (0);
346 }
347 
348 /*
349  * http_set_proxy - Establish the proxy name/port.
350  *
351  *     ret = http_set_proxy(handle, proxy);
352  *
353  * Arguments:
354  *	handle	- Handle associated with the desired connection
355  *	proxy	- The hostport definition for the proxy. If NULL,
356  *		  The next connect will not use a proxy.
357  *
358  * Returns:
359  *	0	- Success
360  *	-1	- An error occurred.  Check http_get_lasterr().
361  */
362 int
363 http_set_proxy(http_handle_t handle, const url_hport_t *proxy)
364 {
365 	http_conn_t *c_id = handle;
366 
367 	if (!http_check_conn(c_id))
368 		return (-1);
369 
370 	if (proxy != NULL) {
371 		c_id->proxy = *proxy;
372 		c_id->proxied = B_TRUE;
373 	} else {
374 		CONN_PROXY_HOSTNAME[0] = '\0';
375 		c_id->proxied = B_FALSE;
376 	}
377 
378 	return (0);
379 }
380 
381 /*
382  * http_set_keepalive - Set keepalive for this connection.
383  *
384  *     http_set_keepalive(handle, on_off);
385  *
386  * Arguments:
387  *	handle	- Handle associated with the desired connection
388  *	on_off	- Boolean turning keepalive on (TRUE) or off (FALSE)
389  *
390  * Returns:
391  *	0	- Success.
392  *	-1	- An error occurred.  Check http_get_lasterr().
393  *
394  * This setting takes effect next time a connection is opened using this
395  * handle.
396  */
397 int
398 http_set_keepalive(http_handle_t handle, boolean_t on_off)
399 {
400 	http_conn_t *c_id = handle;
401 
402 	if (!http_check_conn(c_id))
403 		return (-1);
404 
405 	c_id->keepalive = on_off;
406 	return (0);
407 }
408 
409 /*
410  * http_set_socket_read_timeout - Set the timeout reads
411  *
412  *     http_set_socket_read_timeout(handle, timeout);
413  *
414  * Arguments:
415  *	handle	- Handle associated with the desired connection
416  *	timeout	- Timeout, in seconds.  Zero will default to 10 second
417  *		  timeouts.
418  *
419  * Returns:
420  *	0	- Success.
421  *	-1	- An error occurred.  Check http_get_lasterr().
422  *
423  * This setting takes effect beginning with the next read operation on this
424  * connection.
425  */
426 int
427 http_set_socket_read_timeout(http_handle_t handle, uint_t timout)
428 {
429 	http_conn_t *c_id = handle;
430 
431 	if (!http_check_conn(c_id))
432 		return (-1);
433 
434 	c_id->read_timeout = (timout) ? timout : DEFAULT_TIMEOUT;
435 	return (0);
436 }
437 
438 /*
439  * http_set_basic_auth - Set the basic authorization user ID and password
440  *
441  *     ret = http_set_basic_auth(handle, userid, password);
442  *
443  * Arguments:
444  *	handle	- Handle associated with the desired connection
445  *	userid	- ID to pass as part of http/https request
446  *	password- Password which goes with the user ID
447  *
448  * Returns:
449  *	0	- Success
450  *	-1	- An error occurred.  Check http_get_lasterr().
451  *
452  * This must be set before a https connection is made.
453  */
454 int
455 http_set_basic_auth(http_handle_t handle, const char *userid,
456     const char *password)
457 {
458 	http_conn_t *c_id = handle;
459 
460 	if (!http_check_conn(c_id))
461 		return (-1);
462 
463 	if (password == NULL || userid == NULL || userid[0] == '\0') {
464 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
465 		return (-1);
466 	}
467 
468 	userid = strdup(userid);
469 	password = strdup(password);
470 	if (userid == NULL || password == NULL) {
471 		free((void *)userid);
472 		free((void *)password);
473 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
474 		return (-1);
475 	}
476 
477 	free(c_id->basic_auth_userid);
478 	c_id->basic_auth_userid = (char *)userid;
479 	free(c_id->basic_auth_password);
480 	c_id->basic_auth_password = (char *)password;
481 	return (0);
482 }
483 
484 /*
485  * http_set_random_file - See the pseudo random number generator with file data
486  *
487  *     ret = http_set_random_file(handle, filename);
488  *
489  * Arguments:
490  *	handle	- Handle associated with the desired connection
491  *	filename
492  *		- filename (including path) with random number seed.
493  *
494  * Returns:
495  *	0	- Success
496  *	-1	- An error occurred.  Check http_get_lasterr().
497  *
498  * This must be set before a https connection is made.
499  */
500 int
501 http_set_random_file(http_handle_t handle, const char *fname)
502 {
503 	http_conn_t *c_id = handle;
504 
505 	if (!http_check_conn(c_id))
506 		return (-1);
507 
508 	if (fname != NULL) {
509 		fname = strdup(fname);
510 		if (fname == NULL) {
511 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
512 			return (-1);
513 		}
514 	}
515 
516 	free(c_id->random_file);
517 	c_id->random_file = (char *)fname;
518 	return (0);
519 }
520 
521 /*
522  * http_set_certificate_authority_file - Set the CA file.
523  *
524  *     ret = http_set_certificate_authority_file(filename);
525  *
526  * Arguments:
527  *	filename- File with the certificate authority certs
528  *
529  * Returns:
530  *	0	- Success
531  *	-1	- An error occurred.  Check http_get_lasterr().
532  *
533  * This must be set before https connections to the servers is done.
534  */
535 int
536 http_set_certificate_authority_file(const char *fname)
537 {
538 	early_err = 0;
539 
540 	if (fname != NULL) {
541 		fname = strdup(fname);
542 		if (fname == NULL) {
543 			early_err = EHTTP_NOMEM;
544 			return (-1);
545 		}
546 	}
547 
548 	free(ca_verify_file);
549 	ca_verify_file = (char *)fname;
550 	return (0);
551 }
552 
553 /*
554  * http_set_client_certificate_file - Set the file containing the PKCS#12
555  *		client certificate and optionally its certificate chain.
556  *
557  *     ret = http_set_client_certificate_file(handle, filename);
558  *
559  * Arguments:
560  *	handle	- Handle associated with the desired connection
561  *	filename- File (including path) containing certificate, etc.
562  *
563  * Returns:
564  *	0	- Success
565  *	-1	- An error occurred.  Check http_get_lasterr().
566  *
567  * This must be set before the handle is used to make a https connection
568  * which will require a client certificate.
569  */
570 int
571 http_set_client_certificate_file(http_handle_t handle, const char *fname)
572 {
573 	http_conn_t *c_id = handle;
574 
575 	if (!http_check_conn(c_id))
576 		return (-1);
577 
578 	if (fname != NULL) {
579 		fname = strdup(fname);
580 		if (fname == NULL) {
581 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
582 			return (-1);
583 		}
584 	}
585 
586 	free(c_id->client_cert_file);
587 	c_id->client_cert_file = (char *)fname;
588 	return (0);
589 }
590 
591 /*
592  * http_set_password - Set the password for the private key or pkcs12 file.
593  *
594  *     ret = http_set_password(handle, password);
595  *
596  * Arguments:
597  *	handle	- Handle associated with the desired connection
598  *	password- Password for the client's private key file or pkcs12 file.
599  *
600  * Returns:
601  *	0	- Success
602  *	-1	- An error occurred.  Check http_get_lasterr().
603  *
604  * This must be set before the handle is used to make a https connection.
605  */
606 int
607 http_set_password(http_handle_t handle, const char *password)
608 {
609 	http_conn_t *c_id = handle;
610 
611 	if (!http_check_conn(c_id))
612 		return (-1);
613 
614 	if (password != NULL) {
615 		password = strdup(password);
616 		if (password == NULL) {
617 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
618 			return (-1);
619 		}
620 	}
621 
622 	free(c_id->file_password);
623 	c_id->file_password = (char *)password;
624 	return (0);
625 }
626 
627 /*
628  * http_set_key_file_password - Set the password for the private key
629  *		file.
630  *
631  *     ret = http_set_key_file_password(handle, password);
632  *
633  * Arguments:
634  *	handle	- Handle associated with the desired connection
635  *	password- Password for the client's private key file.
636  *
637  * Returns:
638  *	0	- Success
639  *	-1	- An error occurred.  Check http_get_lasterr().
640  *
641  * This must be set before the handle is used to make a https connection.
642  */
643 int
644 http_set_key_file_password(http_handle_t handle, const char *password)
645 {
646 	return (http_set_password(handle, password));
647 }
648 
649 /*
650  * http_set_private_key_file - Set the file containing the PKCS#12
651  *		private key for this client.
652  *
653  *     ret = http_set_private_key_file(handle, filename);
654  *
655  * Arguments:
656  *	handle	- Handle associated with the desired connection
657  *	filename- File (including path) containing the private key.
658  *
659  * Returns:
660  *	0	- Success
661  *	-1	- An error occurred.  Check http_get_lasterr().
662  *
663  * This must be set before the handle is used to make a https connection.
664  */
665 int
666 http_set_private_key_file(http_handle_t handle, const char *fname)
667 {
668 	http_conn_t *c_id = handle;
669 
670 	if (!http_check_conn(c_id))
671 		return (-1);
672 
673 	if (fname != NULL) {
674 		fname = strdup(fname);
675 		if (fname == NULL) {
676 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
677 			return (-1);
678 		}
679 	}
680 
681 	free(c_id->private_key_file);
682 	c_id->private_key_file = (char *)fname;
683 	return (0);
684 }
685 
686 /*
687  * http_srv_connect - Establish a connection to the server
688  *
689  *     ret = http_srv_connect(handle);
690  *
691  * Arguments:
692  *	handle	- Handle associated with the desired connection
693  *
694  * Returns:
695  *	0	- Success
696  *	-1	- An error occurred.  Check http_get_lasterr() for specifics.
697  */
698 int
699 http_srv_connect(http_handle_t handle)
700 {
701 	http_conn_t	*c_id = handle;
702 	SSL_CTX		*ctx = NULL;
703 	int		retval;
704 
705 	ERR_clear_error();
706 	if (!http_check_conn(c_id))
707 		return (-1);
708 
709 	if (CONN_HTTPS) {
710 		/* Build our SSL context (this function sets any errors) */
711 		ctx = initialize_ctx(c_id);
712 		if (ctx == NULL) {
713 			libbootlog(BOOTLOG_CRIT,
714 			    "http_srv_connect: initialize_ctx returned NULL");
715 			return (-1);
716 		}
717 	}
718 
719 	/* Connect the TCP socket */
720 	if (c_id->proxied) {
721 		c_id->fd = proxy_connect(c_id);
722 	} else {
723 		c_id->fd = tcp_connect(c_id, CONN_HOSTNAME, CONN_PORT);
724 	}
725 
726 	if (c_id->fd < 0) {
727 		if (ctx != NULL)
728 			SSL_CTX_free(ctx);
729 			libbootlog(BOOTLOG_CRIT,
730 			    "http_srv_connect: %s returned %d",
731 			    (c_id->proxied) ? "proxy_connect" : "tcp_connect",
732 			    c_id->fd);
733 		return (-1);
734 	}
735 
736 	if (CONN_HTTPS) {
737 		/* Connect the SSL socket */
738 		if ((c_id->ssl = SSL_new(ctx)) == NULL) {
739 			ulong_t err;
740 			while ((err = ERR_get_error()) != 0)
741 				SET_ERR(c_id, ERRSRC_LIBSSL, err);
742 				libbootlog(BOOTLOG_CRIT,
743 				    "http_srv_connect: SSL_new returned "
744 				    "NULL");
745 			(void) free_ctx_ssl(c_id);
746 			return (-1);
747 		}
748 		if (verbosemode)
749 			print_ciphers(c_id->ssl);
750 
751 		/* Ensure automatic negotiations will do things right */
752 		SSL_set_connect_state(c_id->ssl);
753 
754 		if (SSL_set_fd(c_id->ssl, c_id->fd) == 0) {
755 			ulong_t err;
756 			while ((err = ERR_get_error()) != 0)
757 				SET_ERR(c_id, ERRSRC_LIBSSL, err);
758 				libbootlog(BOOTLOG_CRIT,
759 				    "http_srv_connect: SSL_set_fd returned 0");
760 			(void) free_ctx_ssl(c_id);
761 			return (-1);
762 		}
763 
764 		if ((retval = SSL_connect(c_id->ssl)) <= 0) {
765 			handle_ssl_error(c_id, retval);
766 			libbootlog(BOOTLOG_CRIT,
767 			    "http_srv_connect: SSL_connect");
768 			(void) free_ctx_ssl(c_id);
769 			return (-1);
770 		}
771 
772 		if (check_cert_chain(c_id, CONN_HOSTNAME) != 0) {
773 			(void) free_ctx_ssl(c_id);
774 			return (-1);
775 		}
776 
777 		if (verbosemode)
778 			print_ciphers(c_id->ssl);
779 	}
780 
781 	return (0);
782 }
783 
784 /*
785  * http_head_request - Issue http HEAD request
786  *
787  *     ret = http_head_request(handle, abs_path);
788  *
789  * Arguments:
790  *	handle	- Handle associated with the desired connection
791  *	abs_path- File name portion of the URI, beginning with a /.  Query,
792  *		  segment, etc are allowed.
793  *
794  * Returns:
795  *	0	- Success
796  *	-1	- An error occurred.  Check http_get_lasterr().
797  */
798 int
799 http_head_request(http_handle_t handle, const char *abs_path)
800 {
801 	return (http_req(handle, abs_path, HTTP_REQ_TYPE_HEAD, 0, 0));
802 }
803 
804 /*
805  * http_get_request - Issue http GET request without a range.
806  *
807  *     ret = http_get_request(handle, abs_path);
808  *
809  * Arguments:
810  *	handle	- Handle associated with the desired connection
811  *	abs_path- File name portion of the URI, beginning with a /.  Query,
812  *		  segment, etc are allowed.
813  *
814  * Returns:
815  *	0	- Success
816  *	-1	- An error occurred.  Check http_get_lasterr().
817  */
818 int
819 http_get_request(http_handle_t handle, const char *abs_path)
820 {
821 	return (http_req(handle, abs_path, HTTP_REQ_TYPE_GET, -1, 0));
822 }
823 
824 /*
825  * http_get_range_request - Issue http GET request using a range.
826  *
827  *     ret = http_get_range_request(handle, abs_path, curpos, len);
828  *
829  * Arguments:
830  *	handle	- Handle associated with the desired connection
831  *	abs_path- File name portion of the URI, beginning with a /.  Query,
832  *		  segment, etc are allowed.
833  *	curpos  - >=0 - Beginning of range
834  *	len	- = 0 - Range ends at the end of the file
835  *		  > 0 - Length of range.
836  *
837  * Returns:
838  *	0	- Success
839  *	-1	- An error occurred.  Check http_get_lasterr().
840  */
841 int
842 http_get_range_request(http_handle_t handle, const char *abs_path,
843     offset_t curpos, offset_t len)
844 {
845 	http_conn_t *c_id = handle;
846 
847 	if (!http_check_conn(c_id))
848 		return (-1);
849 
850 	if (curpos < 0) {
851 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
852 		return (-1);
853 	}
854 
855 	return (http_req(handle, abs_path, HTTP_REQ_TYPE_GET, curpos, len));
856 }
857 
858 /*
859  * http_free_respinfo - Free a respinfo structure
860  *
861  *     ret = http_free_respinfo(resp);
862  *
863  * Arguments:
864  *	resp	- respinfo structure presumably allocated by
865  *		  http_process_headers() or http_process_part_headers()
866  *
867  * Note that if resp is NULL, then this results in a NOOP.
868  *
869  */
870 void
871 http_free_respinfo(http_respinfo_t *resp)
872 {
873 	if (resp == NULL) {
874 		return;
875 	}
876 
877 	if (resp->statusmsg != NULL) {
878 		free(resp->statusmsg);
879 	}
880 	free(resp);
881 }
882 
883 /*
884  * http_process_headers - Read in the header lines from the response
885  *
886  *     ret = http_process_headers(handle, resp);
887  *
888  * Arguments:
889  *	handle	- Handle associated with the connection where the request
890  *		  was made.
891  *	resp	- Summary information about the response.
892  *
893  * Returns:
894  *	0	- Success
895  *	< 0	- An error occurred.  Specifics of the error can
896  *		  be gotten using http_get_lasterr().
897  *
898  * Process the HTTP headers in the response. Check for a valid response
899  * status line.  Allocate and return response information via the 'resp'
900  * argument. Header lines are stored locally, are are returned using calls
901  * to http_get_response_header() and http_get_header_value().
902  *
903  * Note that the errors will be set in the http_conn_t struct before the
904  * function which detected the error returns.
905  *
906  * Note that if resp is non-NULL, then upon a successful return, information
907  * about the status line, the code in the status line and the number of
908  * header lines are returned in the http_respinfo_t structure. The caller is
909  * responsible for freeing the resources allocated to this structure via
910  * http_free_respinfo().
911  *
912  * Note that the counters used to read message bodies are initialized here.
913  *
914  * Calling this function replaces the header information which is
915  * queried using http_get_response_header() and http_get_header_value().
916  * Once this function is called, headers read by the previous call
917  * to http_process_headers() or http_process_part_headers() is lost.
918  */
919 int
920 http_process_headers(http_handle_t handle, http_respinfo_t **resp)
921 {
922 	http_conn_t *c_id = handle;
923 	http_respinfo_t *lresp;
924 	char	line[MAXHOSTNAMELEN];
925 	char	*ptr;
926 	int	i;
927 
928 	ERR_clear_error();
929 	if (!http_check_conn(c_id))
930 		return (-1);
931 
932 	if (resp != NULL) {
933 		if ((lresp = malloc(sizeof (http_respinfo_t))) == NULL) {
934 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
935 			return (-1);
936 		}
937 
938 		bzero(lresp, sizeof (http_respinfo_t));
939 	}
940 
941 	/*
942 	 * check the response status line, expecting
943 	 * HTTP/1.1 200 OK
944 	 */
945 	i = getaline(c_id, line, sizeof (line), B_FALSE);
946 	if (i == 0) {
947 		if (resp != NULL) {
948 			*resp = lresp;
949 		}
950 		return (0);
951 	}
952 
953 	if (i < 0) {
954 		/*
955 		 * Cause of I/O error was already put into
956 		 * error stack.  This is an additional error.
957 		 */
958 		http_free_respinfo(lresp);
959 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NODATA);
960 		return (-1);
961 	}
962 
963 	free_response(c_id, B_TRUE);
964 
965 	if (verbosemode)
966 		libbootlog(BOOTLOG_VERBOSE, "http_process_headers: %s", line);
967 
968 	ptr = line;
969 	if (strncmp(ptr, "HTTP/1.1", 8) != 0) {
970 		http_free_respinfo(lresp);
971 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOT_1_1);
972 		return (-1);
973 	}
974 
975 	/* skip to the code */
976 	ptr += 8;
977 	while (isspace(*ptr))
978 		ptr++;
979 
980 	/* make sure it's three digits */
981 	i = 0;
982 	while (isdigit(ptr[i]))
983 		i++;
984 	if (i != 3) {
985 		http_free_respinfo(lresp);
986 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADHDR);
987 		return (-1);
988 	}
989 	c_id->resp.code = strtol(ptr, NULL, 10);
990 
991 	/* skip to the message */
992 	ptr += 3;
993 	while (isspace(*ptr))
994 		ptr++;
995 
996 	/* save the message */
997 	c_id->resp.statusmsg = malloc(strlen(ptr) + 1);
998 	if (c_id->resp.statusmsg == NULL) {
999 		http_free_respinfo(lresp);
1000 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1001 		return (-1);
1002 	}
1003 	(void) strcpy(c_id->resp.statusmsg, ptr);
1004 
1005 	if ((i = read_headerlines(c_id, B_FALSE)) < 0) {
1006 		/*
1007 		 * Error stack was already set at a lower level.
1008 		 * 'statusmsg' will be cleaned up next time
1009 		 * headers are read.
1010 		 */
1011 		http_free_respinfo(lresp);
1012 		return (-1);
1013 	}
1014 
1015 	/*
1016 	 * See if there is a 'content-type: multipart/mixed' line in the
1017 	 * headers.  If so, get the boundary string.
1018 	 */
1019 	ptr = http_get_header_value(handle, "Content-Type");
1020 	if (ptr != NULL) {
1021 		char *ptr2;
1022 
1023 		ptr2 = ptr;
1024 		while (isspace(*ptr2))
1025 			ptr2 ++;
1026 		if (startswith((const char **)&ptr2, "Multipart/Mixed;")) {
1027 			while (isspace(*ptr2))
1028 				ptr2 ++;
1029 			if (startswith((const char **)&ptr2, "Boundary=")) {
1030 				if (ptr2[0] == '"') {
1031 					ptr2 ++;
1032 					if (ptr2[strlen(ptr2) - 1] == '"')
1033 						ptr2[strlen(ptr2) - 1] = '\0';
1034 				}
1035 				c_id->boundary = strdup(ptr2);
1036 				if (c_id->boundary == NULL) {
1037 					free(ptr);
1038 					http_free_respinfo(lresp);
1039 					SET_ERR(c_id, ERRSRC_LIBHTTP,
1040 					    EHTTP_NOMEM);
1041 					return (-1);
1042 				}
1043 				c_id->boundary_len = strlen(c_id->boundary);
1044 				c_id->is_multipart = B_TRUE;
1045 				c_id->is_firstpart = B_TRUE;
1046 			}
1047 		}
1048 		free(ptr);
1049 	}
1050 
1051 	/*
1052 	 * Initialize the counters used to process message bodies.
1053 	 */
1054 	if (init_bread(c_id) != 0) {
1055 		/*
1056 		 * Error stack was already set at a lower level.
1057 		 */
1058 		http_free_respinfo(lresp);
1059 		return (-1);
1060 	}
1061 
1062 	/* Copy fields to the caller's structure */
1063 	if (resp != NULL) {
1064 		lresp->code = c_id->resp.code;
1065 		lresp->nresphdrs = c_id->resp.nresphdrs;
1066 		lresp->statusmsg = strdup(c_id->resp.statusmsg);
1067 		if (lresp->statusmsg == NULL) {
1068 			http_free_respinfo(lresp);
1069 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1070 			return (-1);
1071 		}
1072 		*resp = lresp;
1073 	}
1074 
1075 	return (0);
1076 }
1077 
1078 /*
1079  * http_process_part_headers - Read in part boundary and header lines for the
1080  *                             next part of a multipart message.
1081  *
1082  *        ret = http_process_part_headers(handle, resp);
1083  *
1084  * Arguments:
1085  *   handle	- Handle associated with the connection where the request
1086  *		  was made.
1087  *   resp	- Return address for summary information about the
1088  *		  header block.
1089  *
1090  * Returns:
1091  *   = 1	- The end part was found.
1092  *   = 0	- Success, with header info returned in 'resp'
1093  *   = -1	- An error occurred.  Specifics of the error can
1094  *		  be gotten using http_get_lasterr().
1095  *
1096  * This function reads any \r\n sequences (empty lines) and expects to get
1097  * a boundary line as the next non-empty line.  It then reads header lines
1098  * (content-length, etc) until it gets another empty lines, which ends the
1099  * header section.
1100  *
1101  * Note that if resp is non-NULL, then upon a successful return, information
1102  * about the the number of header lines is returned in the http_respinfo_t
1103  * structure. The caller is responsible for freeing the resources allocated
1104  * to this structure via http_free_respinfo().
1105  *
1106  * Headers values can be returned using http_get_response_header() and
1107  * http_get_header_value().
1108  *
1109  * Calling this function replaces the header information which is
1110  * queried using http_get_response_header() and http_get_header_value().
1111  * Once this function is called, information returned by the previous call
1112  * to http_process_headers() or http_process_part_headers() is gone.
1113  */
1114 int
1115 http_process_part_headers(http_handle_t handle, http_respinfo_t **resp)
1116 {
1117 	http_conn_t *c_id = handle;
1118 	char	line[MAXHOSTNAMELEN];
1119 	int	count;
1120 	int 	limit;
1121 	int	i;
1122 
1123 	ERR_clear_error();
1124 	if (!http_check_conn(c_id))
1125 		return (-1);
1126 
1127 	if (c_id->is_multipart == 0) {
1128 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOTMULTI);
1129 		return (-1);
1130 	}
1131 
1132 	/*
1133 	 * Figure out how many empty lines to allow.  Before the first
1134 	 * boundary of the transmission, there can be any number of
1135 	 * empty lines (from 0 up).  Limit these to some reasonable
1136 	 * failsafe.
1137 	 *
1138 	 * For the 2nd and later boundaries, there is supposed to be
1139 	 * one crlf pair.  However, many implementations don't require
1140 	 * it.  So don't require it.
1141 	 */
1142 	if (c_id->is_firstpart) {
1143 		limit = FAILSAFE;
1144 		c_id->is_firstpart = B_FALSE;
1145 	} else
1146 		limit = 1;
1147 
1148 	/* Look for the boundary line. */
1149 	count = 0;
1150 	while ((i = getaline(c_id, line, sizeof (line), B_TRUE)) == 0 &&
1151 	    count < FAILSAFE)
1152 		count ++;
1153 	if (i < 0 || count > limit) {
1154 		/*
1155 		 * If I/O error, cause was already put into
1156 		 * error stack.  This is an additional error.
1157 		 */
1158 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOBOUNDARY);
1159 		return (-1);
1160 	}
1161 
1162 	free_response(c_id, B_FALSE);
1163 
1164 	if (verbosemode)
1165 		libbootlog(BOOTLOG_VERBOSE,
1166 		    "http_process_part_headers: %s", line);
1167 
1168 	/* Look for boundary line - '--<boundary text> */
1169 	if (line[0] != '-' || line[1] != '-' ||
1170 	    strncmp(&line[2], c_id->boundary, c_id->boundary_len) != 0) {
1171 		/* No boundary line.... */
1172 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOBOUNDARY);
1173 		return (-1);
1174 	}
1175 
1176 	/* Is this the end-of-parts boundary (ends with a trailing '--') */
1177 	if (strcmp(&line[c_id->boundary_len + 2], "--") == 0) {
1178 		return (1);
1179 	}
1180 
1181 	free_response(c_id, B_FALSE);
1182 	if (read_headerlines(c_id, B_TRUE) < 0) {
1183 		/* Error stack was already set at a lower level. */
1184 		return (-1);
1185 	}
1186 
1187 	/* Copy fields to the caller's structure */
1188 	if (resp != NULL) {
1189 		if ((*resp = malloc(sizeof (http_respinfo_t))) == NULL) {
1190 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1191 			return (-1);
1192 		}
1193 		bzero(*resp, sizeof (http_respinfo_t));
1194 		(*resp)->code = ' ';
1195 		(*resp)->nresphdrs = c_id->resp.nresphdrs;
1196 	}
1197 
1198 	return (0);
1199 }
1200 
1201 /*
1202  * http_get_response_header - Get a line from the response header
1203  *
1204  *     ret = http_get_response_header(handle, whichline);
1205  *
1206  * Arguments:
1207  *	handle	- Handle associated with the desired connection
1208  *	whichline - Which line of the header to return.  This must be between
1209  *		  zero and resp.nresphdrs which was returned by the call to
1210  *		  http_process_headers().
1211  *
1212  * Returns:
1213  *	ptr	- Points to a copy of the header line.
1214  *	NULL	- An error occurred.  Check http_get_lasterr().
1215  */
1216 char *
1217 http_get_response_header(http_handle_t handle, uint_t which)
1218 {
1219 	http_conn_t *c_id = handle;
1220 	char *res;
1221 
1222 	if (!http_check_conn(c_id))
1223 		return (NULL);
1224 
1225 	if (which >= c_id->resp.nresphdrs) {
1226 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_OORANGE);
1227 		return (NULL);
1228 	}
1229 
1230 	res = strdup(c_id->resphdr[which]);
1231 	if (res == NULL) {
1232 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1233 		return (NULL);
1234 	}
1235 	return (res);
1236 }
1237 
1238 /*
1239  * http_get_header_value - Get the value of a header line.
1240  *
1241  *     ret = http_get_header_value(handle, what);
1242  *
1243  * Arguments:
1244  *	handle	- Handle associated with the desired connection
1245  *	what	- The field name to look up.
1246  *
1247  * Returns:
1248  *	ptr	- Points to a copy of the header value.
1249  *	NULL	- An error occurred.  Check http_get_lasterr().
1250  */
1251 char *
1252 http_get_header_value(http_handle_t handle, const char *field_name)
1253 {
1254 	http_conn_t *c_id = handle;
1255 	char	*ptr;
1256 	char	*res;
1257 	int	i;
1258 	int	n;
1259 
1260 	if (!http_check_conn(c_id))
1261 		return (NULL);
1262 
1263 	if (field_name == NULL || field_name[0] == '\0') {
1264 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1265 		return (NULL);
1266 	}
1267 
1268 	for (i = 0; i < c_id->resp.nresphdrs; i++) {
1269 		ptr = c_id->resphdr[i];
1270 		n = strlen(field_name);
1271 		if (strncasecmp(field_name, ptr, n) == 0 && ptr[n] == ':') {
1272 			ptr += n + 1;
1273 
1274 			while (isspace(*ptr))
1275 				ptr++;
1276 
1277 			res = strdup(ptr);
1278 			if (res == NULL) {
1279 				SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1280 				return (NULL);
1281 			}
1282 			return (res);
1283 		}
1284 	}
1285 	SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMATCH);
1286 	return (NULL);
1287 }
1288 
1289 /*
1290  * http_read_body - Read the HTTP response body.
1291  *
1292  *     ret = http_read_body(handle, recv_buf_ptr, recv_buf_size);
1293  *
1294  * Arguments:
1295  *	handle	- Handle associated with the relevant connection
1296  *	recv_buf_ptr - Points to buffer to receive buffer
1297  *	recv_buf_size - Length in bytes of buffer.
1298  *
1299  * Returns:
1300  *	n	- Number of bytes read..
1301  *	< 0	- An error occurred.  This is (the number of bytes gotten + 1),
1302  *		  negated.  In other words, if 'n' bytes were read and then an
1303  *		  error occurred, this will return (-(n+1)).  So zero bytes
1304  *		  were read and then an error occurs, this will return -1.  If
1305  *		  1 byte was read, it will return -2, etc.  Specifics of the
1306  *		  error can be gotten using http_get_lasterr().
1307  *
1308  * Note that the errors will be set in the http_conn_t struct before the
1309  * function which detected the error returns.
1310  */
1311 int
1312 http_read_body(http_handle_t handle, char *recv_buf_ptr, size_t recv_buf_size)
1313 {
1314 	http_conn_t *c_id = handle;
1315 
1316 	ERR_clear_error();
1317 	if (!http_check_conn(c_id))
1318 		return (-1);
1319 
1320 	if (recv_buf_ptr == NULL || recv_buf_size == 0) {
1321 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1322 		return (-1);
1323 	}
1324 
1325 	return (getbytes(c_id, recv_buf_ptr, recv_buf_size));
1326 }
1327 
1328 /*
1329  * http_srv_disconnect - Get rid of the connection to the server without
1330  *			freeing the http_conn_t structure.
1331  *
1332  *     ret = http_srv_disconnect(handle);
1333  *
1334  * Arguments:
1335  *	handle	- Handle associated with the connection
1336  *
1337  * Returns:
1338  *	0	- Success
1339  *	-1	- An error occurred.  Specifics of the error can
1340  *		  be gotten using http_get_lasterr().
1341  */
1342 int
1343 http_srv_disconnect(http_handle_t handle)
1344 {
1345 	http_conn_t *c_id = handle;
1346 	int err_ret;
1347 
1348 	ERR_clear_error();
1349 	if (!http_check_conn(c_id))
1350 		return (-1);
1351 
1352 	err_ret = free_ctx_ssl(c_id);
1353 	bzero(&c_id->inbuf, sizeof (c_id->inbuf));
1354 	free_response(c_id, B_TRUE);
1355 
1356 	return (err_ret);
1357 }
1358 
1359 /*
1360  * http_srv_close - Close the connection and clean up the http_conn_t
1361  *		structure.
1362  *
1363  *     http_srv_close(handle);
1364  *
1365  * Arguments:
1366  *	handle	- Handle associated with the desired connection
1367  *
1368  * Returns:
1369  *	0	- Success
1370  *	-1	- An error occurred.  Specifics of the error can
1371  *		  be gotten using http_get_lasterr().
1372  */
1373 int
1374 http_srv_close(http_handle_t handle)
1375 {
1376 	http_conn_t *c_id = handle;
1377 	int err_ret = 0;
1378 
1379 	if (!http_check_conn(c_id))
1380 		return (-1);
1381 
1382 	if (c_id->ctx != NULL || c_id->ssl != NULL || c_id->fd != -1)
1383 		err_ret = http_srv_disconnect(handle);
1384 
1385 	free(c_id->basic_auth_userid);
1386 	free(c_id->basic_auth_password);
1387 	free(c_id->resp.statusmsg);
1388 	free(c_id->client_cert_file);
1389 	free(c_id->private_key_file);
1390 	free(c_id->random_file);
1391 	free(c_id->file_password);
1392 	c_id->signature = 0;
1393 
1394 	free(c_id);
1395 	return (err_ret);
1396 }
1397 
1398 /*
1399  * http_get_conn_info - Return current information about the connection
1400  *
1401  *     err = http_get_conn_info(handle);
1402  *
1403  * Arguments:
1404  *	handle	- Handle associated with the connection in question
1405  *
1406  * Returns:
1407  *	non_NULL- Points to structure
1408  *	NULL	- An error exists.  Check http_get_lasterr().
1409  */
1410 http_conninfo_t *
1411 http_get_conn_info(http_handle_t handle)
1412 {
1413 	http_conn_t *c_id = handle;
1414 	http_conninfo_t *info;
1415 
1416 	if (!http_check_conn(c_id))
1417 		return (NULL);
1418 
1419 	info = malloc(sizeof (*info));
1420 	if (info == NULL) {
1421 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1422 		return (NULL);
1423 	}
1424 
1425 	bzero(info, sizeof (*info));
1426 
1427 	info->uri = c_id->uri;
1428 	info->proxy = c_id->proxy;
1429 	info->keepalive = c_id->keepalive;
1430 	info->read_timeout = c_id->read_timeout;
1431 
1432 	return (info);
1433 }
1434 
1435 /*
1436  * http_get_lasterr - Return the next error on the last operation
1437  *
1438  *     err = http_get_lasterr(handle, errsrc);
1439  *
1440  * Arguments:
1441  *	handle	- Handle associated with the connection in question
1442  *		  If no valid handle exists yet, this can be NULL.
1443  *		  However, it must be checked with the very next call.
1444  *	errsrc	- Returns the Sources of errors (ERRSRC_* values).
1445  *
1446  * Returns:
1447  *	0	- No error exists
1448  *	<> 0	- The error.
1449  */
1450 ulong_t
1451 http_get_lasterr(http_handle_t handle, uint_t *errsrc)
1452 {
1453 	http_conn_t *c_id = handle;
1454 	ulong_t src;
1455 	ulong_t err;
1456 
1457 	if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) {
1458 		if (errsrc)
1459 			*errsrc = ERRSRC_LIBHTTP;
1460 		err = early_err;
1461 		early_err = 0;
1462 		return (err);
1463 	}
1464 
1465 	GET_ERR(c_id, src, err);
1466 	if (src == 0 && err == 0) {
1467 		if (errsrc)
1468 			*errsrc = ERRSRC_LIBHTTP;
1469 		err = early_err;
1470 		early_err = 0;
1471 		return (err);
1472 	}
1473 	if (errsrc)
1474 		*errsrc = src;
1475 	return (err);
1476 }
1477 
1478 /*
1479  * http_decode_err - Decode a libssl error
1480  *
1481  *     err = http_decode_err(err, errlib, errfunc, errcode);
1482  *
1483  * Arguments:
1484  *	err	- libssl/libcrypto error returned.
1485  *	errlib	- returns libssl/libcrypto sublibrary that caused the error
1486  *	errfunc	- returns function in that library
1487  *	errcode - returns error code
1488  *
1489  * Returns:
1490  *	None other than the above.
1491  */
1492 void
1493 http_decode_err(ulong_t err, int *errlib, int *errfunc, int *errcode)
1494 {
1495 	if (errlib)
1496 		*errlib = ERR_GET_LIB(err);
1497 	if (errfunc)
1498 		*errfunc = ERR_GET_FUNC(err);
1499 	if (errcode)
1500 		*errcode = ERR_GET_REASON(err);
1501 }
1502 
1503 /* ---------------------- private functions ----------------------- */
1504 
1505 /*
1506  * http_req - Issue http request (either HEAD or GET)
1507  *
1508  *     ret = http_req(handle, abs_path, reqtype, curpos, len);
1509  *
1510  * Arguments:
1511  *	handle	- Handle associated with the desired connection
1512  *	abs_path- File name portion of the URI, beginning with a /.  Query,
1513  *		  segment, etc are allowed.
1514  *	type	- HTTP_REQ_TYPE_HEAD or HTTP_REQ_TYPE_GET
1515  *
1516  *	In the case of GET requests,
1517  *	  curpos- -1  - Range not used
1518  *		  >=0 - Beginning of range
1519  *	  len	- 0   - Range ends at the end of the file
1520  *		  >0  - Length of range.
1521  *
1522  * Returns:
1523  *	0	- Success
1524  *	-1	- An error occurred.  Check http_get_lasterr().
1525  */
1526 static int
1527 http_req(http_handle_t handle, const char *abs_path, http_req_t type,
1528     offset_t curpos, offset_t len)
1529 {
1530 	http_conn_t *c_id = handle;
1531 	char	*request;
1532 	char	*reqtypename;
1533 	char	*newreq;
1534 	int	requestlen;
1535 	int	retval;
1536 	int	j;
1537 
1538 	ERR_clear_error();
1539 	if (!http_check_conn(c_id))
1540 		return (-1);
1541 
1542 	if (abs_path == NULL || abs_path[0] == '\0') {
1543 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1544 		return (-1);
1545 	}
1546 
1547 	/* Determine the name for the request type */
1548 	switch (type) {
1549 	case HTTP_REQ_TYPE_GET:
1550 		reqtypename = "GET";
1551 		if (curpos < 0 && curpos != -1) {
1552 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1553 			return (-1);
1554 		}
1555 		break;
1556 
1557 	case HTTP_REQ_TYPE_HEAD:
1558 		reqtypename = "HEAD";
1559 		break;
1560 
1561 	default:
1562 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1563 		return (-1);
1564 	}
1565 
1566 	/* Do rudimentary checks on the absolute path */
1567 	if (abs_path == NULL || *abs_path != '/') {
1568 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1569 		libbootlog(BOOTLOG_CRIT, "http_req: invalid file path");
1570 		if (abs_path != NULL)
1571 			libbootlog(BOOTLOG_CRIT, " %s", abs_path);
1572 		return (-1);
1573 	}
1574 	(void) strlcpy(CONN_ABSPATH, abs_path, MAXHOSTNAMELEN);
1575 
1576 	/*
1577 	 * Size the request.
1578 	 *
1579 	 * With proxy:
1580 	 *   reqtypename + " http://" + host + ":" + port + path +
1581 	 *						" HTTP/1.1\r\n" +
1582 	 * Without proxy:
1583 	 *   reqtypename + " " + path + " HTTP/1.1\r\n" +
1584 	 */
1585 	requestlen = strlen(reqtypename) + 8 + strlen(CONN_HOSTNAME) + 1 +
1586 	    count_digits(CONN_PORT) + strlen(CONN_ABSPATH) + 11;
1587 
1588 	/*
1589 	 * Plus the rest:
1590 	 *   "Host: " + targethost + ":" + count_digits(port) + "\r\n" +
1591 	 *   "Connection: Keep-Alive\r\n" plus trailing "\r\n\0"
1592 	 */
1593 	requestlen += 6 + strlen(CONN_HOSTNAME) + 1 +
1594 	    count_digits(CONN_PORT) + 2 + 24 + 3;
1595 	if ((request = malloc(requestlen)) == NULL) {
1596 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1597 		return (-1);
1598 	}
1599 
1600 	/* The request line */
1601 	if (c_id->proxied && c_id->ssl == NULL) {
1602 		j = snprintf(request, requestlen,
1603 		    "%s http://%s:%d%s HTTP/1.1\r\n",
1604 		    reqtypename, CONN_HOSTNAME, CONN_PORT,
1605 		    CONN_ABSPATH);
1606 	} else {
1607 		j = snprintf(request, requestlen, "%s %s HTTP/1.1\r\n",
1608 		    reqtypename, CONN_ABSPATH);
1609 	}
1610 
1611 	/* Ancillary headers */
1612 	j += snprintf(&request[j], requestlen - j, "Host: %s:%d\r\n",
1613 	    CONN_HOSTNAME, CONN_PORT);
1614 	if (!c_id->keepalive)
1615 		j += snprintf(&request[j], requestlen - j,
1616 		    "Connection: close\r\n");
1617 	else
1618 		j += snprintf(&request[j], requestlen - j,
1619 		    "Connection: Keep-Alive\r\n");
1620 	/*
1621 	 * We only send the range header on GET requests
1622 	 *
1623 	 * "Range: bytes=" + from + "-" + end + "\r\n" or
1624 	 * "Range: bytes=" + from + "-"  "\r\n"
1625 	 */
1626 	if (type == HTTP_REQ_TYPE_GET && curpos >= 0) {
1627 		offset_t endpos;
1628 
1629 		requestlen += 13 + count_digits(curpos) + 1 + 2;
1630 		if (len > 0) {
1631 			endpos = curpos + len - 1;
1632 			requestlen += count_digits(endpos);
1633 		}
1634 
1635 		if ((newreq = realloc(request, requestlen)) == NULL) {
1636 			free(request);
1637 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1638 			return (-1);
1639 		}
1640 		request = newreq;
1641 
1642 		j += sprintf(&request[j], "Range: bytes=%lld-", curpos);
1643 		if (len > 0)
1644 			j += sprintf(&request[j], "%lld", endpos);
1645 		j += sprintf(&request[j], "\r\n");
1646 	}
1647 
1648 	/*
1649 	 * Authorization is added only if provided (RFC 2617, Section 2)
1650 	 *
1651 	 * "Authorization: Basic " + authencstr + "\r\n"
1652 	 */
1653 	if (c_id->basic_auth_userid && c_id->basic_auth_password) {
1654 		char *authstr;
1655 		char *authencstr;
1656 		int authlen;
1657 
1658 		/*
1659 		 * Allow for concat(basic_auth_userid ":" basic_auth_password)
1660 		 */
1661 		authlen = strlen(c_id->basic_auth_userid) + 2 +
1662 		    strlen(c_id->basic_auth_password);
1663 		if ((authstr = malloc(authlen + 1)) == NULL) {
1664 			free(request);
1665 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1666 			return (-1);
1667 		}
1668 		(void) snprintf(authstr, authlen + 1, "%s:%s",
1669 		    c_id->basic_auth_userid, c_id->basic_auth_password);
1670 
1671 		/* 3 bytes encoded as 4 (round up) with null termination */
1672 		if ((authencstr = malloc((authlen + 2) / 3 * 4 + 1)) == NULL) {
1673 			free(authstr);
1674 			free(request);
1675 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1676 			return (-1);
1677 		}
1678 
1679 		(void) EVP_EncodeBlock((unsigned char *)authencstr,
1680 		    (unsigned char *)authstr, authlen);
1681 
1682 		/*
1683 		 * Finally do concat(Authorization: Basic " authencstr "\r\n")
1684 		 */
1685 		requestlen += 21 + strlen(authencstr) + 2;
1686 		if ((newreq = realloc(request, requestlen)) == NULL) {
1687 			free(authencstr);
1688 			free(authstr);
1689 			free(request);
1690 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1691 			return (-1);
1692 		}
1693 		request = newreq;
1694 
1695 		j += snprintf(&request[j], requestlen - j,
1696 		    "Authorization: Basic %s\r\n", authencstr);
1697 
1698 		free(authencstr);
1699 		free(authstr);
1700 	}
1701 
1702 	j += sprintf(&request[j], "\r\n");
1703 
1704 	if (verbosemode)
1705 		libbootlog(BOOTLOG_VERBOSE, "%s", request);
1706 
1707 	/* send the HTTP request */
1708 	retval = http_srv_send(c_id, request, j);
1709 
1710 	free(request);
1711 	if (retval != j) {
1712 		/* Assume error in was set by send request. */
1713 		return (-1);
1714 	}
1715 
1716 	return (0);
1717 }
1718 
1719 /*
1720  * password_cb - Callback to get private key password and return it
1721  *               to SSL.  (Used for PEM certificates only.)
1722  *
1723  * 	len = passwd_cb(buf, buflen, rwflag, userdata);
1724  *
1725  *  Arguments:
1726  *     buf	- Buffer for the password
1727  *     buflen	- Length of 'buf'
1728  *     rwflag	- password will be used for reading/decryption (== 0)
1729  *		  or writing/encryption (== 1).
1730  *     userdata	- Points to connection-specific information.
1731  *
1732  *  Returns:
1733  *     > 0	- Length of password that was put into 'buf'.
1734  *     0 	- No password was returned (usually error occurred)
1735  *
1736  * NOTE:  The password code is not thread safe
1737  */
1738 /* ARGSUSED */
1739 static int
1740 password_cb(char *buf, int buflen, int rwflag, void *userdata)
1741 {
1742 	http_conn_t *c_id = userdata;
1743 
1744 	if (c_id == NULL || c_id->signature != HTTP_CONN_INFO)
1745 		return (0);
1746 
1747 	if (c_id->file_password == NULL ||
1748 	    buflen < strlen(c_id->file_password) + 1)
1749 		return (0);
1750 
1751 	return (strlcpy(buf, c_id->file_password, buflen));
1752 }
1753 
1754 /*
1755  * initialize_ctx - Initialize the context for a connection.
1756  *
1757  *       ctx = initialize_ctx(c_id);
1758  *
1759  *  Arguments:
1760  *     None.
1761  *
1762  *  Returns:
1763  *     non-NULL	- Points to ctx structure.
1764  *     NULL	- An error occurred.  Any cleanup is done and error
1765  *                information is in the error stack.
1766  */
1767 static SSL_CTX *
1768 initialize_ctx(http_conn_t *c_id)
1769 {
1770 	SSL_METHOD	*meth;
1771 	SSL_CTX		*ctx;
1772 
1773 	ERR_clear_error();
1774 
1775 	/* Global system initialization */
1776 	if (ssl_init == 0) {
1777 		sunw_crypto_init();
1778 		SSL_load_error_strings();
1779 		ssl_init = 1;
1780 	}
1781 
1782 	/* Create our context */
1783 	meth = SSLv3_client_method();
1784 	if ((ctx = SSL_CTX_new(meth)) == NULL) {
1785 		ulong_t err;
1786 		while ((err = ERR_get_error()) != 0)
1787 			SET_ERR(c_id, ERRSRC_LIBSSL, err);
1788 			libbootlog(BOOTLOG_CRIT,
1789 			    "initialize_ctx: SSL_CTX_new returned NULL");
1790 		return (NULL);
1791 	}
1792 
1793 	/*
1794 	 * Ensure that any renegotiations for blocking connections will
1795 	 * be done automatically.  (The alternative is to return partial
1796 	 * reads to the caller and let it oversee the renegotiations.)
1797 	 */
1798 	if (SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY) == 0) {
1799 		ulong_t err;
1800 		while ((err = ERR_get_error()) != 0)
1801 			SET_ERR(c_id, ERRSRC_LIBSSL, err);
1802 			libbootlog(BOOTLOG_CRIT,
1803 			    "initialize_ctx: SSL_CTX_set_mode returned 0");
1804 		(void) SSL_CTX_free(ctx);
1805 		return (NULL);
1806 	}
1807 
1808 	/* set cipher list if provided */
1809 	if (cipher_list != NULL) {
1810 		if (!SSL_CTX_set_cipher_list(ctx, cipher_list)) {
1811 			ulong_t err;
1812 			while ((err = ERR_get_error()) != 0)
1813 				SET_ERR(c_id, ERRSRC_LIBSSL, err);
1814 				libbootlog(BOOTLOG_CRIT,
1815 				    "initialize_ctx: Error in cipher list");
1816 			SSL_CTX_free(ctx);
1817 			return (NULL);
1818 		}
1819 	}
1820 
1821 	/*
1822 	 * We attempt to use the client_certificate_file for the private
1823 	 * key input scheme *only* in the absence of private_key_file. In
1824 	 * this instance the scheme will be the same as that used for the
1825 	 * certificate input.
1826 	 */
1827 
1828 	/* Load our certificates */
1829 	if (c_id->client_cert_file != NULL) {
1830 		if (p12_format) {
1831 			/* Load pkcs12-formated files */
1832 			if (sunw_p12_use_certfile(ctx, c_id->client_cert_file,
1833 			    c_id->file_password)
1834 			    <= 0) {
1835 				ulong_t err;
1836 				while ((err = ERR_get_error()) != 0)
1837 					SET_ERR(c_id, ERRSRC_LIBSSL, err);
1838 					libbootlog(BOOTLOG_CRIT,
1839 					    "initialize_ctx: Couldn't read "
1840 					    "PKCS12 certificate file");
1841 				SSL_CTX_free(ctx);
1842 				return (NULL);
1843 			}
1844 		} else {
1845 			/* Load PEM-formated files */
1846 			if (SSL_CTX_use_certificate_file(ctx,
1847 			    c_id->client_cert_file, SSL_FILETYPE_PEM) <= 0) {
1848 				ulong_t err;
1849 				while ((err = ERR_get_error()) != 0)
1850 					SET_ERR(c_id, ERRSRC_LIBSSL, err);
1851 					libbootlog(BOOTLOG_CRIT,
1852 					    "initialize_ctx: Couldn't read "
1853 					    "PEM certificate file");
1854 				SSL_CTX_free(ctx);
1855 				return (NULL);
1856 			}
1857 		}
1858 		if (c_id->private_key_file == NULL)
1859 			c_id->private_key_file = c_id->client_cert_file;
1860 	}
1861 
1862 	/* Load our keys */
1863 	if (p12_format) {
1864 		/* Load pkcs12-formated files */
1865 		if (c_id->private_key_file != NULL) {
1866 			if (sunw_p12_use_keyfile(ctx, c_id->private_key_file,
1867 			    c_id->file_password)
1868 			    <= 0) {
1869 				ulong_t err;
1870 				while ((err = ERR_get_error()) != 0)
1871 					SET_ERR(c_id, ERRSRC_LIBSSL, err);
1872 					libbootlog(BOOTLOG_CRIT,
1873 					    "initialize_ctx: Couldn't read "
1874 					    "PKCS12 key file");
1875 				SSL_CTX_free(ctx);
1876 				return (NULL);
1877 			}
1878 		}
1879 	} else {
1880 		/* Load PEM-formated files */
1881 		SSL_CTX_set_default_passwd_cb(ctx, password_cb);
1882 		SSL_CTX_set_default_passwd_cb_userdata(ctx, c_id);
1883 		if (c_id->private_key_file != NULL) {
1884 			if (SSL_CTX_use_PrivateKey_file(ctx,
1885 			    c_id->private_key_file, SSL_FILETYPE_PEM) <= 0) {
1886 				ulong_t err;
1887 				while ((err = ERR_get_error()) != 0)
1888 					SET_ERR(c_id, ERRSRC_LIBSSL, err);
1889 					libbootlog(BOOTLOG_CRIT,
1890 					    "initialize_ctx: Couldn't read "
1891 					    "PEM key file");
1892 				SSL_CTX_free(ctx);
1893 				return (NULL);
1894 			}
1895 		}
1896 	}
1897 
1898 	/* Load the CAs we trust */
1899 	if (ca_verify_file != NULL) {
1900 		if (p12_format) {
1901 			if (sunw_p12_use_trustfile(ctx, ca_verify_file,
1902 			    c_id->file_password)
1903 			    <= 0) {
1904 				ulong_t err;
1905 				while ((err = ERR_get_error()) != 0)
1906 					SET_ERR(c_id, ERRSRC_LIBSSL, err);
1907 					libbootlog(BOOTLOG_CRIT,
1908 					    "initialize_ctx: Couldn't read "
1909 					    "PKCS12 CA list file");
1910 				SSL_CTX_free(ctx);
1911 				return (NULL);
1912 			}
1913 		} else {
1914 			if (SSL_CTX_load_verify_locations(ctx, ca_verify_file,
1915 			    NULL) == 0) {
1916 				ulong_t err;
1917 				while ((err = ERR_get_error()) != 0)
1918 					SET_ERR(c_id, ERRSRC_LIBSSL, err);
1919 					libbootlog(BOOTLOG_CRIT,
1920 					    "initialize_ctx: Couldn't read PEM"
1921 					    " CA list file");
1922 				SSL_CTX_free(ctx);
1923 				return (NULL);
1924 			}
1925 		}
1926 	}
1927 
1928 	SSL_CTX_set_verify_depth(ctx, verify_depth);
1929 
1930 	/* Load randomness */
1931 	if (c_id->random_file != NULL &&
1932 	    RAND_load_file(c_id->random_file, 1024 * 1024) <= 0) {
1933 		ulong_t err;
1934 		while ((err = ERR_get_error()) != 0)
1935 			SET_ERR(c_id, ERRSRC_LIBSSL, err);
1936 			libbootlog(BOOTLOG_CRIT,
1937 			    "initialize_ctx: Couldn't load random file");
1938 		SSL_CTX_free(ctx);
1939 		return (NULL);
1940 	}
1941 	if (RAND_status() <= 0) {
1942 		ulong_t err;
1943 		while ((err = ERR_get_error()) != 0)
1944 			SET_ERR(c_id, ERRSRC_LIBSSL, err);
1945 			libbootlog(BOOTLOG_CRIT,
1946 			    "initialize_ctx: PRNG not seeded");
1947 		SSL_CTX_free(ctx);
1948 		return (NULL);
1949 	}
1950 
1951 	return (ctx);
1952 }
1953 
1954 /*
1955  * tcp_connect - Set up a TCP connection.
1956  *
1957  *         sock = tcp_connect(c_id, hostname, port);
1958  *
1959  * Arguments:
1960  *      c_id	 - Structure associated with the desired connection
1961  *	hostname - the host to connect to
1962  *	port	 - the port to connect to
1963  *
1964  * Returns:
1965  *      >= 0	- Socket number.
1966  *      -1	- Error occurred.  Error information is set in the
1967  *                error stack.  Any cleanup is done.
1968  *
1969  * This function established a connection to the target host.  When
1970  * it returns, the connection is ready for a HEAD or GET request.
1971  */
1972 static int
1973 tcp_connect(http_conn_t *c_id, const char *hostname, uint16_t port)
1974 {
1975 	struct hostent	*hp;
1976 	struct sockaddr_in addr;
1977 	int	sock;
1978 	int	status;
1979 
1980 	if ((hp = gethostbyname(hostname)) == NULL) {
1981 		SET_ERR(c_id, ERRSRC_RESOLVE, h_errno);
1982 		return (-1);
1983 	}
1984 
1985 	bzero(&addr, sizeof (addr));
1986 	/* LINTED */
1987 	addr.sin_addr = *(struct in_addr *)hp->h_addr;
1988 	addr.sin_family = AF_INET;
1989 	addr.sin_port = htons(port);
1990 
1991 	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
1992 		SET_ERR(c_id, ERRSRC_SYSTEM, errno);
1993 		return (-1);
1994 	}
1995 
1996 	status = connect(sock, (struct sockaddr *)&addr, sizeof (addr));
1997 	if (status < 0) {
1998 		SET_ERR(c_id, ERRSRC_SYSTEM, errno);
1999 		(void) socket_close(sock);
2000 		return (-1);
2001 	}
2002 
2003 	c_id->host_addr = addr;	/* save for future sendto calls */
2004 	c_id->fd = sock;
2005 
2006 	return (sock);
2007 }
2008 
2009 /*
2010  * readline - Get a line from the socket.  Discard the end-of-line
2011  *            (CR or CR/LF or LF).
2012  *
2013  *         ret = readline(c_id, sock, buf, len);
2014  *
2015  * Arguments:
2016  *      c_id	- Structure associated with the desired connection
2017  *      sock	- Socket to read
2018  *      buf   	- Buffer for the line
2019  *      len	- Length of the buffer
2020  *
2021  * Returns:
2022  *      0	- Success.  'buf' contains the line.
2023  *      -1	- Error occurred.  Error information is set in the
2024  *                error stack.
2025  */
2026 static int
2027 readline(http_conn_t *c_id, int sock, char *buf, int len)
2028 {
2029 	int	n, r;
2030 	char	*ptr = buf;
2031 
2032 	for (n = 0; n < len; n++) {
2033 		r = socket_read(sock, ptr, 1, c_id->read_timeout);
2034 
2035 		if (r < 0) {
2036 			SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2037 			return (-1);
2038 		} else if (r == 0) {
2039 			libbootlog(BOOTLOG_WARNING, "Readline: no data");
2040 			return (0);
2041 		}
2042 
2043 		if (*ptr == '\n') {
2044 			*ptr = '\0';
2045 
2046 			/* Strip off the CR if it's there */
2047 			if (buf[n-1] == '\r') {
2048 				buf[n-1] = '\0';
2049 				n--;
2050 			}
2051 
2052 			return (n);
2053 		}
2054 
2055 		ptr++;
2056 	}
2057 
2058 	libbootlog(BOOTLOG_WARNING, "readline: Buffer too short\n");
2059 	return (0);
2060 }
2061 
2062 /*
2063  * proxy_connect - Set up a proxied TCP connection to the target host.
2064  *
2065  *         sock = proxy_connect(c_id);
2066  *
2067  * Arguments:
2068  *      c_id  -	Structure associated with the desired connection
2069  *
2070  * Returns:
2071  *      >= 0	- Socket number.
2072  *      -1	- Error occurred.  Error information is set in the
2073  *                error stack.  Any cleanup is done.
2074  *
2075  * This function established a connection to the proxy and then sends
2076  * the request to connect to the target host.  It reads the response
2077  * (the status line and any headers).  When it returns, the connection
2078  * is ready for a HEAD or GET request.
2079  */
2080 static int
2081 proxy_connect(http_conn_t *c_id)
2082 {
2083 	struct sockaddr_in addr;
2084 	int	sock;
2085 	char	buf[1024];
2086 	char	*ptr;
2087 	int	i;
2088 
2089 	if ((sock = tcp_connect(c_id, CONN_PROXY_HOSTNAME,
2090 	    CONN_PROXY_PORT)) < 0) {
2091 		return (-1);
2092 	}
2093 
2094 	if (!CONN_HTTPS) {
2095 		return (sock);
2096 	}
2097 
2098 	/* Now that we're connected, do the proxy request */
2099 	(void) snprintf(buf, sizeof (buf),
2100 	    "CONNECT %s:%d HTTP/1.0\r\n\r\n", CONN_HOSTNAME, CONN_PORT);
2101 
2102 	/* socket_write sets the errors */
2103 	if (socket_write(sock, buf, strlen(buf), &addr) <= 0) {
2104 		SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2105 		(void) socket_close(sock);
2106 		return (-1);
2107 	}
2108 
2109 	/* And read the response */
2110 	i = readline(c_id, sock, buf, sizeof (buf));
2111 	if (i <= 0) {
2112 		if (i == 0)
2113 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NORESP);
2114 			libbootlog(BOOTLOG_CRIT,
2115 			    "proxy_connect: Empty response from proxy");
2116 		(void) socket_close(sock);
2117 		return (-1);
2118 	}
2119 
2120 	ptr = buf;
2121 	if (strncmp(ptr, "HTTP", 4) != 0) {
2122 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOT_1_1);
2123 		libbootlog(BOOTLOG_CRIT,
2124 		    "proxy_connect: Unrecognized protocol");
2125 		(void) socket_close(sock);
2126 		return (-1);
2127 	}
2128 
2129 	/* skip to the code */
2130 	ptr += 4;
2131 	while (*ptr != ' ' && *ptr != '\0')
2132 		ptr++;
2133 	while (*ptr == ' ' && *ptr != '\0')
2134 		ptr++;
2135 
2136 	/* make sure it's three digits */
2137 	if (strncmp(ptr, "200", 3) != 0) {
2138 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADRESP);
2139 		libbootlog(BOOTLOG_CRIT,
2140 		    "proxy_connect: Received error from proxy server");
2141 		(void) socket_close(sock);
2142 		return (-1);
2143 	}
2144 	ptr += 3;
2145 	if (isdigit(*ptr)) {
2146 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADRESP);
2147 		(void) socket_close(sock);
2148 		return (-1);
2149 	}
2150 
2151 	/* Look for the blank line that signals end of proxy header */
2152 	while ((i = readline(c_id, sock, buf, sizeof (buf))) > 0)
2153 		;
2154 
2155 	if (i < 0) {
2156 		(void) socket_close(sock);
2157 		return (-1);
2158 	}
2159 
2160 	return (sock);
2161 }
2162 
2163 /*
2164  * check_cert_chain - Check if we have a valid certificate chain.
2165  *
2166  *      ret = check_cert_chain(c_id, host);
2167  *
2168  * Arguments:
2169  *    c_id	- Connection info.
2170  *    host	- Name to compare with the common name in the certificate.
2171  *
2172  * Returns:
2173  *    0		- Certificate chain and common name are both OK.
2174  *    -1	- Certificate chain and/or common name is not valid.
2175  */
2176 static int
2177 check_cert_chain(http_conn_t *c_id, char *host)
2178 {
2179 	X509	*peer;
2180 	char	peer_CN[256];
2181 	long	verify_err;
2182 
2183 	if ((verify_err = SSL_get_verify_result(c_id->ssl)) != X509_V_OK) {
2184 		SET_ERR(c_id, ERRSRC_VERIFERR, verify_err);
2185 		libbootlog(BOOTLOG_CRIT,
2186 		    "check_cert_chain: Certificate doesn't verify");
2187 		return (-1);
2188 	}
2189 
2190 	/*
2191 	 * Check the cert chain. The chain length
2192 	 * is automatically checked by OpenSSL when we
2193 	 * set the verify depth in the ctx
2194 	 *
2195 	 * All we need to do here is check that the CN
2196 	 * matches
2197 	 */
2198 
2199 	/* Check the common name */
2200 	if ((peer = SSL_get_peer_certificate(c_id->ssl)) == NULL) {
2201 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOCERT);
2202 		libbootlog(BOOTLOG_CRIT,
2203 		    "check_cert_chain: Peer did not present a certificate");
2204 		return (-1);
2205 	}
2206 	(void) X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
2207 	    NID_commonName, peer_CN, 256);
2208 
2209 	if (verbosemode)
2210 		libbootlog(BOOTLOG_VERBOSE,
2211 		    "server cert's peer_CN is %s, host is %s", peer_CN, host);
2212 
2213 	if (strcasecmp(peer_CN, host)) {
2214 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMATCH);
2215 		libbootlog(BOOTLOG_CRIT,
2216 		    "check_cert_chain: Common name doesn't match host name");
2217 		libbootlog(BOOTLOG_CRIT,
2218 		    "peer_CN = %s, host = %s", peer_CN, host);
2219 		return (-1);
2220 	}
2221 
2222 	return (0);
2223 }
2224 
2225 /*
2226  * print_ciphers - Print the list of ciphers for debugging.
2227  *
2228  *       print_ciphers(ssl);
2229  *
2230  * Arguments:
2231  *     ssl	- SSL connection.
2232  *
2233  * Returns:
2234  *     none
2235  */
2236 static void
2237 print_ciphers(SSL *ssl)
2238 {
2239 	SSL_CIPHER	*c;
2240 	STACK_OF(SSL_CIPHER)	*sk;
2241 	int	i;
2242 	const char	*name;
2243 
2244 	if (ssl == NULL)
2245 		return;
2246 
2247 	sk = SSL_get_ciphers(ssl);
2248 	if (sk == NULL)
2249 		return;
2250 
2251 	for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
2252 		/* LINTED */
2253 		c = sk_SSL_CIPHER_value(sk, i);
2254 		libbootlog(BOOTLOG_VERBOSE, "%08lx %s", c->id, c->name);
2255 	}
2256 	name = SSL_get_cipher_name(ssl);
2257 	if (name == NULL)
2258 		name = "";
2259 	libbootlog(BOOTLOG_VERBOSE, "Current cipher = %s", name);
2260 }
2261 
2262 /*
2263  * read_headerlines - Get the header lines from the server.  This reads
2264  *              lines until it gets a empty line indicating end of headers.
2265  *
2266  *       ret = read_headerlines(c_id);
2267  *
2268  * Arguments:
2269  *     c_id	- Info about the connection being read.
2270  *     bread	- TRUE if the headerlines are part of the message body.
2271  *
2272  * Returns:
2273  *     0	- Header lines were read.
2274  *     -1	- Error occurred.  The errors information is already in
2275  *                the error stack.
2276  *
2277  *  Read the lines.  If the current line begins with a space or tab, it is
2278  *  a continuation.  Take the new line and append it to the end of the
2279  *  previous line rather than making an entry for another line in
2280  *  c_id->resphdr.
2281  *
2282  *  Note that I/O errors are put into the error stack by http_srv_recv(),
2283  *  which is called by getaline().
2284  */
2285 static int
2286 read_headerlines(http_conn_t *c_id, boolean_t bread)
2287 {
2288 	char	line[MAXHOSTNAMELEN];
2289 	char	**new_buf;
2290 	char	*ptr;
2291 	int	next;
2292 	int	cur;
2293 	int	n;
2294 
2295 	/* process headers, stop when we get to an empty line */
2296 	cur = 0;
2297 	next = 0;
2298 	while ((n = getaline(c_id, line, sizeof (line), bread)) > 0) {
2299 
2300 		if (verbosemode)
2301 			libbootlog(BOOTLOG_VERBOSE,
2302 			    "read_headerlines: %s", line);
2303 		/*
2304 		 * See if this is a continuation line (first col is a
2305 		 * space or a tab)
2306 		 */
2307 		if (line[0] != ' ' && line[0] != '	') {
2308 			cur = next;
2309 			next ++;
2310 			new_buf =
2311 			    realloc(c_id->resphdr, (cur + 1) * sizeof (void *));
2312 			if (new_buf == NULL) {
2313 				SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
2314 				return (-1);
2315 			}
2316 			c_id->resphdr = new_buf;
2317 
2318 			c_id->resphdr[cur] = strdup(line);
2319 			if (c_id->resphdr[cur] == NULL) {
2320 				SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
2321 				return (-1);
2322 			}
2323 		} else {
2324 			ptr = line;
2325 			while (isspace(*ptr))
2326 				ptr ++;
2327 			c_id->resphdr[cur] = realloc(c_id->resphdr[cur],
2328 			    strlen(c_id->resphdr[cur]) + strlen(ptr) + 1);
2329 			if (c_id->resphdr[cur] == NULL) {
2330 				SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
2331 				return (-1);
2332 			}
2333 			(void) strcat(c_id->resphdr[cur], ptr);
2334 		}
2335 		ptr = &(c_id->resphdr[cur][strlen(c_id->resphdr[cur]) - 1]);
2336 		while (ptr > c_id->resphdr[cur] && isspace(*ptr))
2337 			ptr --;
2338 	}
2339 	c_id->resp.nresphdrs = next;
2340 
2341 	/* Cause of any I/O error was already put into error stack. */
2342 	return (n >= 0 ? 0 : -1);
2343 }
2344 
2345 static void
2346 free_response(http_conn_t *c_id, int free_boundary)
2347 {
2348 	int i;
2349 
2350 	/* free memory from previous calls */
2351 	if (c_id->resp.statusmsg != NULL) {
2352 		free(c_id->resp.statusmsg);
2353 		c_id->resp.statusmsg = NULL;
2354 	}
2355 	for (i = 0; i < c_id->resp.nresphdrs; i++) {
2356 		free(c_id->resphdr[i]);
2357 		c_id->resphdr[i] = NULL;
2358 	}
2359 	c_id->resp.nresphdrs = 0;
2360 	if (c_id->resphdr != NULL) {
2361 		free(c_id->resphdr);
2362 		c_id->resphdr = NULL;
2363 	}
2364 
2365 	if (free_boundary && c_id->boundary) {
2366 		free(c_id->boundary);
2367 		c_id->boundary = NULL;
2368 		c_id->is_multipart = B_FALSE;
2369 	}
2370 }
2371 
2372 static int
2373 free_ctx_ssl(http_conn_t *c_id)
2374 {
2375 	int err_ret = 0;
2376 
2377 	if (c_id->ssl != NULL) {
2378 		if (SSL_shutdown(c_id->ssl) <= 0) {
2379 			ulong_t err;
2380 			while ((err = ERR_get_error()) != 0)
2381 				SET_ERR(c_id, ERRSRC_LIBSSL, err);
2382 			err_ret = -1;
2383 		}
2384 		SSL_free(c_id->ssl);
2385 		c_id->ssl = NULL;
2386 	}
2387 
2388 	if (c_id->fd != -1 && socket_close(c_id->fd) < 0) {
2389 		SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2390 		err_ret = -1;
2391 	}
2392 	c_id->fd = -1;
2393 
2394 	if (c_id->ctx != NULL) {
2395 		SSL_CTX_free(c_id->ctx);
2396 		c_id->ctx = NULL;
2397 	}
2398 
2399 	return (err_ret);
2400 }
2401 
2402 /*
2403  * get_chunk_header - Get a chunk header line
2404  *
2405  * Arguments:
2406  *   c_id   - Structure describing the connection in question.
2407  *
2408  * Returns:
2409  *  >=0	- Length of next chunk
2410  *  -1	- Error occurred.  The error information is in the error stack.
2411  */
2412 static int
2413 get_chunk_header(http_conn_t *c_id)
2414 {
2415 	char	line[MAXHOSTNAMELEN];
2416 	char	*ptr;
2417 	int	value;
2418 	int	ok;
2419 	int	i;
2420 
2421 	/*
2422 	 * Determine whether an extra crlf pair will precede the
2423 	 * chunk header.  For the first one, there is no preceding
2424 	 * crlf.  For later chunks, there is one crlf.
2425 	 */
2426 	if (c_id->is_firstchunk) {
2427 		ok = 1;
2428 		c_id->is_firstchunk = B_FALSE;
2429 	} else {
2430 		ok = ((i = getaline(c_id, line, sizeof (line), B_FALSE)) == 0);
2431 	}
2432 
2433 	if (ok)
2434 		i = getaline(c_id, line, sizeof (line), B_FALSE);
2435 	if (!ok || i < 0) {
2436 		/*
2437 		 * If I/O error, the Cause was already put into
2438 		 * error stack.  This is an additional error.
2439 		 */
2440 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOHEADER);
2441 		return (-1);
2442 	}
2443 
2444 	if (verbosemode)
2445 		libbootlog(BOOTLOG_VERBOSE, "get_chunk_header: <%s>", line);
2446 
2447 
2448 	/*
2449 	 * The first (and probably only) field in the line is the hex
2450 	 * length of the chunk.
2451 	 */
2452 	ptr = line;
2453 	value = 0;
2454 	while (*ptr != '\0' && (i = hexdigit(*ptr)) >= 0) {
2455 		value = (value << 4) + i;
2456 		ptr ++;
2457 	}
2458 
2459 	return (value);
2460 }
2461 
2462 /*
2463  * init_bread - Initialize the counters used to read message bodies.
2464  *
2465  * Arguments:
2466  *   c_id   - Structure describing the connection in question.
2467  *
2468  * Returns:
2469  *   0	- Success
2470  *  -1	- Error occurred.  The error information is in the error stack.
2471  *
2472  *  This routine will determine whether the message body being received is
2473  *  chunked or non-chunked. Once determined, the counters used to read
2474  *  message bodies will be initialized.
2475  */
2476 static int
2477 init_bread(http_conn_t *c_id)
2478 {
2479 	char	*hdr;
2480 	char	*ptr;
2481 	boolean_t sized = B_FALSE;
2482 
2483 	/*
2484 	 * Assume non-chunked reads until proven otherwise.
2485 	 */
2486 	c_id->is_chunked = B_FALSE;
2487 	c_id->is_firstchunk = B_FALSE;
2488 	hdr = http_get_header_value(c_id, "Content-Length");
2489 	if (hdr != NULL) {
2490 		c_id->body_size = strtol(hdr, NULL, 10);
2491 		if (c_id->body_size == 0 && errno != 0) {
2492 			free(hdr);
2493 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADSIZE);
2494 			return (-1);
2495 		}
2496 		free(hdr);
2497 		sized = B_TRUE;
2498 	}
2499 
2500 	/*
2501 	 * If size was not determined above, then see if this is a
2502 	 * chunked message. Keep in mind that the first chunk size is
2503 	 * "special".
2504 	 */
2505 	if (!sized) {
2506 		hdr = http_get_header_value(c_id, "Transfer-Encoding");
2507 		if (hdr != NULL) {
2508 			ptr = eat_ws(hdr);
2509 			if (startswith((const char **)&ptr, "chunked;") ||
2510 			    strcasecmp(ptr, "chunked") == 0) {
2511 				c_id->is_firstchunk = B_TRUE;
2512 				c_id->is_chunked = B_TRUE;
2513 			}
2514 			free(hdr);
2515 			if (c_id->is_chunked) {
2516 				c_id->body_size = get_chunk_header(c_id);
2517 				if (c_id->body_size == -1) {
2518 					/*
2519 					 * Error stack was already set at a
2520 					 * lower level.
2521 					 */
2522 					return (-1);
2523 				}
2524 				sized = B_TRUE;
2525 			}
2526 		}
2527 	}
2528 
2529 	/*
2530 	 * Well, isn't this a fine predicament? It wasn't chunked or
2531 	 * non-chunked as far as we can tell.
2532 	 */
2533 	if (!sized) {
2534 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADSIZE);
2535 		return (-1);
2536 	}
2537 
2538 	c_id->body_read = 0;
2539 	c_id->body_size_tot = c_id->body_size;
2540 	c_id->body_read_tot = 0;
2541 
2542 	return (0);
2543 }
2544 
2545 /*
2546  * get_msgcnt - Get the number of bytes left in the message body or chunk.
2547  *
2548  * Arguments:
2549  *   c_id   - Structure describing the connection in question.
2550  *   msgcnt - Where to store the message count.
2551  *
2552  * Returns:
2553  *   0	- Success
2554  *  -1	- Error occurred.  The error information is in the error stack.
2555  *
2556  *  Note that if the message being read is not chunked, then the byte count
2557  *  is simply the message size minus the bytes read thus far. In the case of
2558  *  chunked messages, the byte count returned will be the number of bytes
2559  *  left in the chunk. If the current chunk has been exhausted, then this
2560  *  routine will determine the size of the next chunk. When the next chunk
2561  *  size is zero, the message has been read in its entirety.
2562  */
2563 static int
2564 get_msgcnt(http_conn_t *c_id, ssize_t *msgcnt)
2565 {
2566 	/*
2567 	 * If there are more bytes in the message, then return.
2568 	 */
2569 	*msgcnt = c_id->body_size - c_id->body_read;
2570 	if (*msgcnt != 0) {
2571 		return (0);
2572 	}
2573 	/*
2574 	 * If this is not a chunked message and the body has been
2575 	 * read, then we're done.
2576 	 */
2577 	if (!c_id->is_chunked) {
2578 		return (0);
2579 	}
2580 
2581 	/*
2582 	 * We're looking at a chunked message whose immediate
2583 	 * chunk has been totally processed. See if there is
2584 	 * another chunk.
2585 	 */
2586 	c_id->body_size = get_chunk_header(c_id);
2587 	if (c_id->body_size == -1) {
2588 		/*
2589 		 * Error stack was already set at a
2590 		 * lower level.
2591 		 */
2592 		return (-1);
2593 	}
2594 
2595 	/*
2596 	 * No bytes of this chunk have been processed yet.
2597 	 */
2598 	c_id->body_read = 0;
2599 
2600 	/*
2601 	 * A zero length chunk signals the end of the
2602 	 * message body and chunking.
2603 	 */
2604 	if (c_id->body_size == 0) {
2605 		c_id->is_chunked = B_FALSE;
2606 		return (0);
2607 	}
2608 
2609 	/*
2610 	 * There is another chunk.
2611 	 */
2612 	c_id->body_size_tot += c_id->body_size;
2613 	*msgcnt = c_id->body_size - c_id->body_read;
2614 
2615 	return (0);
2616 }
2617 
2618 /*
2619  * getaline - Get lines of data from the HTTP response, up to 'len' bytes.
2620  *	  NOTE: the line will not end with a NULL if all 'len' bytes
2621  *	  were read.
2622  *
2623  * Arguments:
2624  *   c_id   - Structure describing the connection in question.
2625  *   line   - Where to store the data.
2626  *   len    - Maximum number of bytes in the line.
2627  *   bread  - TRUE if the lines are part of the message body.
2628  *
2629  * Returns:
2630  *   >=0    - The number of bytes successfully read.
2631  *   <0	    - An error occurred.  This is (the number of bytes gotten + 1),
2632  *	      negated.  In other words, if 'n' bytes were read and then an
2633  *	      error occurred, this will return (-(n+1)).  So zero bytes read
2634  *	      and then an error occurs, this will return -1.  If 1 bytes
2635  *	      was read, it will return -2, etc.
2636  *
2637  *	      Specifics of the error can be gotten using http_get_lasterr();
2638  *
2639  *  Note that I/O errors are put into the error stack by http_srv_recv().1
2640  */
2641 static int
2642 getaline(http_conn_t *c_id, char *line, int len, boolean_t bread)
2643 {
2644 	int	i = 0;
2645 	ssize_t	msgcnt = 0;
2646 	ssize_t	cnt;
2647 
2648 	while (i < len) {
2649 		/*
2650 		 * Special processing required for message body reads.
2651 		 */
2652 		if (bread) {
2653 			/*
2654 			 * See if there is another chunk. Obviously, in the
2655 			 * case of non-chunked messages, there won't be.
2656 			 * But in either case, chunked or not, if msgcnt
2657 			 * is still zero after the call to get_msgcnt(),
2658 			 * then we're done.
2659 			 */
2660 			if (msgcnt == 0) {
2661 				if (get_msgcnt(c_id, &msgcnt) == -1) {
2662 					return (-(i+1));
2663 				}
2664 				if (msgcnt == 0) {
2665 					break;
2666 				}
2667 			}
2668 			cnt = MIN(msgcnt, sizeof (c_id->inbuf.buf));
2669 		} else {
2670 			cnt = sizeof (c_id->inbuf.buf);
2671 		}
2672 
2673 		/* read more data if buffer empty */
2674 		if (c_id->inbuf.i == c_id->inbuf.n) {
2675 			c_id->inbuf.i = 0;
2676 			c_id->inbuf.n = http_srv_recv(c_id, c_id->inbuf.buf,
2677 			    cnt);
2678 			if (c_id->inbuf.n == 0) {
2679 				return (i);
2680 			}
2681 			if (c_id->inbuf.n < 0) {
2682 				return (-(i+1));
2683 			}
2684 		}
2685 		/* skip CR */
2686 		if (c_id->inbuf.buf[c_id->inbuf.i] == '\r') {
2687 			INC_BREAD_CNT(bread, msgcnt);
2688 			c_id->inbuf.i++;
2689 			continue;
2690 		}
2691 		if (c_id->inbuf.buf[c_id->inbuf.i] == '\n') {
2692 			INC_BREAD_CNT(bread, msgcnt);
2693 			c_id->inbuf.i++;
2694 			line[i] = '\0';
2695 			return (i);
2696 		}
2697 		/* copy buf from internal buffer */
2698 		INC_BREAD_CNT(bread, msgcnt);
2699 		line[i++] = c_id->inbuf.buf[c_id->inbuf.i++];
2700 	}
2701 	return (i);
2702 }
2703 
2704 /*
2705  * getbytes - Get a block from the HTTP response. Used for the HTTP body.
2706  *
2707  * Arguments:
2708  *   c_id   - Structure describing the connection in question.
2709  *   line   - Where to store the data.
2710  *   len    - Maximum number of bytes in the block.
2711  *
2712  * Returns:
2713  *   >=0    - The number of bytes successfully read.
2714  *   <0	    - An error occurred.  This is (the number of bytes gotten + 1),
2715  *	      negated.  In other words, if 'n' bytes were read and then an
2716  *	      error occurred, this will return (-(n+1)).  So zero bytes read
2717  *	      and then an error occurs, this will return -1.  If 1 bytes
2718  *	      was read, it will return -2, etc.
2719  *
2720  *	      Specifics of the error can be gotten using http_get_lasterr();
2721  *
2722  *  Note that all reads performed here assume that a message body is being
2723  *  read. If this changes in the future, then the logic should more closely
2724  *  resemble getaline().
2725  *
2726  *  Note that I/O errors are put into the error stack by http_srv_recv().
2727  */
2728 static int
2729 getbytes(http_conn_t *c_id, char *line, int len)
2730 {
2731 	int	i = 0;
2732 	ssize_t	msgcnt = 0;
2733 	ssize_t	cnt;
2734 	int	nbytes;
2735 
2736 	while (i < len) {
2737 		/*
2738 		 * See if there is another chunk. Obviously, in the
2739 		 * case of non-chunked messages, there won't be.
2740 		 * But in either case, chunked or not, if msgcnt
2741 		 * is still zero after the call to get_msgcnt(), then
2742 		 * we're done.
2743 		 */
2744 		if (msgcnt == 0) {
2745 			if (get_msgcnt(c_id, &msgcnt) == -1) {
2746 				return (-(i+1));
2747 			}
2748 			if (msgcnt == 0) {
2749 				break;
2750 			}
2751 		}
2752 
2753 		cnt = MIN(msgcnt, len - i);
2754 
2755 		if (c_id->inbuf.n != c_id->inbuf.i) {
2756 			nbytes = (int)MIN(cnt, c_id->inbuf.n - c_id->inbuf.i);
2757 			(void) memcpy(line, &c_id->inbuf.buf[c_id->inbuf.i],
2758 			    nbytes);
2759 			c_id->inbuf.i += nbytes;
2760 		} else {
2761 			nbytes = http_srv_recv(c_id, line, cnt);
2762 			if (nbytes == 0) {
2763 				return (i);
2764 			}
2765 			if (nbytes < 0) {
2766 				return (-(i+1));
2767 			}
2768 		}
2769 
2770 		i += nbytes;
2771 		line += nbytes;
2772 		msgcnt -= nbytes;
2773 		c_id->body_read += nbytes;
2774 		c_id->body_read_tot += nbytes;
2775 	}
2776 
2777 	return (i);
2778 }
2779 
2780 static int
2781 http_srv_send(http_conn_t *c_id, const void *buf, size_t nbyte)
2782 {
2783 	int	retval;
2784 
2785 	if (c_id->ssl != NULL) {
2786 		if ((retval = SSL_write(c_id->ssl, buf, nbyte)) <= 0) {
2787 			handle_ssl_error(c_id, retval);
2788 		}
2789 		return (retval);
2790 	} else {
2791 		retval = socket_write(c_id->fd, buf, nbyte, &c_id->host_addr);
2792 		if (retval < 0) {
2793 			SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2794 			return (-1);
2795 		}
2796 		return (retval);
2797 	}
2798 }
2799 
2800 static int
2801 http_srv_recv(http_conn_t *c_id, void *buf, size_t nbyte)
2802 {
2803 	int	retval;
2804 
2805 	if (c_id->ssl != NULL) {
2806 		if ((retval = SSL_read(c_id->ssl, buf, nbyte)) <= 0) {
2807 			handle_ssl_error(c_id, retval);
2808 		}
2809 		return (retval);
2810 	} else {
2811 		retval = socket_read(c_id->fd, buf, nbyte, c_id->read_timeout);
2812 		if (retval < 0) {
2813 			SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2814 			return (-1);
2815 		}
2816 		return (retval);
2817 	}
2818 }
2819 
2820 static boolean_t
2821 http_check_conn(http_conn_t *c_id)
2822 {
2823 	early_err = 0;
2824 	if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) {
2825 		early_err = EHTTP_BADARG;
2826 		return (B_FALSE);
2827 	}
2828 	RESET_ERR(c_id);
2829 	return (B_TRUE);
2830 }
2831 
2832 static void
2833 handle_ssl_error(http_conn_t *c_id, int retval)
2834 {
2835 	ulong_t err;
2836 
2837 	err = SSL_get_error(c_id->ssl, retval);
2838 
2839 	switch (err) {
2840 	case SSL_ERROR_NONE:
2841 		return;
2842 
2843 	case SSL_ERROR_ZERO_RETURN:
2844 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_CONCLOSED);
2845 		return;
2846 
2847 	case SSL_ERROR_WANT_READ:
2848 	case SSL_ERROR_WANT_WRITE:
2849 	case SSL_ERROR_WANT_CONNECT:
2850 	case SSL_ERROR_WANT_X509_LOOKUP:
2851 		SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_UNEXPECTED);
2852 		return;
2853 
2854 	case SSL_ERROR_SYSCALL:
2855 		err = ERR_get_error();
2856 		if (err == 0)
2857 			SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_EOFERR);
2858 		else if (err == (ulong_t)-1)
2859 			SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2860 		else {
2861 			SET_ERR(c_id, ERRSRC_LIBSSL, err);
2862 			while ((err = ERR_get_error()) != 0)
2863 				SET_ERR(c_id, ERRSRC_LIBSSL, err);
2864 		}
2865 		return;
2866 
2867 	case SSL_ERROR_SSL:
2868 		while ((err = ERR_get_error()) != 0) {
2869 			SET_ERR(c_id, ERRSRC_LIBSSL, err);
2870 		}
2871 		return;
2872 	}
2873 }
2874 
2875 static int
2876 count_digits(int value)
2877 {
2878 	int	count = 1;
2879 
2880 	if (value < 0) {
2881 		count++;
2882 		value = -value;
2883 	}
2884 
2885 	while (value > 9) {
2886 		value /= 10;
2887 		count++;
2888 	}
2889 	return (count);
2890 }
2891 
2892 static int
2893 hexdigit(char ch)
2894 {
2895 	if (ch >= '0' && ch <= '9')
2896 		return (ch - '0');
2897 	if (ch >= 'A' && ch <= 'F')
2898 		return (ch - 'A' + 10);
2899 	if (ch >= 'a' && ch <= 'f')
2900 		return (ch - 'a' + 10);
2901 	return (-1);
2902 }
2903 
2904 static char *
2905 eat_ws(const char *buf)
2906 {
2907 	char *ptr = (char *)buf;
2908 
2909 	while (isspace(*ptr))
2910 		ptr++;
2911 
2912 	return (ptr);
2913 }
2914 
2915 static boolean_t
2916 startswith(const char **strp, const char *starts)
2917 {
2918 	int len = strlen(starts);
2919 
2920 	if (strncasecmp(*strp, starts, len) == 0) {
2921 		*strp += len;
2922 		return (B_TRUE);
2923 	}
2924 	return (B_FALSE);
2925 }
2926