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