Ticket #8452: filezilla_3.6.0_http_proxy_digest_with_md5.patch

File filezilla_3.6.0_http_proxy_digest_with_md5.patch, 22.2 KB (added by Tommy Wu, 7 years ago)

add digest support for http proxy (with internal md5 function)

  • src/engine/proxy.cpp

    diff --strip-trailing-cr -Nur a/src/engine/proxy.cpp b/src/engine/proxy.cpp
    a b  
    11#include <filezilla.h>
    22#include "proxy.h"
    33#include <errno.h>
     4#include <wx/tokenzr.h>
    45#include "ControlSocket.h"
    56
    67enum handshake_state
     
    2526    m_pSendBuffer = 0;
    2627    m_pRecvBuffer = 0;
    2728
     29    m_doAuth = false;
     30
    2831    m_proxyType = unknown;
    2932
    3033    m_can_write = false;
     
    3942    delete [] m_pRecvBuffer;
    4043}
    4144
     45static void AppendSubHex(unsigned char val, wxString& result)
     46{
     47   if (val > 9)
     48   {
     49      result.Append((char)('a'+val-10));
     50   }
     51   else
     52   {
     53      result.Append((char)('0'+val));
     54   }
     55}
     56
     57static void AppendHex(unsigned char val, wxString& result)
     58{
     59   AppendSubHex((val >> 4) & 0xF, result);
     60   AppendSubHex(val&0xF, result);
     61}
     62
     63/*
     64 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
     65 * MD5 Message-Digest Algorithm (RFC 1321).
     66 *
     67 * Homepage:
     68 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
     69 *
     70 * Author:
     71 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
     72 *
     73 * This software was written by Alexander Peslyak in 2001.  No copyright is
     74 * claimed, and the software is hereby placed in the public domain.
     75 * In case this attempt to disclaim copyright and place the software in the
     76 * public domain is deemed null and void, then the software is
     77 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
     78 * general public under the following terms:
     79 *
     80 * Redistribution and use in source and binary forms, with or without
     81 * modification, are permitted.
     82 *
     83 * There's ABSOLUTELY NO WARRANTY, express or implied.
     84 *
     85 * (This is a heavily cut-down "BSD license".)
     86 *
     87 * This differs from Colin Plumb's older public domain implementation in that
     88 * no exactly 32-bit integer data type is required (any 32-bit or wider
     89 * unsigned integer data type will do), there's no compile-time endianness
     90 * configuration, and the function prototypes match OpenSSL's.  No code from
     91 * Colin Plumb's implementation has been reused; this comment merely compares
     92 * the properties of the two independent implementations.
     93 *
     94 * The primary goals of this implementation are portability and ease of use.
     95 * It is meant to be fast, but not as fast as possible.  Some known
     96 * optimizations are not included to reduce source code size and avoid
     97 * compile-time configuration.
     98 */
     99 
     100#include <string.h>
     101 
     102/* Any 32-bit or wider unsigned integer data type will do */
     103typedef unsigned int MD5_u32plus;
     104 
     105typedef struct {
     106    MD5_u32plus lo, hi;
     107    MD5_u32plus a, b, c, d;
     108    unsigned char buffer[64];
     109    MD5_u32plus block[16];
     110} MD5_CTX;
     111 
     112/*
     113 * The basic MD5 functions.
     114 *
     115 * F and G are optimized compared to their RFC 1321 definitions for
     116 * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
     117 * implementation.
     118 */
     119#define F(x, y, z)          ((z) ^ ((x) & ((y) ^ (z))))
     120#define G(x, y, z)          ((y) ^ ((z) & ((x) ^ (y))))
     121#define H(x, y, z)          ((x) ^ (y) ^ (z))
     122#define I(x, y, z)          ((y) ^ ((x) | ~(z)))
     123 
     124/*
     125 * The MD5 transformation for all four rounds.
     126 */
     127#define STEP(f, a, b, c, d, x, t, s) \
     128    (a) += f((b), (c), (d)) + (x) + (t); \
     129    (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
     130    (a) += (b);
     131 
     132/*
     133 * SET reads 4 input bytes in little-endian byte order and stores them
     134 * in a properly aligned word in host byte order.
     135 *
     136 * The check for little-endian architectures that tolerate unaligned
     137 * memory accesses is just an optimization.  Nothing will break if it
     138 * doesn't work.
     139 */
     140#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
     141#define SET(n) \
     142    (*(MD5_u32plus *)&ptr[(n) * 4])
     143#define GET(n) \
     144    SET(n)
     145#else
     146#define SET(n) \
     147    (ctx->block[(n)] = \
     148    (MD5_u32plus)ptr[(n) * 4] | \
     149    ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
     150    ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
     151    ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
     152#define GET(n) \
     153    (ctx->block[(n)])
     154#endif
     155 
     156/*
     157 * This processes one or more 64-byte data blocks, but does NOT update
     158 * the bit counters.  There are no alignment requirements.
     159 */
     160static void *body(MD5_CTX *ctx, void *data, unsigned long size)
     161{
     162    unsigned char *ptr;
     163    MD5_u32plus a, b, c, d;
     164    MD5_u32plus saved_a, saved_b, saved_c, saved_d;
     165 
     166    ptr = (unsigned char *)data;
     167 
     168    a = ctx->a;
     169    b = ctx->b;
     170    c = ctx->c;
     171    d = ctx->d;
     172 
     173    do {
     174        saved_a = a;
     175        saved_b = b;
     176        saved_c = c;
     177        saved_d = d;
     178 
     179/* Round 1 */
     180        STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
     181        STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
     182        STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
     183        STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
     184        STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
     185        STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
     186        STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
     187        STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
     188        STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
     189        STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
     190        STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
     191        STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
     192        STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
     193        STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
     194        STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
     195        STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
     196 
     197/* Round 2 */
     198        STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
     199        STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
     200        STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
     201        STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
     202        STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
     203        STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
     204        STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
     205        STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
     206        STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
     207        STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
     208        STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
     209        STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
     210        STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
     211        STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
     212        STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
     213        STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
     214 
     215/* Round 3 */
     216        STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
     217        STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
     218        STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
     219        STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
     220        STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
     221        STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
     222        STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
     223        STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
     224        STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
     225        STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
     226        STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
     227        STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
     228        STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
     229        STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
     230        STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
     231        STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
     232 
     233/* Round 4 */
     234        STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
     235        STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
     236        STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
     237        STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
     238        STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
     239        STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
     240        STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
     241        STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
     242        STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
     243        STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
     244        STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
     245        STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
     246        STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
     247        STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
     248        STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
     249        STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
     250 
     251        a += saved_a;
     252        b += saved_b;
     253        c += saved_c;
     254        d += saved_d;
     255 
     256        ptr += 64;
     257    } while (size -= 64);
     258 
     259    ctx->a = a;
     260    ctx->b = b;
     261    ctx->c = c;
     262    ctx->d = d;
     263 
     264    return ptr;
     265}
     266 
     267void MD5_Init(MD5_CTX *ctx)
     268{
     269    ctx->a = 0x67452301;
     270    ctx->b = 0xefcdab89;
     271    ctx->c = 0x98badcfe;
     272    ctx->d = 0x10325476;
     273 
     274    ctx->lo = 0;
     275    ctx->hi = 0;
     276}
     277 
     278void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size)
     279{
     280    MD5_u32plus saved_lo;
     281    unsigned long used, free;
     282 
     283    saved_lo = ctx->lo;
     284    if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
     285        ctx->hi++;
     286    ctx->hi += size >> 29;
     287 
     288    used = saved_lo & 0x3f;
     289 
     290    if (used) {
     291        free = 64 - used;
     292 
     293        if (size < free) {
     294            memcpy(&ctx->buffer[used], data, size);
     295            return;
     296        }
     297 
     298        memcpy(&ctx->buffer[used], data, free);
     299        data = (unsigned char *)data + free;
     300        size -= free;
     301        body(ctx, ctx->buffer, 64);
     302    }
     303 
     304    if (size >= 64) {
     305        data = body(ctx, data, size & ~(unsigned long)0x3f);
     306        size &= 0x3f;
     307    }
     308 
     309    memcpy(ctx->buffer, data, size);
     310}
     311 
     312void MD5_Final(unsigned char *result, MD5_CTX *ctx)
     313{
     314    unsigned long used, free;
     315 
     316    used = ctx->lo & 0x3f;
     317 
     318    ctx->buffer[used++] = 0x80;
     319 
     320    free = 64 - used;
     321 
     322    if (free < 8) {
     323        memset(&ctx->buffer[used], 0, free);
     324        body(ctx, ctx->buffer, 64);
     325        used = 0;
     326        free = 64;
     327    }
     328 
     329    memset(&ctx->buffer[used], 0, free - 8);
     330 
     331    ctx->lo <<= 3;
     332    ctx->buffer[56] = ctx->lo;
     333    ctx->buffer[57] = ctx->lo >> 8;
     334    ctx->buffer[58] = ctx->lo >> 16;
     335    ctx->buffer[59] = ctx->lo >> 24;
     336    ctx->buffer[60] = ctx->hi;
     337    ctx->buffer[61] = ctx->hi >> 8;
     338    ctx->buffer[62] = ctx->hi >> 16;
     339    ctx->buffer[63] = ctx->hi >> 24;
     340 
     341    body(ctx, ctx->buffer, 64);
     342 
     343    result[0] = ctx->a;
     344    result[1] = ctx->a >> 8;
     345    result[2] = ctx->a >> 16;
     346    result[3] = ctx->a >> 24;
     347    result[4] = ctx->b;
     348    result[5] = ctx->b >> 8;
     349    result[6] = ctx->b >> 16;
     350    result[7] = ctx->b >> 24;
     351    result[8] = ctx->c;
     352    result[9] = ctx->c >> 8;
     353    result[10] = ctx->c >> 16;
     354    result[11] = ctx->c >> 24;
     355    result[12] = ctx->d;
     356    result[13] = ctx->d >> 8;
     357    result[14] = ctx->d >> 16;
     358    result[15] = ctx->d >> 24;
     359 
     360    memset(ctx, 0, sizeof(*ctx));
     361}
     362 
     363static wxString ComputeMD5(const char *buf, unsigned int len)
     364{
     365    MD5_CTX ctx;
     366    unsigned char signature[16];
     367
     368    MD5_Init(&ctx);
     369    MD5_Update(&ctx, (void *)buf, len);
     370    MD5_Final(signature, &ctx);
     371
     372    wxString result;
     373    for (int j = 0; j < (int)sizeof signature; j++)
     374    {
     375        AppendHex(signature[j], result);
     376    }
     377
     378    return result;
     379}
     380
    42381static wxString base64encode(const wxString& str)
    43382{
    44383    // Code shamelessly taken from wxWidgets and adopted to encode UTF-8 strings.
     
    96435    {
    97436        m_handshakeState = http_wait;
    98437
    99 #if wxUSE_UNICODE
    100         wxWX2MBbuf challenge;
    101 #else
    102         const wxWX2MBbuf challenge;
    103 #endif
    104         int challenge_len;
    105         if (user != _T(""))
    106         {
    107             challenge = base64encode(user + _T(":") + pass).mb_str(wxConvUTF8);
    108             challenge_len = strlen(challenge);
    109         }
    110         else
    111         {
    112             challenge = (size_t)0;
    113             challenge_len = 0;
    114         }
    115 
    116438        // Bit oversized, but be on the safe side
    117         m_pSendBuffer = new char[70 + strlen(host_raw) * 2 + 2*5 + challenge_len + 23];
     439        m_pSendBuffer = new char[70 + strlen(host_raw) * 2 + 2*5 + 23];
    118440
    119         if (!challenge)
    120         {
    121             m_sendBufferLen = sprintf(m_pSendBuffer, "CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nUser-Agent: FileZilla\r\n\r\n",
    122                 (const char*)host_raw, port,
    123                 (const char*)host_raw, port);
    124         }
    125         else
    126         {
    127             m_sendBufferLen = sprintf(m_pSendBuffer, "CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nProxy-Authorization: Basic %s\r\nUser-Agent: FileZilla\r\n\r\n",
    128                 (const char*)host_raw, port,
    129                 (const char*)host_raw, port,
    130                 (const char*)challenge);
    131         }
     441        m_sendBufferLen = sprintf(m_pSendBuffer, "CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nUser-Agent: FileZilla\r\n\r\n",
     442            (const char*)host_raw, port,
     443            (const char*)host_raw, port);
    132444
    133445        m_pRecvBuffer = new char[4096];
    134446        m_recvBufferLen = 4096;
     
    302614            if (!end)
    303615                continue;
    304616
     617            unsigned long int nContentLength = 0;
     618            bool bUseBasic = false;
     619            bool bUseDigest = false;
     620            wxString digestStr = _T("");
     621            wxString authStr = _T("");
     622            wxString header_str(m_pRecvBuffer, wxConvLocal, m_recvBufferPos);
     623            wxStringTokenizer tkz(header_str, wxT("\r\n"));
     624
     625            while (tkz.HasMoreTokens())
     626            {
     627                wxString token = tkz.GetNextToken();
     628                if (token.Mid(0, 15).Lower() == _T("content-length:"))
     629                {
     630                    token.Mid(15).Trim(true).Trim(false).ToULong(&nContentLength);
     631                    continue;
     632                }
     633                if (token.Mid(0, 26).Lower() == _T("proxy-authenticate: basic "))
     634                {
     635                    bUseBasic = true;
     636                    continue;
     637                }
     638                if (token.Mid(0, 27).Lower() == _T("proxy-authenticate: digest "))
     639                {
     640                    authStr = token.Mid(27);
     641                    bUseDigest = true;
     642                    continue;
     643                }
     644            }
     645
     646            // read body
     647            unsigned long int nBodyLength = 0;
     648            char *pBody = new char[nContentLength];
     649            while (nBodyLength < nContentLength) {
     650                int read;
     651
     652                do_read = nContentLength - nBodyLength;
     653
     654                read = m_pSocket->Read(pBody + nBodyLength, do_read, error);
     655                if (read == -1)
     656                {
     657                    if (error != EAGAIN)
     658                    {
     659                        delete [] pBody;
     660                        m_proxyState = noconn;
     661                        CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::close, error);
     662                        CSocketEventDispatcher::Get().SendEvent(evt);
     663                    }
     664                    else
     665                        m_can_read = false;
     666                    continue;
     667                }
     668                if (!read)
     669                {
     670                    delete [] pBody;
     671                    m_proxyState = noconn;
     672                    CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::close, ECONNABORTED);
     673                    CSocketEventDispatcher::Get().SendEvent(evt);
     674                    return;
     675                }
     676                if (m_pSendBuffer)
     677                {
     678                    delete [] pBody;
     679                    m_proxyState = noconn;
     680                    m_pOwner->LogMessage(Debug_Warning, _T("Incoming data before requst fully sent"));
     681                    CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::close, ECONNABORTED);
     682                    CSocketEventDispatcher::Get().SendEvent(evt);
     683                    return;
     684                }
     685                nBodyLength += read;
     686            }
     687
    305688            end = strchr(m_pRecvBuffer, '\r');
    306689            wxASSERT(end);
    307690            *end = 0;
    308691            wxString reply(m_pRecvBuffer, wxConvUTF8);
    309692            m_pOwner->LogMessage(Response, _("Proxy reply: %s"), reply.c_str());
    310693
     694            if (reply.Left(12) == _T("HTTP/1.1 401") || reply.Left(12) == _T("HTTP/1.1 407") ||
     695                reply.Left(12) == _T("HTTP/1.0 401") || reply.Left(12) == _T("HTTP/1.0 407"))
     696            {
     697                if (m_doAuth || m_user == _T(""))
     698                {
     699                    delete [] pBody;
     700                    m_pOwner->LogMessage(Debug_Warning, _("already m_doAuth (%d), or m_user is empty (%s)"), m_doAuth, m_user.c_str());
     701                    m_proxyState = noconn;
     702                    CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::close, ECONNRESET);
     703                    CSocketEventDispatcher::Get().SendEvent(evt);
     704                    return;
     705                }
     706
     707                if (bUseDigest)
     708                {
     709                    wxString realm = _T("");
     710                    wxString nonce = _T("");
     711                    wxString qop = _T("");
     712                    wxStringTokenizer tkz2(authStr, wxT(","));
     713                    while (tkz2.HasMoreTokens())
     714                    {
     715                        wxString token2 = tkz2.GetNextToken();
     716                        wxString name = _T("");
     717                        wxString value = _T("");
     718                        wxStringTokenizer tkz3(token2, wxT("="));
     719                        while (tkz3.HasMoreTokens())
     720                        {
     721                            wxString token3 = tkz3.GetNextToken();
     722                            if (name == _T(""))
     723                            {
     724                                name = token3.Lower().Trim(true).Trim(false);
     725                                continue;
     726                            }
     727                            if (token3.Left(1) == _T("\""))
     728                                value = token3.Mid(1, token3.Len()-2).Trim(true).Trim(false);
     729                            else
     730                                value = token3.Trim(true).Trim(false);
     731                            break;
     732                        }
     733                        if (name == _T("realm"))
     734                            realm = value;
     735                        else if (name == _T("nonce"))
     736                            nonce = value;
     737                        else if (name == _T("qop"))
     738                            qop = value;
     739                    }
     740                    if (realm == _T("") || nonce == _T(""))
     741                    {
     742                        delete [] pBody;
     743                        m_pOwner->LogMessage(Debug_Warning, _T("no realm or nonce"));
     744                        m_proxyState = conn;
     745                        CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::connection, 0);
     746                        CSocketEventDispatcher::Get().SendEvent(evt);
     747                        return;
     748                    }
     749                    // HA1 = md5(username:realm:password)
     750                    // if qop = auth or no qop
     751                    // HA2 = md5(method:digestURI)
     752                    // if qop = auth-int
     753                    // HA2 = md5(method:digestURI:md5(body))
     754                    // if qop = auth or auth-int
     755                    // response = md5(HA1:nonce:nonceCount:clientNonce:qop:HA2)
     756                    // if no qop
     757                    // response = md5(HA1:nonce:HA2)
     758                    wxString ha1, ha2, response;
     759                    wxString s;
     760                    bool bAuth = false;
     761                    bool bAuthInt = false;
     762
     763                    if (qop != _T(""))
     764                    {
     765                        wxStringTokenizer tkz4(qop, wxT(","));
     766                        while (tkz4.HasMoreTokens())
     767                        {
     768                            wxString token4 = tkz4.GetNextToken();
     769                            if (token4 == _T("auth"))
     770                                bAuth = true;
     771                            if (token4 == _T("auth-int"))
     772                                bAuthInt = true;
     773                        }
     774                    }
     775
     776                    s = wxString::Format(_T("%s:%s:%s"), m_user.c_str(), realm.c_str(), m_pass.c_str());
     777                    const wxWX2MBbuf s_raw = s.mb_str(wxConvUTF8);
     778                    ha1 = ComputeMD5((const char *)s_raw, strlen(s_raw));
     779
     780                    wxString uri = _T("");
     781                    if (qop == _T("") || bAuth)
     782                    {
     783                        uri = wxString::Format(_T("%s:%u"), m_host.c_str(), m_port);
     784                        s = wxString::Format(_T("CONNECT:%s"), uri.c_str());
     785                        const wxWX2MBbuf s_raw = s.mb_str(wxConvUTF8);
     786                        ha2 = ComputeMD5((const char *)s_raw, strlen(s_raw));
     787                    }
     788                    else if (bAuthInt)
     789                    {
     790                        uri = wxString::Format(_T("%s:%u"), m_host.c_str(), m_port);
     791                        wxString bodyMD5 = ComputeMD5((const char *)pBody, nBodyLength);
     792                        s = wxString::Format(_T("CONNECT:%s:%s"), uri.c_str(), bodyMD5.c_str());
     793                        const wxWX2MBbuf s_raw = s.mb_str(wxConvLocal);
     794                        ha2 = ComputeMD5((const char *)s_raw, strlen(s_raw));
     795                    }
     796                    else
     797                    {
     798                        delete [] pBody;
     799                        m_pOwner->LogMessage(Debug_Warning, _T("unknown qop: %s"), qop.c_str());
     800                        m_proxyState = conn;
     801                        CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::connection, 0);
     802                        CSocketEventDispatcher::Get().SendEvent(evt);
     803                        return;
     804                    }
     805
     806                    // we don't need body now
     807                    delete [] pBody;
     808                    if (bAuth || bAuthInt)
     809                    {
     810                        wxString clientNonce = wxString::Format(_T("%04x%04x"), GetRandomNumber(0, 0xffff), GetRandomNumber(0, 0xffff));
     811
     812                        s = wxString::Format(_T("%s:%s:%s:%s:%s:%s"),
     813                            ha1.c_str(),
     814                            nonce.c_str(),
     815                            _T("00000001"),
     816                            clientNonce.c_str(),
     817                            bAuth ? _T("auth") : _T("auth-int"),
     818                            ha2.c_str());
     819                        const wxWX2MBbuf s_raw = s.mb_str(wxConvLocal);
     820                        response = ComputeMD5((const char *)s_raw, strlen(s_raw));
     821
     822                        digestStr = wxString::Format(_T("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\", qop=%s, nc=00000001, cnonce=\"%s\""),
     823                            m_user.c_str(),
     824                            realm.c_str(),
     825                            nonce.c_str(),
     826                            uri.c_str(),
     827                            response.c_str(),
     828                            bAuth ? _T("auth") : _T("auth-int"),
     829                            clientNonce.c_str());
     830                    }
     831                    else
     832                    {
     833                        s = wxString::Format(_T("%s:%s:%s"),
     834                            ha1.c_str(),
     835                            nonce.c_str(),
     836                            ha2.c_str());
     837                        const wxWX2MBbuf s_raw = s.mb_str(wxConvLocal);
     838                        response = ComputeMD5((const char *)s_raw, strlen(s_raw));
     839
     840                        digestStr = wxString::Format(_T("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\""),
     841                            m_user.c_str(),
     842                            realm.c_str(),
     843                            nonce.c_str(),
     844                            uri.c_str(),
     845                            response.c_str());
     846                    }
     847
     848                    m_doAuth = true;
     849                                m_recvBufferPos = 0;
     850
     851                    const wxWX2MBbuf host_raw = m_host.mb_str(wxConvUTF8);
     852                    const wxWX2MBbuf digest_raw = digestStr.mb_str(wxConvLocal);
     853
     854                    int challenge_len = digestStr.Len();
     855
     856                    m_pOwner->LogMessage(Status, _("Sending CONNECT with Digest Authorization"));
     857
     858                                // Bit oversized, but be on the safe side
     859                                m_pSendBuffer = new char[70 + m_host.Len() * 2 + 2*5 + challenge_len * 2 + 23 + 40];
     860
     861                    m_sendBufferLen = sprintf(m_pSendBuffer, "CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nProxy-Authorization: %s\r\nUser-Agent: FileZilla\r\n\r\n",
     862                        (const char*)host_raw, m_port,
     863                        (const char*)host_raw, m_port,
     864                        (const char*)digest_raw);
     865
     866                    wxString host = m_pSocket->GetPeerIP();
     867                    unsigned int port = m_pSocket->GetRemotePort(error);
     868
     869                    m_pSocket->Close();
     870                    int res = m_pSocket->Connect(host, port);
     871                    // Treat success same as EINPROGRESS, we wait for connect notification in any case
     872                    if (res && res != EINPROGRESS)
     873                    {
     874                        m_pOwner->LogMessage(Debug_Warning, _T("connect error?"));
     875                        m_proxyState = conn;
     876                        CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::connection, 0);
     877                        CSocketEventDispatcher::Get().SendEvent(evt);
     878                        return;
     879                    }
     880                    return;
     881                }
     882
     883                if (bUseBasic)
     884                {
     885                    // we don't need body for this
     886                    delete [] pBody;
     887                    m_doAuth = true;
     888                                m_recvBufferPos = 0;
     889
     890#if wxUSE_UNICODE
     891                    wxWX2MBbuf challenge;
     892#else
     893                    const wxWX2MBbuf challenge;
     894#endif
     895                    const wxWX2MBbuf host_raw = m_host.mb_str(wxConvUTF8);
     896                    int challenge_len;
     897
     898                    challenge = base64encode(m_user + _T(":") + m_pass).mb_str(wxConvUTF8);
     899                    challenge_len = strlen(challenge);
     900
     901                    m_pOwner->LogMessage(Status, _("Sending CONNECT with Basic Authorization"));
     902                    // Bit oversized, but be on the safe side
     903                    m_pSendBuffer = new char[70 + strlen(host_raw) * 2 + 2*5 + challenge_len + 23];
     904
     905                    m_sendBufferLen = sprintf(m_pSendBuffer, "CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nProxy-Authorization: Basic %s\r\nUser-Agent: FileZilla\r\n\r\n",
     906                        (const char*)host_raw, m_port,
     907                        (const char*)host_raw, m_port,
     908                        (const char*)challenge);
     909
     910                    wxString host = m_pSocket->GetPeerIP();
     911                    unsigned int port = m_pSocket->GetRemotePort(error);
     912
     913                    m_pSocket->Close();
     914                    int res = m_pSocket->Connect(host, port);
     915                    // Treat success same as EINPROGRESS, we wait for connect notification in any case
     916                    if (res && res != EINPROGRESS)
     917                    {
     918                        m_pOwner->LogMessage(Debug_Warning, _T("connect error?"));
     919                        m_proxyState = conn;
     920                        CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::connection, 0);
     921                        CSocketEventDispatcher::Get().SendEvent(evt);
     922                        return;
     923                    }
     924                    return;
     925                }
     926                // other authentication method?
     927            }
     928            delete [] pBody;
     929
    311930            if (reply.Left(10) != _T("HTTP/1.1 2") && reply.Left(10) != _T("HTTP/1.0 2"))
    312931            {
    313932                m_proxyState = noconn;
  • src/engine/proxy.h

    diff --strip-trailing-cr -Nur a/src/engine/proxy.h b/src/engine/proxy.h
    a b  
    6565    int m_recvBufferPos;
    6666    int m_recvBufferLen;
    6767
     68    bool m_doAuth;
     69
    6870    void OnSocketEvent(CSocketEvent& event);
    6971    void OnReceive();
    7072    void OnSend();