xref: /titanic_41/usr/src/psm/stand/boot/sparc/common/wanboot.c (revision ae115bc77f6fcde83175c75b4206dc2e50747966)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 /* EXPORT DELETE START */
31 #include <sys/promif.h>
32 #include <sys/obpdefs.h>
33 #include <sys/bootvfs.h>
34 #include <sys/bootconf.h>
35 #include <netinet/in.h>
36 #include <sys/wanboot_impl.h>
37 #include <boot_http.h>
38 #include <aes.h>
39 #include <des3.h>
40 #include <cbc.h>
41 #include <hmac_sha1.h>
42 #include <sys/sha1.h>
43 #include <sys/sha1_consts.h>
44 #include <bootlog.h>
45 #include <parseURL.h>
46 #include <netboot_paths.h>
47 #include <netinet/inetutil.h>
48 #include <sys/salib.h>
49 #include <inet/mac.h>
50 #include <inet/ipv4.h>
51 #include <dhcp_impl.h>
52 #include <inet/dhcpv4.h>
53 #include <bootinfo.h>
54 #include <wanboot_conf.h>
55 #include "boot_plat.h"
56 #include "ramdisk.h"
57 #include "wbcli.h"
58 
59 /*
60  * Types of downloads
61  */
62 #define	MINIINFO	"miniinfo"
63 #define	MINIROOT	"miniroot"
64 #define	WANBOOTFS	"wanbootfs"
65 
66 #define	WANBOOT_RETRY_NOMAX	-1
67 #define	WANBOOT_RETRY_ROOT_MAX	50
68 #define	WANBOOT_RETRY_MAX	5
69 #define	WANBOOT_RETRY_SECS	5
70 #define	WANBOOT_RETRY_MAX_SECS	30
71 
72 /*
73  * Our read requests should timeout after 25 seconds
74  */
75 #define	SOCKET_READ_TIMEOUT	25
76 
77 /*
78  * Experimentation has shown that an 8K download buffer is optimal
79  */
80 static char	buffer[8192];
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, int fd, 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; *offset += len) {
501 		nleft = ramdisk_size - *offset;
502 
503 		if (nleft > sizeof (buffer))
504 			nleft = sizeof (buffer);
505 
506 		len = http_read_body(handle, buffer, nleft);
507 		if (len <= 0) {
508 			print_errors("http_read_body", handle);
509 			/*
510 			 * In the case of a partial failure, http_read_body()
511 			 * returns into 'len', 1 - the number of bytes read.
512 			 * So, a -65 means 64 bytes read and an error occurred.
513 			 */
514 			if (len != 0) {
515 				len = -(len + 1);
516 			}
517 			ret = 1;
518 		}
519 		if (sha != NULL) {
520 			HMACUpdate(sha, (uchar_t *)buffer, (size_t)len);
521 		}
522 		if (prom_write(fd, buffer, (size_t)len, 0, 0) != (ssize_t)len) {
523 			bootlog("wanboot", BOOTLOG_CRIT,
524 			    "%s: write to ramdisk failed", what);
525 			ret = -1;
526 			continue;
527 		}
528 		if (bootlog_progress == bootlog_message_interval) {
529 			bootlog("wanboot", BOOTLOG_PROGRESS,
530 			    "%s: Read %ld of %ld kB (%ld%%)", what,
531 			    *offset / 1024, ramdisk_size / 1024,
532 			    *offset * 100 / ramdisk_size);
533 			bootlog_progress = 0;
534 		} else {
535 			bootlog_progress++;
536 		}
537 	}
538 	if (ret == 0) {
539 		bootlog("wanboot", BOOTLOG_PROGRESS,
540 		    "%s: Read %ld of %ld kB (%ld%%)", what,
541 		    *offset / 1024, ramdisk_size / 1024,
542 		    *offset * 100 / ramdisk_size);
543 		bootlog("wanboot", BOOTLOG_INFO, "%s: Download complete", what);
544 	}
545 	return (ret);
546 }
547 
548 /*
549  * This routine is called with a bootinfo parameter name.  If the parameter
550  * has a value it should be a URL, and this will be used to initialize the
551  * http_url structure.
552  *
553  * Returns:
554  *	-1 = Non-recoverable error
555  *	 0 = Success
556  *	 1 = DHCP option not set
557  */
558 static int
559 get_url(char *name, url_t *url)
560 {
561 	char	buf[URL_MAX_STRLEN];
562 	size_t	len;
563 	int	ret;
564 
565 	bzero(buf, sizeof (buf));
566 	len = sizeof (buf) - 1;
567 	if (bootinfo_get(name, buf, &len, NULL) != BI_E_SUCCESS || len == 0) {
568 		return (1);
569 	}
570 
571 	/*
572 	 * Parse the URL.
573 	 */
574 	ret = url_parse(buf, url);
575 	if (ret != URL_PARSE_SUCCESS) {
576 		bootlog("wanboot", BOOTLOG_CRIT,
577 		    "Unable to parse URL %s", buf);
578 		return (-1);
579 	}
580 
581 	return (0);
582 }
583 
584 /*
585  * This routine initiates an HTTP request and returns a handle so that
586  * the caller can process the response.
587  *
588  * Notes:
589  *	Requests may be either secure or not. If the request is secure, then
590  *	this routine assumes that a wanboot file system exists and
591  *	uses its contents to provide the HTTP library with the information
592  *	that will be required by SSL.
593  *
594  *	In order to facilitate transmission retries, this routine supports
595  *	range requests. A caller may request a range by providing a non-zero
596  *	offset. In which case, a range request is made that ranges from the
597  *	offet to the end of the file.
598  *
599  *	If the client is configured to use an HTTP proxy, then this routine
600  *	will make the HTTP library aware of the proxy.
601  *
602  *	Any HTTP errors encountered in downloading or processing the message
603  *	are not deemed unrecoverable errors. The caller can simply try the
604  *	request once again.
605  *
606  * Returns:
607  *	-1 = Non-recoverable error
608  *	 0 = Success
609  *	 1 = HTTP download error
610  */
611 static int
612 establish_http_connection(const char *what, http_handle_t *handlep,
613     url_t *url, offset_t offset)
614 {
615 	static boolean_t	is_auth_file_init = B_FALSE;
616 	static boolean_t	is_proxy_init = B_FALSE;
617 	static boolean_t	proxy_exists = B_FALSE;
618 	static url_hport_t	proxy_hp;
619 	http_respinfo_t		*resp;
620 	char			buf[URL_MAX_STRLEN];
621 	size_t			len = sizeof (buf) - 1;
622 	int			ret;
623 
624 	/* Check for HTTP proxy */
625 	if (!is_proxy_init &&
626 	    bootinfo_get(BI_HTTP_PROXY, buf, &len, NULL) == BI_E_SUCCESS &&
627 	    strlen(buf) > 0) {
628 		/*
629 		 * Parse the hostport.
630 		 */
631 		ret = url_parse_hostport(buf, &proxy_hp, URL_DFLT_PROXY_PORT);
632 		if (ret == URL_PARSE_SUCCESS) {
633 			proxy_exists = B_TRUE;
634 		} else {
635 			bootlog("wanboot", BOOTLOG_CRIT,
636 			    "%s is not set to a valid hostport value",
637 			    BI_HTTP_PROXY);
638 			return (-1);
639 		}
640 		is_proxy_init = B_TRUE;
641 	}
642 
643 	http_set_p12_format(use_p12);
644 
645 	/*
646 	 * Initialize the handle that will be used for the request.
647 	 */
648 	*handlep = http_srv_init(url);
649 	if (*handlep == NULL) {
650 		print_errors("http_srv_init", NULL);
651 		return (-1);
652 	}
653 
654 	/*
655 	 * Is the request a secure one? If it is, then we need to do further
656 	 * setup. Search the wanboot file system for files that will be
657 	 * needed by SSL.
658 	 */
659 	if (url->https) {
660 		char		*cas;
661 		boolean_t	client_authentication = B_FALSE;
662 
663 		if (http_set_random_file(*handlep, "/dev/urandom") < 0) {
664 			print_errors("http_set_random_file", *handlep);
665 			(void) http_srv_close(*handlep);
666 			return (-1);
667 		}
668 
669 		/*
670 		 * We only need to initialize the CA once as it is not handle
671 		 * specific.
672 		 */
673 		if (!is_auth_file_init) {
674 			if (http_set_certificate_authority_file(NB_CA_CERT_PATH)
675 			    < 0) {
676 				print_errors(
677 				    "http_set_certificate_authority_file",
678 				    *handlep);
679 				(void) http_srv_close(*handlep);
680 				return (-1);
681 			}
682 
683 			is_auth_file_init = B_TRUE;
684 		}
685 
686 		/*
687 		 * The client certificate and key will not exist unless
688 		 * client authentication has been configured. If it is
689 		 * configured then the webserver will have added these
690 		 * files to the wanboot file system and the HTTP library
691 		 * needs to be made aware of their existence.
692 		 */
693 		if ((cas = bootconf_get(&bc_handle,
694 		    BC_CLIENT_AUTHENTICATION)) != NULL &&
695 		    strcmp(cas, "yes") == 0) {
696 			client_authentication = B_TRUE;
697 
698 			if (http_set_client_certificate_file(*handlep,
699 			    NB_CLIENT_CERT_PATH) < 0) {
700 				print_errors("http_set_client_certificate_file",
701 				    *handlep);
702 				(void) http_srv_close(*handlep);
703 				return (-1);
704 			}
705 
706 			if (http_set_private_key_file(*handlep,
707 			    NB_CLIENT_KEY_PATH) < 0) {
708 				print_errors("http_set_private_key_file",
709 				    *handlep);
710 				(void) http_srv_close(*handlep);
711 				return (-1);
712 			}
713 		}
714 
715 		/*
716 		 * We do not really need to set this unless client
717 		 * authentication is configured or unless pkcs12 files
718 		 * are used.
719 		 */
720 		if ((client_authentication || use_p12) &&
721 		    http_set_password(*handlep, WANBOOT_PASSPHRASE) < 0) {
722 			print_errors("http_set_password", *handlep);
723 			(void) http_srv_close(*handlep);
724 			return (-1);
725 		}
726 	}
727 
728 	/*
729 	 * If the client is using a proxy, tell the library.
730 	 */
731 	if (proxy_exists) {
732 		if (http_set_proxy(*handlep, &proxy_hp) != 0) {
733 			print_errors("http_set_proxy", *handlep);
734 			(void) http_srv_close(*handlep);
735 			return (-1);
736 		}
737 	}
738 
739 	(void) http_set_socket_read_timeout(*handlep, SOCKET_READ_TIMEOUT);
740 
741 	/*
742 	 * Ok, connect to the webserver.
743 	 */
744 	if (http_srv_connect(*handlep) == -1) {
745 		print_errors("http_srv_connect", *handlep);
746 		(void) http_srv_close(*handlep);
747 		return (1);
748 	}
749 
750 	/*
751 	 * If the offset is 0, then we assume that we want the entire
752 	 * message. If the offset is not 0, then we assume that we are
753 	 * retrying a previously interrupted transfer and thus we make
754 	 * a range request.
755 	 */
756 	if (offset == 0) {
757 		if ((ret = http_get_request(*handlep, url->abspath)) == 0) {
758 			bootlog("wanboot", BOOTLOG_VERBOSE,
759 			    "%s: http_get_request: sent", what);
760 		} else {
761 			print_errors("http_get_request", *handlep);
762 			(void) http_srv_close(*handlep);
763 			return (1);
764 		}
765 	} else {
766 		if ((ret = http_get_range_request(*handlep, url->abspath,
767 		    offset, 0)) == 0) {
768 			bootlog("wanboot", BOOTLOG_VERBOSE,
769 			    "%s: http_get_range_request: sent", what);
770 		} else {
771 			print_errors("http_get_range_request", *handlep);
772 			(void) http_srv_close(*handlep);
773 			return (1);
774 		}
775 	}
776 
777 	/*
778 	 * Tell the library to read in the response headers.
779 	 */
780 	ret = http_process_headers(*handlep, &resp);
781 	if (ret == -1) {
782 		print_errors("http_process_headers", *handlep);
783 		(void) http_srv_close(*handlep);
784 		return (1);
785 	}
786 
787 	/*
788 	 * Check for a valid response code.
789 	 */
790 	if ((offset == 0 && resp->code != 200) ||
791 	    (offset != 0 && resp->code != 206)) {
792 		bootlog("wanboot", BOOTLOG_ALERT,
793 			"%s: Request returned code %d", what, resp->code);
794 		if (resp->statusmsg != NULL && resp->statusmsg[0] != '\0')
795 			bootlog("wanboot", BOOTLOG_ALERT,
796 				"%s", resp->statusmsg);
797 		http_free_respinfo(resp);
798 		(void) http_srv_close(*handlep);
799 		return (1);
800 	}
801 	http_free_respinfo(resp);
802 
803 	/*
804 	 * Success.
805 	 */
806 	return (0);
807 }
808 
809 /*
810  * This routine is called by get_miniinfo() to receive the reply
811  * to the request for the miniroot metadata. The reply is a two
812  * part multipart message. The first part of the message contains
813  * the miniroot file size. The second part of the message contains
814  * a hash digest of the miniroot as computed by the server. This
815  * routine receives both message parts and returns them to the caller.
816  *
817  * Notes:
818  *	If the miniroot is going to be downloaded securely or if the
819  *	the server has no hash key for the client, then the hash digest
820  *	downloaded contains all zeros.
821  *
822  *	Any HTTP errors encountered in downloading or processing the message
823  *	are not deemed unrecoverable errors. That is, get_miniinfo()
824  *	tries re-requesting the message and tries processing it again.
825  *
826  * Returns:
827  *	-1 = Non-recoverable error
828  *	 0 = Success
829  *	 1 = HTTP download error
830  */
831 static int
832 process_miniinfo(http_handle_t handle, size_t *mini_size,
833     unsigned char *sdigest)
834 {
835 	char	*lenstr;
836 	size_t	cnt;
837 
838 	/*
839 	 * Process the file size header.
840 	 */
841 	if (http_process_part_headers(handle, NULL) != 0) {
842 		print_errors("http_process_part_headers", handle);
843 		return (1);
844 	}
845 	lenstr = http_get_header_value(handle, CONTENT_LENGTH);
846 	if (lenstr == NULL) {
847 		bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length "
848 		    "of first part of multipart message", MINIINFO);
849 		return (1);
850 	}
851 	cnt = (size_t)strtol(lenstr, NULL, 10);
852 	free(lenstr);
853 	if (cnt == 0 || cnt >= sizeof (buffer)) {
854 		bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part "
855 		    "of multipart message not a legal size", MINIINFO);
856 		return (1);
857 	}
858 
859 	if (read_bytes(handle, buffer, cnt) != 0) {
860 		bootlog("wanboot", BOOTLOG_ALERT,
861 		    "%s: error reading miniroot size", MINIINFO);
862 		return (1);
863 	}
864 	buffer[cnt] = '\0';
865 
866 	*mini_size = (size_t)strtol(buffer, NULL, 10);
867 	if (*mini_size == 0) {
868 		bootlog("wanboot", BOOTLOG_ALERT, "%s: body of first part "
869 		    "of multipart message not a legal size", MINIINFO);
870 		return (1);
871 	}
872 
873 	return (read_digest(MINIINFO, handle, sdigest));
874 }
875 
876 /*
877  * This routine is called by get_miniroot() to retrieve the miniroot
878  * metadata (miniroot size and a hash digest). This routine sends an
879  * HTTP GET request to the webserver to request the download of the
880  * miniroot metadata and relies on process_miniinfo() to receive the
881  * reply, process it and ultimately return to it the miniroot size and
882  * the hash digest.
883  *
884  * Note:
885  *	Any HTTP errors encountered in downloading or processing the message
886  *	are not deemed unrecoverable errors. That is, get_miniinfo() should
887  *	try re-requesting the message and try processing again.
888  *
889  * Returns:
890  *	-1 = Non-recoverable error
891  *	 0 = Success
892  */
893 int
894 get_miniinfo(const url_t *server_url, size_t *mini_size,
895     unsigned char *sdigest)
896 {
897 	http_handle_t	handle;
898 	url_t		req_url;
899 	int		retry_cnt = 0;
900 	int		retry_max = WANBOOT_RETRY_MAX;
901 	int		ret;
902 
903 	/*
904 	 * Build the URL to request the miniroot info.
905 	 */
906 	if (build_request_url(&req_url, URLtype_miniroot, server_url) == -1) {
907 		bootlog("wanboot", BOOTLOG_CRIT,
908 		    "Can't build the URL to make the %s request",
909 		    CGIcontent(URLtype_miniroot));
910 		return (-1);
911 	}
912 
913 	/*
914 	 * Go get the miniroot info. If we fail reading the
915 	 * response we re-request the info in its entirety.
916 	 */
917 	bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot info");
918 
919 	do {
920 		if ((ret = establish_http_connection(MINIINFO, &handle,
921 		    &req_url, 0)) < 0) {
922 			break;
923 		} else if (ret > 0) {
924 			if (wanboot_retry(++retry_cnt, retry_max)) {
925 				continue;
926 			} else {
927 				break;
928 			}
929 		}
930 
931 		if ((ret = process_miniinfo(handle, mini_size,
932 			sdigest)) > 0) {
933 			if (!wanboot_retry(++retry_cnt, retry_max)) {
934 				(void) http_srv_close(handle);
935 				break;
936 			}
937 		}
938 
939 		(void) http_srv_close(handle);
940 
941 	} while (ret > 0);
942 
943 	/*
944 	 * Success.
945 	 */
946 	if (ret == 0) {
947 		bootlog("wanboot", BOOTLOG_VERBOSE,
948 		    "Miniroot info download successful");
949 		return (0);
950 	} else {
951 		bootlog("wanboot", BOOTLOG_CRIT,
952 		    "Miniroot info download aborted");
953 		return (-1);
954 	}
955 }
956 
957 /*
958  * This routine is called by get_miniroot() to receive the reply to
959  * the request for the miniroot download. The miniroot is written
960  * to ramdisk as it is received and a hash digest is optionally computed
961  * as it does so. The miniroot is downloaded as one large message.
962  * Because the message is so large, this routine is prepared to deal
963  * with errors in the middle of download. If an error occurs during
964  * download, then this message processes all received data up to the
965  * point of the error and returns to get_miniroot() an error signifying
966  * that a download error has occurred. Presumably, get_miniroot()
967  * re-requests the remaining part of the miniroot not yet processed and
968  * calls this routine back to process the reply. When this routine
969  * returns succesfully, it returns a devpath to the ramdisk and the
970  * computed hash (if computed).
971  *
972  * Note:
973  *	In order to facilitate reentry, the ramdisk is left open
974  *	and the original miniroot_size and HMAC handle are kept
975  *	static.
976  *
977  * Returns:
978  *	-1 = Non-recoverable error
979  *	 0 = Success
980  *	 1 = HTTP download error
981  */
982 static int
983 process_miniroot(http_handle_t handle, hash_type_t htype,
984     size_t length, char **devpath, off_t *offset, unsigned char *cdigest)
985 {
986 	static SHA1_CTX	sha;
987 	static size_t	miniroot_size;
988 	static int	fd = -1;
989 	int		ret;
990 
991 	if (fd == -1) {
992 		if (htype == HASH_HMAC_SHA1) {
993 			bootlog("wanboot", BOOTLOG_INFO,
994 			    "%s: Authentication will use HMAC-SHA1", MINIROOT);
995 			HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE);
996 		}
997 
998 		miniroot_size = length;
999 
1000 		fd = create_ramdisk(RD_ROOTFS, miniroot_size, devpath);
1001 	}
1002 
1003 	if (prom_seek(fd, *offset) == -1) {
1004 		bootlog("wanboot", BOOTLOG_CRIT,
1005 			"%s: prom_seek error", MINIROOT);
1006 		return (-1);
1007 	}
1008 
1009 	if ((ret = write_msg_to_ramdisk(MINIROOT, fd, handle, miniroot_size,
1010 	    offset, (htype == HASH_NONE) ? NULL : &sha)) != 0) {
1011 		if (ret < 0) {
1012 			/*
1013 			 * Reentry not supported.
1014 			 */
1015 			(void) prom_close(fd);
1016 		}
1017 		return (ret);
1018 	}
1019 
1020 	if (htype != HASH_NONE) {
1021 		HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest);
1022 	}
1023 
1024 	(void) prom_close(fd);
1025 
1026 	return (0);
1027 }
1028 
1029 /*
1030  * This routine retrieves the miniroot from the webserver. The miniroot
1031  * is retrieved in two steps. First a request is made to the server
1032  * to retrieve miniroot metadata (miniroot size and a hash digest).
1033  * The second request actually results in the download of the miniroot.
1034  *
1035  * This routine relies on get_miniinfo() to make and process
1036  * the request for the miniroot metadata and returns the
1037  * miniroot size and the hash digest of the miniroot as computed by
1038  * the server.
1039  *
1040  * If get_miniinfo() returns successfully, then this routine sends
1041  * an HTTP GET request to the webserver to request download of the
1042  * miniroot. This routine relies on process_miniroot() to receive
1043  * the reply, process it and ultimately return to it a device path to
1044  * a ramdisk containing the miniroot and a client computed hash digest.
1045  * This routine verifies that the client computed hash digest matches
1046  * the one retrieved by get_miniinfo().
1047  *
1048  * If an error occurs in the transfer of the miniroot from the server
1049  * to the client, then the client re-requests the download of the
1050  * miniroot using a range request and only requests the part of the
1051  * miniroot not previously downloaded and written to ramdisk. The
1052  * process_miniroot() routine has the intelligence to recognize that
1053  * it is processing a range request. Errors not related to the actual
1054  * message download are deemed unrecoverable.
1055  *
1056  * Note:
1057  *	If the client request for the miniroot is a secure request or
1058  *	if the server is not configured with a hash key for the client,
1059  *	then the hash digest downloaded from the server will contain
1060  *	all zeros. This routine verifies that the server and client are
1061  *	in-sync with respect to the need for hash verification.
1062  *
1063  * Returns:
1064  *	-1 = Non-recoverable error
1065  *	 0 = Success
1066  */
1067 int
1068 get_miniroot(char **devpath)
1069 {
1070 	http_handle_t	handle;
1071 	unsigned char	cdigest[HMAC_DIGEST_LEN];
1072 	unsigned char	sdigest[HMAC_DIGEST_LEN];
1073 	char		*urlstr;
1074 	url_t		server_url;
1075 	size_t		mini_size;
1076 	off_t		offset;
1077 	int		plen;
1078 	int		retry_cnt = 0;
1079 	int		retry_max = WANBOOT_RETRY_ROOT_MAX;
1080 	int		ret;
1081 
1082 	/*
1083 	 * Get the miniroot URL.
1084 	 */
1085 	if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_SERVER)) == NULL) {
1086 		bootlog("wanboot", BOOTLOG_CRIT,
1087 		    "Missing root_server URL");
1088 		return (-1);
1089 	} else if (url_parse(urlstr, &server_url) != URL_PARSE_SUCCESS) {
1090 		bootlog("wanboot", BOOTLOG_CRIT,
1091 		    "Unable to parse URL %s", urlstr);
1092 		return (-1);
1093 	}
1094 
1095 	/*
1096 	 * We must get the miniroot info before we can request
1097 	 * the miniroot itself.
1098 	 */
1099 	if (get_miniinfo(&server_url, &mini_size, sdigest) != 0) {
1100 		return (-1);
1101 	}
1102 
1103 	plen = sizeof (server_url.abspath);
1104 	if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_FILE)) == NULL ||
1105 	    strlcpy(server_url.abspath, urlstr, plen) >= plen) {
1106 		bootlog("wanboot", BOOTLOG_CRIT,
1107 		    "Cannot retrieve the miniroot path");
1108 		return (-1);
1109 	}
1110 
1111 	/*
1112 	 * Go get the miniroot. If we fail reading the response
1113 	 * then we re-request only the range we have yet to read,
1114 	 * unless the error was "unrecoverable" in which case we
1115 	 * re-request the entire file system.
1116 	 */
1117 	bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot");
1118 
1119 	bzero(cdigest, sizeof (cdigest));
1120 	offset = 0;
1121 	do {
1122 		if ((ret = establish_http_connection(MINIROOT, &handle,
1123 		    &server_url, offset)) < 0) {
1124 			break;
1125 		} else if (ret > 0) {
1126 			if (wanboot_retry(++retry_cnt, retry_max)) {
1127 				continue;
1128 			} else {
1129 				break;
1130 			}
1131 		}
1132 
1133 		if ((ret = process_miniroot(handle,
1134 		    server_url.https ? HASH_NONE : hash_type,
1135 		    mini_size, devpath, &offset, cdigest)) > 0) {
1136 			if (!wanboot_retry(++retry_cnt, retry_max)) {
1137 				(void) http_srv_close(handle);
1138 				break;
1139 			}
1140 		}
1141 
1142 		(void) http_srv_close(handle);
1143 
1144 	} while (ret > 0);
1145 
1146 	/*
1147 	 * Validate the computed digest against the one received.
1148 	 */
1149 	if (ret != 0 || !verify_digests(MINIROOT, cdigest, sdigest)) {
1150 		bootlog("wanboot", BOOTLOG_CRIT,
1151 		    "Miniroot download aborted");
1152 		return (-1);
1153 	}
1154 
1155 	bootlog("wanboot", BOOTLOG_VERBOSE, "Miniroot download successful");
1156 	return (0);
1157 }
1158 
1159 /*
1160  * This routine is called to finish the decryption process.
1161  * Its purpose is to free the resources allocated by the
1162  * encryption init routines.
1163  */
1164 static void
1165 encr_fini(encr_type_t etype, void *eh)
1166 {
1167 	switch (etype) {
1168 	case ENCR_3DES:
1169 		des3_fini(eh);
1170 		break;
1171 	case ENCR_AES:
1172 		aes_fini(eh);
1173 		break;
1174 	default:
1175 		break;
1176 	}
1177 }
1178 
1179 /*
1180  * This routine is called by process_wanbootfs() to read the encrypted
1181  * file system from ramdisk and decrypt it. This routine will rewrite
1182  * the file system back to ramdisk in place. The method of decryption
1183  * (algorithm) will have already been determined by process_wanbootfs()
1184  * and the cbc_handle passed to this routine will already have been
1185  * initialized appropriately.
1186  *
1187  * Returns:
1188  *	-1 = Non-recoverable error
1189  *	 0 = Success
1190  */
1191 static int
1192 decrypt_wanbootfs(int fd, cbc_handle_t *ch, uint8_t *iv,
1193     size_t block_size, size_t wanbootfs_size)
1194 {
1195 	size_t total;
1196 	size_t len;
1197 	size_t nleft;
1198 	size_t max_read_size;
1199 
1200 	max_read_size = (sizeof (buffer) / block_size) * block_size;
1201 	for (total = 0; total < wanbootfs_size; total += len) {
1202 		if (prom_seek(fd, total) == -1) {
1203 			bootlog("wanboot", BOOTLOG_CRIT,
1204 			    "%s: prom_seek error", WANBOOTFS);
1205 			return (-1);
1206 		}
1207 		nleft = wanbootfs_size - total;
1208 		if (nleft > max_read_size)
1209 			nleft = max_read_size;
1210 		len = prom_read(fd, buffer, nleft, 0, 0);
1211 		if (len != nleft) {
1212 			bootlog("wanboot", BOOTLOG_CRIT,
1213 			    "%s: prom_read error", WANBOOTFS);
1214 			return (-1);
1215 		}
1216 		if (!cbc_decrypt(ch, (uint8_t *)buffer, len, iv)) {
1217 			bootlog("wanboot", BOOTLOG_CRIT,
1218 			    "%s: cbc decrypt error", WANBOOTFS);
1219 			return (-1);
1220 		}
1221 		if (prom_seek(fd, total) == -1) {
1222 			bootlog("wanboot", BOOTLOG_CRIT,
1223 			    "%s: prom_seek error", WANBOOTFS);
1224 			return (-1);
1225 		}
1226 		if (prom_write(fd, buffer, len, 0, 0) != len) {
1227 			bootlog("wanboot", BOOTLOG_CRIT,
1228 			    "%s: prom_write error", WANBOOTFS);
1229 			return (-1);
1230 		}
1231 	}
1232 	return (0);
1233 }
1234 
1235 /*
1236  * This routine is called by get_wanbootfs() to receive the reply to
1237  * the request for the wanboot file system. The reply is a multipart message.
1238  * The first part of the message is the file system (which may or may
1239  * not be encrypted).  If encrypted, then the first block of the message
1240  * part is the CBC IV value used by the server to encrypt the remaining
1241  * part of the message part and is used by the client to decrypt it. The
1242  * second message part is a hash digest of the first part (the file
1243  * system) as computed by the server. If no hash key is configured
1244  * for the client, then the hash digest simply contains all zeros. This
1245  * routine receives both message parts. The file system is written to ramdisk
1246  * as it is received and simultaneously computes a hash digest (if a hash
1247  * key exists). Once the entire part is received, if the file system is
1248  * encrypted, it is read from ramdisk, decrypted and rewritten back to
1249  * ramdisk. The server computed hash digest is then read and along with the
1250  * ramdisk device path and the client computed hash digest is returned to the
1251  * caller.
1252  *
1253  * Notes:
1254  *	In order to decrypt the file system and to compute the client
1255  *	hash digest, an encryption key and a hash key is retrieved from
1256  *	the PROM (or the wanboot interpreter). The non-existence of these
1257  *	keys has implications on how the message response is processed and
1258  *	it is assumed that the server is configured identically.
1259  *
1260  *	Any HTTP errors encountered in downloading or processing the message
1261  *	are not deemed unrecoverable errors. That is, get_wanbootfs() will
1262  *	try re-requesting the message and will try processing it again.
1263  *
1264  * Returns:
1265  *	-1 = Non-recoverable error
1266  *	 0 = Success
1267  *	 1 = HTTP download error
1268  */
1269 static int
1270 process_wanbootfs(http_handle_t handle, char **devpath,
1271     unsigned char *cdigest, unsigned char *sdigest)
1272 {
1273 	/* iv[] must be sized to store the largest possible encryption block */
1274 	uint8_t		iv[WANBOOT_MAXBLOCKLEN];
1275 	cbc_handle_t	ch;
1276 	void		*eh;
1277 	SHA1_CTX	sha;
1278 	char		*lenstr;
1279 	size_t		wanbootfs_size;
1280 	size_t		block_size;
1281 	off_t		offset;
1282 	static int	fd = -1;
1283 	int		ret;
1284 
1285 	switch (hash_type) {
1286 	case HASH_HMAC_SHA1:
1287 		bootlog("wanboot", BOOTLOG_INFO,
1288 		    "%s: Authentication will use HMAC-SHA1", WANBOOTFS);
1289 		HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE);
1290 		break;
1291 	case HASH_NONE:
1292 		break;
1293 	default:
1294 		bootlog("wanboot", BOOTLOG_CRIT,
1295 		    "%s: unrecognized hash type", WANBOOTFS);
1296 		return (-1);
1297 	}
1298 
1299 	switch (encr_type) {
1300 	case ENCR_3DES:
1301 		bootlog("wanboot",
1302 		    BOOTLOG_INFO, "%s: Decryption will use 3DES", WANBOOTFS);
1303 		if (des3_init(&eh) != 0) {
1304 			return (-1);
1305 		}
1306 		block_size = DES3_BLOCK_SIZE;
1307 		des3_key(eh, g_encr_key);
1308 		cbc_makehandle(&ch, eh, DES3_KEY_SIZE, block_size,
1309 		    DES3_IV_SIZE, des3_encrypt, des3_decrypt);
1310 
1311 		break;
1312 	case ENCR_AES:
1313 		bootlog("wanboot",
1314 		    BOOTLOG_INFO, "%s: Decryption will use AES", WANBOOTFS);
1315 		if (aes_init(&eh) != 0) {
1316 			return (-1);
1317 		}
1318 		block_size = AES_BLOCK_SIZE;
1319 		aes_key(eh, g_encr_key, AES_128_KEY_SIZE);
1320 		cbc_makehandle(&ch, eh, AES_128_KEY_SIZE, block_size,
1321 		    AES_IV_SIZE, aes_encrypt, aes_decrypt);
1322 		break;
1323 	case ENCR_NONE:
1324 		break;
1325 	default:
1326 		bootlog("wanboot", BOOTLOG_CRIT,
1327 		    "%s: unrecognized encryption type", WANBOOTFS);
1328 		return (-1);
1329 	}
1330 
1331 	/*
1332 	 * Process the header.
1333 	 */
1334 	if (http_process_part_headers(handle, NULL) != 0) {
1335 		print_errors("http_process_part_headers", handle);
1336 		return (1);
1337 	}
1338 	lenstr = http_get_header_value(handle, CONTENT_LENGTH);
1339 	if (lenstr == NULL) {
1340 		bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length "
1341 		    "of first part of multipart message", WANBOOTFS);
1342 		return (1);
1343 	}
1344 	wanbootfs_size = (size_t)strtol(lenstr, NULL, 10);
1345 	free(lenstr);
1346 	if (wanbootfs_size == 0) {
1347 		bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part "
1348 		    "of multipart message not a legal size", WANBOOTFS);
1349 		return (1);
1350 	}
1351 
1352 	/*
1353 	 * If encrypted, then read the iv.
1354 	 */
1355 	if (encr_type != ENCR_NONE) {
1356 		if (read_bytes(handle, (char *)iv, block_size) != 0) {
1357 			bootlog("wanboot", BOOTLOG_ALERT,
1358 			    "%s: error reading hash iv", WANBOOTFS);
1359 			return (1);
1360 		}
1361 		wanbootfs_size -= block_size;
1362 		if (hash_type != HASH_NONE) {
1363 			HMACUpdate(&sha, (uchar_t *)iv, block_size);
1364 		}
1365 	}
1366 
1367 	/*
1368 	 * We can only create the ramdisk once. So, if we've
1369 	 * already created it, then it means we've re-entered
1370 	 * this routine from an earlier partial failure. Use
1371 	 * the already existing ramdisk and seek back to the
1372 	 * beginning of the file.
1373 	 */
1374 	if (fd == -1) {
1375 		fd = create_ramdisk(RD_BOOTFS, wanbootfs_size, devpath);
1376 	}
1377 
1378 	offset = 0;
1379 	if (prom_seek(fd, offset) == -1) {
1380 		bootlog("wanboot", BOOTLOG_CRIT,
1381 			"%s: prom_seek error", WANBOOTFS);
1382 		return (-1);
1383 	}
1384 
1385 	if ((ret = write_msg_to_ramdisk(WANBOOTFS, fd, handle, wanbootfs_size,
1386 	    &offset, (hash_type == HASH_NONE) ? NULL : &sha)) != 0) {
1387 		if (ret < 0) {
1388 			/*
1389 			 * Reentry not supported.
1390 			 */
1391 			(void) prom_close(fd);
1392 		}
1393 		return (ret);
1394 	}
1395 
1396 	if (hash_type != HASH_NONE) {
1397 		HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest);
1398 	}
1399 
1400 	/*
1401 	 * If encrypted, then decrypt it.
1402 	 */
1403 	if (encr_type != ENCR_NONE) {
1404 		ret = decrypt_wanbootfs(fd, &ch, iv, block_size,
1405 		    wanbootfs_size);
1406 		if (ret != 0) {
1407 			encr_fini(encr_type, eh);
1408 			(void) prom_close(fd);
1409 			return (-1);
1410 		}
1411 		encr_fini(encr_type, eh);
1412 	}
1413 
1414 	(void) prom_close(fd);
1415 
1416 	return (read_digest(WANBOOTFS, handle, sdigest));
1417 }
1418 
1419 /*
1420  * This routine sends an HTTP GET request to the webserver to
1421  * request the wanboot file system for the client. The server
1422  * will reply by sending a multipart message. This routine will rely
1423  * on process_wanbootfs() to receive the multipart message, process it
1424  * and ultimately return to it a device path to a ramdisk containing
1425  * the wanboot file system, a client computed hash digest and a
1426  * server computed hash digest. This routine will verify that the
1427  * client computed hash digest matches the one sent by the server. This
1428  * routine will also verify that the nonce received in the reply matches
1429  * the one sent in the request.
1430  *
1431  * If an error occurs in the transfer of the message from the server
1432  * to the client, then the client re-requests the download in its
1433  * entirety. Errors not related to the actual message download are
1434  * deemed unrecoverable.
1435  *
1436  * Returns:
1437  *	-1 = Non-recoverable error
1438  *	 0 = Success
1439  */
1440 int
1441 get_wanbootfs(const url_t *server_url)
1442 {
1443 	http_handle_t	handle;
1444 	unsigned char	cdigest[HMAC_DIGEST_LEN];
1445 	unsigned char	sdigest[HMAC_DIGEST_LEN];
1446 	url_t		req_url;
1447 	char		*devpath;
1448 	int		ret;
1449 	int		fd;
1450 	char		buf[NONCELEN + 1];
1451 	int		retry_cnt = 0;
1452 	int		retry_max = WANBOOT_RETRY_MAX;
1453 
1454 	/*
1455 	 * Build the URL to request the wanboot file system. This URL
1456 	 * will include the CGI script name and the IP, CID, and
1457 	 * NONCE parameters.
1458 	 */
1459 	if (build_request_url(&req_url, URLtype_wanbootfs, server_url) == -1) {
1460 		bootlog("wanboot", BOOTLOG_CRIT,
1461 		    "Can't build the URL to make the %s request",
1462 		    CGIcontent(URLtype_wanbootfs));
1463 		return (-1);
1464 	}
1465 
1466 	/*
1467 	 * Go get the wanboot file system. If we fail reading the
1468 	 * response we re-request the entire file system.
1469 	 */
1470 	bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading wanboot file system");
1471 
1472 	bzero(cdigest, sizeof (cdigest));
1473 	do {
1474 		if ((ret = establish_http_connection(WANBOOTFS, &handle,
1475 			&req_url, 0)) < 0) {
1476 			break;
1477 		} else if (ret > 0) {
1478 			if (wanboot_retry(++retry_cnt, retry_max)) {
1479 				continue;
1480 			} else {
1481 				break;
1482 			}
1483 		}
1484 
1485 		if ((ret = process_wanbootfs(handle, &devpath,
1486 			cdigest, sdigest)) > 0) {
1487 			if (!wanboot_retry(++retry_cnt, retry_max)) {
1488 				(void) http_srv_close(handle);
1489 				break;
1490 			}
1491 		}
1492 
1493 		(void) http_srv_close(handle);
1494 
1495 	} while (ret > 0);
1496 
1497 	/*
1498 	 * Validate the computed digest against the one received.
1499 	 */
1500 	if (ret != 0 ||
1501 		!verify_digests(WANBOOTFS, cdigest, sdigest)) {
1502 		bootlog("wanboot", BOOTLOG_CRIT,
1503 		    "The wanboot file system download aborted");
1504 		return (-1);
1505 	}
1506 
1507 	/*
1508 	 * Mount the wanboot file system.
1509 	 */
1510 	if (determine_fstype_and_mountroot(devpath) != VFS_SUCCESS) {
1511 		bootlog("wanboot", BOOTLOG_CRIT,
1512 		    "Could not mount the wanboot filesystem.");
1513 		bootlog("wanboot", BOOTLOG_CRIT,
1514 		    "This may signify a client/server key mismatch");
1515 		if (encr_type != ENCR_NONE) {
1516 			bootlog("wanboot", BOOTLOG_CRIT,
1517 			    "(client has key but wrong encryption_type?)");
1518 		} else {
1519 			bootlog("wanboot", BOOTLOG_CRIT,
1520 			    "(encryption_type specified but no client key?)");
1521 		}
1522 		return (-1);
1523 	}
1524 	bootlog("wanboot", BOOTLOG_VERBOSE,
1525 	    "The wanboot file system has been mounted");
1526 
1527 	/*
1528 	 * The wanboot file system should contain a nonce. Read it
1529 	 * and compare it against the nonce sent in the request.
1530 	 */
1531 	if ((fd = open(WANBOOTFS_NONCE_FILE, O_RDONLY)) == -1) {
1532 		bootlog("wanboot", BOOTLOG_CRIT,
1533 			"No nonce found in the wanboot file system");
1534 		bootlog("wanboot", BOOTLOG_CRIT,
1535 		    "The wanboot file system download aborted");
1536 		return (-1);
1537 	}
1538 
1539 	if (read(fd, buf, NONCELEN) != NONCELEN ||
1540 	    bcmp(nonce, buf, NONCELEN) != 0) {
1541 		(void) close(fd);
1542 		bootlog("wanboot", BOOTLOG_CRIT,
1543 			"Invalid nonce found in the wanboot file system");
1544 		bootlog("wanboot", BOOTLOG_CRIT,
1545 		    "The wanboot file system download aborted");
1546 		return (-1);
1547 	}
1548 
1549 	(void) close(fd);
1550 
1551 	bootlog("wanboot", BOOTLOG_VERBOSE,
1552 	    "The wanboot file system download was successful");
1553 	return (0);
1554 }
1555 
1556 static boolean_t
1557 init_netdev(char *bpath)
1558 {
1559 	pnode_t		anode;
1560 	int		proplen;
1561 	static char	netalias[OBP_MAXPATHLEN];
1562 
1563 	/*
1564 	 * Wanboot will either have loaded over the network (in which case
1565 	 * bpath will name a network device), or from CD-ROM or disk.  In
1566 	 * both cases ensure that the 'net' alias corresponds to a network
1567 	 * device, and that if a network boot was performed that it is
1568 	 * identical to bpath.  This is so that the interface name can always
1569 	 * be determined for CD-ROM or disk boots, and for manually-configured
1570 	 * network boots.  The latter restriction may be relaxed in the future.
1571 	 */
1572 	anode = prom_alias_node();
1573 	if ((proplen = prom_getproplen(anode, "net")) > 0 &&
1574 	    proplen < sizeof (netalias)) {
1575 		(void) prom_getprop(anode, "net", (caddr_t)netalias);
1576 
1577 		if (is_netdev(netalias)) {
1578 			char	*p;
1579 
1580 			/*
1581 			 * Strip device arguments from netalias[].
1582 			 */
1583 			if ((p = strchr(netalias, ':')) != NULL) {
1584 				*p = '\0';
1585 			}
1586 
1587 			/*
1588 			 * If bpath is a network device path, then v2path
1589 			 * will be a copy of this sans device arguments.
1590 			 */
1591 			if (!is_netdev(bpath) ||
1592 			    strcmp(v2path, netalias) == 0) {
1593 				/*
1594 				 * Stash the netdev_path bootprop value, then
1595 				 * initialize the hardware and return success.
1596 				 */
1597 				netdev_path = netalias;
1598 				mac_init(netalias);
1599 				return (B_TRUE);
1600 			}
1601 
1602 			bootlog("wanboot", BOOTLOG_CRIT,
1603 			    "wanboot requires that the 'net' alias refers to ");
1604 			bootlog("wanboot", BOOTLOG_CRIT,
1605 			    "the network device path from which it loaded");
1606 			return (B_FALSE);
1607 		}
1608 	}
1609 
1610 	/*
1611 	 * If we haven't established a device path for a network interface,
1612 	 * then we're doomed.
1613 	 */
1614 	bootlog("wanboot", BOOTLOG_CRIT,
1615 	    "No network device available for wanboot!");
1616 	bootlog("wanboot", BOOTLOG_CRIT,
1617 	    "(Ensure that the 'net' alias is set correctly)");
1618 	return (B_FALSE);
1619 }
1620 
1621 /*
1622  * This implementation of bootprog() is used solely by wanboot.
1623  *
1624  * The basic algorithm is as follows:
1625  *
1626  * - The wanboot options (those specified using the "-o" flag) are processed,
1627  *   and if necessary the wanboot interpreter is invoked to collect other
1628  *   options.
1629  *
1630  * - The wanboot filesystem (containing certificates, wanboot.conf file, etc.)
1631  *   is then downloaded into the bootfs ramdisk, which is mounted for use
1632  *   by OpenSSL, access to wanboot.conf, etc.
1633  *
1634  * - The wanboot miniroot is downloaded over http/https into the rootfs
1635  *   ramdisk.  The bootfs filesystem is unmounted, and the rootfs filesystem
1636  *   is mounted.
1637  */
1638 /* EXPORT DELETE END */
1639 /*ARGSUSED*/
1640 int
1641 bootprog(char *bpath, char *bargs, boolean_t user_specified_filename)
1642 {
1643 /* EXPORT DELETE START */
1644 	char		*miniroot_path;
1645 	url_t		server_url;
1646 	int		ret;
1647 
1648 	if (!init_netdev(bpath)) {
1649 		return (-1);
1650 	}
1651 
1652 	if (!bootinfo_init()) {
1653 		bootlog("wanboot", BOOTLOG_CRIT, "Cannot initialize bootinfo");
1654 		return (-1);
1655 	}
1656 
1657 	/*
1658 	 * Get default values from PROM, etc., process any boot arguments
1659 	 * (specified with the "-o" option), and initialize the interface.
1660 	 */
1661 	if (!wanboot_init_interface(wanboot_arguments)) {
1662 		return (-1);
1663 	}
1664 
1665 	/*
1666 	 * Determine which encryption and hashing algorithms the client
1667 	 * is configured to use.
1668 	 */
1669 	init_encryption();
1670 	init_hashing();
1671 
1672 	/*
1673 	 * Get the bootserver value.  Should be of the form:
1674 	 *	http://host[:port]/abspath.
1675 	 */
1676 	ret = get_url(BI_BOOTSERVER, &server_url);
1677 	if (ret != 0) {
1678 		bootlog("wanboot", BOOTLOG_CRIT,
1679 		    "Unable to retrieve the bootserver URL");
1680 		return (-1);
1681 	}
1682 
1683 	/*
1684 	 * Get the wanboot file system and mount it. Contains metdata
1685 	 * needed by wanboot.
1686 	 */
1687 	if (get_wanbootfs(&server_url) != 0) {
1688 		return (-1);
1689 	}
1690 
1691 	/*
1692 	 * Check that there is a valid wanboot.conf file in the wanboot
1693 	 * file system.
1694 	 */
1695 	if (bootconf_init(&bc_handle, NULL) != BC_E_NOERROR) {
1696 		bootlog("wanboot", BOOTLOG_CRIT,
1697 		    "wanboot.conf error (code=%d)", bc_handle.bc_error_code);
1698 		return (-1);
1699 	}
1700 
1701 	/*
1702 	 * Set the time
1703 	 */
1704 	init_boot_time();
1705 
1706 	/*
1707 	 * Verify that URLs in wanboot.conf can be reached, etc.
1708 	 */
1709 	if (!wanboot_verify_config()) {
1710 		return (-1);
1711 	}
1712 
1713 	/*
1714 	 * Retrieve the miniroot.
1715 	 */
1716 	if (get_miniroot(&miniroot_path) != 0) {
1717 		return (-1);
1718 	}
1719 
1720 	/*
1721 	 * We don't need the wanboot file system mounted anymore and
1722 	 * should unmount it so that we can mount the miniroot.
1723 	 */
1724 	(void) unmountroot();
1725 
1726 	/*
1727 	 * Mount the miniroot.
1728 	 */
1729 	if (determine_fstype_and_mountroot(miniroot_path) != VFS_SUCCESS) {
1730 		bootlog("wanboot", BOOTLOG_CRIT,
1731 		    "Could not mount miniroot filesystem");
1732 		return (-1);
1733 	}
1734 	bootlog("wanboot", BOOTLOG_VERBOSE, "The miniroot has been mounted");
1735 
1736 	v2path = "/ramdisk-rootfs:a";
1737 	bootlog("wanboot", BOOTLOG_VERBOSE, "device path '%s'", v2path);
1738 
1739 	/*
1740 	 * kernname (default-name) might have changed if mountroot() called
1741 	 * boot_nfs_mountroot(), and it called set_default_filename().
1742 	 */
1743 	if (! user_specified_filename)
1744 		(void) strcpy(filename, kernname);
1745 
1746 	bootlog("wanboot", BOOTLOG_VERBOSE,
1747 	    "standalone = `%s', args = `%s'", filename, bargs);
1748 
1749 	set_client_bootargs(filename, bargs);
1750 
1751 	/*
1752 	 * We're done with the mac interface that was initialized by
1753 	 * mac_init() inside init_netdev().
1754 	 */
1755 	mac_fini();
1756 
1757 	bootconf_end(&bc_handle);
1758 	bootinfo_end();
1759 
1760 /* EXPORT DELETE END */
1761 	return (0);
1762 }
1763