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