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 /*
  23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
  25  */
  26 
  27 #include <errno.h>
  28 #include <sys/types.h>
  29 #include <sys/socket.h>
  30 #include <netinet/in.h>
  31 #include <arpa/inet.h>
  32 #include <ctype.h>
  33 #include <stdio.h>
  34 #include <strings.h>
  35 #include <stdlib.h>
  36 #include <netdb.h>
  37 
  38 #include <openssl/ssl.h>
  39 #include <openssl/err.h>
  40 #include <openssl/rand.h>
  41 #include <openssl/pkcs12.h>
  42 
  43 /* this must be included after ssl.h to avoid re-defining 'offsetof' */
  44 #include <sys/sysmacros.h>
  45 
  46 #include <boot_http.h>
  47 #include <socket_inet.h>
  48 #include <p12access.h>
  49 
  50 #include "bootlog.h"
  51 
  52 #define BOOT_HTTP_MAJOR_VERSION 1
  53 #define BOOT_HTTP_MINOR_VERSION 0
  54 #define BOOT_HTTP_MICRO_VERSION 0
  55 
  56 static boot_http_ver_t boot_http_ver = {
  57         BOOT_HTTP_MAJOR_VERSION,
  58         BOOT_HTTP_MINOR_VERSION,
  59         BOOT_HTTP_MICRO_VERSION
  60 };
  61 
  62 static int      early_err;      /* Error from before error occurred */
  63 
  64 static boolean_t verbosemode = B_FALSE;
  65 static char     *cipher_list = NULL; /* Ciphers supported (if not default) */
  66 
  67 typedef struct {
  68         int     i;              /* current position in buffer */
  69         int     n;              /* number of bytes in buffer */
  70         char    buf[512];       /* buffer */
  71 } buf_struct_t;
  72 
  73 typedef struct {
  74         uint_t  errsrc;         /* Source of this error */
  75         ulong_t error;          /* Which error? */
  76 } errent_t;
  77 
  78 
  79 typedef enum {
  80         HTTP_REQ_TYPE_HEAD = 1,
  81         HTTP_REQ_TYPE_GET
  82 } http_req_t;
  83 
  84 #define FAILSAFE 20             /* Max # empty lines to accept */
  85 #define DEFAULT_TIMEOUT 10      /* Default socket read timeout value */
  86 #define HTTP_CONN_INFO 0x90919293 /* Identifies a http_conn_t struct */
  87 #define ESTACK_SIZE     20      /* Size of the stack */
  88 
  89 typedef struct http_conn_t {
  90         uint_t  signature;      /* Cookie indicating this is a handle */
  91         int     fd;             /* Connection's fd... */
  92         SSL_CTX *ctx;
  93         void    *ssl;           /* Handle to ssl data structure */
  94         int     read_timeout;   /* Timeout to use on read requests in sec */
  95         char    *basic_auth_userid;   /* Basic authentication user ID */
  96         char    *basic_auth_password; /* and password */
  97         char    is_multipart;   /* B_TRUE if doing multipart/mixed download */
  98         char    is_firstpart;   /* B_TRUE if first part in a multipart xfer */
  99         char    is_firstchunk;  /* B_TRUE if first chunk in chunked xfer */
 100         char    is_chunked;     /* B_TRUE if message body is chunked */
 101         boolean_t keepalive;
 102         struct  sockaddr_in  host_addr; /* Address of host */
 103         url_t           uri;            /* The current URI */
 104         url_hport_t     proxy;          /* The proxy info */
 105         boolean_t       proxied;        /* Connection is proxied */
 106         char    *random_file;   /* File with seed info for pseudo random  */
 107                                 /* number generator */
 108         char    *client_cert_file;      /* File holding client's certificate */
 109         char    *private_key_file;      /* File with the private key */
 110         char    *file_password; /* file with password to key or pkcs12 file. */
 111         http_respinfo_t resp;   /* Response summary info */
 112         char    **resphdr;      /* Array of header response lines */
 113         buf_struct_t inbuf;
 114         char    *boundary;      /* Boundary text (multipart downloads only) */
 115         uint_t  boundary_len;   /* Length of boundary string */
 116         uint_t  numerrs;
 117         uint_t  nexterr;        /* Next error to return */
 118         ssize_t body_size;      /* Size of message body or chunk */
 119         ssize_t body_read;      /* # of bytes of body_size processed */
 120         ssize_t body_size_tot;  /* Total message body size */
 121         ssize_t body_read_tot;  /* # of bytes of body_size_tot processed */
 122         errent_t errs[ESTACK_SIZE]; /* stack of errors on the last request */
 123                                 /* (libssl can return multiple errors on one */
 124                                 /* operation) */
 125 } http_conn_t;
 126 
 127 /*
 128  * Convenient macros for accessing fields in connection structure.
 129  */
 130 #define CONN_HOSTNAME           c_id->uri.hport.hostname
 131 #define CONN_PORT               c_id->uri.hport.port
 132 #define CONN_ABSPATH            c_id->uri.abspath
 133 #define CONN_HTTPS              c_id->uri.https
 134 #define CONN_PROXY_HOSTNAME     c_id->proxy.hostname
 135 #define CONN_PROXY_PORT         c_id->proxy.port
 136 
 137 #define RESET_ERR(c_id) (c_id)->numerrs = 0, (c_id)->nexterr = 0
 138 #define SET_ERR(c_id, src, err) if ((c_id)->numerrs < ESTACK_SIZE) \
 139                 (c_id)->errs[(c_id)->numerrs].errsrc = (src), \
 140                 (c_id)->errs[(c_id)->numerrs ++].error = (err)
 141 
 142 #define GET_ERR(c_id, e_src, e_code) \
 143                 if ((c_id)->nexterr < (c_id)->numerrs) \
 144                         (e_src) = (c_id)->errs[((c_id)->nexterr)].errsrc, \
 145                         (e_code) = (c_id)->errs[((c_id)->nexterr)++].error; \
 146                 else \
 147                         (e_src) = 0, (e_code) = 0
 148 
 149 /*
 150  * Macro used to increment message body read counters
 151  */
 152 #define INC_BREAD_CNT(bool, bcnt) \
 153         if (bool) { \
 154                 bcnt--; \
 155                 c_id->body_read++;\
 156                 c_id->body_read_tot++; \
 157         }
 158 
 159 static int      ssl_init = 0;           /* 1 when ssl has been initialized */
 160 static char     *ca_verify_file;        /* List of trusted CA's  */
 161 static int      verify_depth = 16;      /* Certificate chain depth to verify */
 162 static int      p12_format = 0;         /* Default to PEM format */
 163 
 164 
 165 /* prototypes for local functions */
 166 static int      http_req(http_handle_t, const char *, http_req_t, offset_t,
 167     offset_t);
 168 static boolean_t http_check_conn(http_conn_t *);
 169 static SSL_CTX *initialize_ctx(http_conn_t *);
 170 static int      tcp_connect(http_conn_t *, const char *, uint16_t);
 171 static int      readline(http_conn_t *, int, char *, int);
 172 static int      proxy_connect(http_conn_t *);
 173 static int      check_cert_chain(http_conn_t *, char *);
 174 static void     print_ciphers(SSL *);
 175 static int      read_headerlines(http_conn_t *, boolean_t);
 176 static void     free_response(http_conn_t *, int);
 177 static int      free_ctx_ssl(http_conn_t *);
 178 static int      get_chunk_header(http_conn_t *);
 179 static int      init_bread(http_conn_t *);
 180 static int      get_msgcnt(http_conn_t *, ssize_t *);
 181 static int      getaline(http_conn_t *, char *, int, boolean_t);
 182 static int      getbytes(http_conn_t *, char *, int);
 183 static int      http_srv_send(http_conn_t *, const void *, size_t);
 184 static int      http_srv_recv(http_conn_t *, void *, size_t);
 185 static void     handle_ssl_error(http_conn_t *, int);
 186 static int      count_digits(int);
 187 static int      hexdigit(char);
 188 static char     *eat_ws(const char *);
 189 static boolean_t startswith(const char **strp, const char *starts);
 190 
 191 /* ---------------------- public functions ----------------------- */
 192 
 193 /*
 194  * http_set_p12_format - Set flag indicating that certs & keys will be in
 195  *                    pkcs12 format.
 196  *
 197  * Default is PEM certs.  When this is called, the default can be changed to
 198  * pcs12 format.
 199  */
 200 void
 201 http_set_p12_format(int on_off)
 202 {
 203         p12_format = on_off;
 204 }
 205 
 206 /*
 207  * http_get_version - Get current boot http support version
 208  *
 209  *     pVer = http_get_version();
 210  *
 211  * Arguments:
 212  *      None.
 213  *
 214  * Returns:
 215  *      Pointer to struct with version information.
 216  *
 217  * Returns the version of the http support in the current library.  This
 218  * is a struct with unsigned integsrs for <major>, <minor> and
 219  * <micro> version numbers.  <major> changes when an incompatible change
 220  * is made.  <minor> changes when an upwardly-compatible API change is
 221  * made.  <micro> consists of bug fixes, etc.
 222  */
 223 boot_http_ver_t const *
 224 http_get_version(void)
 225 {
 226         return (&boot_http_ver);
 227 }
 228 
 229 /*
 230  * http_set_verbose - Turn verbose on/off
 231  *
 232  *     http_set_verbose(on_off);
 233  *
 234  * Arguments:
 235  *      on_off  - When TRUE, turn verbose mode one.  When FALSE, turn
 236  *                verbose off.
 237  *
 238  * Returns:
 239  *      None.
 240  *
 241  * When enabled, information is logged to bootlog (or the Solaris equivalent).
 242  */
 243 void
 244 http_set_verbose(boolean_t on_off)
 245 {
 246         verbosemode = on_off;
 247 }
 248 
 249 /*
 250  * http_set_cipher_list - Change the list of ciphers that can be used.
 251  *
 252  *     ret = http_set_cipher_list(handle, list);
 253  *
 254  * Arguments:
 255  *      list    - List of ciphers that can be used.
 256  *
 257  * Returns:
 258  *      0       - Success
 259  *      -1      - An error occurred.  Check http_get_lasterr().
 260  */
 261 int
 262 http_set_cipher_list(const char *list)
 263 {
 264         early_err = 0;
 265 
 266         if (list != NULL) {
 267                 list = strdup(list);
 268                 if (list == NULL) {
 269                         early_err = EHTTP_NOMEM;
 270                         return (-1);
 271                 }
 272         }
 273 
 274         free(cipher_list);
 275         cipher_list = (char *)list;
 276         return (0);
 277 }
 278 
 279 /*
 280  * http_srv_init - Set up a structure for a connection.
 281  *
 282  *     handle = http_srv_init(url);
 283  *
 284  * Arguments:
 285  *      url - the structure that contains the URI.
 286  *
 287  * Returns:
 288  *      != NULL - A handle for referring to this connection.
 289  *      == NULL - An error occurred.  Get the exact error from
 290  *                http_get_lasterr().
 291  */
 292 http_handle_t
 293 http_srv_init(const url_t *url)
 294 {
 295         http_conn_t     *c_id;
 296 
 297         early_err = 0;
 298         if (url == NULL) {
 299                 early_err = EHTTP_BADARG;
 300                 return (NULL);
 301         }
 302 
 303         if ((c_id = malloc(sizeof (*c_id))) == NULL) {
 304                 early_err = EHTTP_NOMEM;
 305                 return (NULL);
 306         }
 307 
 308         bzero(c_id, sizeof (*c_id));
 309         c_id->uri = *url;
 310         c_id->proxied = B_FALSE;
 311         c_id->read_timeout = DEFAULT_TIMEOUT;
 312         c_id->keepalive = B_TRUE;
 313         c_id->fd = -1;
 314 
 315         /* Do this at the end, just in case.... */
 316         c_id->signature = HTTP_CONN_INFO;
 317 
 318         return (c_id);
 319 }
 320 
 321 /*
 322  * http_conn_is_https - Determine whether the scheme is http or https.
 323  *
 324  *      B_TRUE  - Connection is an SSL connection.
 325  *      B_FALSE - Connection isn't SSL.
 326  *
 327  *     ret = http_conn_is_https(handle, boolean_t *bool);
 328  *
 329  * Arguments:
 330  *      handle  - Handle associated with the desired connection
 331  *      bool    - Ptr to boolean in which to place result
 332  *
 333  * Returns:
 334  *      0       - Success
 335  *      -1      - Some error occurred.
 336  */
 337 int
 338 http_conn_is_https(http_handle_t handle, boolean_t *bool)
 339 {
 340         http_conn_t     *c_id = handle;
 341 
 342         if (!http_check_conn(c_id))
 343                 return (-1);
 344 
 345         *bool = CONN_HTTPS;
 346         return (0);
 347 }
 348 
 349 /*
 350  * http_set_proxy - Establish the proxy name/port.
 351  *
 352  *     ret = http_set_proxy(handle, proxy);
 353  *
 354  * Arguments:
 355  *      handle  - Handle associated with the desired connection
 356  *      proxy   - The hostport definition for the proxy. If NULL,
 357  *                The next connect will not use a proxy.
 358  *
 359  * Returns:
 360  *      0       - Success
 361  *      -1      - An error occurred.  Check http_get_lasterr().
 362  */
 363 int
 364 http_set_proxy(http_handle_t handle, const url_hport_t *proxy)
 365 {
 366         http_conn_t *c_id = handle;
 367 
 368         if (!http_check_conn(c_id))
 369                 return (-1);
 370 
 371         if (proxy != NULL) {
 372                 c_id->proxy = *proxy;
 373                 c_id->proxied = B_TRUE;
 374         } else {
 375                 CONN_PROXY_HOSTNAME[0] = '\0';
 376                 c_id->proxied = B_FALSE;
 377         }
 378 
 379         return (0);
 380 }
 381 
 382 /*
 383  * http_set_keepalive - Set keepalive for this connection.
 384  *
 385  *     http_set_keepalive(handle, on_off);
 386  *
 387  * Arguments:
 388  *      handle  - Handle associated with the desired connection
 389  *      on_off  - Boolean turning keepalive on (TRUE) or off (FALSE)
 390  *
 391  * Returns:
 392  *      0       - Success.
 393  *      -1      - An error occurred.  Check http_get_lasterr().
 394  *
 395  * This setting takes effect next time a connection is opened using this
 396  * handle.
 397  */
 398 int
 399 http_set_keepalive(http_handle_t handle, boolean_t on_off)
 400 {
 401         http_conn_t *c_id = handle;
 402 
 403         if (!http_check_conn(c_id))
 404                 return (-1);
 405 
 406         c_id->keepalive = on_off;
 407         return (0);
 408 }
 409 
 410 /*
 411  * http_set_socket_read_timeout - Set the timeout reads
 412  *
 413  *     http_set_socket_read_timeout(handle, timeout);
 414  *
 415  * Arguments:
 416  *      handle  - Handle associated with the desired connection
 417  *      timeout - Timeout, in seconds.  Zero will default to 10 second
 418  *                timeouts.
 419  *
 420  * Returns:
 421  *      0       - Success.
 422  *      -1      - An error occurred.  Check http_get_lasterr().
 423  *
 424  * This setting takes effect beginning with the next read operation on this
 425  * connection.
 426  */
 427 int
 428 http_set_socket_read_timeout(http_handle_t handle, uint_t timout)
 429 {
 430         http_conn_t *c_id = handle;
 431 
 432         if (!http_check_conn(c_id))
 433                 return (-1);
 434 
 435         c_id->read_timeout = (timout) ? timout : DEFAULT_TIMEOUT;
 436         return (0);
 437 }
 438 
 439 /*
 440  * http_set_basic_auth - Set the basic authorization user ID and password
 441  *
 442  *     ret = http_set_basic_auth(handle, userid, password);
 443  *
 444  * Arguments:
 445  *      handle  - Handle associated with the desired connection
 446  *      userid  - ID to pass as part of http/https request
 447  *      password- Password which goes with the user ID
 448  *
 449  * Returns:
 450  *      0       - Success
 451  *      -1      - An error occurred.  Check http_get_lasterr().
 452  *
 453  * This must be set before a https connection is made.
 454  */
 455 int
 456 http_set_basic_auth(http_handle_t handle, const char *userid,
 457     const char *password)
 458 {
 459         http_conn_t *c_id = handle;
 460 
 461         if (!http_check_conn(c_id))
 462                 return (-1);
 463 
 464         if (password == NULL || userid == NULL || userid[0] == '\0') {
 465                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
 466                 return (-1);
 467         }
 468 
 469         userid = strdup(userid);
 470         password = strdup(password);
 471         if (userid == NULL || password == NULL) {
 472                 free((void *)userid);
 473                 free((void *)password);
 474                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
 475                 return (-1);
 476         }
 477 
 478         free(c_id->basic_auth_userid);
 479         c_id->basic_auth_userid = (char *)userid;
 480         free(c_id->basic_auth_password);
 481         c_id->basic_auth_password = (char *)password;
 482         return (0);
 483 }
 484 
 485 /*
 486  * http_set_random_file - See the pseudo random number generator with file data
 487  *
 488  *     ret = http_set_random_file(handle, filename);
 489  *
 490  * Arguments:
 491  *      handle  - Handle associated with the desired connection
 492  *      filename
 493  *              - filename (including path) with random number seed.
 494  *
 495  * Returns:
 496  *      0       - Success
 497  *      -1      - An error occurred.  Check http_get_lasterr().
 498  *
 499  * This must be set before a https connection is made.
 500  */
 501 int
 502 http_set_random_file(http_handle_t handle, const char *fname)
 503 {
 504         http_conn_t *c_id = handle;
 505 
 506         if (!http_check_conn(c_id))
 507                 return (-1);
 508 
 509         if (fname != NULL) {
 510                 fname = strdup(fname);
 511                 if (fname == NULL) {
 512                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
 513                         return (-1);
 514                 }
 515         }
 516 
 517         free(c_id->random_file);
 518         c_id->random_file = (char *)fname;
 519         return (0);
 520 }
 521 
 522 /*
 523  * http_set_certificate_authority_file - Set the CA file.
 524  *
 525  *     ret = http_set_certificate_authority_file(filename);
 526  *
 527  * Arguments:
 528  *      filename- File with the certificate authority certs
 529  *
 530  * Returns:
 531  *      0       - Success
 532  *      -1      - An error occurred.  Check http_get_lasterr().
 533  *
 534  * This must be set before https connections to the servers is done.
 535  */
 536 int
 537 http_set_certificate_authority_file(const char *fname)
 538 {
 539         early_err = 0;
 540 
 541         if (fname != NULL) {
 542                 fname = strdup(fname);
 543                 if (fname == NULL) {
 544                         early_err = EHTTP_NOMEM;
 545                         return (-1);
 546                 }
 547         }
 548 
 549         free(ca_verify_file);
 550         ca_verify_file = (char *)fname;
 551         return (0);
 552 }
 553 
 554 /*
 555  * http_set_client_certificate_file - Set the file containing the PKCS#12
 556  *              client certificate and optionally its certificate chain.
 557  *
 558  *     ret = http_set_client_certificate_file(handle, filename);
 559  *
 560  * Arguments:
 561  *      handle  - Handle associated with the desired connection
 562  *      filename- File (including path) containing certificate, etc.
 563  *
 564  * Returns:
 565  *      0       - Success
 566  *      -1      - An error occurred.  Check http_get_lasterr().
 567  *
 568  * This must be set before the handle is used to make a https connection
 569  * which will require a client certificate.
 570  */
 571 int
 572 http_set_client_certificate_file(http_handle_t handle, const char *fname)
 573 {
 574         http_conn_t *c_id = handle;
 575 
 576         if (!http_check_conn(c_id))
 577                 return (-1);
 578 
 579         if (fname != NULL) {
 580                 fname = strdup(fname);
 581                 if (fname == NULL) {
 582                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
 583                         return (-1);
 584                 }
 585         }
 586 
 587         free(c_id->client_cert_file);
 588         c_id->client_cert_file = (char *)fname;
 589         return (0);
 590 }
 591 
 592 /*
 593  * http_set_password - Set the password for the private key or pkcs12 file.
 594  *
 595  *     ret = http_set_password(handle, password);
 596  *
 597  * Arguments:
 598  *      handle  - Handle associated with the desired connection
 599  *      password- Password for the client's private key file or pkcs12 file.
 600  *
 601  * Returns:
 602  *      0       - Success
 603  *      -1      - An error occurred.  Check http_get_lasterr().
 604  *
 605  * This must be set before the handle is used to make a https connection.
 606  */
 607 int
 608 http_set_password(http_handle_t handle, const char *password)
 609 {
 610         http_conn_t *c_id = handle;
 611 
 612         if (!http_check_conn(c_id))
 613                 return (-1);
 614 
 615         if (password != NULL) {
 616                 password = strdup(password);
 617                 if (password == NULL) {
 618                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
 619                         return (-1);
 620                 }
 621         }
 622 
 623         free(c_id->file_password);
 624         c_id->file_password = (char *)password;
 625         return (0);
 626 }
 627 
 628 /*
 629  * http_set_key_file_password - Set the password for the private key
 630  *              file.
 631  *
 632  *     ret = http_set_key_file_password(handle, password);
 633  *
 634  * Arguments:
 635  *      handle  - Handle associated with the desired connection
 636  *      password- Password for the client's private key file.
 637  *
 638  * Returns:
 639  *      0       - Success
 640  *      -1      - An error occurred.  Check http_get_lasterr().
 641  *
 642  * This must be set before the handle is used to make a https connection.
 643  */
 644 int
 645 http_set_key_file_password(http_handle_t handle, const char *password)
 646 {
 647         return (http_set_password(handle, password));
 648 }
 649 
 650 /*
 651  * http_set_private_key_file - Set the file containing the PKCS#12
 652  *              private key for this client.
 653  *
 654  *     ret = http_set_private_key_file(handle, filename);
 655  *
 656  * Arguments:
 657  *      handle  - Handle associated with the desired connection
 658  *      filename- File (including path) containing the private key.
 659  *
 660  * Returns:
 661  *      0       - Success
 662  *      -1      - An error occurred.  Check http_get_lasterr().
 663  *
 664  * This must be set before the handle is used to make a https connection.
 665  */
 666 int
 667 http_set_private_key_file(http_handle_t handle, const char *fname)
 668 {
 669         http_conn_t *c_id = handle;
 670 
 671         if (!http_check_conn(c_id))
 672                 return (-1);
 673 
 674         if (fname != NULL) {
 675                 fname = strdup(fname);
 676                 if (fname == NULL) {
 677                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
 678                         return (-1);
 679                 }
 680         }
 681 
 682         free(c_id->private_key_file);
 683         c_id->private_key_file = (char *)fname;
 684         return (0);
 685 }
 686 
 687 /*
 688  * http_srv_connect - Establish a connection to the server
 689  *
 690  *     ret = http_srv_connect(handle);
 691  *
 692  * Arguments:
 693  *      handle  - Handle associated with the desired connection
 694  *
 695  * Returns:
 696  *      0       - Success
 697  *      -1      - An error occurred.  Check http_get_lasterr() for specifics.
 698  */
 699 int
 700 http_srv_connect(http_handle_t handle)
 701 {
 702         http_conn_t     *c_id = handle;
 703         SSL_CTX         *ctx = NULL;
 704         int             retval;
 705 
 706         ERR_clear_error();
 707         if (!http_check_conn(c_id))
 708                 return (-1);
 709 
 710         if (CONN_HTTPS) {
 711                 /* Build our SSL context (this function sets any errors) */
 712                 ctx = initialize_ctx(c_id);
 713                 if (ctx == NULL) {
 714                         libbootlog(BOOTLOG_CRIT,
 715                             "http_srv_connect: initialize_ctx returned NULL");
 716                         return (-1);
 717                 }
 718         }
 719 
 720         /* Connect the TCP socket */
 721         if (c_id->proxied) {
 722                 c_id->fd = proxy_connect(c_id);
 723         } else {
 724                 c_id->fd = tcp_connect(c_id, CONN_HOSTNAME, CONN_PORT);
 725         }
 726 
 727         if (c_id->fd < 0) {
 728                 if (ctx != NULL)
 729                         SSL_CTX_free(ctx);
 730                         libbootlog(BOOTLOG_CRIT,
 731                             "http_srv_connect: %s returned %d",
 732                             (c_id->proxied) ? "proxy_connect" : "tcp_connect",
 733                             c_id->fd);
 734                 return (-1);
 735         }
 736 
 737         if (CONN_HTTPS) {
 738                 /* Connect the SSL socket */
 739                 if ((c_id->ssl = SSL_new(ctx)) == NULL) {
 740                         ulong_t err;
 741                         while ((err = ERR_get_error()) != 0)
 742                                 SET_ERR(c_id, ERRSRC_LIBSSL, err);
 743                                 libbootlog(BOOTLOG_CRIT,
 744                                     "http_srv_connect: SSL_new returned "
 745                                     "NULL");
 746                         (void) free_ctx_ssl(c_id);
 747                         return (-1);
 748                 }
 749                 if (verbosemode)
 750                         print_ciphers(c_id->ssl);
 751 
 752                 /* Ensure automatic negotiations will do things right */
 753                 SSL_set_connect_state(c_id->ssl);
 754 
 755                 if (SSL_set_fd(c_id->ssl, c_id->fd) == 0) {
 756                         ulong_t err;
 757                         while ((err = ERR_get_error()) != 0)
 758                                 SET_ERR(c_id, ERRSRC_LIBSSL, err);
 759                                 libbootlog(BOOTLOG_CRIT,
 760                                     "http_srv_connect: SSL_set_fd returned 0");
 761                         (void) free_ctx_ssl(c_id);
 762                         return (-1);
 763                 }
 764 
 765                 if ((retval = SSL_connect(c_id->ssl)) <= 0) {
 766                         handle_ssl_error(c_id, retval);
 767                         libbootlog(BOOTLOG_CRIT,
 768                             "http_srv_connect: SSL_connect");
 769                         (void) free_ctx_ssl(c_id);
 770                         return (-1);
 771                 }
 772 
 773                 if (check_cert_chain(c_id, CONN_HOSTNAME) != 0) {
 774                         (void) free_ctx_ssl(c_id);
 775                         return (-1);
 776                 }
 777 
 778                 if (verbosemode)
 779                         print_ciphers(c_id->ssl);
 780         }
 781 
 782         return (0);
 783 }
 784 
 785 /*
 786  * http_head_request - Issue http HEAD request
 787  *
 788  *     ret = http_head_request(handle, abs_path);
 789  *
 790  * Arguments:
 791  *      handle  - Handle associated with the desired connection
 792  *      abs_path- File name portion of the URI, beginning with a /.  Query,
 793  *                segment, etc are allowed.
 794  *
 795  * Returns:
 796  *      0       - Success
 797  *      -1      - An error occurred.  Check http_get_lasterr().
 798  */
 799 int
 800 http_head_request(http_handle_t handle, const char *abs_path)
 801 {
 802         return (http_req(handle, abs_path, HTTP_REQ_TYPE_HEAD, 0, 0));
 803 }
 804 
 805 /*
 806  * http_get_request - Issue http GET request without a range.
 807  *
 808  *     ret = http_get_request(handle, abs_path);
 809  *
 810  * Arguments:
 811  *      handle  - Handle associated with the desired connection
 812  *      abs_path- File name portion of the URI, beginning with a /.  Query,
 813  *                segment, etc are allowed.
 814  *
 815  * Returns:
 816  *      0       - Success
 817  *      -1      - An error occurred.  Check http_get_lasterr().
 818  */
 819 int
 820 http_get_request(http_handle_t handle, const char *abs_path)
 821 {
 822         return (http_req(handle, abs_path, HTTP_REQ_TYPE_GET, -1, 0));
 823 }
 824 
 825 /*
 826  * http_get_range_request - Issue http GET request using a range.
 827  *
 828  *     ret = http_get_range_request(handle, abs_path, curpos, len);
 829  *
 830  * Arguments:
 831  *      handle  - Handle associated with the desired connection
 832  *      abs_path- File name portion of the URI, beginning with a /.  Query,
 833  *                segment, etc are allowed.
 834  *      curpos  - >=0 - Beginning of range
 835  *      len     - = 0 - Range ends at the end of the file
 836  *                > 0 - Length of range.
 837  *
 838  * Returns:
 839  *      0       - Success
 840  *      -1      - An error occurred.  Check http_get_lasterr().
 841  */
 842 int
 843 http_get_range_request(http_handle_t handle, const char *abs_path,
 844     offset_t curpos, offset_t len)
 845 {
 846         http_conn_t *c_id = handle;
 847 
 848         if (!http_check_conn(c_id))
 849                 return (-1);
 850 
 851         if (curpos < 0) {
 852                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
 853                 return (-1);
 854         }
 855 
 856         return (http_req(handle, abs_path, HTTP_REQ_TYPE_GET, curpos, len));
 857 }
 858 
 859 /*
 860  * http_free_respinfo - Free a respinfo structure
 861  *
 862  *     ret = http_free_respinfo(resp);
 863  *
 864  * Arguments:
 865  *      resp    - respinfo structure presumably allocated by
 866  *                http_process_headers() or http_process_part_headers()
 867  *
 868  * Note that if resp is NULL, then this results in a NOOP.
 869  *
 870  */
 871 void
 872 http_free_respinfo(http_respinfo_t *resp)
 873 {
 874         if (resp == NULL) {
 875                 return;
 876         }
 877 
 878         if (resp->statusmsg != NULL) {
 879                 free(resp->statusmsg);
 880         }
 881         free(resp);
 882 }
 883 
 884 /*
 885  * http_process_headers - Read in the header lines from the response
 886  *
 887  *     ret = http_process_headers(handle, resp);
 888  *
 889  * Arguments:
 890  *      handle  - Handle associated with the connection where the request
 891  *                was made.
 892  *      resp    - Summary information about the response.
 893  *
 894  * Returns:
 895  *      0       - Success
 896  *      < 0  - An error occurred.  Specifics of the error can
 897  *                be gotten using http_get_lasterr().
 898  *
 899  * Process the HTTP headers in the response. Check for a valid response
 900  * status line.  Allocate and return response information via the 'resp'
 901  * argument. Header lines are stored locally, are are returned using calls
 902  * to http_get_response_header() and http_get_header_value().
 903  *
 904  * Note that the errors will be set in the http_conn_t struct before the
 905  * function which detected the error returns.
 906  *
 907  * Note that if resp is non-NULL, then upon a successful return, information
 908  * about the status line, the code in the status line and the number of
 909  * header lines are returned in the http_respinfo_t structure. The caller is
 910  * responsible for freeing the resources allocated to this structure via
 911  * http_free_respinfo().
 912  *
 913  * Note that the counters used to read message bodies are initialized here.
 914  *
 915  * Calling this function replaces the header information which is
 916  * queried using http_get_response_header() and http_get_header_value().
 917  * Once this function is called, headers read by the previous call
 918  * to http_process_headers() or http_process_part_headers() is lost.
 919  */
 920 int
 921 http_process_headers(http_handle_t handle, http_respinfo_t **resp)
 922 {
 923         http_conn_t *c_id = handle;
 924         http_respinfo_t *lresp;
 925         char    line[MAXHOSTNAMELEN];
 926         char    *ptr;
 927         int     i;
 928 
 929         ERR_clear_error();
 930         if (!http_check_conn(c_id))
 931                 return (-1);
 932 
 933         if (resp != NULL) {
 934                 if ((lresp = malloc(sizeof (http_respinfo_t))) == NULL) {
 935                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
 936                         return (-1);
 937                 }
 938 
 939                 bzero(lresp, sizeof (http_respinfo_t));
 940         }
 941 
 942         /*
 943          * check the response status line, expecting
 944          * HTTP/1.1 200 OK
 945          */
 946         i = getaline(c_id, line, sizeof (line), B_FALSE);
 947         if (i == 0) {
 948                 if (resp != NULL) {
 949                         *resp = lresp;
 950                 }
 951                 return (0);
 952         }
 953 
 954         if (i < 0) {
 955                 /*
 956                  * Cause of I/O error was already put into
 957                  * error stack.  This is an additional error.
 958                  */
 959                 http_free_respinfo(lresp);
 960                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NODATA);
 961                 return (-1);
 962         }
 963 
 964         free_response(c_id, B_TRUE);
 965 
 966         if (verbosemode)
 967                 libbootlog(BOOTLOG_VERBOSE, "http_process_headers: %s", line);
 968 
 969         ptr = line;
 970         if (strncmp(ptr, "HTTP/1.1", 8) != 0) {
 971                 http_free_respinfo(lresp);
 972                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOT_1_1);
 973                 return (-1);
 974         }
 975 
 976         /* skip to the code */
 977         ptr += 8;
 978         while (isspace(*ptr))
 979                 ptr++;
 980 
 981         /* make sure it's three digits */
 982         i = 0;
 983         while (isdigit(ptr[i]))
 984                 i++;
 985         if (i != 3) {
 986                 http_free_respinfo(lresp);
 987                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADHDR);
 988                 return (-1);
 989         }
 990         c_id->resp.code = strtol(ptr, NULL, 10);
 991 
 992         /* skip to the message */
 993         ptr += 3;
 994         while (isspace(*ptr))
 995                 ptr++;
 996 
 997         /* save the message */
 998         c_id->resp.statusmsg = malloc(strlen(ptr) + 1);
 999         if (c_id->resp.statusmsg == NULL) {
1000                 http_free_respinfo(lresp);
1001                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1002                 return (-1);
1003         }
1004         (void) strcpy(c_id->resp.statusmsg, ptr);
1005 
1006         if ((i = read_headerlines(c_id, B_FALSE)) < 0) {
1007                 /*
1008                  * Error stack was already set at a lower level.
1009                  * 'statusmsg' will be cleaned up next time
1010                  * headers are read.
1011                  */
1012                 http_free_respinfo(lresp);
1013                 return (-1);
1014         }
1015 
1016         /*
1017          * See if there is a 'content-type: multipart/mixed' line in the
1018          * headers.  If so, get the boundary string.
1019          */
1020         ptr = http_get_header_value(handle, "Content-Type");
1021         if (ptr != NULL) {
1022                 char *ptr2;
1023 
1024                 ptr2 = ptr;
1025                 while (isspace(*ptr2))
1026                         ptr2 ++;
1027                 if (startswith((const char **)&ptr2, "Multipart/Mixed;")) {
1028                         while (isspace(*ptr2))
1029                                 ptr2 ++;
1030                         if (startswith((const char **)&ptr2, "Boundary=")) {
1031                                 if (ptr2[0] == '"') {
1032                                         ptr2 ++;
1033                                         if (ptr2[strlen(ptr2) - 1] == '"')
1034                                                 ptr2[strlen(ptr2) - 1] = '\0';
1035                                 }
1036                                 c_id->boundary = strdup(ptr2);
1037                                 if (c_id->boundary == NULL) {
1038                                         free(ptr);
1039                                         http_free_respinfo(lresp);
1040                                         SET_ERR(c_id, ERRSRC_LIBHTTP,
1041                                             EHTTP_NOMEM);
1042                                         return (-1);
1043                                 }
1044                                 c_id->boundary_len = strlen(c_id->boundary);
1045                                 c_id->is_multipart = B_TRUE;
1046                                 c_id->is_firstpart = B_TRUE;
1047                         }
1048                 }
1049                 free(ptr);
1050         }
1051 
1052         /*
1053          * Initialize the counters used to process message bodies.
1054          */
1055         if (init_bread(c_id) != 0) {
1056                 /*
1057                  * Error stack was already set at a lower level.
1058                  */
1059                 http_free_respinfo(lresp);
1060                 return (-1);
1061         }
1062 
1063         /* Copy fields to the caller's structure */
1064         if (resp != NULL) {
1065                 lresp->code = c_id->resp.code;
1066                 lresp->nresphdrs = c_id->resp.nresphdrs;
1067                 lresp->statusmsg = strdup(c_id->resp.statusmsg);
1068                 if (lresp->statusmsg == NULL) {
1069                         http_free_respinfo(lresp);
1070                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1071                         return (-1);
1072                 }
1073                 *resp = lresp;
1074         }
1075 
1076         return (0);
1077 }
1078 
1079 /*
1080  * http_process_part_headers - Read in part boundary and header lines for the
1081  *                             next part of a multipart message.
1082  *
1083  *        ret = http_process_part_headers(handle, resp);
1084  *
1085  * Arguments:
1086  *   handle     - Handle associated with the connection where the request
1087  *                was made.
1088  *   resp       - Return address for summary information about the
1089  *                header block.
1090  *
1091  * Returns:
1092  *   = 1        - The end part was found.
1093  *   = 0        - Success, with header info returned in 'resp'
1094  *   = -1       - An error occurred.  Specifics of the error can
1095  *                be gotten using http_get_lasterr().
1096  *
1097  * This function reads any \r\n sequences (empty lines) and expects to get
1098  * a boundary line as the next non-empty line.  It then reads header lines
1099  * (content-length, etc) until it gets another empty lines, which ends the
1100  * header section.
1101  *
1102  * Note that if resp is non-NULL, then upon a successful return, information
1103  * about the the number of header lines is returned in the http_respinfo_t
1104  * structure. The caller is responsible for freeing the resources allocated
1105  * to this structure via http_free_respinfo().
1106  *
1107  * Headers values can be returned using http_get_response_header() and
1108  * http_get_header_value().
1109  *
1110  * Calling this function replaces the header information which is
1111  * queried using http_get_response_header() and http_get_header_value().
1112  * Once this function is called, information returned by the previous call
1113  * to http_process_headers() or http_process_part_headers() is gone.
1114  */
1115 int
1116 http_process_part_headers(http_handle_t handle, http_respinfo_t **resp)
1117 {
1118         http_conn_t *c_id = handle;
1119         char    line[MAXHOSTNAMELEN];
1120         int     count;
1121         int     limit;
1122         int     i;
1123 
1124         ERR_clear_error();
1125         if (!http_check_conn(c_id))
1126                 return (-1);
1127 
1128         if (c_id->is_multipart == 0) {
1129                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOTMULTI);
1130                 return (-1);
1131         }
1132 
1133         /*
1134          * Figure out how many empty lines to allow.  Before the first
1135          * boundary of the transmission, there can be any number of
1136          * empty lines (from 0 up).  Limit these to some reasonable
1137          * failsafe.
1138          *
1139          * For the 2nd and later boundaries, there is supposed to be
1140          * one crlf pair.  However, many implementations don't require
1141          * it.  So don't require it.
1142          */
1143         if (c_id->is_firstpart) {
1144                 limit = FAILSAFE;
1145                 c_id->is_firstpart = B_FALSE;
1146         } else
1147                 limit = 1;
1148 
1149         /* Look for the boundary line. */
1150         count = 0;
1151         while ((i = getaline(c_id, line, sizeof (line), B_TRUE)) == 0 &&
1152             count < FAILSAFE)
1153                 count ++;
1154         if (i < 0 || count > limit) {
1155                 /*
1156                  * If I/O error, cause was already put into
1157                  * error stack.  This is an additional error.
1158                  */
1159                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOBOUNDARY);
1160                 return (-1);
1161         }
1162 
1163         free_response(c_id, B_FALSE);
1164 
1165         if (verbosemode)
1166                 libbootlog(BOOTLOG_VERBOSE,
1167                     "http_process_part_headers: %s", line);
1168 
1169         /* Look for boundary line - '--<boundary text> */
1170         if (line[0] != '-' || line[1] != '-' ||
1171             strncmp(&line[2], c_id->boundary, c_id->boundary_len) != 0) {
1172                 /* No boundary line.... */
1173                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOBOUNDARY);
1174                 return (-1);
1175         }
1176 
1177         /* Is this the end-of-parts boundary (ends with a trailing '--') */
1178         if (strcmp(&line[c_id->boundary_len + 2], "--") == 0) {
1179                 return (1);
1180         }
1181 
1182         free_response(c_id, B_FALSE);
1183         if (read_headerlines(c_id, B_TRUE) < 0) {
1184                 /* Error stack was already set at a lower level. */
1185                 return (-1);
1186         }
1187 
1188         /* Copy fields to the caller's structure */
1189         if (resp != NULL) {
1190                 if ((*resp = malloc(sizeof (http_respinfo_t))) == NULL) {
1191                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1192                         return (-1);
1193                 }
1194                 bzero(*resp, sizeof (http_respinfo_t));
1195                 (*resp)->code = ' ';
1196                 (*resp)->nresphdrs = c_id->resp.nresphdrs;
1197         }
1198 
1199         return (0);
1200 }
1201 
1202 /*
1203  * http_get_response_header - Get a line from the response header
1204  *
1205  *     ret = http_get_response_header(handle, whichline);
1206  *
1207  * Arguments:
1208  *      handle  - Handle associated with the desired connection
1209  *      whichline - Which line of the header to return.  This must be between
1210  *                zero and resp.nresphdrs which was returned by the call to
1211  *                http_process_headers().
1212  *
1213  * Returns:
1214  *      ptr     - Points to a copy of the header line.
1215  *      NULL    - An error occurred.  Check http_get_lasterr().
1216  */
1217 char *
1218 http_get_response_header(http_handle_t handle, uint_t which)
1219 {
1220         http_conn_t *c_id = handle;
1221         char *res;
1222 
1223         if (!http_check_conn(c_id))
1224                 return (NULL);
1225 
1226         if (which >= c_id->resp.nresphdrs) {
1227                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_OORANGE);
1228                 return (NULL);
1229         }
1230 
1231         res = strdup(c_id->resphdr[which]);
1232         if (res == NULL) {
1233                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1234                 return (NULL);
1235         }
1236         return (res);
1237 }
1238 
1239 /*
1240  * http_get_header_value - Get the value of a header line.
1241  *
1242  *     ret = http_get_header_value(handle, what);
1243  *
1244  * Arguments:
1245  *      handle  - Handle associated with the desired connection
1246  *      what    - The field name to look up.
1247  *
1248  * Returns:
1249  *      ptr     - Points to a copy of the header value.
1250  *      NULL    - An error occurred.  Check http_get_lasterr().
1251  */
1252 char *
1253 http_get_header_value(http_handle_t handle, const char *field_name)
1254 {
1255         http_conn_t *c_id = handle;
1256         char    *ptr;
1257         char    *res;
1258         int     i;
1259         int     n;
1260 
1261         if (!http_check_conn(c_id))
1262                 return (NULL);
1263 
1264         if (field_name == NULL || field_name[0] == '\0') {
1265                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1266                 return (NULL);
1267         }
1268 
1269         for (i = 0; i < c_id->resp.nresphdrs; i++) {
1270                 ptr = c_id->resphdr[i];
1271                 n = strlen(field_name);
1272                 if (strncasecmp(field_name, ptr, n) == 0 && ptr[n] == ':') {
1273                         ptr += n + 1;
1274 
1275                         while (isspace(*ptr))
1276                                 ptr++;
1277 
1278                         res = strdup(ptr);
1279                         if (res == NULL) {
1280                                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1281                                 return (NULL);
1282                         }
1283                         return (res);
1284                 }
1285         }
1286         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMATCH);
1287         return (NULL);
1288 }
1289 
1290 /*
1291  * http_read_body - Read the HTTP response body.
1292  *
1293  *     ret = http_read_body(handle, recv_buf_ptr, recv_buf_size);
1294  *
1295  * Arguments:
1296  *      handle  - Handle associated with the relevant connection
1297  *      recv_buf_ptr - Points to buffer to receive buffer
1298  *      recv_buf_size - Length in bytes of buffer.
1299  *
1300  * Returns:
1301  *      n       - Number of bytes read..
1302  *      < 0  - An error occurred.  This is (the number of bytes gotten + 1),
1303  *                negated.  In other words, if 'n' bytes were read and then an
1304  *                error occurred, this will return (-(n+1)).  So zero bytes
1305  *                were read and then an error occurs, this will return -1.  If
1306  *                1 byte was read, it will return -2, etc.  Specifics of the
1307  *                error can be gotten using http_get_lasterr().
1308  *
1309  * Note that the errors will be set in the http_conn_t struct before the
1310  * function which detected the error returns.
1311  */
1312 int
1313 http_read_body(http_handle_t handle, char *recv_buf_ptr, size_t recv_buf_size)
1314 {
1315         http_conn_t *c_id = handle;
1316 
1317         ERR_clear_error();
1318         if (!http_check_conn(c_id))
1319                 return (-1);
1320 
1321         if (recv_buf_ptr == NULL || recv_buf_size == 0) {
1322                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1323                 return (-1);
1324         }
1325 
1326         return (getbytes(c_id, recv_buf_ptr, recv_buf_size));
1327 }
1328 
1329 /*
1330  * http_srv_disconnect - Get rid of the connection to the server without
1331  *                      freeing the http_conn_t structure.
1332  *
1333  *     ret = http_srv_disconnect(handle);
1334  *
1335  * Arguments:
1336  *      handle  - Handle associated with the connection
1337  *
1338  * Returns:
1339  *      0       - Success
1340  *      -1      - An error occurred.  Specifics of the error can
1341  *                be gotten using http_get_lasterr().
1342  */
1343 int
1344 http_srv_disconnect(http_handle_t handle)
1345 {
1346         http_conn_t *c_id = handle;
1347         int err_ret;
1348 
1349         ERR_clear_error();
1350         if (!http_check_conn(c_id))
1351                 return (-1);
1352 
1353         err_ret = free_ctx_ssl(c_id);
1354         bzero(&c_id->inbuf, sizeof (c_id->inbuf));
1355         free_response(c_id, B_TRUE);
1356 
1357         return (err_ret);
1358 }
1359 
1360 /*
1361  * http_srv_close - Close the connection and clean up the http_conn_t
1362  *              structure.
1363  *
1364  *     http_srv_close(handle);
1365  *
1366  * Arguments:
1367  *      handle  - Handle associated with the desired connection
1368  *
1369  * Returns:
1370  *      0       - Success
1371  *      -1      - An error occurred.  Specifics of the error can
1372  *                be gotten using http_get_lasterr().
1373  */
1374 int
1375 http_srv_close(http_handle_t handle)
1376 {
1377         http_conn_t *c_id = handle;
1378         int err_ret = 0;
1379 
1380         if (!http_check_conn(c_id))
1381                 return (-1);
1382 
1383         if (c_id->ctx != NULL || c_id->ssl != NULL || c_id->fd != -1)
1384                 err_ret = http_srv_disconnect(handle);
1385 
1386         free(c_id->basic_auth_userid);
1387         free(c_id->basic_auth_password);
1388         free(c_id->resp.statusmsg);
1389         free(c_id->client_cert_file);
1390         free(c_id->private_key_file);
1391         free(c_id->random_file);
1392         free(c_id->file_password);
1393         c_id->signature = 0;
1394 
1395         free(c_id);
1396         return (err_ret);
1397 }
1398 
1399 /*
1400  * http_get_conn_info - Return current information about the connection
1401  *
1402  *     err = http_get_conn_info(handle);
1403  *
1404  * Arguments:
1405  *      handle  - Handle associated with the connection in question
1406  *
1407  * Returns:
1408  *      non_NULL- Points to structure
1409  *      NULL    - An error exists.  Check http_get_lasterr().
1410  */
1411 http_conninfo_t *
1412 http_get_conn_info(http_handle_t handle)
1413 {
1414         http_conn_t *c_id = handle;
1415         http_conninfo_t *info;
1416 
1417         if (!http_check_conn(c_id))
1418                 return (NULL);
1419 
1420         info = malloc(sizeof (*info));
1421         if (info == NULL) {
1422                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1423                 return (NULL);
1424         }
1425 
1426         bzero(info, sizeof (*info));
1427 
1428         info->uri = c_id->uri;
1429         info->proxy = c_id->proxy;
1430         info->keepalive = c_id->keepalive;
1431         info->read_timeout = c_id->read_timeout;
1432 
1433         return (info);
1434 }
1435 
1436 /*
1437  * http_get_lasterr - Return the next error on the last operation
1438  *
1439  *     err = http_get_lasterr(handle, errsrc);
1440  *
1441  * Arguments:
1442  *      handle  - Handle associated with the connection in question
1443  *                If no valid handle exists yet, this can be NULL.
1444  *                However, it must be checked with the very next call.
1445  *      errsrc  - Returns the Sources of errors (ERRSRC_* values).
1446  *
1447  * Returns:
1448  *      0       - No error exists
1449  *      <> 0      - The error.
1450  */
1451 ulong_t
1452 http_get_lasterr(http_handle_t handle, uint_t *errsrc)
1453 {
1454         http_conn_t *c_id = handle;
1455         ulong_t src;
1456         ulong_t err;
1457 
1458         if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) {
1459                 if (errsrc)
1460                         *errsrc = ERRSRC_LIBHTTP;
1461                 err = early_err;
1462                 early_err = 0;
1463                 return (err);
1464         }
1465 
1466         GET_ERR(c_id, src, err);
1467         if (src == 0 && err == 0) {
1468                 if (errsrc)
1469                         *errsrc = ERRSRC_LIBHTTP;
1470                 err = early_err;
1471                 early_err = 0;
1472                 return (err);
1473         }
1474         if (errsrc)
1475                 *errsrc = src;
1476         return (err);
1477 }
1478 
1479 /*
1480  * http_decode_err - Decode a libssl error
1481  *
1482  *     err = http_decode_err(err, errlib, errfunc, errcode);
1483  *
1484  * Arguments:
1485  *      err     - libssl/libcrypto error returned.
1486  *      errlib  - returns libssl/libcrypto sublibrary that caused the error
1487  *      errfunc - returns function in that library
1488  *      errcode - returns error code
1489  *
1490  * Returns:
1491  *      None other than the above.
1492  */
1493 void
1494 http_decode_err(ulong_t err, int *errlib, int *errfunc, int *errcode)
1495 {
1496         if (errlib)
1497                 *errlib = ERR_GET_LIB(err);
1498         if (errfunc)
1499                 *errfunc = ERR_GET_FUNC(err);
1500         if (errcode)
1501                 *errcode = ERR_GET_REASON(err);
1502 }
1503 
1504 /* ---------------------- private functions ----------------------- */
1505 
1506 /*
1507  * http_req - Issue http request (either HEAD or GET)
1508  *
1509  *     ret = http_req(handle, abs_path, reqtype, curpos, len);
1510  *
1511  * Arguments:
1512  *      handle  - Handle associated with the desired connection
1513  *      abs_path- File name portion of the URI, beginning with a /.  Query,
1514  *                segment, etc are allowed.
1515  *      type    - HTTP_REQ_TYPE_HEAD or HTTP_REQ_TYPE_GET
1516  *
1517  *      In the case of GET requests,
1518  *        curpos- -1  - Range not used
1519  *                >=0 - Beginning of range
1520  *        len   - 0   - Range ends at the end of the file
1521  *                >0  - Length of range.
1522  *
1523  * Returns:
1524  *      0       - Success
1525  *      -1      - An error occurred.  Check http_get_lasterr().
1526  */
1527 static int
1528 http_req(http_handle_t handle, const char *abs_path, http_req_t type,
1529     offset_t curpos, offset_t len)
1530 {
1531         http_conn_t *c_id = handle;
1532         char    *request;
1533         char    *reqtypename;
1534         char    *newreq;
1535         int     requestlen;
1536         int     retval;
1537         int     j;
1538 
1539         ERR_clear_error();
1540         if (!http_check_conn(c_id))
1541                 return (-1);
1542 
1543         if (abs_path == NULL || abs_path[0] == '\0') {
1544                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1545                 return (-1);
1546         }
1547 
1548         /* Determine the name for the request type */
1549         switch (type) {
1550         case HTTP_REQ_TYPE_GET:
1551                 reqtypename = "GET";
1552                 if (curpos < 0 && curpos != -1) {
1553                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1554                         return (-1);
1555                 }
1556                 break;
1557 
1558         case HTTP_REQ_TYPE_HEAD:
1559                 reqtypename = "HEAD";
1560                 break;
1561 
1562         default:
1563                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1564                 return (-1);
1565         }
1566 
1567         /* Do rudimentary checks on the absolute path */
1568         if (abs_path == NULL || *abs_path != '/') {
1569                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1570                 libbootlog(BOOTLOG_CRIT, "http_req: invalid file path");
1571                 if (abs_path != NULL)
1572                         libbootlog(BOOTLOG_CRIT, " %s", abs_path);
1573                 return (-1);
1574         }
1575         (void) strlcpy(CONN_ABSPATH, abs_path, MAXHOSTNAMELEN);
1576 
1577         /*
1578          * Size the request.
1579          *
1580          * With proxy:
1581          *   reqtypename + " http://" + host + ":" + port + path +
1582          *                                              " HTTP/1.1\r\n" +
1583          * Without proxy:
1584          *   reqtypename + " " + path + " HTTP/1.1\r\n" +
1585          */
1586         requestlen = strlen(reqtypename) + 8 + strlen(CONN_HOSTNAME) + 1 +
1587             count_digits(CONN_PORT) + strlen(CONN_ABSPATH) + 11;
1588 
1589         /*
1590          * Plus the rest:
1591          *   "Host: " + targethost + ":" + count_digits(port) + "\r\n" +
1592          *   "Connection: Keep-Alive\r\n" plus trailing "\r\n\0"
1593          */
1594         requestlen += 6 + strlen(CONN_HOSTNAME) + 1 +
1595             count_digits(CONN_PORT) + 2 + 24 + 3;
1596         if ((request = malloc(requestlen)) == NULL) {
1597                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1598                 return (-1);
1599         }
1600 
1601         /* The request line */
1602         if (c_id->proxied && c_id->ssl == NULL) {
1603                 j = snprintf(request, requestlen,
1604                     "%s http://%s:%d%s HTTP/1.1\r\n",
1605                     reqtypename, CONN_HOSTNAME, CONN_PORT,
1606                     CONN_ABSPATH);
1607         } else {
1608                 j = snprintf(request, requestlen, "%s %s HTTP/1.1\r\n",
1609                     reqtypename, CONN_ABSPATH);
1610         }
1611 
1612         /* Ancillary headers */
1613         j += snprintf(&request[j], requestlen - j, "Host: %s:%d\r\n",
1614             CONN_HOSTNAME, CONN_PORT);
1615         if (!c_id->keepalive)
1616                 j += snprintf(&request[j], requestlen - j,
1617                     "Connection: close\r\n");
1618         else
1619                 j += snprintf(&request[j], requestlen - j,
1620                     "Connection: Keep-Alive\r\n");
1621         /*
1622          * We only send the range header on GET requests
1623          *
1624          * "Range: bytes=" + from + "-" + end + "\r\n" or
1625          * "Range: bytes=" + from + "-"  "\r\n"
1626          */
1627         if (type == HTTP_REQ_TYPE_GET && curpos >= 0) {
1628                 offset_t endpos;
1629 
1630                 requestlen += 13 + count_digits(curpos) + 1 + 2;
1631                 if (len > 0) {
1632                         endpos = curpos + len - 1;
1633                         requestlen += count_digits(endpos);
1634                 }
1635 
1636                 if ((newreq = realloc(request, requestlen)) == NULL) {
1637                         free(request);
1638                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1639                         return (-1);
1640                 }
1641                 request = newreq;
1642 
1643                 j += sprintf(&request[j], "Range: bytes=%lld-", curpos);
1644                 if (len > 0)
1645                         j += sprintf(&request[j], "%lld", endpos);
1646                 j += sprintf(&request[j], "\r\n");
1647         }
1648 
1649         /*
1650          * Authorization is added only if provided (RFC 2617, Section 2)
1651          *
1652          * "Authorization: Basic " + authencstr + "\r\n"
1653          */
1654         if (c_id->basic_auth_userid && c_id->basic_auth_password) {
1655                 char *authstr;
1656                 char *authencstr;
1657                 int authlen;
1658 
1659                 /*
1660                  * Allow for concat(basic_auth_userid ":" basic_auth_password)
1661                  */
1662                 authlen = strlen(c_id->basic_auth_userid) + 2 +
1663                     strlen(c_id->basic_auth_password);
1664                 if ((authstr = malloc(authlen + 1)) == NULL) {
1665                         free(request);
1666                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1667                         return (-1);
1668                 }
1669                 (void) snprintf(authstr, authlen + 1, "%s:%s",
1670                     c_id->basic_auth_userid, c_id->basic_auth_password);
1671 
1672                 /* 3 bytes encoded as 4 (round up) with null termination */
1673                 if ((authencstr = malloc((authlen + 2) / 3 * 4 + 1)) == NULL) {
1674                         free(authstr);
1675                         free(request);
1676                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1677                         return (-1);
1678                 }
1679 
1680                 (void) EVP_EncodeBlock((unsigned char *)authencstr,
1681                     (unsigned char *)authstr, authlen);
1682 
1683                 /*
1684                  * Finally do concat(Authorization: Basic " authencstr "\r\n")
1685                  */
1686                 requestlen += 21 + strlen(authencstr) + 2;
1687                 if ((newreq = realloc(request, requestlen)) == NULL) {
1688                         free(authencstr);
1689                         free(authstr);
1690                         free(request);
1691                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1692                         return (-1);
1693                 }
1694                 request = newreq;
1695 
1696                 j += snprintf(&request[j], requestlen - j,
1697                     "Authorization: Basic %s\r\n", authencstr);
1698 
1699                 free(authencstr);
1700                 free(authstr);
1701         }
1702 
1703         j += sprintf(&request[j], "\r\n");
1704 
1705         if (verbosemode)
1706                 libbootlog(BOOTLOG_VERBOSE, "%s", request);
1707 
1708         /* send the HTTP request */
1709         retval = http_srv_send(c_id, request, j);
1710 
1711         free(request);
1712         if (retval != j) {
1713                 /* Assume error in was set by send request. */
1714                 return (-1);
1715         }
1716 
1717         return (0);
1718 }
1719 
1720 /*
1721  * password_cb - Callback to get private key password and return it
1722  *               to SSL.  (Used for PEM certificates only.)
1723  *
1724  *      len = passwd_cb(buf, buflen, rwflag, userdata);
1725  *
1726  *  Arguments:
1727  *     buf      - Buffer for the password
1728  *     buflen   - Length of 'buf'
1729  *     rwflag   - password will be used for reading/decryption (== 0)
1730  *                or writing/encryption (== 1).
1731  *     userdata - Points to connection-specific information.
1732  *
1733  *  Returns:
1734  *     > 0   - Length of password that was put into 'buf'.
1735  *     0        - No password was returned (usually error occurred)
1736  *
1737  * NOTE:  The password code is not thread safe
1738  */
1739 /* ARGSUSED */
1740 static int
1741 password_cb(char *buf, int buflen, int rwflag, void *userdata)
1742 {
1743         http_conn_t *c_id = userdata;
1744 
1745         if (c_id == NULL || c_id->signature != HTTP_CONN_INFO)
1746                 return (0);
1747 
1748         if (c_id->file_password == NULL ||
1749             buflen < strlen(c_id->file_password) + 1)
1750                 return (0);
1751 
1752         return (strlcpy(buf, c_id->file_password, buflen));
1753 }
1754 
1755 /*
1756  * initialize_ctx - Initialize the context for a connection.
1757  *
1758  *       ctx = initialize_ctx(c_id);
1759  *
1760  *  Arguments:
1761  *     None.
1762  *
1763  *  Returns:
1764  *     non-NULL - Points to ctx structure.
1765  *     NULL     - An error occurred.  Any cleanup is done and error
1766  *                information is in the error stack.
1767  */
1768 static SSL_CTX *
1769 initialize_ctx(http_conn_t *c_id)
1770 {
1771 #if OPENSSL_VERSION_NUMBER < 0x10000000L
1772         SSL_METHOD      *meth;
1773 #else
1774         const SSL_METHOD        *meth;
1775 #endif
1776         SSL_CTX         *ctx;
1777 
1778         ERR_clear_error();
1779 
1780         /* Global system initialization */
1781         if (ssl_init == 0) {
1782                 sunw_crypto_init();
1783                 SSL_load_error_strings();
1784                 ssl_init = 1;
1785         }
1786 
1787         /* Create our context */
1788         meth = SSLv3_client_method();
1789         if ((ctx = SSL_CTX_new(meth)) == NULL) {
1790                 ulong_t err;
1791                 while ((err = ERR_get_error()) != 0)
1792                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
1793                         libbootlog(BOOTLOG_CRIT,
1794                             "initialize_ctx: SSL_CTX_new returned NULL");
1795                 return (NULL);
1796         }
1797 
1798         /*
1799          * Ensure that any renegotiations for blocking connections will
1800          * be done automatically.  (The alternative is to return partial
1801          * reads to the caller and let it oversee the renegotiations.)
1802          */
1803         if (SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY) == 0) {
1804                 ulong_t err;
1805                 while ((err = ERR_get_error()) != 0)
1806                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
1807                         libbootlog(BOOTLOG_CRIT,
1808                             "initialize_ctx: SSL_CTX_set_mode returned 0");
1809                 (void) SSL_CTX_free(ctx);
1810                 return (NULL);
1811         }
1812 
1813         /* set cipher list if provided */
1814         if (cipher_list != NULL) {
1815                 if (!SSL_CTX_set_cipher_list(ctx, cipher_list)) {
1816                         ulong_t err;
1817                         while ((err = ERR_get_error()) != 0)
1818                                 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1819                                 libbootlog(BOOTLOG_CRIT,
1820                                     "initialize_ctx: Error in cipher list");
1821                         SSL_CTX_free(ctx);
1822                         return (NULL);
1823                 }
1824         }
1825 
1826         /*
1827          * We attempt to use the client_certificate_file for the private
1828          * key input scheme *only* in the absence of private_key_file. In
1829          * this instance the scheme will be the same as that used for the
1830          * certificate input.
1831          */
1832 
1833         /* Load our certificates */
1834         if (c_id->client_cert_file != NULL) {
1835                 if (p12_format) {
1836                         /* Load pkcs12-formated files */
1837                         if (sunw_p12_use_certfile(ctx, c_id->client_cert_file,
1838                             c_id->file_password)
1839                             <= 0) {
1840                                 ulong_t err;
1841                                 while ((err = ERR_get_error()) != 0)
1842                                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
1843                                         libbootlog(BOOTLOG_CRIT,
1844                                             "initialize_ctx: Couldn't read "
1845                                             "PKCS12 certificate file");
1846                                 SSL_CTX_free(ctx);
1847                                 return (NULL);
1848                         }
1849                 } else {
1850                         /* Load PEM-formated files */
1851                         if (SSL_CTX_use_certificate_file(ctx,
1852                             c_id->client_cert_file, SSL_FILETYPE_PEM) <= 0) {
1853                                 ulong_t err;
1854                                 while ((err = ERR_get_error()) != 0)
1855                                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
1856                                         libbootlog(BOOTLOG_CRIT,
1857                                             "initialize_ctx: Couldn't read "
1858                                             "PEM certificate file");
1859                                 SSL_CTX_free(ctx);
1860                                 return (NULL);
1861                         }
1862                 }
1863                 if (c_id->private_key_file == NULL)
1864                         c_id->private_key_file = c_id->client_cert_file;
1865         }
1866 
1867         /* Load our keys */
1868         if (p12_format) {
1869                 /* Load pkcs12-formated files */
1870                 if (c_id->private_key_file != NULL) {
1871                         if (sunw_p12_use_keyfile(ctx, c_id->private_key_file,
1872                             c_id->file_password)
1873                             <= 0) {
1874                                 ulong_t err;
1875                                 while ((err = ERR_get_error()) != 0)
1876                                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
1877                                         libbootlog(BOOTLOG_CRIT,
1878                                             "initialize_ctx: Couldn't read "
1879                                             "PKCS12 key file");
1880                                 SSL_CTX_free(ctx);
1881                                 return (NULL);
1882                         }
1883                 }
1884         } else {
1885                 /* Load PEM-formated files */
1886                 SSL_CTX_set_default_passwd_cb(ctx, password_cb);
1887                 SSL_CTX_set_default_passwd_cb_userdata(ctx, c_id);
1888                 if (c_id->private_key_file != NULL) {
1889                         if (SSL_CTX_use_PrivateKey_file(ctx,
1890                             c_id->private_key_file, SSL_FILETYPE_PEM) <= 0) {
1891                                 ulong_t err;
1892                                 while ((err = ERR_get_error()) != 0)
1893                                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
1894                                         libbootlog(BOOTLOG_CRIT,
1895                                             "initialize_ctx: Couldn't read "
1896                                             "PEM key file");
1897                                 SSL_CTX_free(ctx);
1898                                 return (NULL);
1899                         }
1900                 }
1901         }
1902 
1903         /* Load the CAs we trust */
1904         if (ca_verify_file != NULL) {
1905                 if (p12_format) {
1906                         if (sunw_p12_use_trustfile(ctx, ca_verify_file,
1907                             c_id->file_password)
1908                             <= 0) {
1909                                 ulong_t err;
1910                                 while ((err = ERR_get_error()) != 0)
1911                                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
1912                                         libbootlog(BOOTLOG_CRIT,
1913                                             "initialize_ctx: Couldn't read "
1914                                             "PKCS12 CA list file");
1915                                 SSL_CTX_free(ctx);
1916                                 return (NULL);
1917                         }
1918                 } else {
1919                         if (SSL_CTX_load_verify_locations(ctx, ca_verify_file,
1920                             NULL) == 0) {
1921                                 ulong_t err;
1922                                 while ((err = ERR_get_error()) != 0)
1923                                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
1924                                         libbootlog(BOOTLOG_CRIT,
1925                                             "initialize_ctx: Couldn't read PEM"
1926                                             " CA list file");
1927                                 SSL_CTX_free(ctx);
1928                                 return (NULL);
1929                         }
1930                 }
1931         }
1932 
1933         SSL_CTX_set_verify_depth(ctx, verify_depth);
1934 
1935         /* Load randomness */
1936         if (c_id->random_file != NULL &&
1937             RAND_load_file(c_id->random_file, 1024 * 1024) <= 0) {
1938                 ulong_t err;
1939                 while ((err = ERR_get_error()) != 0)
1940                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
1941                         libbootlog(BOOTLOG_CRIT,
1942                             "initialize_ctx: Couldn't load random file");
1943                 SSL_CTX_free(ctx);
1944                 return (NULL);
1945         }
1946         if (RAND_status() <= 0) {
1947                 ulong_t err;
1948                 while ((err = ERR_get_error()) != 0)
1949                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
1950                         libbootlog(BOOTLOG_CRIT,
1951                             "initialize_ctx: PRNG not seeded");
1952                 SSL_CTX_free(ctx);
1953                 return (NULL);
1954         }
1955 
1956         return (ctx);
1957 }
1958 
1959 /*
1960  * tcp_connect - Set up a TCP connection.
1961  *
1962  *         sock = tcp_connect(c_id, hostname, port);
1963  *
1964  * Arguments:
1965  *      c_id     - Structure associated with the desired connection
1966  *      hostname - the host to connect to
1967  *      port     - the port to connect to
1968  *
1969  * Returns:
1970  *      >= 0 - Socket number.
1971  *      -1      - Error occurred.  Error information is set in the
1972  *                error stack.  Any cleanup is done.
1973  *
1974  * This function established a connection to the target host.  When
1975  * it returns, the connection is ready for a HEAD or GET request.
1976  */
1977 static int
1978 tcp_connect(http_conn_t *c_id, const char *hostname, uint16_t port)
1979 {
1980         struct hostent  *hp;
1981         struct sockaddr_in addr;
1982         int     sock;
1983         int     status;
1984 
1985         if ((hp = gethostbyname(hostname)) == NULL) {
1986                 SET_ERR(c_id, ERRSRC_RESOLVE, h_errno);
1987                 return (-1);
1988         }
1989 
1990         bzero(&addr, sizeof (addr));
1991         /* LINTED */
1992         addr.sin_addr = *(struct in_addr *)hp->h_addr;
1993         addr.sin_family = AF_INET;
1994         addr.sin_port = htons(port);
1995 
1996         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
1997                 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
1998                 return (-1);
1999         }
2000 
2001         status = connect(sock, (struct sockaddr *)&addr, sizeof (addr));
2002         if (status < 0) {
2003                 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2004                 (void) socket_close(sock);
2005                 return (-1);
2006         }
2007 
2008         c_id->host_addr = addr;      /* save for future sendto calls */
2009         c_id->fd = sock;
2010 
2011         return (sock);
2012 }
2013 
2014 /*
2015  * readline - Get a line from the socket.  Discard the end-of-line
2016  *            (CR or CR/LF or LF).
2017  *
2018  *         ret = readline(c_id, sock, buf, len);
2019  *
2020  * Arguments:
2021  *      c_id    - Structure associated with the desired connection
2022  *      sock    - Socket to read
2023  *      buf     - Buffer for the line
2024  *      len     - Length of the buffer
2025  *
2026  * Returns:
2027  *      0       - Success.  'buf' contains the line.
2028  *      -1      - Error occurred.  Error information is set in the
2029  *                error stack.
2030  */
2031 static int
2032 readline(http_conn_t *c_id, int sock, char *buf, int len)
2033 {
2034         int     n, r;
2035         char    *ptr = buf;
2036 
2037         for (n = 0; n < len; n++) {
2038                 r = socket_read(sock, ptr, 1, c_id->read_timeout);
2039 
2040                 if (r < 0) {
2041                         SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2042                         return (-1);
2043                 } else if (r == 0) {
2044                         libbootlog(BOOTLOG_WARNING, "Readline: no data");
2045                         return (0);
2046                 }
2047 
2048                 if (*ptr == '\n') {
2049                         *ptr = '\0';
2050 
2051                         /* Strip off the CR if it's there */
2052                         if (buf[n-1] == '\r') {
2053                                 buf[n-1] = '\0';
2054                                 n--;
2055                         }
2056 
2057                         return (n);
2058                 }
2059 
2060                 ptr++;
2061         }
2062 
2063         libbootlog(BOOTLOG_WARNING, "readline: Buffer too short\n");
2064         return (0);
2065 }
2066 
2067 /*
2068  * proxy_connect - Set up a proxied TCP connection to the target host.
2069  *
2070  *         sock = proxy_connect(c_id);
2071  *
2072  * Arguments:
2073  *      c_id  - Structure associated with the desired connection
2074  *
2075  * Returns:
2076  *      >= 0 - Socket number.
2077  *      -1      - Error occurred.  Error information is set in the
2078  *                error stack.  Any cleanup is done.
2079  *
2080  * This function established a connection to the proxy and then sends
2081  * the request to connect to the target host.  It reads the response
2082  * (the status line and any headers).  When it returns, the connection
2083  * is ready for a HEAD or GET request.
2084  */
2085 static int
2086 proxy_connect(http_conn_t *c_id)
2087 {
2088         struct sockaddr_in addr;
2089         int     sock;
2090         char    buf[1024];
2091         char    *ptr;
2092         int     i;
2093 
2094         if ((sock = tcp_connect(c_id, CONN_PROXY_HOSTNAME,
2095             CONN_PROXY_PORT)) < 0) {
2096                 return (-1);
2097         }
2098 
2099         if (!CONN_HTTPS) {
2100                 return (sock);
2101         }
2102 
2103         /* Now that we're connected, do the proxy request */
2104         (void) snprintf(buf, sizeof (buf),
2105             "CONNECT %s:%d HTTP/1.0\r\n\r\n", CONN_HOSTNAME, CONN_PORT);
2106 
2107         /* socket_write sets the errors */
2108         if (socket_write(sock, buf, strlen(buf), &addr) <= 0) {
2109                 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2110                 (void) socket_close(sock);
2111                 return (-1);
2112         }
2113 
2114         /* And read the response */
2115         i = readline(c_id, sock, buf, sizeof (buf));
2116         if (i <= 0) {
2117                 if (i == 0)
2118                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NORESP);
2119                         libbootlog(BOOTLOG_CRIT,
2120                             "proxy_connect: Empty response from proxy");
2121                 (void) socket_close(sock);
2122                 return (-1);
2123         }
2124 
2125         ptr = buf;
2126         if (strncmp(ptr, "HTTP", 4) != 0) {
2127                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOT_1_1);
2128                 libbootlog(BOOTLOG_CRIT,
2129                     "proxy_connect: Unrecognized protocol");
2130                 (void) socket_close(sock);
2131                 return (-1);
2132         }
2133 
2134         /* skip to the code */
2135         ptr += 4;
2136         while (*ptr != ' ' && *ptr != '\0')
2137                 ptr++;
2138         while (*ptr == ' ' && *ptr != '\0')
2139                 ptr++;
2140 
2141         /* make sure it's three digits */
2142         if (strncmp(ptr, "200", 3) != 0) {
2143                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADRESP);
2144                 libbootlog(BOOTLOG_CRIT,
2145                     "proxy_connect: Received error from proxy server");
2146                 (void) socket_close(sock);
2147                 return (-1);
2148         }
2149         ptr += 3;
2150         if (isdigit(*ptr)) {
2151                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADRESP);
2152                 (void) socket_close(sock);
2153                 return (-1);
2154         }
2155 
2156         /* Look for the blank line that signals end of proxy header */
2157         while ((i = readline(c_id, sock, buf, sizeof (buf))) > 0)
2158                 ;
2159 
2160         if (i < 0) {
2161                 (void) socket_close(sock);
2162                 return (-1);
2163         }
2164 
2165         return (sock);
2166 }
2167 
2168 /*
2169  * check_cert_chain - Check if we have a valid certificate chain.
2170  *
2171  *      ret = check_cert_chain(c_id, host);
2172  *
2173  * Arguments:
2174  *    c_id      - Connection info.
2175  *    host      - Name to compare with the common name in the certificate.
2176  *
2177  * Returns:
2178  *    0         - Certificate chain and common name are both OK.
2179  *    -1        - Certificate chain and/or common name is not valid.
2180  */
2181 static int
2182 check_cert_chain(http_conn_t *c_id, char *host)
2183 {
2184         X509    *peer;
2185         char    peer_CN[256];
2186         long    verify_err;
2187 
2188         if ((verify_err = SSL_get_verify_result(c_id->ssl)) != X509_V_OK) {
2189                 SET_ERR(c_id, ERRSRC_VERIFERR, verify_err);
2190                 libbootlog(BOOTLOG_CRIT,
2191                     "check_cert_chain: Certificate doesn't verify");
2192                 return (-1);
2193         }
2194 
2195         /*
2196          * Check the cert chain. The chain length
2197          * is automatically checked by OpenSSL when we
2198          * set the verify depth in the ctx
2199          *
2200          * All we need to do here is check that the CN
2201          * matches
2202          */
2203 
2204         /* Check the common name */
2205         if ((peer = SSL_get_peer_certificate(c_id->ssl)) == NULL) {
2206                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOCERT);
2207                 libbootlog(BOOTLOG_CRIT,
2208                     "check_cert_chain: Peer did not present a certificate");
2209                 return (-1);
2210         }
2211         (void) X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
2212             NID_commonName, peer_CN, 256);
2213 
2214         if (verbosemode)
2215                 libbootlog(BOOTLOG_VERBOSE,
2216                     "server cert's peer_CN is %s, host is %s", peer_CN, host);
2217 
2218         if (strcasecmp(peer_CN, host)) {
2219                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMATCH);
2220                 libbootlog(BOOTLOG_CRIT,
2221                     "check_cert_chain: Common name doesn't match host name");
2222                 libbootlog(BOOTLOG_CRIT,
2223                     "peer_CN = %s, host = %s", peer_CN, host);
2224                 return (-1);
2225         }
2226 
2227         return (0);
2228 }
2229 
2230 /*
2231  * print_ciphers - Print the list of ciphers for debugging.
2232  *
2233  *       print_ciphers(ssl);
2234  *
2235  * Arguments:
2236  *     ssl      - SSL connection.
2237  *
2238  * Returns:
2239  *     none
2240  */
2241 static void
2242 print_ciphers(SSL *ssl)
2243 {
2244         SSL_CIPHER      *c;
2245         STACK_OF(SSL_CIPHER)    *sk;
2246         int     i;
2247         const char      *name;
2248 
2249         if (ssl == NULL)
2250                 return;
2251 
2252         sk = SSL_get_ciphers(ssl);
2253         if (sk == NULL)
2254                 return;
2255 
2256         for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
2257                 /* LINTED */
2258                 c = sk_SSL_CIPHER_value(sk, i);
2259                 libbootlog(BOOTLOG_VERBOSE, "%08lx %s", c->id, c->name);
2260         }
2261         name = SSL_get_cipher_name(ssl);
2262         if (name == NULL)
2263                 name = "";
2264         libbootlog(BOOTLOG_VERBOSE, "Current cipher = %s", name);
2265 }
2266 
2267 /*
2268  * read_headerlines - Get the header lines from the server.  This reads
2269  *              lines until it gets a empty line indicating end of headers.
2270  *
2271  *       ret = read_headerlines(c_id);
2272  *
2273  * Arguments:
2274  *     c_id     - Info about the connection being read.
2275  *     bread    - TRUE if the headerlines are part of the message body.
2276  *
2277  * Returns:
2278  *     0        - Header lines were read.
2279  *     -1       - Error occurred.  The errors information is already in
2280  *                the error stack.
2281  *
2282  *  Read the lines.  If the current line begins with a space or tab, it is
2283  *  a continuation.  Take the new line and append it to the end of the
2284  *  previous line rather than making an entry for another line in
2285  *  c_id->resphdr.
2286  *
2287  *  Note that I/O errors are put into the error stack by http_srv_recv(),
2288  *  which is called by getaline().
2289  */
2290 static int
2291 read_headerlines(http_conn_t *c_id, boolean_t bread)
2292 {
2293         char    line[MAXHOSTNAMELEN];
2294         char    **new_buf;
2295         char    *ptr;
2296         int     next;
2297         int     cur;
2298         int     n;
2299 
2300         /* process headers, stop when we get to an empty line */
2301         cur = 0;
2302         next = 0;
2303         while ((n = getaline(c_id, line, sizeof (line), bread)) > 0) {
2304 
2305                 if (verbosemode)
2306                         libbootlog(BOOTLOG_VERBOSE,
2307                             "read_headerlines: %s", line);
2308                 /*
2309                  * See if this is a continuation line (first col is a
2310                  * space or a tab)
2311                  */
2312                 if (line[0] != ' ' && line[0] != '      ') {
2313                         cur = next;
2314                         next ++;
2315                         new_buf =
2316                             realloc(c_id->resphdr, (cur + 1) * sizeof (void *));
2317                         if (new_buf == NULL) {
2318                                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
2319                                 return (-1);
2320                         }
2321                         c_id->resphdr = new_buf;
2322 
2323                         c_id->resphdr[cur] = strdup(line);
2324                         if (c_id->resphdr[cur] == NULL) {
2325                                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
2326                                 return (-1);
2327                         }
2328                 } else {
2329                         ptr = line;
2330                         while (isspace(*ptr))
2331                                 ptr ++;
2332                         c_id->resphdr[cur] = realloc(c_id->resphdr[cur],
2333                             strlen(c_id->resphdr[cur]) + strlen(ptr) + 1);
2334                         if (c_id->resphdr[cur] == NULL) {
2335                                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
2336                                 return (-1);
2337                         }
2338                         (void) strcat(c_id->resphdr[cur], ptr);
2339                 }
2340                 ptr = &(c_id->resphdr[cur][strlen(c_id->resphdr[cur]) - 1]);
2341                 while (ptr > c_id->resphdr[cur] && isspace(*ptr))
2342                         ptr --;
2343         }
2344         c_id->resp.nresphdrs = next;
2345 
2346         /* Cause of any I/O error was already put into error stack. */
2347         return (n >= 0 ? 0 : -1);
2348 }
2349 
2350 static void
2351 free_response(http_conn_t *c_id, int free_boundary)
2352 {
2353         int i;
2354 
2355         /* free memory from previous calls */
2356         if (c_id->resp.statusmsg != NULL) {
2357                 free(c_id->resp.statusmsg);
2358                 c_id->resp.statusmsg = NULL;
2359         }
2360         for (i = 0; i < c_id->resp.nresphdrs; i++) {
2361                 free(c_id->resphdr[i]);
2362                 c_id->resphdr[i] = NULL;
2363         }
2364         c_id->resp.nresphdrs = 0;
2365         if (c_id->resphdr != NULL) {
2366                 free(c_id->resphdr);
2367                 c_id->resphdr = NULL;
2368         }
2369 
2370         if (free_boundary && c_id->boundary) {
2371                 free(c_id->boundary);
2372                 c_id->boundary = NULL;
2373                 c_id->is_multipart = B_FALSE;
2374         }
2375 }
2376 
2377 static int
2378 free_ctx_ssl(http_conn_t *c_id)
2379 {
2380         int err_ret = 0;
2381 
2382         if (c_id->ssl != NULL) {
2383                 if (SSL_shutdown(c_id->ssl) <= 0) {
2384                         ulong_t err;
2385                         while ((err = ERR_get_error()) != 0)
2386                                 SET_ERR(c_id, ERRSRC_LIBSSL, err);
2387                         err_ret = -1;
2388                 }
2389                 SSL_free(c_id->ssl);
2390                 c_id->ssl = NULL;
2391         }
2392 
2393         if (c_id->fd != -1 && socket_close(c_id->fd) < 0) {
2394                 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2395                 err_ret = -1;
2396         }
2397         c_id->fd = -1;
2398 
2399         if (c_id->ctx != NULL) {
2400                 SSL_CTX_free(c_id->ctx);
2401                 c_id->ctx = NULL;
2402         }
2403 
2404         return (err_ret);
2405 }
2406 
2407 /*
2408  * get_chunk_header - Get a chunk header line
2409  *
2410  * Arguments:
2411  *   c_id   - Structure describing the connection in question.
2412  *
2413  * Returns:
2414  *  >=0      - Length of next chunk
2415  *  -1  - Error occurred.  The error information is in the error stack.
2416  */
2417 static int
2418 get_chunk_header(http_conn_t *c_id)
2419 {
2420         char    line[MAXHOSTNAMELEN];
2421         char    *ptr;
2422         int     value;
2423         int     ok;
2424         int     i;
2425 
2426         /*
2427          * Determine whether an extra crlf pair will precede the
2428          * chunk header.  For the first one, there is no preceding
2429          * crlf.  For later chunks, there is one crlf.
2430          */
2431         if (c_id->is_firstchunk) {
2432                 ok = 1;
2433                 c_id->is_firstchunk = B_FALSE;
2434         } else {
2435                 ok = ((i = getaline(c_id, line, sizeof (line), B_FALSE)) == 0);
2436         }
2437 
2438         if (ok)
2439                 i = getaline(c_id, line, sizeof (line), B_FALSE);
2440         if (!ok || i < 0) {
2441                 /*
2442                  * If I/O error, the Cause was already put into
2443                  * error stack.  This is an additional error.
2444                  */
2445                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOHEADER);
2446                 return (-1);
2447         }
2448 
2449         if (verbosemode)
2450                 libbootlog(BOOTLOG_VERBOSE, "get_chunk_header: <%s>", line);
2451 
2452 
2453         /*
2454          * The first (and probably only) field in the line is the hex
2455          * length of the chunk.
2456          */
2457         ptr = line;
2458         value = 0;
2459         while (*ptr != '\0' && (i = hexdigit(*ptr)) >= 0) {
2460                 value = (value << 4) + i;
2461                 ptr ++;
2462         }
2463 
2464         return (value);
2465 }
2466 
2467 /*
2468  * init_bread - Initialize the counters used to read message bodies.
2469  *
2470  * Arguments:
2471  *   c_id   - Structure describing the connection in question.
2472  *
2473  * Returns:
2474  *   0  - Success
2475  *  -1  - Error occurred.  The error information is in the error stack.
2476  *
2477  *  This routine will determine whether the message body being received is
2478  *  chunked or non-chunked. Once determined, the counters used to read
2479  *  message bodies will be initialized.
2480  */
2481 static int
2482 init_bread(http_conn_t *c_id)
2483 {
2484         char    *hdr;
2485         char    *ptr;
2486         boolean_t sized = B_FALSE;
2487 
2488         /*
2489          * Assume non-chunked reads until proven otherwise.
2490          */
2491         c_id->is_chunked = B_FALSE;
2492         c_id->is_firstchunk = B_FALSE;
2493         hdr = http_get_header_value(c_id, "Content-Length");
2494         if (hdr != NULL) {
2495                 c_id->body_size = strtol(hdr, NULL, 10);
2496                 if (c_id->body_size == 0 && errno != 0) {
2497                         free(hdr);
2498                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADSIZE);
2499                         return (-1);
2500                 }
2501                 free(hdr);
2502                 sized = B_TRUE;
2503         }
2504 
2505         /*
2506          * If size was not determined above, then see if this is a
2507          * chunked message. Keep in mind that the first chunk size is
2508          * "special".
2509          */
2510         if (!sized) {
2511                 hdr = http_get_header_value(c_id, "Transfer-Encoding");
2512                 if (hdr != NULL) {
2513                         ptr = eat_ws(hdr);
2514                         if (startswith((const char **)&ptr, "chunked;") ||
2515                             strcasecmp(ptr, "chunked") == 0) {
2516                                 c_id->is_firstchunk = B_TRUE;
2517                                 c_id->is_chunked = B_TRUE;
2518                         }
2519                         free(hdr);
2520                         if (c_id->is_chunked) {
2521                                 c_id->body_size = get_chunk_header(c_id);
2522                                 if (c_id->body_size == -1) {
2523                                         /*
2524                                          * Error stack was already set at a
2525                                          * lower level.
2526                                          */
2527                                         return (-1);
2528                                 }
2529                                 sized = B_TRUE;
2530                         }
2531                 }
2532         }
2533 
2534         /*
2535          * Well, isn't this a fine predicament? It wasn't chunked or
2536          * non-chunked as far as we can tell.
2537          */
2538         if (!sized) {
2539                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADSIZE);
2540                 return (-1);
2541         }
2542 
2543         c_id->body_read = 0;
2544         c_id->body_size_tot = c_id->body_size;
2545         c_id->body_read_tot = 0;
2546 
2547         return (0);
2548 }
2549 
2550 /*
2551  * get_msgcnt - Get the number of bytes left in the message body or chunk.
2552  *
2553  * Arguments:
2554  *   c_id   - Structure describing the connection in question.
2555  *   msgcnt - Where to store the message count.
2556  *
2557  * Returns:
2558  *   0  - Success
2559  *  -1  - Error occurred.  The error information is in the error stack.
2560  *
2561  *  Note that if the message being read is not chunked, then the byte count
2562  *  is simply the message size minus the bytes read thus far. In the case of
2563  *  chunked messages, the byte count returned will be the number of bytes
2564  *  left in the chunk. If the current chunk has been exhausted, then this
2565  *  routine will determine the size of the next chunk. When the next chunk
2566  *  size is zero, the message has been read in its entirety.
2567  */
2568 static int
2569 get_msgcnt(http_conn_t *c_id, ssize_t *msgcnt)
2570 {
2571         /*
2572          * If there are more bytes in the message, then return.
2573          */
2574         *msgcnt = c_id->body_size - c_id->body_read;
2575         if (*msgcnt != 0) {
2576                 return (0);
2577         }
2578         /*
2579          * If this is not a chunked message and the body has been
2580          * read, then we're done.
2581          */
2582         if (!c_id->is_chunked) {
2583                 return (0);
2584         }
2585 
2586         /*
2587          * We're looking at a chunked message whose immediate
2588          * chunk has been totally processed. See if there is
2589          * another chunk.
2590          */
2591         c_id->body_size = get_chunk_header(c_id);
2592         if (c_id->body_size == -1) {
2593                 /*
2594                  * Error stack was already set at a
2595                  * lower level.
2596                  */
2597                 return (-1);
2598         }
2599 
2600         /*
2601          * No bytes of this chunk have been processed yet.
2602          */
2603         c_id->body_read = 0;
2604 
2605         /*
2606          * A zero length chunk signals the end of the
2607          * message body and chunking.
2608          */
2609         if (c_id->body_size == 0) {
2610                 c_id->is_chunked = B_FALSE;
2611                 return (0);
2612         }
2613 
2614         /*
2615          * There is another chunk.
2616          */
2617         c_id->body_size_tot += c_id->body_size;
2618         *msgcnt = c_id->body_size - c_id->body_read;
2619 
2620         return (0);
2621 }
2622 
2623 /*
2624  * getaline - Get lines of data from the HTTP response, up to 'len' bytes.
2625  *        NOTE: the line will not end with a NULL if all 'len' bytes
2626  *        were read.
2627  *
2628  * Arguments:
2629  *   c_id   - Structure describing the connection in question.
2630  *   line   - Where to store the data.
2631  *   len    - Maximum number of bytes in the line.
2632  *   bread  - TRUE if the lines are part of the message body.
2633  *
2634  * Returns:
2635  *   >=0    - The number of bytes successfully read.
2636  *   <0          - An error occurred.  This is (the number of bytes gotten + 1),
2637  *            negated.  In other words, if 'n' bytes were read and then an
2638  *            error occurred, this will return (-(n+1)).  So zero bytes read
2639  *            and then an error occurs, this will return -1.  If 1 bytes
2640  *            was read, it will return -2, etc.
2641  *
2642  *            Specifics of the error can be gotten using http_get_lasterr();
2643  *
2644  *  Note that I/O errors are put into the error stack by http_srv_recv().1
2645  */
2646 static int
2647 getaline(http_conn_t *c_id, char *line, int len, boolean_t bread)
2648 {
2649         int     i = 0;
2650         ssize_t msgcnt = 0;
2651         ssize_t cnt;
2652 
2653         while (i < len) {
2654                 /*
2655                  * Special processing required for message body reads.
2656                  */
2657                 if (bread) {
2658                         /*
2659                          * See if there is another chunk. Obviously, in the
2660                          * case of non-chunked messages, there won't be.
2661                          * But in either case, chunked or not, if msgcnt
2662                          * is still zero after the call to get_msgcnt(),
2663                          * then we're done.
2664                          */
2665                         if (msgcnt == 0) {
2666                                 if (get_msgcnt(c_id, &msgcnt) == -1) {
2667                                         return (-(i+1));
2668                                 }
2669                                 if (msgcnt == 0) {
2670                                         break;
2671                                 }
2672                         }
2673                         cnt = MIN(msgcnt, sizeof (c_id->inbuf.buf));
2674                 } else {
2675                         cnt = sizeof (c_id->inbuf.buf);
2676                 }
2677 
2678                 /* read more data if buffer empty */
2679                 if (c_id->inbuf.i == c_id->inbuf.n) {
2680                         c_id->inbuf.i = 0;
2681                         c_id->inbuf.n = http_srv_recv(c_id, c_id->inbuf.buf,
2682                             cnt);
2683                         if (c_id->inbuf.n == 0) {
2684                                 return (i);
2685                         }
2686                         if (c_id->inbuf.n < 0) {
2687                                 return (-(i+1));
2688                         }
2689                 }
2690                 /* skip CR */
2691                 if (c_id->inbuf.buf[c_id->inbuf.i] == '\r') {
2692                         INC_BREAD_CNT(bread, msgcnt);
2693                         c_id->inbuf.i++;
2694                         continue;
2695                 }
2696                 if (c_id->inbuf.buf[c_id->inbuf.i] == '\n') {
2697                         INC_BREAD_CNT(bread, msgcnt);
2698                         c_id->inbuf.i++;
2699                         line[i] = '\0';
2700                         return (i);
2701                 }
2702                 /* copy buf from internal buffer */
2703                 INC_BREAD_CNT(bread, msgcnt);
2704                 line[i++] = c_id->inbuf.buf[c_id->inbuf.i++];
2705         }
2706         return (i);
2707 }
2708 
2709 /*
2710  * getbytes - Get a block from the HTTP response. Used for the HTTP body.
2711  *
2712  * Arguments:
2713  *   c_id   - Structure describing the connection in question.
2714  *   line   - Where to store the data.
2715  *   len    - Maximum number of bytes in the block.
2716  *
2717  * Returns:
2718  *   >=0    - The number of bytes successfully read.
2719  *   <0          - An error occurred.  This is (the number of bytes gotten + 1),
2720  *            negated.  In other words, if 'n' bytes were read and then an
2721  *            error occurred, this will return (-(n+1)).  So zero bytes read
2722  *            and then an error occurs, this will return -1.  If 1 bytes
2723  *            was read, it will return -2, etc.
2724  *
2725  *            Specifics of the error can be gotten using http_get_lasterr();
2726  *
2727  *  Note that all reads performed here assume that a message body is being
2728  *  read. If this changes in the future, then the logic should more closely
2729  *  resemble getaline().
2730  *
2731  *  Note that I/O errors are put into the error stack by http_srv_recv().
2732  */
2733 static int
2734 getbytes(http_conn_t *c_id, char *line, int len)
2735 {
2736         int     i = 0;
2737         ssize_t msgcnt = 0;
2738         ssize_t cnt;
2739         int     nbytes;
2740 
2741         while (i < len) {
2742                 /*
2743                  * See if there is another chunk. Obviously, in the
2744                  * case of non-chunked messages, there won't be.
2745                  * But in either case, chunked or not, if msgcnt
2746                  * is still zero after the call to get_msgcnt(), then
2747                  * we're done.
2748                  */
2749                 if (msgcnt == 0) {
2750                         if (get_msgcnt(c_id, &msgcnt) == -1) {
2751                                 return (-(i+1));
2752                         }
2753                         if (msgcnt == 0) {
2754                                 break;
2755                         }
2756                 }
2757 
2758                 cnt = MIN(msgcnt, len - i);
2759 
2760                 if (c_id->inbuf.n != c_id->inbuf.i) {
2761                         nbytes = (int)MIN(cnt, c_id->inbuf.n - c_id->inbuf.i);
2762                         (void) memcpy(line, &c_id->inbuf.buf[c_id->inbuf.i],
2763                             nbytes);
2764                         c_id->inbuf.i += nbytes;
2765                 } else {
2766                         nbytes = http_srv_recv(c_id, line, cnt);
2767                         if (nbytes == 0) {
2768                                 return (i);
2769                         }
2770                         if (nbytes < 0) {
2771                                 return (-(i+1));
2772                         }
2773                 }
2774 
2775                 i += nbytes;
2776                 line += nbytes;
2777                 msgcnt -= nbytes;
2778                 c_id->body_read += nbytes;
2779                 c_id->body_read_tot += nbytes;
2780         }
2781 
2782         return (i);
2783 }
2784 
2785 static int
2786 http_srv_send(http_conn_t *c_id, const void *buf, size_t nbyte)
2787 {
2788         int     retval;
2789 
2790         if (c_id->ssl != NULL) {
2791                 if ((retval = SSL_write(c_id->ssl, buf, nbyte)) <= 0) {
2792                         handle_ssl_error(c_id, retval);
2793                 }
2794                 return (retval);
2795         } else {
2796                 retval = socket_write(c_id->fd, buf, nbyte, &c_id->host_addr);
2797                 if (retval < 0) {
2798                         SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2799                         return (-1);
2800                 }
2801                 return (retval);
2802         }
2803 }
2804 
2805 static int
2806 http_srv_recv(http_conn_t *c_id, void *buf, size_t nbyte)
2807 {
2808         int     retval;
2809 
2810         if (c_id->ssl != NULL) {
2811                 if ((retval = SSL_read(c_id->ssl, buf, nbyte)) <= 0) {
2812                         handle_ssl_error(c_id, retval);
2813                 }
2814                 return (retval);
2815         } else {
2816                 retval = socket_read(c_id->fd, buf, nbyte, c_id->read_timeout);
2817                 if (retval < 0) {
2818                         SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2819                         return (-1);
2820                 }
2821                 return (retval);
2822         }
2823 }
2824 
2825 static boolean_t
2826 http_check_conn(http_conn_t *c_id)
2827 {
2828         early_err = 0;
2829         if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) {
2830                 early_err = EHTTP_BADARG;
2831                 return (B_FALSE);
2832         }
2833         RESET_ERR(c_id);
2834         return (B_TRUE);
2835 }
2836 
2837 static void
2838 handle_ssl_error(http_conn_t *c_id, int retval)
2839 {
2840         ulong_t err;
2841 
2842         err = SSL_get_error(c_id->ssl, retval);
2843 
2844         switch (err) {
2845         case SSL_ERROR_NONE:
2846                 return;
2847 
2848         case SSL_ERROR_ZERO_RETURN:
2849                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_CONCLOSED);
2850                 return;
2851 
2852         case SSL_ERROR_WANT_READ:
2853         case SSL_ERROR_WANT_WRITE:
2854         case SSL_ERROR_WANT_CONNECT:
2855         case SSL_ERROR_WANT_X509_LOOKUP:
2856                 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_UNEXPECTED);
2857                 return;
2858 
2859         case SSL_ERROR_SYSCALL:
2860                 err = ERR_get_error();
2861                 if (err == 0)
2862                         SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_EOFERR);
2863                 else if (err == (ulong_t)-1)
2864                         SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2865                 else {
2866                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
2867                         while ((err = ERR_get_error()) != 0)
2868                                 SET_ERR(c_id, ERRSRC_LIBSSL, err);
2869                 }
2870                 return;
2871 
2872         case SSL_ERROR_SSL:
2873                 while ((err = ERR_get_error()) != 0) {
2874                         SET_ERR(c_id, ERRSRC_LIBSSL, err);
2875                 }
2876                 return;
2877         }
2878 }
2879 
2880 static int
2881 count_digits(int value)
2882 {
2883         int     count = 1;
2884 
2885         if (value < 0) {
2886                 count++;
2887                 value = -value;
2888         }
2889 
2890         while (value > 9) {
2891                 value /= 10;
2892                 count++;
2893         }
2894         return (count);
2895 }
2896 
2897 static int
2898 hexdigit(char ch)
2899 {
2900         if (ch >= '0' && ch <= '9')
2901                 return (ch - '0');
2902         if (ch >= 'A' && ch <= 'F')
2903                 return (ch - 'A' + 10);
2904         if (ch >= 'a' && ch <= 'f')
2905                 return (ch - 'a' + 10);
2906         return (-1);
2907 }
2908 
2909 static char *
2910 eat_ws(const char *buf)
2911 {
2912         char *ptr = (char *)buf;
2913 
2914         while (isspace(*ptr))
2915                 ptr++;
2916 
2917         return (ptr);
2918 }
2919 
2920 static boolean_t
2921 startswith(const char **strp, const char *starts)
2922 {
2923         int len = strlen(starts);
2924 
2925         if (strncasecmp(*strp, starts, len) == 0) {
2926                 *strp += len;
2927                 return (B_TRUE);
2928         }
2929         return (B_FALSE);
2930 }