Home | History | Annotate | Download | only in common
      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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/types.h>
     27 /* EXPORT DELETE START */
     28 #include <sys/promif.h>
     29 #include <sys/obpdefs.h>
     30 #include <sys/bootvfs.h>
     31 #include <sys/bootconf.h>
     32 #include <netinet/in.h>
     33 #include <sys/wanboot_impl.h>
     34 #include <boot_http.h>
     35 #include <aes.h>
     36 #include <des3.h>
     37 #include <cbc.h>
     38 #include <hmac_sha1.h>
     39 #include <sys/sha1.h>
     40 #include <sys/sha1_consts.h>
     41 #include <bootlog.h>
     42 #include <parseURL.h>
     43 #include <netboot_paths.h>
     44 #include <netinet/inetutil.h>
     45 #include <sys/salib.h>
     46 #include <inet/mac.h>
     47 #include <inet/ipv4.h>
     48 #include <dhcp_impl.h>
     49 #include <inet/dhcpv4.h>
     50 #include <bootinfo.h>
     51 #include <wanboot_conf.h>
     52 #include "boot_plat.h"
     53 #include "ramdisk.h"
     54 #include "wbcli.h"
     55 
     56 /*
     57  * Types of downloads
     58  */
     59 #define	MINIINFO	"miniinfo"
     60 #define	MINIROOT	"miniroot"
     61 #define	WANBOOTFS	"wanbootfs"
     62 
     63 #define	WANBOOT_RETRY_NOMAX	-1
     64 #define	WANBOOT_RETRY_ROOT_MAX	50
     65 #define	WANBOOT_RETRY_MAX	5
     66 #define	WANBOOT_RETRY_SECS	5
     67 #define	WANBOOT_RETRY_MAX_SECS	30
     68 
     69 /*
     70  * Our read requests should timeout after 25 seconds
     71  */
     72 #define	SOCKET_READ_TIMEOUT	25
     73 
     74 /*
     75  * Experimentation has shown that an 8K download buffer is optimal
     76  */
     77 #define	HTTP_XFER_SIZE		8192
     78 static char	buffer[HTTP_XFER_SIZE];
     79 
     80 bc_handle_t	bc_handle;
     81 
     82 extern int	determine_fstype_and_mountroot(char *);
     83 extern uint64_t	get_ticks(void);
     84 
     85 /*
     86  * The following is used to determine whether the certs and private key
     87  * files will be in PEM format or PKCS12 format.  'use_p12' is zero
     88  * to use PEM format, and 1 when PKCS12 format is to be used.  It is
     89  * done this way, as a global, so that it can be patched if needs be
     90  * using the OBP debugger.
     91  */
     92 uint32_t	use_p12 = 1;
     93 
     94 #define	CONTENT_LENGTH		"Content-Length"
     95 
     96 #define	NONCELEN	(2 * HMAC_DIGEST_LEN) /* two hex nibbles/byte */
     97 #define	WANBOOTFS_NONCE_FILE	"/nonce"
     98 
     99 static char nonce[NONCELEN + 1];
    100 
    101 enum URLtype {
    102 	URLtype_wanbootfs = 0,
    103 	URLtype_miniroot = 1
    104 };
    105 
    106 static char *URLtoCGIcontent[] = {
    107 	"bootfs",
    108 	"rootfs"
    109 };
    110 #define	CGIcontent(urltype)	URLtoCGIcontent[urltype]
    111 
    112 /* Encryption algorithms */
    113 typedef enum {
    114 	ENCR_NONE,
    115 	ENCR_3DES,
    116 	ENCR_AES
    117 } encr_type_t;
    118 
    119 /* Hash algorithms */
    120 typedef enum {
    121 	HASH_NONE,
    122 	HASH_HMAC_SHA1
    123 } hash_type_t;
    124 
    125 /*
    126  * Keys ...
    127  */
    128 static encr_type_t	encr_type = ENCR_NONE;
    129 static unsigned char	*g_encr_key = NULL;
    130 
    131 static hash_type_t	hash_type = HASH_NONE;
    132 static unsigned char	*g_hash_key = NULL;
    133 
    134 void
    135 print_errors(const char *func, http_handle_t handle)
    136 {
    137 	char const *msg;
    138 	ulong_t err;
    139 	uint_t src;
    140 
    141 	while ((err = http_get_lasterr(handle, &src)) != 0) {
    142 		msg = http_errorstr(src, err);
    143 		bootlog("wanboot", BOOTLOG_ALERT,
    144 		    "%s: errsrc %u, err %lu (0x%lx)", func, src, err, err);
    145 		bootlog("wanboot", BOOTLOG_ALERT, "%s", msg);
    146 	}
    147 }
    148 
    149 /*
    150  * This routine is called by a consumer to determine whether or not a
    151  * retry should be attempted. If a retry is in order (depends upon the
    152  * 'retry_cnt' and 'retry_max' arguments), then this routine will print a
    153  * message indicating this is the case and will determine an appropriate
    154  * "sleep" time before retrying. The "sleep" time will depend upon the
    155  * 'retry_cnt' and will max out at WANBOOT_RETRY_MAX_SECS.
    156  *
    157  * Returns:
    158  *	 B_TRUE  = retry is in order
    159  *	 B_FALSE = retry limit exceeded
    160  */
    161 boolean_t
    162 wanboot_retry(int retry_cnt, int retry_max)
    163 {
    164 	unsigned int seconds;
    165 
    166 	if (retry_max == WANBOOT_RETRY_NOMAX || retry_cnt <= retry_max) {
    167 		seconds = WANBOOT_RETRY_SECS * retry_cnt;
    168 		if (seconds > WANBOOT_RETRY_MAX_SECS) {
    169 			seconds = WANBOOT_RETRY_MAX_SECS;
    170 		}
    171 		bootlog("wanboot", BOOTLOG_INFO,
    172 		    "Will retry in %d seconds ...", seconds);
    173 		(void) sleep(seconds);
    174 		return (B_TRUE);
    175 	} else {
    176 		bootlog("wanboot", BOOTLOG_INFO,
    177 		    "Maximum retries exceeded.");
    178 		return (B_FALSE);
    179 	}
    180 }
    181 
    182 /*
    183  * Determine which encryption algorithm the client is configured to use.
    184  * WAN boot determines which key to use by order of priority.  That is
    185  * multiple encryption keys may exist in the PROM, but the first one found
    186  * (while searching in a preferred order) is the one that will be used.
    187  */
    188 static void
    189 init_encryption(void)
    190 {
    191 	static unsigned char	key[WANBOOT_MAXKEYLEN];
    192 	size_t			len = sizeof (key);
    193 
    194 	if (bootinfo_get(BI_AES_KEY, (char *)&key, &len, NULL) ==
    195 	    BI_E_SUCCESS) {
    196 		encr_type = ENCR_AES;
    197 		g_encr_key = key;
    198 	} else if (bootinfo_get(BI_3DES_KEY, (char *)&key, &len, NULL) ==
    199 	    BI_E_SUCCESS) {
    200 		encr_type = ENCR_3DES;
    201 		g_encr_key = key;
    202 	}
    203 }
    204 
    205 /*
    206  * Determine whether the client is configured to use hashing.
    207  */
    208 static void
    209 init_hashing(void)
    210 {
    211 	static unsigned char	key[WANBOOT_HMAC_KEY_SIZE];
    212 	size_t			len = sizeof (key);
    213 
    214 	if (bootinfo_get(BI_SHA1_KEY, (char *)&key, &len, NULL) ==
    215 	    BI_E_SUCCESS) {
    216 		hash_type = HASH_HMAC_SHA1;
    217 		g_hash_key = key;
    218 	}
    219 }
    220 
    221 /*
    222  * Read some CPU-specific rapidly-varying data (assumed to be of length
    223  * sizeof (hrtime_t) in the non-SPARC case), and digestify it to further
    224  * randomize the output.
    225  */
    226 char *
    227 generate_nonce(void)
    228 {
    229 	uint64_t	t;
    230 	SHA1_CTX	c;
    231 	unsigned char	digest[HMAC_DIGEST_LEN];
    232 	uint_t		nlen = sizeof (nonce);
    233 
    234 	int		err;
    235 
    236 	/*
    237 	 * Read SPARC %tick register or x86 TSC
    238 	 */
    239 	t = get_ticks();
    240 	SHA1Init(&c);
    241 	SHA1Update(&c, (const uint8_t *)&t, sizeof (t));
    242 	SHA1Final(digest, &c);
    243 
    244 	err = octet_to_hexascii(digest, sizeof (digest), nonce, &nlen);
    245 	if (err != 0) {
    246 		bootlog("wanboot", BOOTLOG_CRIT,
    247 		    "cannot convert nonce to ASCII: error %d", err);
    248 		return (NULL);
    249 	}
    250 	nonce[NONCELEN] = '\0';
    251 	return (nonce);
    252 }
    253 
    254 /*
    255  * Given a server URL, builds a URL to request one of the wanboot
    256  * datastreams.
    257  *
    258  * Returns:
    259  *	-1 = Non-recoverable error
    260  *	 0 = Success
    261  */
    262 static int
    263 build_request_url(url_t *req_url, enum URLtype ut, const url_t *server_url)
    264 {
    265 	char		clid[WB_MAX_CID_LEN];
    266 	size_t		clen;
    267 	char		wid[WB_MAX_CID_LEN * 2 + 1];
    268 	uint_t		wlen;
    269 	struct in_addr	ip;
    270 	struct in_addr	mask;
    271 	char		*netstr;
    272 	char		*ppath;
    273 	size_t		plen;
    274 	const char	reqstr[] = "/?CONTENT=%s&IP=%s&CID=%s";
    275 
    276 	/*
    277 	 * Initialize the request
    278 	 */
    279 	*req_url = *server_url;
    280 
    281 	/*
    282 	 * Build the network number string
    283 	 */
    284 	ipv4_getipaddr(&ip);
    285 	ipv4_getnetmask(&mask);
    286 	ip.s_addr = ip.s_addr & mask.s_addr;
    287 	netstr = inet_ntoa(ip);
    288 
    289 	/*
    290 	 * Get the wan id
    291 	 */
    292 	clen = sizeof (clid);
    293 	if (bootinfo_get(BI_CLIENT_ID, clid, &clen, NULL) != BI_E_SUCCESS) {
    294 		bootlog("wanboot", BOOTLOG_CRIT,
    295 		    "Cannot retrieve the client ID");
    296 		return (-1);
    297 	}
    298 	wlen = sizeof (wid);
    299 	(void) octet_to_hexascii(clid, clen, wid, &wlen);
    300 
    301 	/*
    302 	 * Build the request, making sure that the length of the
    303 	 * constructed URL falls within the supported maximum.
    304 	 */
    305 	plen = strlen(req_url->abspath);
    306 	ppath = req_url->abspath + plen;
    307 	if (snprintf(ppath, URL_MAX_PATHLEN - plen, reqstr,
    308 	    CGIcontent(ut), netstr, wid) >= URL_MAX_PATHLEN - plen) {
    309 		bootlog("wanboot", BOOTLOG_CRIT,
    310 		    "The URL path length of the %s request is greater than "
    311 		    "the maximum of %d", CGIcontent(ut), URL_MAX_PATHLEN);
    312 		return (-1);
    313 	}
    314 
    315 	/*
    316 	 * If the URL type requires a nonce, then supply it.
    317 	 * It will be returned in the reply to detect attempted
    318 	 * replays.
    319 	 */
    320 	if (ut == URLtype_wanbootfs) {
    321 		char	*n = generate_nonce();
    322 
    323 		if (n != NULL) {
    324 			plen += strlen("&NONCE=") + NONCELEN;
    325 			if (plen > URL_MAX_PATHLEN)
    326 				return (-1);
    327 			(void) strcat(req_url->abspath, "&NONCE=");
    328 			(void) strcat(req_url->abspath, n);
    329 		}
    330 	}
    331 
    332 	return (0);
    333 }
    334 
    335 /*
    336  * This routine reads data from an HTTP connection into a buffer.
    337  *
    338  * Returns:
    339  *	 0 = Success
    340  *	 1 = HTTP download error
    341  */
    342 static int
    343 read_bytes(http_handle_t handle, char *buffer, size_t cnt)
    344 {
    345 	int len;
    346 	size_t i;
    347 
    348 	for (i = 0; i < cnt; i += len) {
    349 		len = http_read_body(handle, &buffer[i], cnt - i);
    350 		if (len <= 0) {
    351 			print_errors("http_read_body", handle);
    352 			return (1);
    353 		}
    354 	}
    355 	return (0);
    356 }
    357 
    358 /*
    359  * This routine compares two hash digests, one computed by the server and
    360  * the other computed by the client to verify that a transmitted message
    361  * was received without corruption.
    362  *
    363  * Notes:
    364  *	The client only computes a digest if it is configured with a
    365  *	hash key. If it is not, then the server should not have a hash
    366  *	key for the client either and therefore should have sent a
    367  *	zero filled digest.
    368  *
    369  * Returns:
    370  *	 B_TRUE  = digest was verified
    371  *	 B_FALSE = digest did not verify
    372  */
    373 static boolean_t
    374 verify_digests(const char *what, unsigned char *cdigest, unsigned char *sdigest)
    375 {
    376 	static char	null_digest[HMAC_DIGEST_LEN];
    377 
    378 	if (bcmp(sdigest, cdigest, HMAC_DIGEST_LEN) != 0) {
    379 		bootlog("wanboot", BOOTLOG_CRIT,
    380 		    "%s: invalid hash digest", what);
    381 		bootlog("wanboot", BOOTLOG_CRIT,
    382 		    "This may signify a client/server key mismatch");
    383 		if (bcmp(sdigest, null_digest, HMAC_DIGEST_LEN) == 0) {
    384 			bootlog("wanboot", BOOTLOG_CRIT,
    385 			    "(client has key but wrong signature_type?)");
    386 		} else if (bcmp(cdigest, null_digest, HMAC_DIGEST_LEN) == 0) {
    387 			bootlog("wanboot", BOOTLOG_CRIT,
    388 			    "(signature_type specified but no client key?)");
    389 		}
    390 		bootlog("wanboot", BOOTLOG_CRIT,
    391 		    "or possible corruption of the image in transit");
    392 		return (B_FALSE);
    393 	}
    394 
    395 	return (B_TRUE);
    396 }
    397 
    398 /*
    399  * This routine reads the part of a multipart message that contains a
    400  * hash digest. Errors in reading the digest are differentiated from
    401  * other kinds of errors so that the caller can decide whether or
    402  * not a retry is worthwhile.
    403  *
    404  * Note:
    405  *	The hash digest can either be an HMAC digest or it can be
    406  *	a zero length message (representing no hash digest).
    407  *
    408  * Returns:
    409  *	-1 = Non-recoverable error
    410  *	 0 = Success
    411  *	 1 = HTTP download error
    412  */
    413 static int
    414 read_digest(const char *what, http_handle_t handle, unsigned char *sdigest)
    415 {
    416 	char *lenstr;
    417 	size_t digest_size;
    418 
    419 	/*
    420 	 * Process the HMAC digest header.
    421 	 */
    422 	if (http_process_part_headers(handle, NULL) != 0) {
    423 		print_errors("http_process_part_headers", handle);
    424 		return (1);
    425 	}
    426 	lenstr = http_get_header_value(handle, CONTENT_LENGTH);
    427 	if (lenstr == NULL) {
    428 		bootlog("wanboot", BOOTLOG_ALERT,
    429 		    "%s: error getting digest length", what);
    430 		return (1);
    431 	}
    432 	digest_size = (size_t)strtol(lenstr, NULL, 10);
    433 	free(lenstr);
    434 
    435 	/*
    436 	 * Validate the HMAC digest length.
    437 	 */
    438 	if (digest_size != HMAC_DIGEST_LEN) {
    439 		bootlog("wanboot", BOOTLOG_CRIT,
    440 		    "%s: error validating response - invalid digest size",
    441 		    what);
    442 		return (-1);
    443 	}
    444 
    445 	/*
    446 	 * Read the HMAC digest.
    447 	 */
    448 	if (read_bytes(handle, (char *)sdigest, digest_size) != 0) {
    449 		bootlog("wanboot", BOOTLOG_ALERT,
    450 		    "%s: error reading digest", what);
    451 		return (1);
    452 	}
    453 
    454 	return (0);
    455 }
    456 
    457 /*
    458  * This routine reads data from an HTTP connection and writes the data
    459  * to a ramdisk. It also, optionally computes a hash digest of the processed
    460  * data. This routine may be called to continue writing a previously aborted
    461  * write. If this is the case, then the offset will be non-zero and the write
    462  * pointer into the ramdisk will be positioned correctly by the caller.
    463  *
    464  * Returns:
    465  *	-1 = Non-recoverable error
    466  *	 0 = Success
    467  *	 1 = HTTP download error
    468  */
    469 static int
    470 write_msg_to_ramdisk(const char *what, caddr_t addr, http_handle_t handle,
    471     size_t ramdisk_size, off_t *offset, SHA1_CTX *sha)
    472 {
    473 	int len;
    474 	long nleft;
    475 	static int bootlog_message_interval;
    476 	static int bootlog_progress;
    477 	int ret;
    478 
    479 	/*
    480 	 * Read the data and write it to the ramdisk.
    481 	 */
    482 	if (*offset == 0) {
    483 		bootlog_progress = 0;
    484 		bootlog_message_interval = ramdisk_size / sizeof (buffer);
    485 		if (bootlog_message_interval < 500)
    486 			bootlog_message_interval /= 5;
    487 		else
    488 			bootlog_message_interval /= 50;
    489 
    490 		bootlog("wanboot", BOOTLOG_VERBOSE,
    491 		    "Reading %s file system (%ld kB)",
    492 		    what, ramdisk_size / 1024);
    493 	} else {
    494 		bootlog("wanboot", BOOTLOG_VERBOSE,
    495 		    "Continuing read of %s file system (%ld kB)",
    496 		    what, ramdisk_size / 1024);
    497 	}
    498 	for (ret = 0; ret == 0 && *offset < ramdisk_size;
    499 	    *offset += len, addr += len) {
    500 		nleft = ramdisk_size - *offset;
    501 
    502 		if (nleft > sizeof (buffer))
    503 			nleft = sizeof (buffer);
    504 
    505 		len = http_read_body(handle, addr, nleft);
    506 		if (len <= 0) {
    507 			print_errors("http_read_body", handle);
    508 			/*
    509 			 * In the case of a partial failure, http_read_body()
    510 			 * returns into 'len', 1 - the number of bytes read.
    511 			 * So, a -65 means 64 bytes read and an error occurred.
    512 			 */
    513 			if (len != 0) {
    514 				len = -(len + 1);
    515 			}
    516 			ret = 1;
    517 		}
    518 		if (sha != NULL) {
    519 			HMACUpdate(sha, (uchar_t *)addr, (size_t)len);
    520 		}
    521 		if (bootlog_progress == bootlog_message_interval) {
    522 			bootlog("wanboot", BOOTLOG_PROGRESS,
    523 			    "%s: Read %ld of %ld kB (%ld%%)", what,
    524 			    *offset / 1024, ramdisk_size / 1024,
    525 			    *offset * 100 / ramdisk_size);
    526 			bootlog_progress = 0;
    527 		} else {
    528 			bootlog_progress++;
    529 		}
    530 	}
    531 	if (ret == 0) {
    532 		bootlog("wanboot", BOOTLOG_PROGRESS,
    533 		    "%s: Read %ld of %ld kB (%ld%%)", what,
    534 		    *offset / 1024, ramdisk_size / 1024,
    535 		    *offset * 100 / ramdisk_size);
    536 		bootlog("wanboot", BOOTLOG_INFO, "%s: Download complete", what);
    537 	}
    538 	return (ret);
    539 }
    540 
    541 /*
    542  * This routine is called with a bootinfo parameter name.  If the parameter
    543  * has a value it should be a URL, and this will be used to initialize the
    544  * http_url structure.
    545  *
    546  * Returns:
    547  *	-1 = Non-recoverable error
    548  *	 0 = Success
    549  *	 1 = DHCP option not set
    550  */
    551 static int
    552 get_url(char *name, url_t *url)
    553 {
    554 	char	buf[URL_MAX_STRLEN];
    555 	size_t	len;
    556 	int	ret;
    557 
    558 	bzero(buf, sizeof (buf));
    559 	len = sizeof (buf) - 1;
    560 	if (bootinfo_get(name, buf, &len, NULL) != BI_E_SUCCESS || len == 0) {
    561 		return (1);
    562 	}
    563 
    564 	/*
    565 	 * Parse the URL.
    566 	 */
    567 	ret = url_parse(buf, url);
    568 	if (ret != URL_PARSE_SUCCESS) {
    569 		bootlog("wanboot", BOOTLOG_CRIT,
    570 		    "Unable to parse URL %s", buf);
    571 		return (-1);
    572 	}
    573 
    574 	return (0);
    575 }
    576 
    577 /*
    578  * This routine initiates an HTTP request and returns a handle so that
    579  * the caller can process the response.
    580  *
    581  * Notes:
    582  *	Requests may be either secure or not. If the request is secure, then
    583  *	this routine assumes that a wanboot file system exists and
    584  *	uses its contents to provide the HTTP library with the information
    585  *	that will be required by SSL.
    586  *
    587  *	In order to facilitate transmission retries, this routine supports
    588  *	range requests. A caller may request a range by providing a non-zero
    589  *	offset. In which case, a range request is made that ranges from the
    590  *	offet to the end of the file.
    591  *
    592  *	If the client is configured to use an HTTP proxy, then this routine
    593  *	will make the HTTP library aware of the proxy.
    594  *
    595  *	Any HTTP errors encountered in downloading or processing the message
    596  *	are not deemed unrecoverable errors. The caller can simply try the
    597  *	request once again.
    598  *
    599  * Returns:
    600  *	-1 = Non-recoverable error
    601  *	 0 = Success
    602  *	 1 = HTTP download error
    603  */
    604 static int
    605 establish_http_connection(const char *what, http_handle_t *handlep,
    606     url_t *url, offset_t offset)
    607 {
    608 	static boolean_t	is_auth_file_init = B_FALSE;
    609 	static boolean_t	is_proxy_init = B_FALSE;
    610 	static boolean_t	proxy_exists = B_FALSE;
    611 	static url_hport_t	proxy_hp;
    612 	http_respinfo_t		*resp;
    613 	char			buf[URL_MAX_STRLEN];
    614 	size_t			len = sizeof (buf) - 1;
    615 	int			ret;
    616 
    617 	/* Check for HTTP proxy */
    618 	if (!is_proxy_init &&
    619 	    bootinfo_get(BI_HTTP_PROXY, buf, &len, NULL) == BI_E_SUCCESS &&
    620 	    strlen(buf) > 0) {
    621 		/*
    622 		 * Parse the hostport.
    623 		 */
    624 		ret = url_parse_hostport(buf, &proxy_hp, URL_DFLT_PROXY_PORT);
    625 		if (ret == URL_PARSE_SUCCESS) {
    626 			proxy_exists = B_TRUE;
    627 		} else {
    628 			bootlog("wanboot", BOOTLOG_CRIT,
    629 			    "%s is not set to a valid hostport value",
    630 			    BI_HTTP_PROXY);
    631 			return (-1);
    632 		}
    633 		is_proxy_init = B_TRUE;
    634 	}
    635 
    636 	http_set_p12_format(use_p12);
    637 
    638 	/*
    639 	 * Initialize the handle that will be used for the request.
    640 	 */
    641 	*handlep = http_srv_init(url);
    642 	if (*handlep == NULL) {
    643 		print_errors("http_srv_init", NULL);
    644 		return (-1);
    645 	}
    646 
    647 	/*
    648 	 * Is the request a secure one? If it is, then we need to do further
    649 	 * setup. Search the wanboot file system for files that will be
    650 	 * needed by SSL.
    651 	 */
    652 	if (url->https) {
    653 		char		*cas;
    654 		boolean_t	client_authentication = B_FALSE;
    655 
    656 		if (http_set_random_file(*handlep, "/dev/urandom") < 0) {
    657 			print_errors("http_set_random_file", *handlep);
    658 			(void) http_srv_close(*handlep);
    659 			return (-1);
    660 		}
    661 
    662 		/*
    663 		 * We only need to initialize the CA once as it is not handle
    664 		 * specific.
    665 		 */
    666 		if (!is_auth_file_init) {
    667 			if (http_set_certificate_authority_file(NB_CA_CERT_PATH)
    668 			    < 0) {
    669 				print_errors(
    670 				    "http_set_certificate_authority_file",
    671 				    *handlep);
    672 				(void) http_srv_close(*handlep);
    673 				return (-1);
    674 			}
    675 
    676 			is_auth_file_init = B_TRUE;
    677 		}
    678 
    679 		/*
    680 		 * The client certificate and key will not exist unless
    681 		 * client authentication has been configured. If it is
    682 		 * configured then the webserver will have added these
    683 		 * files to the wanboot file system and the HTTP library
    684 		 * needs to be made aware of their existence.
    685 		 */
    686 		if ((cas = bootconf_get(&bc_handle,
    687 		    BC_CLIENT_AUTHENTICATION)) != NULL &&
    688 		    strcmp(cas, "yes") == 0) {
    689 			client_authentication = B_TRUE;
    690 
    691 			if (http_set_client_certificate_file(*handlep,
    692 			    NB_CLIENT_CERT_PATH) < 0) {
    693 				print_errors("http_set_client_certificate_file",
    694 				    *handlep);
    695 				(void) http_srv_close(*handlep);
    696 				return (-1);
    697 			}
    698 
    699 			if (http_set_private_key_file(*handlep,
    700 			    NB_CLIENT_KEY_PATH) < 0) {
    701 				print_errors("http_set_private_key_file",
    702 				    *handlep);
    703 				(void) http_srv_close(*handlep);
    704 				return (-1);
    705 			}
    706 		}
    707 
    708 		/*
    709 		 * We do not really need to set this unless client
    710 		 * authentication is configured or unless pkcs12 files
    711 		 * are used.
    712 		 */
    713 		if ((client_authentication || use_p12) &&
    714 		    http_set_password(*handlep, WANBOOT_PASSPHRASE) < 0) {
    715 			print_errors("http_set_password", *handlep);
    716 			(void) http_srv_close(*handlep);
    717 			return (-1);
    718 		}
    719 	}
    720 
    721 	/*
    722 	 * If the client is using a proxy, tell the library.
    723 	 */
    724 	if (proxy_exists) {
    725 		if (http_set_proxy(*handlep, &proxy_hp) != 0) {
    726 			print_errors("http_set_proxy", *handlep);
    727 			(void) http_srv_close(*handlep);
    728 			return (-1);
    729 		}
    730 	}
    731 
    732 	(void) http_set_socket_read_timeout(*handlep, SOCKET_READ_TIMEOUT);
    733 
    734 	/*
    735 	 * Ok, connect to the webserver.
    736 	 */
    737 	if (http_srv_connect(*handlep) == -1) {
    738 		print_errors("http_srv_connect", *handlep);
    739 		(void) http_srv_close(*handlep);
    740 		return (1);
    741 	}
    742 
    743 	/*
    744 	 * If the offset is 0, then we assume that we want the entire
    745 	 * message. If the offset is not 0, then we assume that we are
    746 	 * retrying a previously interrupted transfer and thus we make
    747 	 * a range request.
    748 	 */
    749 	if (offset == 0) {
    750 		if ((ret = http_get_request(*handlep, url->abspath)) == 0) {
    751 			bootlog("wanboot", BOOTLOG_VERBOSE,
    752 			    "%s: http_get_request: sent", what);
    753 		} else {
    754 			print_errors("http_get_request", *handlep);
    755 			(void) http_srv_close(*handlep);
    756 			return (1);
    757 		}
    758 	} else {
    759 		if ((ret = http_get_range_request(*handlep, url->abspath,
    760 		    offset, 0)) == 0) {
    761 			bootlog("wanboot", BOOTLOG_VERBOSE,
    762 			    "%s: http_get_range_request: sent", what);
    763 		} else {
    764 			print_errors("http_get_range_request", *handlep);
    765 			(void) http_srv_close(*handlep);
    766 			return (1);
    767 		}
    768 	}
    769 
    770 	/*
    771 	 * Tell the library to read in the response headers.
    772 	 */
    773 	ret = http_process_headers(*handlep, &resp);
    774 	if (ret == -1) {
    775 		print_errors("http_process_headers", *handlep);
    776 		(void) http_srv_close(*handlep);
    777 		return (1);
    778 	}
    779 
    780 	/*
    781 	 * Check for a valid response code.
    782 	 */
    783 	if ((offset == 0 && resp->code != 200) ||
    784 	    (offset != 0 && resp->code != 206)) {
    785 		bootlog("wanboot", BOOTLOG_ALERT,
    786 		    "%s: Request returned code %d", what, resp->code);
    787 		if (resp->statusmsg != NULL && resp->statusmsg[0] != '\0')
    788 			bootlog("wanboot", BOOTLOG_ALERT,
    789 			    "%s", resp->statusmsg);
    790 		http_free_respinfo(resp);
    791 		(void) http_srv_close(*handlep);
    792 		return (1);
    793 	}
    794 	http_free_respinfo(resp);
    795 
    796 	/*
    797 	 * Success.
    798 	 */
    799 	return (0);
    800 }
    801 
    802 /*
    803  * This routine is called by get_miniinfo() to receive the reply
    804  * to the request for the miniroot metadata. The reply is a two
    805  * part multipart message. The first part of the message contains
    806  * the miniroot file size. The second part of the message contains
    807  * a hash digest of the miniroot as computed by the server. This
    808  * routine receives both message parts and returns them to the caller.
    809  *
    810  * Notes:
    811  *	If the miniroot is going to be downloaded securely or if the
    812  *	the server has no hash key for the client, then the hash digest
    813  *	downloaded contains all zeros.
    814  *
    815  *	Any HTTP errors encountered in downloading or processing the message
    816  *	are not deemed unrecoverable errors. That is, get_miniinfo()
    817  *	tries re-requesting the message and tries processing it again.
    818  *
    819  * Returns:
    820  *	-1 = Non-recoverable error
    821  *	 0 = Success
    822  *	 1 = HTTP download error
    823  */
    824 static int
    825 process_miniinfo(http_handle_t handle, size_t *mini_size,
    826     unsigned char *sdigest)
    827 {
    828 	char	*lenstr;
    829 	size_t	cnt;
    830 
    831 	/*
    832 	 * Process the file size header.
    833 	 */
    834 	if (http_process_part_headers(handle, NULL) != 0) {
    835 		print_errors("http_process_part_headers", handle);
    836 		return (1);
    837 	}
    838 	lenstr = http_get_header_value(handle, CONTENT_LENGTH);
    839 	if (lenstr == NULL) {
    840 		bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length "
    841 		    "of first part of multipart message", MINIINFO);
    842 		return (1);
    843 	}
    844 	cnt = (size_t)strtol(lenstr, NULL, 10);
    845 	free(lenstr);
    846 	if (cnt == 0 || cnt >= sizeof (buffer)) {
    847 		bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part "
    848 		    "of multipart message not a legal size", MINIINFO);
    849 		return (1);
    850 	}
    851 
    852 	if (read_bytes(handle, buffer, cnt) != 0) {
    853 		bootlog("wanboot", BOOTLOG_ALERT,
    854 		    "%s: error reading miniroot size", MINIINFO);
    855 		return (1);
    856 	}
    857 	buffer[cnt] = '\0';
    858 
    859 	*mini_size = (size_t)strtol(buffer, NULL, 10);
    860 	if (*mini_size == 0) {
    861 		bootlog("wanboot", BOOTLOG_ALERT, "%s: body of first part "
    862 		    "of multipart message not a legal size", MINIINFO);
    863 		return (1);
    864 	}
    865 
    866 	return (read_digest(MINIINFO, handle, sdigest));
    867 }
    868 
    869 /*
    870  * This routine is called by get_miniroot() to retrieve the miniroot
    871  * metadata (miniroot size and a hash digest). This routine sends an
    872  * HTTP GET request to the webserver to request the download of the
    873  * miniroot metadata and relies on process_miniinfo() to receive the
    874  * reply, process it and ultimately return to it the miniroot size and
    875  * the hash digest.
    876  *
    877  * Note:
    878  *	Any HTTP errors encountered in downloading or processing the message
    879  *	are not deemed unrecoverable errors. That is, get_miniinfo() should
    880  *	try re-requesting the message and try processing again.
    881  *
    882  * Returns:
    883  *	-1 = Non-recoverable error
    884  *	 0 = Success
    885  */
    886 int
    887 get_miniinfo(const url_t *server_url, size_t *mini_size,
    888     unsigned char *sdigest)
    889 {
    890 	http_handle_t	handle;
    891 	url_t		req_url;
    892 	int		retry_cnt = 0;
    893 	int		retry_max = WANBOOT_RETRY_MAX;
    894 	int		ret;
    895 
    896 	/*
    897 	 * Build the URL to request the miniroot info.
    898 	 */
    899 	if (build_request_url(&req_url, URLtype_miniroot, server_url) == -1) {
    900 		bootlog("wanboot", BOOTLOG_CRIT,
    901 		    "Can't build the URL to make the %s request",
    902 		    CGIcontent(URLtype_miniroot));
    903 		return (-1);
    904 	}
    905 
    906 	/*
    907 	 * Go get the miniroot info. If we fail reading the
    908 	 * response we re-request the info in its entirety.
    909 	 */
    910 	bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot info");
    911 
    912 	do {
    913 		if ((ret = establish_http_connection(MINIINFO, &handle,
    914 		    &req_url, 0)) < 0) {
    915 			break;
    916 		} else if (ret > 0) {
    917 			if (wanboot_retry(++retry_cnt, retry_max)) {
    918 				continue;
    919 			} else {
    920 				break;
    921 			}
    922 		}
    923 
    924 		if ((ret = process_miniinfo(handle, mini_size,
    925 		    sdigest)) > 0) {
    926 			if (!wanboot_retry(++retry_cnt, retry_max)) {
    927 				(void) http_srv_close(handle);
    928 				break;
    929 			}
    930 		}
    931 
    932 		(void) http_srv_close(handle);
    933 
    934 	} while (ret > 0);
    935 
    936 	/*
    937 	 * Success.
    938 	 */
    939 	if (ret == 0) {
    940 		bootlog("wanboot", BOOTLOG_VERBOSE,
    941 		    "Miniroot info download successful");
    942 		return (0);
    943 	} else {
    944 		bootlog("wanboot", BOOTLOG_CRIT,
    945 		    "Miniroot info download aborted");
    946 		return (-1);
    947 	}
    948 }
    949 
    950 /*
    951  * This routine is called by get_miniroot() to receive the reply to
    952  * the request for the miniroot download. The miniroot is written
    953  * to ramdisk as it is received and a hash digest is optionally computed
    954  * as it does so. The miniroot is downloaded as one large message.
    955  * Because the message is so large, this routine is prepared to deal
    956  * with errors in the middle of download. If an error occurs during
    957  * download, then this message processes all received data up to the
    958  * point of the error and returns to get_miniroot() an error signifying
    959  * that a download error has occurred. Presumably, get_miniroot()
    960  * re-requests the remaining part of the miniroot not yet processed and
    961  * calls this routine back to process the reply. When this routine
    962  * returns succesfully, it returns a devpath to the ramdisk and the
    963  * computed hash (if computed).
    964  *
    965  * Note:
    966  *	In order to facilitate reentry, the ramdisk is left open
    967  *	and the original miniroot_size and HMAC handle are kept
    968  *	static.
    969  *
    970  * Returns:
    971  *	-1 = Non-recoverable error
    972  *	 0 = Success
    973  *	 1 = HTTP download error
    974  */
    975 static int
    976 process_miniroot(http_handle_t handle, hash_type_t htype,
    977     size_t length, char **devpath, off_t *offset, unsigned char *cdigest)
    978 {
    979 	static SHA1_CTX	sha;
    980 	static size_t	miniroot_size;
    981 	static caddr_t	miniroot_vaddr = NULL;
    982 	int		ret;
    983 
    984 	if (miniroot_vaddr == NULL) {
    985 		if (htype == HASH_HMAC_SHA1) {
    986 			bootlog("wanboot", BOOTLOG_INFO,
    987 			    "%s: Authentication will use HMAC-SHA1", MINIROOT);
    988 			HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE);
    989 		}
    990 
    991 		miniroot_size = length;
    992 
    993 		miniroot_vaddr = create_ramdisk(RD_ROOTFS, miniroot_size,
    994 		    devpath);
    995 	}
    996 
    997 	miniroot_vaddr += *offset;
    998 
    999 	if ((ret = write_msg_to_ramdisk(MINIROOT, miniroot_vaddr, handle,
   1000 	    miniroot_size, offset, (htype == HASH_NONE) ? NULL : &sha)) != 0) {
   1001 		return (ret);
   1002 	}
   1003 
   1004 	if (htype != HASH_NONE) {
   1005 		HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest);
   1006 	}
   1007 
   1008 	return (0);
   1009 }
   1010 
   1011 /*
   1012  * This routine retrieves the miniroot from the webserver. The miniroot
   1013  * is retrieved in two steps. First a request is made to the server
   1014  * to retrieve miniroot metadata (miniroot size and a hash digest).
   1015  * The second request actually results in the download of the miniroot.
   1016  *
   1017  * This routine relies on get_miniinfo() to make and process
   1018  * the request for the miniroot metadata and returns the
   1019  * miniroot size and the hash digest of the miniroot as computed by
   1020  * the server.
   1021  *
   1022  * If get_miniinfo() returns successfully, then this routine sends
   1023  * an HTTP GET request to the webserver to request download of the
   1024  * miniroot. This routine relies on process_miniroot() to receive
   1025  * the reply, process it and ultimately return to it a device path to
   1026  * a ramdisk containing the miniroot and a client computed hash digest.
   1027  * This routine verifies that the client computed hash digest matches
   1028  * the one retrieved by get_miniinfo().
   1029  *
   1030  * If an error occurs in the transfer of the miniroot from the server
   1031  * to the client, then the client re-requests the download of the
   1032  * miniroot using a range request and only requests the part of the
   1033  * miniroot not previously downloaded and written to ramdisk. The
   1034  * process_miniroot() routine has the intelligence to recognize that
   1035  * it is processing a range request. Errors not related to the actual
   1036  * message download are deemed unrecoverable.
   1037  *
   1038  * Note:
   1039  *	If the client request for the miniroot is a secure request or
   1040  *	if the server is not configured with a hash key for the client,
   1041  *	then the hash digest downloaded from the server will contain
   1042  *	all zeros. This routine verifies that the server and client are
   1043  *	in-sync with respect to the need for hash verification.
   1044  *
   1045  * Returns:
   1046  *	-1 = Non-recoverable error
   1047  *	 0 = Success
   1048  */
   1049 int
   1050 get_miniroot(char **devpath)
   1051 {
   1052 	http_handle_t	handle;
   1053 	unsigned char	cdigest[HMAC_DIGEST_LEN];
   1054 	unsigned char	sdigest[HMAC_DIGEST_LEN];
   1055 	char		*urlstr;
   1056 	url_t		server_url;
   1057 	size_t		mini_size;
   1058 	off_t		offset;
   1059 	int		plen;
   1060 	int		retry_cnt = 0;
   1061 	int		retry_max = WANBOOT_RETRY_ROOT_MAX;
   1062 	int		ret;
   1063 
   1064 	/*
   1065 	 * Get the miniroot URL.
   1066 	 */
   1067 	if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_SERVER)) == NULL) {
   1068 		bootlog("wanboot", BOOTLOG_CRIT,
   1069 		    "Missing root_server URL");
   1070 		return (-1);
   1071 	} else if (url_parse(urlstr, &server_url) != URL_PARSE_SUCCESS) {
   1072 		bootlog("wanboot", BOOTLOG_CRIT,
   1073 		    "Unable to parse URL %s", urlstr);
   1074 		return (-1);
   1075 	}
   1076 
   1077 	/*
   1078 	 * We must get the miniroot info before we can request
   1079 	 * the miniroot itself.
   1080 	 */
   1081 	if (get_miniinfo(&server_url, &mini_size, sdigest) != 0) {
   1082 		return (-1);
   1083 	}
   1084 
   1085 	plen = sizeof (server_url.abspath);
   1086 	if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_FILE)) == NULL ||
   1087 	    strlcpy(server_url.abspath, urlstr, plen) >= plen) {
   1088 		bootlog("wanboot", BOOTLOG_CRIT,
   1089 		    "Cannot retrieve the miniroot path");
   1090 		return (-1);
   1091 	}
   1092 
   1093 	/*
   1094 	 * Go get the miniroot. If we fail reading the response
   1095 	 * then we re-request only the range we have yet to read,
   1096 	 * unless the error was "unrecoverable" in which case we
   1097 	 * re-request the entire file system.
   1098 	 */
   1099 	bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot");
   1100 
   1101 	bzero(cdigest, sizeof (cdigest));
   1102 	offset = 0;
   1103 	do {
   1104 		if ((ret = establish_http_connection(MINIROOT, &handle,
   1105 		    &server_url, offset)) < 0) {
   1106 			break;
   1107 		} else if (ret > 0) {
   1108 			if (wanboot_retry(++retry_cnt, retry_max)) {
   1109 				continue;
   1110 			} else {
   1111 				break;
   1112 			}
   1113 		}
   1114 
   1115 		if ((ret = process_miniroot(handle,
   1116 		    server_url.https ? HASH_NONE : hash_type,
   1117 		    mini_size, devpath, &offset, cdigest)) > 0) {
   1118 			if (!wanboot_retry(++retry_cnt, retry_max)) {
   1119 				(void) http_srv_close(handle);
   1120 				break;
   1121 			}
   1122 		}
   1123 
   1124 		(void) http_srv_close(handle);
   1125 
   1126 	} while (ret > 0);
   1127 
   1128 	/*
   1129 	 * Validate the computed digest against the one received.
   1130 	 */
   1131 	if (ret != 0 || !verify_digests(MINIROOT, cdigest, sdigest)) {
   1132 		bootlog("wanboot", BOOTLOG_CRIT,
   1133 		    "Miniroot download aborted");
   1134 		return (-1);
   1135 	}
   1136 
   1137 	bootlog("wanboot", BOOTLOG_VERBOSE, "Miniroot download successful");
   1138 	return (0);
   1139 }
   1140 
   1141 /*
   1142  * This routine is called to finish the decryption process.
   1143  * Its purpose is to free the resources allocated by the
   1144  * encryption init routines.
   1145  */
   1146 static void
   1147 encr_fini(encr_type_t etype, void *eh)
   1148 {
   1149 	switch (etype) {
   1150 	case ENCR_3DES:
   1151 		des3_fini(eh);
   1152 		break;
   1153 	case ENCR_AES:
   1154 		aes_fini(eh);
   1155 		break;
   1156 	default:
   1157 		break;
   1158 	}
   1159 }
   1160 
   1161 /*
   1162  * This routine is called by process_wanbootfs() to decrypt the encrypted
   1163  * file system from ramdisk in place.  The method of decryption
   1164  * (algorithm) will have already been determined by process_wanbootfs()
   1165  * and the cbc_handle passed to this routine will already have been
   1166  * initialized appropriately.
   1167  *
   1168  * Returns:
   1169  *	-1 = Non-recoverable error
   1170  *	 0 = Success
   1171  */
   1172 static int
   1173 decrypt_wanbootfs(caddr_t addr, cbc_handle_t *ch, uint8_t *iv,
   1174     size_t wanbootfs_size)
   1175 {
   1176 	if (!cbc_decrypt(ch, (uint8_t *)addr, wanbootfs_size, iv)) {
   1177 		bootlog("wanboot", BOOTLOG_CRIT,
   1178 		    "%s: cbc decrypt error", WANBOOTFS);
   1179 		return (-1);
   1180 	}
   1181 	return (0);
   1182 }
   1183 
   1184 /*
   1185  * This routine is called by get_wanbootfs() to receive the reply to
   1186  * the request for the wanboot file system. The reply is a multipart message.
   1187  * The first part of the message is the file system (which may or may
   1188  * not be encrypted).  If encrypted, then the first block of the message
   1189  * part is the CBC IV value used by the server to encrypt the remaining
   1190  * part of the message part and is used by the client to decrypt it. The
   1191  * second message part is a hash digest of the first part (the file
   1192  * system) as computed by the server. If no hash key is configured
   1193  * for the client, then the hash digest simply contains all zeros. This
   1194  * routine receives both message parts. The file system is written to ramdisk
   1195  * as it is received and simultaneously computes a hash digest (if a hash
   1196  * key exists). Once the entire part is received, if the file system is
   1197  * encrypted, it is read from ramdisk, decrypted and rewritten back to
   1198  * ramdisk. The server computed hash digest is then read and along with the
   1199  * ramdisk device path and the client computed hash digest is returned to the
   1200  * caller.
   1201  *
   1202  * Notes:
   1203  *	In order to decrypt the file system and to compute the client
   1204  *	hash digest, an encryption key and a hash key is retrieved from
   1205  *	the PROM (or the wanboot interpreter). The non-existence of these
   1206  *	keys has implications on how the message response is processed and
   1207  *	it is assumed that the server is configured identically.
   1208  *
   1209  *	Any HTTP errors encountered in downloading or processing the message
   1210  *	are not deemed unrecoverable errors. That is, get_wanbootfs() will
   1211  *	try re-requesting the message and will try processing it again.
   1212  *
   1213  * Returns:
   1214  *	-1 = Non-recoverable error
   1215  *	 0 = Success
   1216  *	 1 = HTTP download error
   1217  */
   1218 static int
   1219 process_wanbootfs(http_handle_t handle, char **devpath,
   1220     unsigned char *cdigest, unsigned char *sdigest)
   1221 {
   1222 	/* iv[] must be sized to store the largest possible encryption block */
   1223 	uint8_t		iv[WANBOOT_MAXBLOCKLEN];
   1224 	cbc_handle_t	ch;
   1225 	void		*eh;
   1226 	SHA1_CTX	sha;
   1227 	char		*lenstr;
   1228 	size_t		wanbootfs_size;
   1229 	size_t		block_size;
   1230 	off_t		offset;
   1231 	static caddr_t	bootfs_vaddr = NULL;
   1232 	int		ret;
   1233 
   1234 	switch (hash_type) {
   1235 	case HASH_HMAC_SHA1:
   1236 		bootlog("wanboot", BOOTLOG_INFO,
   1237 		    "%s: Authentication will use HMAC-SHA1", WANBOOTFS);
   1238 		HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE);
   1239 		break;
   1240 	case HASH_NONE:
   1241 		break;
   1242 	default:
   1243 		bootlog("wanboot", BOOTLOG_CRIT,
   1244 		    "%s: unrecognized hash type", WANBOOTFS);
   1245 		return (-1);
   1246 	}
   1247 
   1248 	switch (encr_type) {
   1249 	case ENCR_3DES:
   1250 		bootlog("wanboot",
   1251 		    BOOTLOG_INFO, "%s: Decryption will use 3DES", WANBOOTFS);
   1252 		if (des3_init(&eh) != 0) {
   1253 			return (-1);
   1254 		}
   1255 		block_size = DES3_BLOCK_SIZE;
   1256 		des3_key(eh, g_encr_key);
   1257 		cbc_makehandle(&ch, eh, DES3_KEY_SIZE, block_size,
   1258 		    DES3_IV_SIZE, des3_encrypt, des3_decrypt);
   1259 
   1260 		break;
   1261 	case ENCR_AES:
   1262 		bootlog("wanboot",
   1263 		    BOOTLOG_INFO, "%s: Decryption will use AES", WANBOOTFS);
   1264 		if (aes_init(&eh) != 0) {
   1265 			return (-1);
   1266 		}
   1267 		block_size = AES_BLOCK_SIZE;
   1268 		aes_key(eh, g_encr_key, AES_128_KEY_SIZE);
   1269 		cbc_makehandle(&ch, eh, AES_128_KEY_SIZE, block_size,
   1270 		    AES_IV_SIZE, aes_encrypt, aes_decrypt);
   1271 		break;
   1272 	case ENCR_NONE:
   1273 		break;
   1274 	default:
   1275 		bootlog("wanboot", BOOTLOG_CRIT,
   1276 		    "%s: unrecognized encryption type", WANBOOTFS);
   1277 		return (-1);
   1278 	}
   1279 
   1280 	/*
   1281 	 * Process the header.
   1282 	 */
   1283 	if (http_process_part_headers(handle, NULL) != 0) {
   1284 		print_errors("http_process_part_headers", handle);
   1285 		return (1);
   1286 	}
   1287 	lenstr = http_get_header_value(handle, CONTENT_LENGTH);
   1288 	if (lenstr == NULL) {
   1289 		bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length "
   1290 		    "of first part of multipart message", WANBOOTFS);
   1291 		return (1);
   1292 	}
   1293 	wanbootfs_size = (size_t)strtol(lenstr, NULL, 10);
   1294 	free(lenstr);
   1295 	if (wanbootfs_size == 0) {
   1296 		bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part "
   1297 		    "of multipart message not a legal size", WANBOOTFS);
   1298 		return (1);
   1299 	}
   1300 
   1301 	/*
   1302 	 * If encrypted, then read the iv.
   1303 	 */
   1304 	if (encr_type != ENCR_NONE) {
   1305 		if (read_bytes(handle, (char *)iv, block_size) != 0) {
   1306 			bootlog("wanboot", BOOTLOG_ALERT,
   1307 			    "%s: error reading hash iv", WANBOOTFS);
   1308 			return (1);
   1309 		}
   1310 		wanbootfs_size -= block_size;
   1311 		if (hash_type != HASH_NONE) {
   1312 			HMACUpdate(&sha, (uchar_t *)iv, block_size);
   1313 		}
   1314 	}
   1315 
   1316 	/*
   1317 	 * We can only create the ramdisk once. So, if we've
   1318 	 * already created it, then it means we've re-entered
   1319 	 * this routine from an earlier partial failure. Use
   1320 	 * the already existing ramdisk and seek back to the
   1321 	 * beginning of the file.
   1322 	 */
   1323 	if (bootfs_vaddr == NULL) {
   1324 		bootfs_vaddr = create_ramdisk(RD_BOOTFS, wanbootfs_size,
   1325 		    devpath);
   1326 	}
   1327 
   1328 	offset = 0;
   1329 
   1330 	if ((ret = write_msg_to_ramdisk(WANBOOTFS, bootfs_vaddr, handle,
   1331 	    wanbootfs_size, &offset, (hash_type == HASH_NONE) ? NULL : &sha))
   1332 	    != 0) {
   1333 		return (ret);
   1334 	}
   1335 
   1336 	if (hash_type != HASH_NONE) {
   1337 		HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest);
   1338 	}
   1339 
   1340 	/*
   1341 	 * If encrypted, then decrypt it.
   1342 	 */
   1343 	if (encr_type != ENCR_NONE) {
   1344 		ret = decrypt_wanbootfs(bootfs_vaddr, &ch, iv, wanbootfs_size);
   1345 		if (ret != 0) {
   1346 			encr_fini(encr_type, eh);
   1347 			return (-1);
   1348 		}
   1349 		encr_fini(encr_type, eh);
   1350 	}
   1351 
   1352 	return (read_digest(WANBOOTFS, handle, sdigest));
   1353 }
   1354 
   1355 /*
   1356  * This routine sends an HTTP GET request to the webserver to
   1357  * request the wanboot file system for the client. The server
   1358  * will reply by sending a multipart message. This routine will rely
   1359  * on process_wanbootfs() to receive the multipart message, process it
   1360  * and ultimately return to it a device path to a ramdisk containing
   1361  * the wanboot file system, a client computed hash digest and a
   1362  * server computed hash digest. This routine will verify that the
   1363  * client computed hash digest matches the one sent by the server. This
   1364  * routine will also verify that the nonce received in the reply matches
   1365  * the one sent in the request.
   1366  *
   1367  * If an error occurs in the transfer of the message from the server
   1368  * to the client, then the client re-requests the download in its
   1369  * entirety. Errors not related to the actual message download are
   1370  * deemed unrecoverable.
   1371  *
   1372  * Returns:
   1373  *	-1 = Non-recoverable error
   1374  *	 0 = Success
   1375  */
   1376 int
   1377 get_wanbootfs(const url_t *server_url)
   1378 {
   1379 	http_handle_t	handle;
   1380 	unsigned char	cdigest[HMAC_DIGEST_LEN];
   1381 	unsigned char	sdigest[HMAC_DIGEST_LEN];
   1382 	url_t		req_url;
   1383 	char		*devpath;
   1384 	int		ret;
   1385 	int		fd;
   1386 	char		buf[NONCELEN + 1];
   1387 	int		retry_cnt = 0;
   1388 	int		retry_max = WANBOOT_RETRY_MAX;
   1389 
   1390 	/*
   1391 	 * Build the URL to request the wanboot file system. This URL
   1392 	 * will include the CGI script name and the IP, CID, and
   1393 	 * NONCE parameters.
   1394 	 */
   1395 	if (build_request_url(&req_url, URLtype_wanbootfs, server_url) == -1) {
   1396 		bootlog("wanboot", BOOTLOG_CRIT,
   1397 		    "Can't build the URL to make the %s request",
   1398 		    CGIcontent(URLtype_wanbootfs));
   1399 		return (-1);
   1400 	}
   1401 
   1402 	/*
   1403 	 * Go get the wanboot file system. If we fail reading the
   1404 	 * response we re-request the entire file system.
   1405 	 */
   1406 	bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading wanboot file system");
   1407 
   1408 	bzero(cdigest, sizeof (cdigest));
   1409 	do {
   1410 		if ((ret = establish_http_connection(WANBOOTFS, &handle,
   1411 		    &req_url, 0)) < 0) {
   1412 			break;
   1413 		} else if (ret > 0) {
   1414 			if (wanboot_retry(++retry_cnt, retry_max)) {
   1415 				continue;
   1416 			} else {
   1417 				break;
   1418 			}
   1419 		}
   1420 
   1421 		if ((ret = process_wanbootfs(handle, &devpath,
   1422 		    cdigest, sdigest)) > 0) {
   1423 			if (!wanboot_retry(++retry_cnt, retry_max)) {
   1424 				(void) http_srv_close(handle);
   1425 				break;
   1426 			}
   1427 		}
   1428 
   1429 		(void) http_srv_close(handle);
   1430 
   1431 	} while (ret > 0);
   1432 
   1433 	/*
   1434 	 * Validate the computed digest against the one received.
   1435 	 */
   1436 	if (ret != 0 ||
   1437 	    !verify_digests(WANBOOTFS, cdigest, sdigest)) {
   1438 		bootlog("wanboot", BOOTLOG_CRIT,
   1439 		    "The wanboot file system download aborted");
   1440 		return (-1);
   1441 	}
   1442 
   1443 	/*
   1444 	 * Mount the wanboot file system.
   1445 	 */
   1446 	if (determine_fstype_and_mountroot(devpath) != VFS_SUCCESS) {
   1447 		bootlog("wanboot", BOOTLOG_CRIT,
   1448 		    "Could not mount the wanboot filesystem.");
   1449 		bootlog("wanboot", BOOTLOG_CRIT,
   1450 		    "This may signify a client/server key mismatch");
   1451 		if (encr_type != ENCR_NONE) {
   1452 			bootlog("wanboot", BOOTLOG_CRIT,
   1453 			    "(client has key but wrong encryption_type?)");
   1454 		} else {
   1455 			bootlog("wanboot", BOOTLOG_CRIT,
   1456 			    "(encryption_type specified but no client key?)");
   1457 		}
   1458 		return (-1);
   1459 	}
   1460 	bootlog("wanboot", BOOTLOG_VERBOSE,
   1461 	    "The wanboot file system has been mounted");
   1462 
   1463 	/*
   1464 	 * The wanboot file system should contain a nonce. Read it
   1465 	 * and compare it against the nonce sent in the request.
   1466 	 */
   1467 	if ((fd = open(WANBOOTFS_NONCE_FILE, O_RDONLY)) == -1) {
   1468 		bootlog("wanboot", BOOTLOG_CRIT,
   1469 		    "No nonce found in the wanboot file system");
   1470 		bootlog("wanboot", BOOTLOG_CRIT,
   1471 		    "The wanboot file system download aborted");
   1472 		return (-1);
   1473 	}
   1474 
   1475 	if (read(fd, buf, NONCELEN) != NONCELEN ||
   1476 	    bcmp(nonce, buf, NONCELEN) != 0) {
   1477 		(void) close(fd);
   1478 		bootlog("wanboot", BOOTLOG_CRIT,
   1479 		    "Invalid nonce found in the wanboot file system");
   1480 		bootlog("wanboot", BOOTLOG_CRIT,
   1481 		    "The wanboot file system download aborted");
   1482 		return (-1);
   1483 	}
   1484 
   1485 	(void) close(fd);
   1486 
   1487 	bootlog("wanboot", BOOTLOG_VERBOSE,
   1488 	    "The wanboot file system download was successful");
   1489 	return (0);
   1490 }
   1491 
   1492 static boolean_t
   1493 init_netdev(char *bpath)
   1494 {
   1495 	pnode_t		anode;
   1496 	int		proplen;
   1497 	char		netalias[OBP_MAXPATHLEN];
   1498 	static char	devpath[OBP_MAXPATHLEN];
   1499 	char		*p;
   1500 
   1501 	bzero(netalias, sizeof (netalias));
   1502 	bzero(devpath, sizeof (devpath));
   1503 
   1504 	/*
   1505 	 * Wanboot will either have loaded over the network (in which case
   1506 	 * bpath will name a network device), or from CD-ROM or disk.  In
   1507 	 * either case ensure that the 'net' alias corresponds to a network
   1508 	 * device, and that if a network boot was performed that it is
   1509 	 * identical to bpath.  This is so that the interface name can always
   1510 	 * be determined for CD-ROM or disk boots, and for manually-configured
   1511 	 * network boots.  The latter restriction may be relaxed in the future.
   1512 	 */
   1513 	anode = prom_alias_node();
   1514 	if ((proplen = prom_getproplen(anode, "net")) <= 0 ||
   1515 	    proplen > sizeof (netalias)) {
   1516 		goto error;
   1517 	}
   1518 	(void) prom_getprop(anode, "net", (caddr_t)netalias);
   1519 
   1520 	/*
   1521 	 * Strip boot arguments from the net device to form
   1522 	 * the boot device path, returned as netdev_path.
   1523 	 */
   1524 	if (strlcpy(devpath, netalias, sizeof (devpath)) >= sizeof (devpath))
   1525 		goto error;
   1526 	if ((p = strchr(devpath, ':')) != NULL) {
   1527 		*p = '\0';
   1528 	}
   1529 
   1530 	if (!is_netdev(netalias)) {
   1531 		bootlog("wanboot", BOOTLOG_CRIT, "'net'=%s\n", netalias);
   1532 		goto error;
   1533 	}
   1534 
   1535 	if (is_netdev(bpath)) {
   1536 		/*
   1537 		 * If bpath is a network device path, then v2path
   1538 		 * will be a copy of this sans device arguments.
   1539 		 */
   1540 		if (strcmp(v2path, devpath) != 0) {
   1541 			bootlog("wanboot", BOOTLOG_CRIT,
   1542 			    "'net'=%s\n", netalias);
   1543 			bootlog("wanboot", BOOTLOG_CRIT,
   1544 			    "wanboot requires that the 'net' alias refers to ");
   1545 			bootlog("wanboot", BOOTLOG_CRIT,
   1546 			    "the network device path from which it loaded");
   1547 			return (B_FALSE);
   1548 		}
   1549 	} else {
   1550 		bpath = netalias;
   1551 	}
   1552 
   1553 	/*
   1554 	 * Configure the network and return the network device.
   1555 	 */
   1556 	bootlog("wanboot", BOOTLOG_INFO, "configuring %s\n", bpath);
   1557 	netdev_path = devpath;
   1558 	mac_init(bpath);
   1559 	return (B_TRUE);
   1560 
   1561 error:
   1562 	/*
   1563 	 * If we haven't established a device path for a network interface,
   1564 	 * then we're doomed.
   1565 	 */
   1566 	bootlog("wanboot", BOOTLOG_CRIT,
   1567 	    "No network device available for wanboot!");
   1568 	bootlog("wanboot", BOOTLOG_CRIT,
   1569 	    "(Ensure that the 'net' alias is set correctly)");
   1570 	return (B_FALSE);
   1571 }
   1572 
   1573 /*
   1574  * This implementation of bootprog() is used solely by wanboot.
   1575  *
   1576  * The basic algorithm is as follows:
   1577  *
   1578  * - The wanboot options (those specified using the "-o" flag) are processed,
   1579  *   and if necessary the wanboot interpreter is invoked to collect other
   1580  *   options.
   1581  *
   1582  * - The wanboot filesystem (containing certificates, wanboot.conf file, etc.)
   1583  *   is then downloaded into the bootfs ramdisk, which is mounted for use
   1584  *   by OpenSSL, access to wanboot.conf, etc.
   1585  *
   1586  * - The wanboot miniroot is downloaded over http/https into the rootfs
   1587  *   ramdisk.  The bootfs filesystem is unmounted, and the rootfs filesystem
   1588  *   is booted.
   1589  */
   1590 /* EXPORT DELETE END */
   1591 /*ARGSUSED*/
   1592 int
   1593 bootprog(char *bpath, char *bargs, boolean_t user_specified_filename)
   1594 {
   1595 /* EXPORT DELETE START */
   1596 	char		*miniroot_path;
   1597 	url_t		server_url;
   1598 	int		ret;
   1599 
   1600 	if (!init_netdev(bpath)) {
   1601 		return (-1);
   1602 	}
   1603 
   1604 	if (!bootinfo_init()) {
   1605 		bootlog("wanboot", BOOTLOG_CRIT, "Cannot initialize bootinfo");
   1606 		return (-1);
   1607 	}
   1608 
   1609 	/*
   1610 	 * Get default values from PROM, etc., process any boot arguments
   1611 	 * (specified with the "-o" option), and initialize the interface.
   1612 	 */
   1613 	if (!wanboot_init_interface(wanboot_arguments)) {
   1614 		return (-1);
   1615 	}
   1616 
   1617 	/*
   1618 	 * Determine which encryption and hashing algorithms the client
   1619 	 * is configured to use.
   1620 	 */
   1621 	init_encryption();
   1622 	init_hashing();
   1623 
   1624 	/*
   1625 	 * Get the bootserver value.  Should be of the form:
   1626 	 *	http://host[:port]/abspath.
   1627 	 */
   1628 	ret = get_url(BI_BOOTSERVER, &server_url);
   1629 	if (ret != 0) {
   1630 		bootlog("wanboot", BOOTLOG_CRIT,
   1631 		    "Unable to retrieve the bootserver URL");
   1632 		return (-1);
   1633 	}
   1634 
   1635 	/*
   1636 	 * Get the wanboot file system and mount it. Contains metdata
   1637 	 * needed by wanboot.
   1638 	 */
   1639 	if (get_wanbootfs(&server_url) != 0) {
   1640 		return (-1);
   1641 	}
   1642 
   1643 	/*
   1644 	 * Check that there is a valid wanboot.conf file in the wanboot
   1645 	 * file system.
   1646 	 */
   1647 	if (bootconf_init(&bc_handle, NULL) != BC_E_NOERROR) {
   1648 		bootlog("wanboot", BOOTLOG_CRIT,
   1649 		    "wanboot.conf error (code=%d)", bc_handle.bc_error_code);
   1650 		return (-1);
   1651 	}
   1652 
   1653 	/*
   1654 	 * Set the time
   1655 	 */
   1656 	init_boot_time();
   1657 
   1658 	/*
   1659 	 * Verify that URLs in wanboot.conf can be reached, etc.
   1660 	 */
   1661 	if (!wanboot_verify_config()) {
   1662 		return (-1);
   1663 	}
   1664 
   1665 	/*
   1666 	 * Retrieve the miniroot.
   1667 	 */
   1668 	if (get_miniroot(&miniroot_path) != 0) {
   1669 		return (-1);
   1670 	}
   1671 
   1672 	/*
   1673 	 * We don't need the wanboot file system mounted anymore and
   1674 	 * should unmount it so that we can mount the miniroot.
   1675 	 */
   1676 	(void) unmountroot();
   1677 
   1678 	boot_ramdisk(RD_ROOTFS);
   1679 
   1680 /* EXPORT DELETE END */
   1681 	return (0);
   1682 }
   1683