| | @@ -16,12 +16,15 @@ |
| 16 | 16 | ******************************************************************************* |
| 17 | 17 | ** |
| 18 | 18 | ** This file manages low-level SSL communications. |
| 19 | 19 | ** |
| 20 | 20 | ** This file implements a singleton. A single SSL connection may be active |
| 21 | | -** at a time. State information is stored in static variables. The identity |
| 22 | | -** of the server is held in global variables that are set by url_parse(). |
| 21 | +** at a time. State information is stored in static variables. |
| 22 | +** |
| 23 | +** The SSL connections can be either a client or a server. But all |
| 24 | +** connections for a single process must be of the same type, either client |
| 25 | +** or server. |
| 23 | 26 | ** |
| 24 | 27 | ** SSL support is abstracted out into this module because Fossil can |
| 25 | 28 | ** be compiled without SSL support (which requires OpenSSL library) |
| 26 | 29 | */ |
| 27 | 30 | |
| | @@ -41,11 +44,11 @@ |
| 41 | 44 | /* |
| 42 | 45 | ** There can only be a single OpenSSL IO connection open at a time. |
| 43 | 46 | ** State information about that IO is stored in the following |
| 44 | 47 | ** local variables: |
| 45 | 48 | */ |
| 46 | | -static int sslIsInit = 0; /* True after global initialization */ |
| 49 | +static int sslIsInit = 0; /* 0: uninit 1: init as client 2: init as server */ |
| 47 | 50 | static BIO *iBio = 0; /* OpenSSL I/O abstraction */ |
| 48 | 51 | static char *sslErrMsg = 0; /* Text of most recent OpenSSL error */ |
| 49 | 52 | static SSL_CTX *sslCtx; /* SSL context */ |
| 50 | 53 | static SSL *ssl; |
| 51 | 54 | static struct { /* Accept this SSL cert for this session only */ |
| | @@ -134,11 +137,11 @@ |
| 134 | 137 | |
| 135 | 138 | /* |
| 136 | 139 | ** Call this routine once before any other use of the SSL interface. |
| 137 | 140 | ** This routine does initial configuration of the SSL module. |
| 138 | 141 | */ |
| 139 | | -void ssl_global_init(void){ |
| 142 | +static void ssl_global_init_client(void){ |
| 140 | 143 | const char *zCaSetting = 0, *zCaFile = 0, *zCaDirectory = 0; |
| 141 | 144 | const char *identityFile; |
| 142 | 145 | |
| 143 | 146 | if( sslIsInit==0 ){ |
| 144 | 147 | SSL_library_init(); |
| | @@ -193,10 +196,12 @@ |
| 193 | 196 | /* Register a callback to tell the user what to do when the server asks |
| 194 | 197 | ** for a cert */ |
| 195 | 198 | SSL_CTX_set_client_cert_cb(sslCtx, ssl_client_cert_callback); |
| 196 | 199 | |
| 197 | 200 | sslIsInit = 1; |
| 201 | + }else{ |
| 202 | + assert( sslIsInit==1 ); |
| 198 | 203 | } |
| 199 | 204 | } |
| 200 | 205 | |
| 201 | 206 | /* |
| 202 | 207 | ** Call this routine to shutdown the SSL module prior to program exit. |
| | @@ -208,14 +213,14 @@ |
| 208 | 213 | sslIsInit = 0; |
| 209 | 214 | } |
| 210 | 215 | } |
| 211 | 216 | |
| 212 | 217 | /* |
| 213 | | -** Close the currently open SSL connection. If no connection is open, |
| 218 | +** Close the currently open client SSL connection. If no connection is open, |
| 214 | 219 | ** this routine is a no-op. |
| 215 | 220 | */ |
| 216 | | -void ssl_close(void){ |
| 221 | +void ssl_close_client(void){ |
| 217 | 222 | if( iBio!=NULL ){ |
| 218 | 223 | (void)BIO_reset(iBio); |
| 219 | 224 | BIO_free_all(iBio); |
| 220 | 225 | iBio = NULL; |
| 221 | 226 | } |
| | @@ -280,34 +285,36 @@ |
| 280 | 285 | void ssl_disable_cert_verification(void){ |
| 281 | 286 | sslNoCertVerify = 1; |
| 282 | 287 | } |
| 283 | 288 | |
| 284 | 289 | /* |
| 285 | | -** Open an SSL connection. The identify of the server is determined |
| 286 | | -** as follows: |
| 290 | +** Open an SSL connection as a client that is to connect to the server |
| 291 | +** identified by pUrlData. |
| 292 | +** |
| 293 | +* The identify of the server is determined as follows: |
| 287 | 294 | ** |
| 288 | 295 | ** pUrlData->name Name of the server. Ex: fossil-scm.org |
| 289 | 296 | ** g.url.name Name of the proxy server, if proxying. |
| 290 | 297 | ** pUrlData->port TCP/IP port to use. Ex: 80 |
| 291 | 298 | ** |
| 292 | 299 | ** Return the number of errors. |
| 293 | 300 | */ |
| 294 | | -int ssl_open(UrlData *pUrlData){ |
| 301 | +int ssl_open_client(UrlData *pUrlData){ |
| 295 | 302 | X509 *cert; |
| 296 | 303 | const char *zRemoteHost; |
| 297 | 304 | |
| 298 | | - ssl_global_init(); |
| 305 | + ssl_global_init_client(); |
| 299 | 306 | if( pUrlData->useProxy ){ |
| 300 | 307 | int rc; |
| 301 | 308 | char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port); |
| 302 | 309 | BIO *sBio = BIO_new_connect(connStr); |
| 303 | 310 | free(connStr); |
| 304 | 311 | if( BIO_do_connect(sBio)<=0 ){ |
| 305 | 312 | ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)", |
| 306 | 313 | pUrlData->name, pUrlData->port, |
| 307 | 314 | ERR_reason_error_string(ERR_get_error())); |
| 308 | | - ssl_close(); |
| 315 | + ssl_close_client(); |
| 309 | 316 | return 1; |
| 310 | 317 | } |
| 311 | 318 | rc = establish_proxy_tunnel(pUrlData, sBio); |
| 312 | 319 | if( rc<200||rc>299 ){ |
| 313 | 320 | ssl_set_errmsg("SSL: proxy connect failed with HTTP status code %d", rc); |
| | @@ -355,29 +362,29 @@ |
| 355 | 362 | free(connStr); |
| 356 | 363 | if( BIO_do_connect(iBio)<=0 ){ |
| 357 | 364 | ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)", |
| 358 | 365 | pUrlData->name, pUrlData->port, |
| 359 | 366 | ERR_reason_error_string(ERR_get_error())); |
| 360 | | - ssl_close(); |
| 367 | + ssl_close_client(); |
| 361 | 368 | return 1; |
| 362 | 369 | } |
| 363 | 370 | } |
| 364 | 371 | |
| 365 | 372 | if( BIO_do_handshake(iBio)<=0 ) { |
| 366 | 373 | ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)", |
| 367 | 374 | pUrlData->useProxy?pUrlData->hostname:pUrlData->name, |
| 368 | 375 | pUrlData->useProxy?pUrlData->proxyOrigPort:pUrlData->port, |
| 369 | 376 | ERR_reason_error_string(ERR_get_error())); |
| 370 | | - ssl_close(); |
| 377 | + ssl_close_client(); |
| 371 | 378 | return 1; |
| 372 | 379 | } |
| 373 | 380 | /* Check if certificate is valid */ |
| 374 | 381 | cert = SSL_get_peer_certificate(ssl); |
| 375 | 382 | |
| 376 | 383 | if ( cert==NULL ){ |
| 377 | 384 | ssl_set_errmsg("No SSL certificate was presented by the peer"); |
| 378 | | - ssl_close(); |
| 385 | + ssl_close_client(); |
| 379 | 386 | return 1; |
| 380 | 387 | } |
| 381 | 388 | |
| 382 | 389 | /* Debugging hint: On unix-like system, run something like: |
| 383 | 390 | ** |
| | @@ -441,11 +448,11 @@ |
| 441 | 448 | if( cReply!='y' && cReply!='Y' |
| 442 | 449 | && fossil_stricmp(blob_str(&ans),zHash)!=0 |
| 443 | 450 | ){ |
| 444 | 451 | X509_free(cert); |
| 445 | 452 | ssl_set_errmsg("SSL cert declined"); |
| 446 | | - ssl_close(); |
| 453 | + ssl_close_client(); |
| 447 | 454 | blob_reset(&ans); |
| 448 | 455 | return 1; |
| 449 | 456 | } |
| 450 | 457 | blob_reset(&ans); |
| 451 | 458 | ssl_one_time_exception(pUrlData, zHash); |
| | @@ -528,11 +535,12 @@ |
| 528 | 535 | fossil_free(sException.zHash); |
| 529 | 536 | sException.zHash = fossil_strdup(zHash); |
| 530 | 537 | } |
| 531 | 538 | |
| 532 | 539 | /* |
| 533 | | -** Send content out over the SSL connection. |
| 540 | +** Send content out over the SSL connection from the client to |
| 541 | +** the server. |
| 534 | 542 | */ |
| 535 | 543 | size_t ssl_send(void *NotUsed, void *pContent, size_t N){ |
| 536 | 544 | size_t total = 0; |
| 537 | 545 | while( N>0 ){ |
| 538 | 546 | int sent = BIO_write(iBio, pContent, N); |
| | @@ -548,11 +556,12 @@ |
| 548 | 556 | } |
| 549 | 557 | return total; |
| 550 | 558 | } |
| 551 | 559 | |
| 552 | 560 | /* |
| 553 | | -** Receive content back from the SSL connection. |
| 561 | +** Receive content back from the client SSL connection. In other |
| 562 | +** words read the reply back from the server. |
| 554 | 563 | */ |
| 555 | 564 | size_t ssl_receive(void *NotUsed, void *pContent, size_t N){ |
| 556 | 565 | size_t total = 0; |
| 557 | 566 | while( N>0 ){ |
| 558 | 567 | int got = BIO_read(iBio, pContent, N); |
| | @@ -566,10 +575,143 @@ |
| 566 | 575 | N -= got; |
| 567 | 576 | pContent = (void*)&((char*)pContent)[got]; |
| 568 | 577 | } |
| 569 | 578 | return total; |
| 570 | 579 | } |
| 580 | + |
| 581 | +/* |
| 582 | +** Initialize the SSL library so that it is able to handle |
| 583 | +** server-side connections. Invoke fossil_fatal() if there are |
| 584 | +** any problems. |
| 585 | +** |
| 586 | +** zKeyFile may be NULL, in which case zCertFile will contain both |
| 587 | +** the private key and the cert. |
| 588 | +*/ |
| 589 | +void ssl_init_server(const char *zCertFile, const char *zKeyFile){ |
| 590 | + if( sslIsInit==0 ){ |
| 591 | + SSL_library_init(); |
| 592 | + SSL_load_error_strings(); |
| 593 | + OpenSSL_add_all_algorithms(); |
| 594 | + sslCtx = SSL_CTX_new(SSLv23_server_method()); |
| 595 | + if( sslCtx==0 ){ |
| 596 | + ERR_print_errors_fp(stderr); |
| 597 | + fossil_fatal("Error initializing the SSL server"); |
| 598 | + } |
| 599 | + if( SSL_CTX_use_certificate_file(sslCtx, zCertFile, SSL_FILETYPE_PEM)<=0 ){ |
| 600 | + ERR_print_errors_fp(stderr); |
| 601 | + fossil_fatal("Error loading CERT file \"%s\"", zCertFile); |
| 602 | + } |
| 603 | + if( zKeyFile==0 ) zKeyFile = zCertFile; |
| 604 | + if( SSL_CTX_use_PrivateKey_file(sslCtx, zKeyFile, SSL_FILETYPE_PEM)<=0 ){ |
| 605 | + ERR_print_errors_fp(stderr); |
| 606 | + fossil_fatal("Error loading PRIVATE KEY from file \"%s\"", zKeyFile); |
| 607 | + } |
| 608 | + if( !SSL_CTX_check_private_key(sslCtx) ){ |
| 609 | + fossil_fatal("PRIVATE KEY \"%s\" does not match CERT \"%s\"", |
| 610 | + zKeyFile, zCertFile); |
| 611 | + } |
| 612 | + sslIsInit = 2; |
| 613 | + }else{ |
| 614 | + assert( sslIsInit==2 ); |
| 615 | + } |
| 616 | +} |
| 617 | + |
| 618 | +typedef struct SslServerConn { |
| 619 | + SSL *ssl; /* The SSL codec */ |
| 620 | + int atEof; /* True when EOF reached. */ |
| 621 | + int fd0; /* Read channel, or socket */ |
| 622 | + int fd1; /* Write channel */ |
| 623 | +} SslServerConn; |
| 624 | + |
| 625 | +/* |
| 626 | +** Create a new server-side codec. The arguments are the file |
| 627 | +** descriptors from which teh codec reads and writes, respectively. |
| 628 | +** |
| 629 | +** If the writeFd is negative, then use then the readFd is a socket |
| 630 | +** over which we both read and write. |
| 631 | +*/ |
| 632 | +void *ssl_new_server(int readFd, int writeFd){ |
| 633 | + SslServerConn *pServer = fossil_malloc_zero(sizeof(*pServer)); |
| 634 | + pServer->ssl = SSL_new(sslCtx); |
| 635 | + pServer->fd0 = readFd; |
| 636 | + pServer->fd1 = writeFd; |
| 637 | + if( writeFd<0 ){ |
| 638 | + SSL_set_fd(pServer->ssl, readFd); |
| 639 | + }else{ |
| 640 | + SSL_set_rfd(pServer->ssl, readFd); |
| 641 | + SSL_set_wfd(pServer->ssl, writeFd); |
| 642 | + } |
| 643 | + return (void*)pServer; |
| 644 | +} |
| 645 | + |
| 646 | +/* |
| 647 | +** Close a server-side code previously returned from ssl_new_server(). |
| 648 | +*/ |
| 649 | +void ssl_close_server(void *pServerArg){ |
| 650 | + SslServerConn *pServer = (SslServerConn*)pServerArg; |
| 651 | + SSL_free(pServer->ssl); |
| 652 | + close(pServer->fd0); |
| 653 | + if( pServer->fd1>=0 ) close(pServer->fd0); |
| 654 | + fossil_free(pServer); |
| 655 | +} |
| 656 | + |
| 657 | +/* |
| 658 | +** Return TRUE if there are no more bytes available to be read from |
| 659 | +** the client. |
| 660 | +*/ |
| 661 | +int ssl_eof(void *pServerArg){ |
| 662 | + SslServerConn *pServer = (SslServerConn*)pServerArg; |
| 663 | + return pServer->atEof; |
| 664 | +} |
| 665 | + |
| 666 | +/* |
| 667 | +** Read cleartext bytes that have been received from the client and |
| 668 | +** decrypted by the SSL server codec. |
| 669 | +*/ |
| 670 | +size_t ssl_read_server(void *pServerArg, char *zBuf, size_t nBuf){ |
| 671 | + int n; |
| 672 | + SslServerConn *pServer = (SslServerConn*)pServerArg; |
| 673 | + if( pServer->atEof ) return 0; |
| 674 | + if( nBuf>0x7fffffff ){ fossil_fatal("SSL read too big"); } |
| 675 | + n = SSL_read(pServer->ssl, zBuf, (int)nBuf); |
| 676 | + if( n<nBuf ) pServer->atEof = 1; |
| 677 | + return n; |
| 678 | +} |
| 679 | + |
| 680 | +/* |
| 681 | +** Read a single line of text from the client. |
| 682 | +*/ |
| 683 | +char *ssl_gets(void *pServerArg, char *zBuf, int nBuf){ |
| 684 | + int n = 0; |
| 685 | + int i; |
| 686 | + SslServerConn *pServer = (SslServerConn*)pServerArg; |
| 687 | + |
| 688 | + if( pServer->atEof ) return 0; |
| 689 | + n = SSL_peek(pServer->ssl, zBuf, nBuf-1); |
| 690 | + if( n==0 ){ |
| 691 | + pServer->atEof = 1; |
| 692 | + return 0; |
| 693 | + } |
| 694 | + for(i=0; i<n && zBuf[i]!='\n'; i++){} |
| 695 | + SSL_read(pServer->ssl, zBuf, i); |
| 696 | + zBuf[i+1] = 0; |
| 697 | + return zBuf; |
| 698 | +} |
| 699 | + |
| 700 | + |
| 701 | +/* |
| 702 | +** Write cleartext bytes into the SSL server codec so that they can |
| 703 | +** be encrypted and sent back to the client. |
| 704 | +*/ |
| 705 | +size_t ssl_write_server(void *pServerArg, char *zBuf, size_t nBuf){ |
| 706 | + int n; |
| 707 | + SslServerConn *pServer = (SslServerConn*)pServerArg; |
| 708 | + if( pServer->atEof ) return 0; |
| 709 | + if( nBuf>0x7fffffff ){ fossil_fatal("SSL write too big"); } |
| 710 | + n = SSL_write(pServer->ssl, zBuf, (int)nBuf); |
| 711 | + return n; |
| 712 | +} |
| 571 | 713 | |
| 572 | 714 | #endif /* FOSSIL_ENABLE_SSL */ |
| 573 | 715 | |
| 574 | 716 | /* |
| 575 | 717 | ** COMMAND: tls-config* |
| 576 | 718 | |