xref: /titanic_50/usr/src/psm/stand/boot/sparc/common/wanboot.c (revision 753a6d457b330b1b29b2d3eefcd0831116ce950d)
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