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