static int add_pem_cert(SSL_CTX *sslCtx, char const* pem_cert)
{
    X509 *cert;
    BIO *mem = BIO_new(BIO_s_mem());
    if (NULL == mem) {
        PUBNUB_LOG_ERROR("SSL_CTX=%p: Failed BIO_new for PEM certificate\n", sslCtx);
        return -1;
    }
    BIO_puts(mem, pem_cert);
    cert = PEM_read_bio_X509(mem, NULL, 0, NULL);
    BIO_free(mem);
    if (NULL == cert) {
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        PUBNUB_LOG_ERROR("SSL_CTX=%p: Failed to read PEM certificate\n", sslCtx);
        return -1;
    }

    if (0 == X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert)) {
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        PUBNUB_LOG_ERROR("SSL_CTX=%p: Failed to add PEM certificate\n", sslCtx);
        X509_free(cert);
        return -1;
    }
    X509_free(cert);

    return 0;
}
예제 #2
0
파일: pbaes256.c 프로젝트: sveljko/c-core
static int do_decrypt(EVP_CIPHER_CTX* aes256, pubnub_bymebl_t data, uint8_t const* key, uint8_t const* iv, pubnub_bymebl_t *msg)
{
    int len = 0;
    if (!EVP_DecryptInit_ex(aes256, EVP_aes_256_cbc(), NULL, key, iv)) {
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        PUBNUB_LOG_ERROR("Failed to initialize AES-256 decryption\n");
        return -1;
    }

    if (!EVP_DecryptUpdate(aes256, msg->ptr, &len, data.ptr, data.size)) {
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        PUBNUB_LOG_ERROR("Failed to AES-256 decrypt the mesage\n");
        return -1;
    }
    msg->size = len;

    if (!EVP_DecryptFinal_ex(aes256, msg->ptr + len, &len)) {
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        PUBNUB_LOG_ERROR("Failed to finalize AES-256 decryption\n");
        return -1;
    }
    msg->size += len;

    return 0;
}
예제 #3
0
파일: pbaes256.c 프로젝트: sveljko/c-core
pubnub_bymebl_t pbaes256_decrypt_alloc(pubnub_bymebl_t data, uint8_t const* key, uint8_t const* iv)
{
    int decrypt_result;
    EVP_CIPHER_CTX *aes256;
    pubnub_bymebl_t result;

    result.size = data.size + EVP_CIPHER_block_size(EVP_aes_256_cbc()) + 1;
    result.ptr = (uint8_t*)malloc(result.size);
    if (NULL == result.ptr) {
        return result;
    }

    aes256 = EVP_CIPHER_CTX_new();
    if (NULL == aes256) {
        PUBNUB_LOG_ERROR("Failed to allocate AES-256 decryption context\n");
        free(result.ptr);
        result.ptr = NULL;
        return result;;
    }

    decrypt_result = do_decrypt(aes256, data, key, iv, &result);

    EVP_CIPHER_CTX_free(aes256);

    if (decrypt_result != 0) {
        PUBNUB_LOG_ERROR("Failed AES-256 decryption\n");
        free(result.ptr);
        result.ptr = NULL;
    }

    return result;
}
enum pbpal_resolv_n_connect_result pbpal_check_connect(pubnub_t *pb)
{
    fd_set read_set, write_set;
    int socket;
    int rslt;
    struct timeval timev = { 0, 300000 };

    if (-1 == BIO_get_fd(pb->pal.socket, &socket)) {
        PUBNUB_LOG_ERROR("pbpal_connected(): Uninitialized BIO!\n");
        return pbpal_connect_resource_failure;
    }
    FD_ZERO(&read_set);
    FD_ZERO(&write_set);
    FD_SET(socket, &read_set);
    FD_SET(socket, &write_set);
    rslt = select(socket + 1, &read_set, &write_set, NULL, &timev);
    if (SOCKET_ERROR == rslt) {
        PUBNUB_LOG_ERROR("pbpal_connected(): select() Error!\n");
        return pbpal_connect_resource_failure;
    }
    else if (rslt > 0) {
        PUBNUB_LOG_TRACE("pbpal_connected(): select() event\n");
        return pbpal_resolv_and_connect(pb);
    }
    PUBNUB_LOG_TRACE("pbpal_connected(): no select() events\n");
    return pbpal_connect_wouldblock;
}
예제 #5
0
파일: pbaes256.c 프로젝트: sveljko/c-core
pubnub_bymebl_t pbaes256_encrypt_alloc(pubnub_bymebl_t msg, uint8_t const* key, uint8_t const* iv)
{
    int encrypt_result;
    pubnub_bymebl_t result = { NULL, 0 };
    EVP_CIPHER_CTX* aes256 = EVP_CIPHER_CTX_new();

    if (NULL == aes256) {
        PUBNUB_LOG_ERROR("Failed to allocate AES-256 encryption context\n");
        return result;
    }

    result.ptr = (uint8_t*)malloc(msg.size + EVP_CIPHER_block_size(EVP_aes_256_cbc()));
    if (NULL == result.ptr) {
        EVP_CIPHER_CTX_free(aes256);
        PUBNUB_LOG_ERROR("Failed to allocate memory for AES-256 encryption\n");
        return result;
    }
    
    encrypt_result = do_encrypt(aes256, msg, key, iv, &result);
    if (-1 == encrypt_result) {
        free(result.ptr);
        result.ptr = NULL;
    }
    EVP_CIPHER_CTX_free(aes256);

    return result;
}
static enum pbpal_resolv_n_connect_result resolv_and_connect_wout_SSL(pubnub_t *pb)
{
    PUBNUB_LOG_TRACE("resolv_and_connect_wout_SSL\n");
    if (NULL == pb->pal.socket) {
        char const*origin = PUBNUB_ORIGIN_SETTABLE ? pb->origin : PUBNUB_ORIGIN;
        PUBNUB_LOG_TRACE("pb=%p: Don't have BIO\n", pb);
        pb->pal.socket = BIO_new_connect((char*)origin);
    }
    if (NULL == pb->pal.socket) {
        return pbpal_resolv_resource_failure;
    }
    BIO_set_conn_port(pb->pal.socket, "http");

    BIO_set_nbio(pb->pal.socket, !pb->options.use_blocking_io);

    WATCH_ENUM(pb->options.use_blocking_io);
    if (BIO_do_connect(pb->pal.socket) <= 0) {
        if (BIO_should_retry(pb->pal.socket)) {
            return pbpal_connect_wouldblock;
        }
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        PUBNUB_LOG_ERROR("BIO_do_connect failed\n");
        return pbpal_connect_failed;
    }

    PUBNUB_LOG_TRACE("pb=%p: BIO connected\n", pb);
    {
        int fd = BIO_get_fd(pb->pal.socket, NULL);
        socket_set_rcv_timeout(fd, pb->transaction_timeout_ms);
    }

    return pbpal_connect_success;
}
static void sublup_context_callback(pubnub_t*         pb,
                                    enum pubnub_trans trans,
                                    enum pubnub_res   result,
                                    void*             user_data)
{
    pubnub_subloop_t* pbsld = (pubnub_subloop_t*)user_data;

    PUBNUB_ASSERT_OPT(pbsld != NULL);

    pubnub_mutex_lock(pbsld->monitor);
    if (PBTT_SUBSCRIBE == trans) {
        if (PNR_OK == result) {
            char const* msg;
            for (msg = pubnub_get(pb); msg != NULL; msg = pubnub_get(pb)) {
                pbsld->cb(pb, msg, PNR_OK);
            }
        }
        else {
            pbsld->cb(pb, NULL, result);
        }
        result = pubnub_subscribe_ex(pbsld->pbp, pbsld->channel, pbsld->options);
        if (result != PNR_STARTED) {
            PUBNUB_LOG_ERROR("Failed to re-subscribe in the subscribe loop, "
                             "error code = %d\n",
                             result);
        }
    }
    pubnub_mutex_unlock(pbsld->monitor);
}
예제 #8
0
파일: pbaes256.c 프로젝트: sveljko/c-core
static int print_to_pubnub_log(const char *s, size_t len, void *p)
{
    PUBNUB_UNUSED(len);
    PUBNUB_UNUSED(p);

    PUBNUB_LOG_ERROR("%s", s);

    return 0;
}
예제 #9
0
int send_dns_query(int skt, struct sockaddr const* dest, char const* host)
{
    uint8_t buf[4096];
    int     to_send;
    int                sent_to;

    if (-1 == pubnub_prepare_dns_request(buf, sizeof buf, host, &to_send)) {
        PUBNUB_LOG_ERROR("Couldn't prepare dns request! : #prepared bytes=%d\n", to_send);
        return -1;
    }
    TRACE_SOCKADDR("Sending DNS query to: ", dest);
    sent_to = sendto(skt, (char*)buf, to_send, 0, dest, sizeof *dest);
    if (sent_to <= 0) {
        return socket_would_block() ? +1 : -1;
    }
    else if (to_send != sent_to) {
        PUBNUB_LOG_ERROR("sendto() sent %d out of %d bytes!\n", sent_to, to_send);
        return -1;
    }
    return 0;
}
예제 #10
0
파일: pbaes256.c 프로젝트: sveljko/c-core
int pbaes256_decrypt(pubnub_bymebl_t data, uint8_t const* key, uint8_t const* iv, pubnub_bymebl_t *msg)
{
    int result;
    EVP_CIPHER_CTX *aes256;

    if (msg->size < data.size + EVP_CIPHER_block_size(EVP_aes_256_cbc()) + 1) {
        PUBNUB_LOG_ERROR("Not enough room to save AES-256 decrypted data\n");
        return -1;
    }

    aes256 = EVP_CIPHER_CTX_new();
    if (NULL == aes256) {
        PUBNUB_LOG_ERROR("Failed to allocate AES-256 decryption context\n");
        return -1;
    }

    result = do_decrypt(aes256, data, key, iv, msg);

    EVP_CIPHER_CTX_free(aes256);

    return result;
}
예제 #11
0
int pbpal_send(pubnub_t *pb, void const *data, size_t n)
{
    if (n == 0) {
        return 0;
    }
    if (pb->sock_state != STATE_NONE) {
        PUBNUB_LOG_ERROR("pbpal_send(): pb->sock_state != STATE_NONE (=%d)\n", pb->sock_state);
        return -1;
    }
    pb->sendptr = (uint8_t*)data;
    pb->sendlen = (uint16_t)n;
    pb->sock_state = STATE_NONE;

    return pbpal_send_status(pb);
}
예제 #12
0
파일: pbaes256.c 프로젝트: sveljko/c-core
int pbaes256_encrypt(pubnub_bymebl_t msg, uint8_t const* key, uint8_t const* iv, pubnub_bymebl_t *encrypted)
{
    int result;
    EVP_CIPHER_CTX* aes256 = EVP_CIPHER_CTX_new();

    if (NULL == aes256) {
        PUBNUB_LOG_ERROR("Failed to allocate AES-256 encryption context\n");
        return -1;
    }

    result = do_encrypt(aes256, msg, key, iv, encrypted);

    EVP_CIPHER_CTX_free(aes256);

    return result;
}
예제 #13
0
int pubnub_free_with_timeout(pubnub_t* pbp, unsigned millisec)
{
    const clock_t t0 = clock();
    const clock_t clocks_till_timeout = (millisec * CLOCKS_PER_SEC) / 1000;

    PUBNUB_ASSERT_OPT(pbp != NULL);

    while (pubnub_free(pbp) != 0) {
        const clock_t elapsed = clock() - t0;
        if (elapsed  > clocks_till_timeout) {
            PUBNUB_LOG_ERROR("Failed to free the context in %u milli seconds\n", millisec);
            return -1;
        }
    }
    PUBNUB_LOG_TRACE("Freed the context in %lf seconds\n",  ((float)clock() - t0) / CLOCKS_PER_SEC);

    return 0;
}
enum pbpal_resolv_n_connect_result pbpal_check_connect(pubnub_t *pb)
{
    fd_set write_set;
    int rslt;
    struct timeval timev = { 0, 300000 };
    
    FD_ZERO(&write_set);
    FD_SET(pb->pal.socket, &write_set);
    rslt = select(pb->pal.socket + 1, NULL, &write_set, NULL, &timev);
    if (SOCKET_ERROR == rslt) {
        PUBNUB_LOG_ERROR("pbpal_connected(): select() Error!\n");
        return pbpal_connect_resource_failure;
    }
    else if (rslt > 0) {
        PUBNUB_LOG_TRACE("pbpal_connected(): select() event\n");
        return pbpal_connect_success;
    }
    PUBNUB_LOG_TRACE("pbpal_connected(): no select() events\n");
    return pbpal_connect_wouldblock;
}
예제 #15
0
void pbproxy_handle_http_header(pubnub_t *p, char const* header)
{
    char scheme_basic[] = "Basic";
    char scheme_NTLM[] = "NTLM";
    char proxy_auth[] = "Proxy-Authenticate: ";
    char const* contents;

    PUBNUB_ASSERT_OPT(p != NULL);
    PUBNUB_ASSERT_OPT(header != NULL);

    if (strncmp(p->core.http_buf, proxy_auth, sizeof proxy_auth - 1) != 0) {
        return;
    }
    contents = p->core.http_buf + sizeof proxy_auth - 1;

    PUBNUB_LOG_TRACE("pbproxy_handle_http_header(header='%s', contents='%s')\n", header, contents);

    if (0 == strncmp(contents, scheme_basic, sizeof scheme_basic -1)) {
        /* We ignore the "realm" for now */
        PUBNUB_LOG_TRACE("pbproxy_handle_http_header() Basic authentication\n");
        p->proxy_auth_scheme = pbhtauBasic;
        p->proxy_authorization_sent = false;
    }
    else if (0 == strncmp(contents, scheme_NTLM, sizeof scheme_NTLM -1)) {
        if (pbhtauNTLM != p->proxy_auth_scheme) {
            pbntlm_core_init(p);
            p->proxy_auth_scheme = pbhtauNTLM;
            p->proxy_authorization_sent = false;
        }
        else {
            char const *base64_msg = contents + sizeof scheme_NTLM;
            pbntlm_core_handle(p, base64_msg, strcspn(base64_msg, " \r\n"));
        }
    }
    else {
        PUBNUB_LOG_ERROR("Proxy Authentication '%s' not supported\n", contents);
        p->proxy_auth_scheme = pbhtauNone;
    }
}
예제 #16
0
int pbpal_start_read(pubnub_t *pb, size_t n)
{
    if (pb->sock_state != STATE_NONE) {
        PUBNUB_LOG_ERROR("pbpal_start_read(): pb->sock_state != STATE_NONE: "); WATCH_ENUM(pb->sock_state);
        return -1;
    }
    if (pb->ptr > (uint8_t*)pb->core.http_buf) {
        unsigned distance = pb->ptr - (uint8_t*)pb->core.http_buf;
        memmove(pb->core.http_buf, pb->ptr, pb->readlen);
        pb->ptr -= distance;
        pb->left += distance;
    }
    else {
        if (pb->left == 0) {
            /* Obviously, our buffer is not big enough, maybe some
               error should be reported */
            buf_setup(pb);
        }
    }
    pb->sock_state = STATE_READ;
    pb->len = n;
    return +1;
}
enum pbpal_resolv_n_connect_result pbpal_resolv_and_connect(pubnub_t *pb)
{
    SSL *ssl = NULL;
    int rslt;
    char const* origin = PUBNUB_ORIGIN_SETTABLE ? pb->origin : PUBNUB_ORIGIN;

    PUBNUB_ASSERT(pb_valid_ctx_ptr(pb));
    PUBNUB_ASSERT_OPT((pb->state == PBS_READY) || (pb->state == PBS_WAIT_CONNECT));

    if (!pb->options.useSSL) {
        return resolv_and_connect_wout_SSL(pb);
    }

    if (NULL == pb->pal.ctx) {
        PUBNUB_LOG_TRACE("pb=%p: Don't have SSL_CTX\n", pb);
        pb->pal.ctx = SSL_CTX_new(SSLv23_client_method());
        if (NULL == pb->pal.ctx) {
            ERR_print_errors_cb(print_to_pubnub_log, NULL);
            PUBNUB_LOG_ERROR("pb=%p SSL_CTX_new failed\n", pb);
            return pbpal_resolv_resource_failure;
        }
        PUBNUB_LOG_TRACE("pb=%p: Got SSL_CTX\n", pb);
        add_pubnub_cert(pb->pal.ctx);
    }

    if (NULL == pb->pal.socket) {
        PUBNUB_LOG_TRACE("pb=%p: Don't have BIO\n", pb);
        pb->pal.socket = BIO_new_ssl_connect(pb->pal.ctx);
        if (PUBNUB_TIMERS_API) {
            pb->pal.connect_timeout = time(NULL)  + pb->transaction_timeout_ms/1000;
        }
    }
    else {
        BIO_get_ssl(pb->pal.socket, &ssl);
        if (NULL == ssl) {
            return resolv_and_connect_wout_SSL(pb);
        }
        ssl = NULL;
    }
    if (NULL == pb->pal.socket) {
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        return pbpal_resolv_resource_failure;
    }

    PUBNUB_LOG_TRACE("pb=%p: Using BIO == %p\n", pb, pb->pal.socket);

    BIO_get_ssl(pb->pal.socket, &ssl);
    PUBNUB_ASSERT(NULL != ssl);
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); /* maybe not auto_retry? */
    if (pb->pal.session != NULL) {
        SSL_set_session(ssl, pb->pal.session);
    }

    BIO_set_conn_hostname(pb->pal.socket, origin);
    BIO_set_conn_port(pb->pal.socket, "https");
    if (pb->pal.ip_timeout != 0) {
        if (pb->pal.ip_timeout < time(NULL)) {
            pb->pal.ip_timeout = 0;
        }
        else {
            PUBNUB_LOG_TRACE("SSL re-connect to: %d.%d.%d.%d\n", pb->pal.ip[0], pb->pal.ip[1], pb->pal.ip[2], pb->pal.ip[3]);
            BIO_set_conn_ip(pb->pal.socket, pb->pal.ip);
        }
    }
    
    BIO_set_nbio(pb->pal.socket, !pb->options.use_blocking_io);
    
    WATCH_ENUM(pb->options.use_blocking_io);
    if (BIO_do_connect(pb->pal.socket) <= 0) {
        if (BIO_should_retry(pb->pal.socket) && PUBNUB_TIMERS_API && (pb->pal.connect_timeout > time(NULL))) {
            PUBNUB_LOG_TRACE("pb=%p: BIO_should_retry\n", pb);
            return pbpal_connect_wouldblock;
        }
        /* Expire the IP for the next connect */
        pb->pal.ip_timeout = 0;
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        if (pb->pal.session != NULL) {
            SSL_SESSION_free(pb->pal.session);
            pb->pal.session = NULL;
        }
        PUBNUB_LOG_ERROR("pb=%p: BIO_do_connect failed\n", pb);
        return pbpal_connect_failed;
    }

    PUBNUB_LOG_TRACE("pb=%p: BIO connected\n", pb);
    {
        int fd = BIO_get_fd(pb->pal.socket, NULL);
        socket_set_rcv_timeout(fd, pb->transaction_timeout_ms);
    }

    rslt = SSL_get_verify_result(ssl);
    if (rslt != X509_V_OK) {
        PUBNUB_LOG_WARNING("pb=%p: SSL_get_verify_result() failed == %d(%s)\n", pb, rslt, X509_verify_cert_error_string(rslt));
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        if (pb->options.fallbackSSL) {
            BIO_free_all(pb->pal.socket);
            pb->pal.socket = NULL;
            return resolv_and_connect_wout_SSL(pb);
        }
        return pbpal_connect_failed;
    }

    PUBNUB_LOG_INFO("pb=%p: SSL session reused: %s\n", pb, SSL_session_reused(ssl) ? "yes" : "no");
    if (pb->pal.session != NULL) {
        SSL_SESSION_free(pb->pal.session);
    }
    pb->pal.session = SSL_get1_session(ssl);
    if (0 == pb->pal.ip_timeout) {
        pb->pal.ip_timeout = SSL_SESSION_get_time(pb->pal.session) + SSL_SESSION_get_timeout(pb->pal.session);
        memcpy(pb->pal.ip, BIO_get_conn_ip(pb->pal.socket), 4);
    }
    PUBNUB_LOG_TRACE("pb=%p: SSL connected to IP: %d.%d.%d.%d\n", pb, pb->pal.ip[0], pb->pal.ip[1], pb->pal.ip[2], pb->pal.ip[3]);

    return pbpal_connect_success;
}
예제 #18
0
void pbproxy_handle_http_header(pubnub_t* p, char const* header)
{
    char        scheme_basic[]  = "Basic";
    char        scheme_digest[] = "Digest";
    char        scheme_NTLM[]   = "NTLM";
    char        proxy_auth[]    = "Proxy-Authenticate: ";
    char const* contents;

    PUBNUB_ASSERT_OPT(p != NULL);
    PUBNUB_ASSERT_OPT(header != NULL);

    switch (header[0]) {
    case ' ':
    case '\t':
        /* Though this is not very nice, we only support multi-line
           headers for Digest proxy. In practice, Basic and NTLM never
           use multi-line headers.
        */
        if (p->proxy_auth_scheme != pbhtauDigest) {
            return;
        }
        pbhttp_digest_parse_header(&p->digest_context, header + 1);
        return;
    default:
        if (strncmp(header, proxy_auth, sizeof proxy_auth - 1) != 0) {
            return;
        }
        break;
    }
    contents = header + sizeof proxy_auth - 1;

    PUBNUB_LOG_TRACE("pbproxy_handle_http_header(header='%s', contents='%s')\n",
                     header,
                     contents);

    if (0 == strncmp(contents, scheme_basic, sizeof scheme_basic - 1)) {
        /* We ignore the "realm" for now */
        PUBNUB_LOG_TRACE("pbproxy_handle_http_header() Basic authentication\n");
        p->proxy_auth_scheme        = pbhtauBasic;
        p->proxy_authorization_sent = false;
    }
    else if (0 == strncmp(contents, scheme_digest, sizeof scheme_digest - 1)) {
        /* We ignore the "realm" for now */
        PUBNUB_LOG_TRACE(
            "pbproxy_handle_http_header() Digest authentication\n");
        p->proxy_auth_scheme = pbhtauDigest;
        pbhttp_digest_init(&p->digest_context);
        pbhttp_digest_parse_header(&p->digest_context,
                                   contents + sizeof scheme_digest);
        p->proxy_authorization_sent = false;
    }
    else if (0 == strncmp(contents, scheme_NTLM, sizeof scheme_NTLM - 1)) {
        if (pbhtauNTLM != p->proxy_auth_scheme) {
            pbntlm_core_init(p);
            p->proxy_auth_scheme        = pbhtauNTLM;
            p->proxy_authorization_sent = false;
        }
        else {
            char const* base64_msg = contents + sizeof scheme_NTLM;
            pbntlm_core_handle(p, base64_msg, strcspn(base64_msg, " \r\n"));
        }
    }
    else {
        PUBNUB_LOG_ERROR("Proxy Authentication '%s' not supported\n", contents);
        p->proxy_auth_scheme = pbhtauNone;
    }
}
예제 #19
0
int pbproxy_http_header_to_send(pubnub_t *p, char* header, size_t n)
{
    PUBNUB_ASSERT_OPT(p != NULL);
    PUBNUB_ASSERT_OPT(header != NULL);

    switch (p->proxy_auth_scheme) {
    case pbhtauBasic:
    {
        int i;
        char prefix[] = "Proxy-Authorization: Basic ";
        char response[128];
        pubnub_bymebl_t data = { (uint8_t*)response, 0 };

        PUBNUB_ASSERT_OPT(n > sizeof prefix);
        memcpy(header, prefix, sizeof prefix);
        n -= sizeof prefix;
        data.size = snprintf(response, sizeof response, "%s:%s", figure_out_username(p), figure_out_password(p));

        PUBNUB_LOG_TRACE("pbproxy_http_header_to_send(): Basic header (before Base64): '%s'\n", response);

        i = pbbase64_encode_std(data, header + sizeof prefix - 1, &n);
        if (0 == i) {
            PUBNUB_LOG_TRACE("pbproxy_http_header_to_send(): Basic header (after Base64): '%s'\n", header);
            p->proxy_authorization_sent = true;
        }
        else {
            PUBNUB_LOG_ERROR("pbproxy_http_header_to_send(): Basic Failed Base64 encoding of header\n");
        }
        return i;
    }
    case pbhtauNTLM:
    {
        char prefix[] = "Proxy-Authorization: NTLM ";
        uint8_t response[PUBNUB_NTLM_MAX_TOKEN];
        pubnub_bymebl_t data = { response, sizeof response };
        int i = pbntlm_core_prep_msg_to_send(p, &data);

        if (i != 0) {
            PUBNUB_LOG_ERROR("pbproxy_http_header_to_send(): NTLM failed preparing message to send'\n");
            return -1;
        }
        if (0 == data.size) {
            return -1;
        }

        PUBNUB_ASSERT_OPT(n > sizeof prefix);
        memcpy(header, prefix, sizeof prefix);
        n -= sizeof prefix;

        i = pbbase64_encode_std(data, header + sizeof prefix - 1, &n);
        if (0 == i) {
            PUBNUB_LOG_TRACE("pbproxy_http_header_to_send(): NTLM header (after Base64): '%s'\n", header);
        }
        else {
            PUBNUB_LOG_ERROR("pbproxy_http_header_to_send(): NTLM Failed Base64 encoding of header\n");
        }

        return i;
    }
    case pbhtauNone:
        return -1;
    default:
        PUBNUB_LOG_ERROR("pbproxy_http_header_to_send(): Proxy auth scheme %d not supported\n", p->proxy_auth_scheme);
        return -1;
    }
}