| | @@ -173,10 +173,58 @@ |
| 173 | 173 | if( iBio!=NULL ){ |
| 174 | 174 | (void)BIO_reset(iBio); |
| 175 | 175 | BIO_free_all(iBio); |
| 176 | 176 | } |
| 177 | 177 | } |
| 178 | + |
| 179 | +/* See RFC2817 for details */ |
| 180 | +static int establish_proxy_tunnel(UrlData *pUrlData, BIO *bio){ |
| 181 | + int rc, httpVerMin; |
| 182 | + char *bbuf; |
| 183 | + Blob snd, reply; |
| 184 | + int done=0,end=0; |
| 185 | + blob_zero(&snd); |
| 186 | + blob_appendf(&snd, "CONNECT %s:%d HTTP/1.1\r\n", pUrlData->hostname, |
| 187 | + pUrlData->proxyOrigPort); |
| 188 | + blob_appendf(&snd, "Host: %s:%d\r\n", pUrlData->hostname, pUrlData->proxyOrigPort); |
| 189 | + if( pUrlData->proxyAuth ){ |
| 190 | + blob_appendf(&snd, "Proxy-Authorization: %s\r\n", pUrlData->proxyAuth); |
| 191 | + } |
| 192 | + blob_append(&snd, "Proxy-Connection: keep-alive\r\n", -1); |
| 193 | + blob_append(&snd, "User-Agent: Fossil/" RELEASE_VERSION "\r\n", -1); |
| 194 | + blob_append(&snd, "\r\n", 2); |
| 195 | + BIO_write(bio, blob_buffer(&snd), blob_size(&snd)); |
| 196 | + blob_reset(&snd); |
| 197 | + |
| 198 | + /* Wait for end of reply */ |
| 199 | + blob_zero(&reply); |
| 200 | + do{ |
| 201 | + int len; |
| 202 | + char buf[256]; |
| 203 | + len = BIO_read(bio, buf, sizeof(buf)); |
| 204 | + blob_append(&reply, buf, len); |
| 205 | + |
| 206 | + bbuf = blob_buffer(&reply); |
| 207 | + len = blob_size(&reply); |
| 208 | + while(end < len) { |
| 209 | + if(bbuf[end] == '\r') { |
| 210 | + if(len - end < 4) { |
| 211 | + /* need more data */ |
| 212 | + break; |
| 213 | + } |
| 214 | + if(memcmp(&bbuf[end], "\r\n\r\n", 4) == 0) { |
| 215 | + done = 1; |
| 216 | + break; |
| 217 | + } |
| 218 | + } |
| 219 | + end++; |
| 220 | + } |
| 221 | + }while(!done); |
| 222 | + sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc); |
| 223 | + blob_reset(&reply); |
| 224 | + return rc; |
| 225 | +} |
| 178 | 226 | |
| 179 | 227 | /* |
| 180 | 228 | ** Open an SSL connection. The identify of the server is determined |
| 181 | 229 | ** by variables that are set using url_parse(): |
| 182 | 230 | ** |
| | @@ -201,41 +249,67 @@ |
| 201 | 249 | X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert); |
| 202 | 250 | X509_free(cert); |
| 203 | 251 | hasSavedCertificate = 1; |
| 204 | 252 | } |
| 205 | 253 | |
| 206 | | - iBio = BIO_new_ssl_connect(sslCtx); |
| 254 | + if( pUrlData->useProxy ){ |
| 255 | + int rc; |
| 256 | + BIO *sBio; |
| 257 | + char *connStr; |
| 258 | + connStr = mprintf("%s:%d", g.urlName, pUrlData->port); |
| 259 | + sBio = BIO_new_connect(connStr); |
| 260 | + free(connStr); |
| 261 | + if( BIO_do_connect(sBio)<=0 ){ |
| 262 | + ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)", |
| 263 | + pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error())); |
| 264 | + ssl_close(); |
| 265 | + return 1; |
| 266 | + } |
| 267 | + rc = establish_proxy_tunnel(pUrlData, sBio); |
| 268 | + if( rc<200||rc>299 ){ |
| 269 | + ssl_set_errmsg("SSL: proxy connect failed with HTTP status code %d", rc); |
| 270 | + return 1; |
| 271 | + } |
| 272 | + |
| 273 | + pUrlData->path = pUrlData->proxyUrlPath; |
| 274 | + |
| 275 | + iBio = BIO_new_ssl(sslCtx, 1); |
| 276 | + BIO_push(iBio, sBio); |
| 277 | + }else{ |
| 278 | + iBio = BIO_new_ssl_connect(sslCtx); |
| 279 | + } |
| 280 | + if( iBio==NULL ) { |
| 281 | + ssl_set_errmsg("SSL: cannot open SSL (%s)", |
| 282 | + ERR_reason_error_string(ERR_get_error())); |
| 283 | + return 1; |
| 284 | + } |
| 207 | 285 | BIO_get_ssl(iBio, &ssl); |
| 208 | 286 | |
| 209 | 287 | #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT) |
| 210 | | - if( !SSL_set_tlsext_host_name(ssl, pUrlData->name) ){ |
| 288 | + if( !SSL_set_tlsext_host_name(ssl, pUrlData->useProxy?pUrlData->hostname:pUrlData->name) ){ |
| 211 | 289 | fossil_warning("WARNING: failed to set server name indication (SNI), " |
| 212 | 290 | "continuing without it.\n"); |
| 213 | 291 | } |
| 214 | 292 | #endif |
| 215 | 293 | |
| 216 | 294 | SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); |
| 217 | | - if( iBio==NULL ) { |
| 218 | | - ssl_set_errmsg("SSL: cannot open SSL (%s)", |
| 219 | | - ERR_reason_error_string(ERR_get_error())); |
| 220 | | - return 1; |
| 221 | | - } |
| 222 | | - |
| 223 | | - BIO_set_conn_hostname(iBio, pUrlData->name); |
| 224 | | - BIO_set_conn_int_port(iBio, &pUrlData->port); |
| 225 | | - |
| 226 | | - if( BIO_do_connect(iBio)<=0 ){ |
| 227 | | - ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)", |
| 228 | | - pUrlData->name, pUrlData->port, |
| 229 | | - ERR_reason_error_string(ERR_get_error())); |
| 230 | | - ssl_close(); |
| 231 | | - return 1; |
| 295 | + |
| 296 | + if( !pUrlData->useProxy ){ |
| 297 | + BIO_set_conn_hostname(iBio, pUrlData->name); |
| 298 | + BIO_set_conn_int_port(iBio, &pUrlData->port); |
| 299 | + if( BIO_do_connect(iBio)<=0 ){ |
| 300 | + ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)", |
| 301 | + pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error())); |
| 302 | + ssl_close(); |
| 303 | + return 1; |
| 304 | + } |
| 232 | 305 | } |
| 233 | 306 | |
| 234 | 307 | if( BIO_do_handshake(iBio)<=0 ) { |
| 235 | 308 | ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)", |
| 236 | | - pUrlData->name, pUrlData->port, |
| 309 | + pUrlData->useProxy?pUrlData->hostname:pUrlData->name, |
| 310 | + pUrlData->useProxy?pUrlData->proxyOrigPort:pUrlData->port, |
| 237 | 311 | ERR_reason_error_string(ERR_get_error())); |
| 238 | 312 | ssl_close(); |
| 239 | 313 | return 1; |
| 240 | 314 | } |
| 241 | 315 | /* Check if certificate is valid */ |
| | @@ -283,11 +357,11 @@ |
| 283 | 357 | " certificates list\n\n" |
| 284 | 358 | "If you are not expecting this message, answer no and " |
| 285 | 359 | "contact your server\nadministrator.\n\n" |
| 286 | 360 | "Accept certificate for host %s (a=always/y/N)? ", |
| 287 | 361 | X509_verify_cert_error_string(e), desc, warning, |
| 288 | | - pUrlData->name); |
| 362 | + pUrlData->useProxy?pUrlData->hostname:pUrlData->name); |
| 289 | 363 | BIO_free(mem); |
| 290 | 364 | |
| 291 | 365 | prompt_user(prompt, &ans); |
| 292 | 366 | free(prompt); |
| 293 | 367 | cReply = blob_str(&ans)[0]; |
| | @@ -333,14 +407,14 @@ |
| 333 | 407 | |
| 334 | 408 | mem = BIO_new(BIO_s_mem()); |
| 335 | 409 | PEM_write_bio_X509(mem, cert); |
| 336 | 410 | BIO_write(mem, "", 1); /* nul-terminate mem buffer */ |
| 337 | 411 | BIO_get_mem_data(mem, &zCert); |
| 338 | | - zHost = mprintf("cert:%s", pUrlData->name); |
| 412 | + zHost = mprintf("cert:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name); |
| 339 | 413 | db_set(zHost, zCert, 1); |
| 340 | 414 | free(zHost); |
| 341 | | - zHost = mprintf("trusted:%s", pUrlData->name); |
| 415 | + zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name); |
| 342 | 416 | db_set_int(zHost, trusted, 1); |
| 343 | 417 | free(zHost); |
| 344 | 418 | BIO_free(mem); |
| 345 | 419 | } |
| 346 | 420 | |
| | @@ -351,18 +425,18 @@ |
| 351 | 425 | X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){ |
| 352 | 426 | char *zHost, *zCert; |
| 353 | 427 | BIO *mem; |
| 354 | 428 | X509 *cert; |
| 355 | 429 | |
| 356 | | - zHost = mprintf("cert:%s", pUrlData->name); |
| 430 | + zHost = mprintf("cert:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name); |
| 357 | 431 | zCert = db_get(zHost, NULL); |
| 358 | 432 | free(zHost); |
| 359 | 433 | if ( zCert==NULL ) |
| 360 | 434 | return NULL; |
| 361 | 435 | |
| 362 | 436 | if ( pTrusted!=0 ){ |
| 363 | | - zHost = mprintf("trusted:%s", pUrlData->name); |
| 437 | + zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name); |
| 364 | 438 | *pTrusted = db_get_int(zHost, 0); |
| 365 | 439 | free(zHost); |
| 366 | 440 | } |
| 367 | 441 | |
| 368 | 442 | mem = BIO_new(BIO_s_mem()); |
| 369 | 443 | |