http_session_new (http_session_t *r_session,
                  const char *intended_hostname, unsigned int flags,
                  http_verify_cb_t verify_cb, void *verify_cb_value)
{
  gpg_error_t err;
  http_session_t sess;

  *r_session = NULL;

  sess = xtrycalloc (1, sizeof *sess);
  if (!sess)
    return gpg_error_from_syserror ();
  sess->magic = HTTP_SESSION_MAGIC;
  sess->refcount = 1;
  sess->flags = flags;
  sess->verify_cb = verify_cb;
  sess->verify_cb_value = verify_cb_value;
  sess->connect_timeout = 0;

#if HTTP_USE_NTBTLS
  {
    (void)intended_hostname; /* Not needed because we do not preload
                              * certificates.  */

    err = ntbtls_new (&sess->tls_session, NTBTLS_CLIENT);
    if (err)
      {
        log_error ("ntbtls_new failed: %s\n", gpg_strerror (err));
        goto leave;
      }

  }
#elif HTTP_USE_GNUTLS
  {
    const char *errpos;
    int rc;
    strlist_t sl;
    int add_system_cas = !!(flags & HTTP_FLAG_TRUST_SYS);
    int is_hkps_pool;

    rc = gnutls_certificate_allocate_credentials (&sess->certcred);
    if (rc < 0)
      {
        log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
                   gnutls_strerror (rc));
        err = gpg_error (GPG_ERR_GENERAL);
        goto leave;
      }

    is_hkps_pool = (intended_hostname
                    && !ascii_strcasecmp (intended_hostname,
                                          get_default_keyserver (1)));

    /* If the user has not specified a CA list, and they are looking
     * for the hkps pool from sks-keyservers.net, then default to
     * Kristian's certificate authority:  */
    if (!tls_ca_certlist && is_hkps_pool)
      {
        char *pemname = make_filename_try (gnupg_datadir (),
                                           "sks-keyservers.netCA.pem", NULL);
        if (!pemname)
          {
            err = gpg_error_from_syserror ();
            log_error ("setting CA from file '%s' failed: %s\n",
                       pemname, gpg_strerror (err));
          }
        else
          {
            rc = gnutls_certificate_set_x509_trust_file
              (sess->certcred, pemname, GNUTLS_X509_FMT_PEM);
            if (rc < 0)
              log_info ("setting CA from file '%s' failed: %s\n",
                        pemname, gnutls_strerror (rc));
            xfree (pemname);
          }
      }

    /* Add configured certificates to the session.  */
    if ((flags & HTTP_FLAG_TRUST_DEF))
      {
        for (sl = tls_ca_certlist; sl; sl = sl->next)
          {
            rc = gnutls_certificate_set_x509_trust_file
              (sess->certcred, sl->d,
               (sl->flags & 1)? GNUTLS_X509_FMT_PEM : GNUTLS_X509_FMT_DER);
            if (rc < 0)
              log_info ("setting CA from file '%s' failed: %s\n",
                        sl->d, gnutls_strerror (rc));
          }
        if (!tls_ca_certlist && !is_hkps_pool)
          add_system_cas = 1;
      }

    /* Add system certificates to the session.  */
    if (add_system_cas)
      {
#if GNUTLS_VERSION_NUMBER >= 0x030014
        static int shown;

        rc = gnutls_certificate_set_x509_system_trust (sess->certcred);
        if (rc < 0)
          log_info ("setting system CAs failed: %s\n", gnutls_strerror (rc));
        else if (!shown)
          {
            shown = 1;
            log_info ("number of system provided CAs: %d\n", rc);
          }
#endif /* gnutls >= 3.0.20 */
      }

    /* Add other configured certificates to the session.  */
    if ((flags & HTTP_FLAG_TRUST_CFG))
      {
        for (sl = cfg_ca_certlist; sl; sl = sl->next)
          {
            rc = gnutls_certificate_set_x509_trust_file
              (sess->certcred, sl->d,
               (sl->flags & 1)? GNUTLS_X509_FMT_PEM : GNUTLS_X509_FMT_DER);
            if (rc < 0)
              log_info ("setting extra CA from file '%s' failed: %s\n",
                        sl->d, gnutls_strerror (rc));
          }
      }


    rc = gnutls_init (&sess->tls_session, GNUTLS_CLIENT);
    if (rc < 0)
      {
        log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc));
        err = gpg_error (GPG_ERR_GENERAL);
        goto leave;
      }
    /* A new session has the transport ptr set to (void*(-1), we need
       it to be NULL.  */
    gnutls_transport_set_ptr (sess->tls_session, NULL);

    rc = gnutls_priority_set_direct (sess->tls_session,
                                     "NORMAL",
                                     &errpos);
    if (rc < 0)
      {
        log_error ("gnutls_priority_set_direct failed at '%s': %s\n",
                   errpos, gnutls_strerror (rc));
        err = gpg_error (GPG_ERR_GENERAL);
        goto leave;
      }

    rc = gnutls_credentials_set (sess->tls_session,
                                 GNUTLS_CRD_CERTIFICATE, sess->certcred);
    if (rc < 0)
      {
        log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc));
        err = gpg_error (GPG_ERR_GENERAL);
        goto leave;
      }
  }
#else /*!HTTP_USE_GNUTLS && !HTTP_USE_NTBTLS*/
  {
    (void)intended_hostname;
    (void)flags;
  }
#endif /*!HTTP_USE_GNUTLS && !HTTP_USE_NTBTLS*/

  if (opt_debug > 1)
    log_debug ("http.c:session_new: sess %p created\n", sess);
  err = 0;

#if USE_TLS
 leave:
#endif /*USE_TLS*/
  if (err)
    http_session_unref (sess);
  else
    *r_session = sess;

  return err;
}