Fossil

Check-in [c039efde]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Support for tunneling https through http proxy.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | jan-httpsproxytunnel
Files: files | file ages | folders
SHA1:c039efde8375b1c3c76b922ec03d37e02d362aba
User & Date: jan 2013-10-07 13:27:10
Context
2013-10-17
09:07
Make proxy connection 'keep-alive' for https tunnel. check-in: ca82d0c1 user: jan tags: jan-httpsproxytunnel
2013-10-07
13:27
Support for tunneling https through http proxy. check-in: c039efde user: jan tags: jan-httpsproxytunnel
07:41
Better error message in case of "manifest file (12892) is malformed". It will now give an additional line: "line ???: wrong size UUID on P-card" (or whatever other parsing error happens), and using the "-n" option it will print out the complete manifest as well. This would have made it much easier to investigate Ron Aaron's commit problem (many thanks for reporting this!), without adding special debugging code to fossil. check-in: ec81aee9 user: jan.nijtmans tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/http_ssl.c.

171
172
173
174
175
176
177















































178
179
180
181
182
183
184
...
199
200
201
202
203
204
205























206






207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222

223
224
225
226
227
228
229
230

231
232
233
234


235
236
237
238
239
240
241
242
*/
void ssl_close(void){
  if( iBio!=NULL ){
    (void)BIO_reset(iBio);
    BIO_free_all(iBio);
  }
}
















































/*
** Open an SSL connection.  The identify of the server is determined
** by global variables that are set using url_parse():
**
**    g.urlName       Name of the server.  Ex: www.fossil-scm.org
**    g.urlPort       TCP/IP port to use.  Ex: 80
................................................................................
  cert = ssl_get_certificate(&trusted);
  if ( cert!=NULL ){
    X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
    X509_free(cert);
    hasSavedCertificate = 1;
  }
























  iBio = BIO_new_ssl_connect(sslCtx);






  BIO_get_ssl(iBio, &ssl);

#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
  if( !SSL_set_tlsext_host_name(ssl, g.urlName) ){
    fossil_warning("WARNING: failed to set server name indication (SNI), "
                  "continuing without it.\n");
  }
#endif

  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
  if( iBio==NULL ) {
    ssl_set_errmsg("SSL: cannot open SSL (%s)", 
                    ERR_reason_error_string(ERR_get_error()));
    return 1;
  }


  BIO_set_conn_hostname(iBio, g.urlName);
  BIO_set_conn_int_port(iBio, &g.urlPort);
  
  if( BIO_do_connect(iBio)<=0 ){
    ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)", 
        g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
    ssl_close();
    return 1;

  }
  
  if( BIO_do_handshake(iBio)<=0 ) {
    ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)", 


        g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
    ssl_close();
    return 1;
  }
  /* Check if certificate is valid */
  cert = SSL_get_peer_certificate(ssl);

  if ( cert==NULL ){







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>



|






<
<
<
<
|
<
>
|
|
<
|
|
|
|
|
>




>
>
|







171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292




293

294
295
296

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
*/
void ssl_close(void){
  if( iBio!=NULL ){
    (void)BIO_reset(iBio);
    BIO_free_all(iBio);
  }
}

static int establish_proxy_tunnel(BIO *bio){
  int rc, httpVerMin;
  char *connStr, *bbuf;
  Blob reply;
  int done=0,end=0;
  if( !g.urlProxyAuth ){
    connStr = mprintf("CONNECT %s:%d HTTP/1.1\r\n"
          "Host: %s:%d\r\n\r\n", g.urlHostname, g.proxyOrigPort,
          g.urlHostname, g.proxyOrigPort);
  }else{
    connStr = mprintf("CONNECT %s:%d HTTP/1.1\r\n"
          "Host: %s:%d\r\n"
          "Proxy-Authorization: %s\r\n\r\n", g.urlHostname, g.proxyOrigPort,
          g.urlHostname, g.proxyOrigPort, g.urlProxyAuth);
  }
  BIO_write(bio, connStr, strlen(connStr));
  free(connStr);

  /* Wait for end of reply */
  blob_zero(&reply);
  do{
    int len;
    char buf[256];
    len = BIO_read(bio, buf, sizeof(buf));
    blob_append(&reply, buf, len);

    bbuf = blob_buffer(&reply);
    len = blob_size(&reply);
    while(end < len) {
      if(bbuf[end] == '\r') {
        if(len - end < 4) {
          /* need more data */
          break;
        }
        if(memcmp(&bbuf[end], "\r\n\r\n", 4) == 0) {
          done = 1;
          break;
        }
      }
      end++;
    }
  }while(!done);
  sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc);
  blob_reset(&reply);
  return rc;
}

/*
** Open an SSL connection.  The identify of the server is determined
** by global variables that are set using url_parse():
**
**    g.urlName       Name of the server.  Ex: www.fossil-scm.org
**    g.urlPort       TCP/IP port to use.  Ex: 80
................................................................................
  cert = ssl_get_certificate(&trusted);
  if ( cert!=NULL ){
    X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
    X509_free(cert);
    hasSavedCertificate = 1;
  }

  if( g.useProxy ){
    int rc;
    BIO *sBio;
    char *connStr;
    connStr = mprintf("%s:%d", g.urlName, g.urlPort);
    sBio = BIO_new_connect(connStr);
    free(connStr);
    if( BIO_do_connect(sBio)<=0 ){
      ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
            g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
      ssl_close();
      return 1;
    }
    rc = establish_proxy_tunnel(sBio);
    if( rc!= 200 ){
      return 1;
    }

    g.urlPath = g.proxyUrlPath;

    iBio = BIO_new_ssl(sslCtx, 1);
    BIO_push(iBio, sBio);
  }else{
    iBio = BIO_new_ssl_connect(sslCtx);
  }
  if( iBio==NULL ) {
    ssl_set_errmsg("SSL: cannot open SSL (%s)", 
                    ERR_reason_error_string(ERR_get_error()));
    return 1;
  }
  BIO_get_ssl(iBio, &ssl);

#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
  if( !SSL_set_tlsext_host_name(ssl, g.urlHostname) ){
    fossil_warning("WARNING: failed to set server name indication (SNI), "
                  "continuing without it.\n");
  }
#endif

  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);






  if( !g.useProxy ){
    BIO_set_conn_hostname(iBio, g.urlName);
    BIO_set_conn_int_port(iBio, &g.urlPort);

    if( BIO_do_connect(iBio)<=0 ){
      ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)", 
          g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
      ssl_close();
      return 1;
    }
  }
  
  if( BIO_do_handshake(iBio)<=0 ) {
    ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)", 
        g.useProxy?g.urlHostname:g.urlName,
        g.useProxy?g.proxyOrigPort:g.urlPort,
        ERR_reason_error_string(ERR_get_error()));
    ssl_close();
    return 1;
  }
  /* Check if certificate is valid */
  cert = SSL_get_peer_certificate(ssl);

  if ( cert==NULL ){

Changes to src/main.c.

175
176
177
178
179
180
181



182
183
184
185
186
187
188
  char *urlProtocol;      /* "http" or "https" */
  int urlPort;            /* TCP port number for http: or https: */
  int urlDfltPort;        /* The default port for the given protocol */
  char *urlPath;          /* Pathname for http: */
  char *urlUser;          /* User id for http: */
  char *urlPasswd;        /* Password for http: */
  char *urlCanonical;     /* Canonical representation of the URL */



  char *urlProxyAuth;     /* Proxy-Authorizer: string */
  char *urlFossil;        /* The fossil query parameter on ssh: */
  char *urlShell;         /* The shell query parameter on ssh: */
  unsigned urlFlags;      /* Boolean flags controlling URL processing */

  const char *zLogin;     /* Login name.  "" if not logged in. */
  const char *zSSLIdentity;  /* Value of --ssl-identity option, filename of







>
>
>







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  char *urlProtocol;      /* "http" or "https" */
  int urlPort;            /* TCP port number for http: or https: */
  int urlDfltPort;        /* The default port for the given protocol */
  char *urlPath;          /* Pathname for http: */
  char *urlUser;          /* User id for http: */
  char *urlPasswd;        /* Password for http: */
  char *urlCanonical;     /* Canonical representation of the URL */
  int useProxy;           /* Used to remember that a proxy is in use */
  char *proxyUrlPath;
  int proxyOrigPort;      /* Tunneled port number for https through proxy */
  char *urlProxyAuth;     /* Proxy-Authorizer: string */
  char *urlFossil;        /* The fossil query parameter on ssh: */
  char *urlShell;         /* The shell query parameter on ssh: */
  unsigned urlFlags;      /* Boolean flags controlling URL processing */

  const char *zLogin;     /* Login name.  "" if not logged in. */
  const char *zSSLIdentity;  /* Value of --ssl-identity option, filename of

Changes to src/url.c.

88
89
90
91
92
93
94

95
96
97
98
99
100
101
...
326
327
328
329
330
331
332

333
334
335


336
337
338
339
340
341
342
...
344
345
346
347
348
349
350




351
352
353
354
355
356
357
  ){
    int iStart;
    char *zLogin;
    char *zExe;
    char cQuerySep = '?';

    g.urlIsFile = 0;

    if( zUrl[4]=='s' ){
      g.urlIsHttps = 1;
      g.urlProtocol = "https";
      g.urlDfltPort = 443;
      iStart = 8;
    }else if( zUrl[0]=='s' ){
      g.urlIsSsh = 1;
................................................................................
    if( zProxy==0 || zProxy[0]==0 || is_truth(zProxy) ){
      zProxy = fossil_getenv("http_proxy");
    }
  }
  if( zProxy && zProxy[0] && !is_false(zProxy)
      && !g.urlIsSsh && !g.urlIsFile ){
    char *zOriginalUrl = g.urlCanonical;

    char *zOriginalHost = g.urlHostname;
    char *zOriginalUser = g.urlUser;
    char *zOriginalPasswd = g.urlPasswd;


    unsigned uOriginalFlags = g.urlFlags;
    g.urlUser = 0;
    g.urlPasswd = "";
    url_parse(zProxy, 0);
    if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical);
    g.urlPath = zOriginalUrl;
    g.urlHostname = zOriginalHost;
................................................................................
      char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd);
      char *zCredentials2 = encode64(zCredentials1, -1);
      g.urlProxyAuth = mprintf("Basic %z", zCredentials2);
      free(zCredentials1);
    }
    g.urlUser = zOriginalUser;
    g.urlPasswd = zOriginalPasswd;




    g.urlFlags = uOriginalFlags;
  }
}

#if INTERFACE
/*
** An instance of this object is used to build a URL with query parameters.







>







 







>



>
>







 







>
>
>
>







88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
...
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  ){
    int iStart;
    char *zLogin;
    char *zExe;
    char cQuerySep = '?';

    g.urlIsFile = 0;
    g.useProxy = 0;
    if( zUrl[4]=='s' ){
      g.urlIsHttps = 1;
      g.urlProtocol = "https";
      g.urlDfltPort = 443;
      iStart = 8;
    }else if( zUrl[0]=='s' ){
      g.urlIsSsh = 1;
................................................................................
    if( zProxy==0 || zProxy[0]==0 || is_truth(zProxy) ){
      zProxy = fossil_getenv("http_proxy");
    }
  }
  if( zProxy && zProxy[0] && !is_false(zProxy)
      && !g.urlIsSsh && !g.urlIsFile ){
    char *zOriginalUrl = g.urlCanonical;
    int fOriginalIsHttps = g.urlIsHttps;
    char *zOriginalHost = g.urlHostname;
    char *zOriginalUser = g.urlUser;
    char *zOriginalPasswd = g.urlPasswd;
    char *zOriginalUrlPath = g.urlPath;
    int iOriginalPort = g.urlPort;
    unsigned uOriginalFlags = g.urlFlags;
    g.urlUser = 0;
    g.urlPasswd = "";
    url_parse(zProxy, 0);
    if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical);
    g.urlPath = zOriginalUrl;
    g.urlHostname = zOriginalHost;
................................................................................
      char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd);
      char *zCredentials2 = encode64(zCredentials1, -1);
      g.urlProxyAuth = mprintf("Basic %z", zCredentials2);
      free(zCredentials1);
    }
    g.urlUser = zOriginalUser;
    g.urlPasswd = zOriginalPasswd;
    g.urlIsHttps = fOriginalIsHttps;
    g.useProxy = 1;
    g.proxyUrlPath = zOriginalUrlPath;
    g.proxyOrigPort = iOriginalPort;
    g.urlFlags = uOriginalFlags;
  }
}

#if INTERFACE
/*
** An instance of this object is used to build a URL with query parameters.