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