tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

client.cgi (15192B)


      1 #!/usr/bin/perl
      2 
      3 # This Source Code Form is subject to the terms of the Mozilla Public
      4 # License, v. 2.0. If a copy of the MPL was not distributed with this
      5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      6 
      7 #--------------------------------------------------------------
      8 # cgi script that parses request argument to appropriate 
      9 # open ssl or tstclntw options and starts ssl client.
     10 #
     11 
     12 use CGI qw/:standard/;
     13 
     14 use subs qw(debug);
     15 
     16 #--------------------------------------------------------------
     17 # Prints out an error string and exits the script with an
     18 # exitStatus.
     19 # Param:
     20 #    str : an error string
     21 #    exitStat: an exit status of the program
     22 #
     23 sub svr_error {
     24     my ($str, $exitStat) = @_;
     25 
     26     if (!defined $str || $str eq "") {
     27         $str = $ERR;
     28     }
     29     print "SERVER ERROR: $str\n";
     30     if ($exitStat) {
     31         print end_html if ($osDataArr{wservRun});
     32         exit $exitStat;
     33     }
     34 }
     35 
     36 #--------------------------------------------------------------
     37 # Prints out a debug message
     38 # Params:
     39 #     str: debug message
     40 #     inVal: additional value to print(optional)
     41 #
     42 sub debug {
     43     my ($str, $inVal) = @_;
     44     
     45     print "-- DEBUG: $str ($inVal)\n" if ($DEBUG == 1);
     46 }
     47 
     48 
     49 #--------------------------------------------------------------
     50 # Initializes execution context depending on a webserver the
     51 # script is running under.
     52 #
     53 sub init {
     54     %osDataArr = (
     55                   loadSupportedCipthersFn => \&osSpecific,
     56                   cipherIsSupportedFn => \&verifyCipherSupport,
     57                   cipherListFn => \&convertCipher,
     58                   buildCipherTableFn => \&buildCipherTable,
     59                   execCmdFn => \&osSpecific,
     60                   );
     61 
     62     $scriptName = $ENV{'SCRIPT_NAME'};
     63     if (!defined $scriptName) {
     64         $DEBUG=1;
     65         debug "Debug is ON";
     66     }
     67     $DEBUG=1;
     68     
     69     $svrSoft = $ENV{'SERVER_SOFTWARE'};
     70     if (defined $svrSoft) {
     71         $_ = $svrSoft;
     72         /.*Microsoft.*/ && ($osDataArr{wserv} = "IIS");
     73         /.*Apache.*/ && ($osDataArr{wserv} = "Apache");
     74         $osDataArr{wservRun} = 1;
     75     } else {
     76         $osDataArr{wserv} = "Apache";
     77         $osDataArr{wservRun} = 0;
     78     }
     79 }
     80 
     81 #--------------------------------------------------------------
     82 # Function-spigot to handle errors is OS specific functions are
     83 # not implemented for a particular OS.
     84 # Returns:
     85 #   always returns 0(failure)
     86 #
     87 sub osSpecific {
     88     $ERR = "This function should be swapped to os specific function.";
     89     return 0;
     90 }
     91 
     92 #--------------------------------------------------------------
     93 # Sets os specific execution context values.
     94 # Returns:
     95 #    1 upon success, or 0 upon failure(if OS was not recognized)
     96 #
     97 sub setFunctRefs {
     98     
     99     debug("Entering setFunctRefs function", $osDataArr{wserv});
    100 
    101     if ($osDataArr{wserv} eq "Apache") {
    102         $osDataArr{osConfigFile} = "apache_unix.cfg";
    103         $osDataArr{suppCiphersCmd} = '$opensslb ciphers ALL:NULL';
    104         $osDataArr{clientRunCmd} = '$opensslb s_client -host $in_host -port $in_port -cert $certDir/$in_cert.crt -key $certDir/$in_cert.key -CAfile $caCertFile $proto $ciphers -ign_eof < $reqFile';
    105         $osDataArr{loadSupportedCipthersFn} = \&getSupportedCipherList_Unix;
    106         $osDataArr{execCmdFn} = \&execClientCmd_Unix;
    107     } elsif ($osDataArr{wserv} eq "IIS") {
    108         $osDataArr{osConfigFile} = "iis_windows.cfg";
    109         $osDataArr{suppCiphersCmd} = '$tstclntwb';
    110         $osDataArr{clientRunCmd} = '$tstclntwb -h $in_host -p $in_port -n $in_cert $proto $ciphers < $reqFile';
    111         $osDataArr{loadSupportedCipthersFn} = \&getSupportedCipherList_Win;
    112         $osDataArr{execCmdFn} = \&execClientCmd_Win;
    113     } else {
    114         $ERR = "Unknown Web Server  type.";
    115         return 0;
    116     }
    117     return 1;
    118 }
    119 
    120 #--------------------------------------------------------------
    121 # Parses data from HTTP request. Will print a form if request
    122 # does not contain sufficient number of parameters.
    123 # Returns: 
    124 #     1 if request has sufficient number of parameters
    125 #     0 if not.
    126 sub getReqData {
    127     my $debug = param('debug');
    128     $in_host = param('host');
    129     $in_port = param('port');
    130     $in_cert = param('cert');
    131     $in_cipher = param('cipher');
    132 
    133     if (!$osDataArr{wservRun}) {
    134         $in_host="goa1";
    135         $in_port="443";
    136         $in_cert="TestUser511";
    137         $in_cipher = "SSL3_RSA_WITH_NULL_SHA";
    138     }
    139 
    140     debug("Entering getReqData function", "$in_port:$in_host:$in_cert:$in_cipher");
    141 
    142     if (defined $debug && $debug == "debug on") {
    143         $DEBUG = 1;
    144     }
    145 
    146     if (!defined $in_host || $in_host eq "" ||
    147         !defined $in_port || $in_port eq "" ||
    148         !defined $in_cert || $in_cert eq "") {
    149         if ($osDataArr{wservRun}) {
    150             print h1('Command description form:'),
    151             start_form(-method=>"get"),
    152             "Host: ",textfield('host'),p,
    153             "Port: ",textfield('port'),p,
    154             "Cert: ",textfield('cert'),p,
    155             "Cipher: ",textfield('cipher'),p,
    156             checkbox_group(-name=>'debug',
    157                            -values=>['debug on  ']),
    158             submit,
    159             end_form,
    160             hr;
    161         } else {
    162             print "Printing html form to get client arguments\n";
    163         }
    164         $ERR = "the following parameters are required: host, port, cert";
    165         return 0;
    166     } else {
    167         print "<pre>" if ($osDataArr{wservRun});
    168         return 1;
    169     }
    170 }
    171 
    172 
    173 #--------------------------------------------------------------
    174 # Building cipher conversion table from file based on the OS.
    175 # Params:
    176 #     tfile: cipher conversion file.
    177 #     sysName: system name
    178 #     tblPrt: returned pointer to a table.
    179 sub buildCipherTable {
    180     my ($tfile, $sysName, $tblPrt) = @_;
    181     my @retArr = @$tblPrt;
    182     my %table, %rtable;
    183     my $strCount = 0;
    184 
    185     debug("Entering getReqData function", "$tfile:$sysName:$tblPrt");
    186 
    187     ($ERR = "No system name supplied" && return 0) if ($sysName =~ /^$/);
    188     if (!open(TFILE, "$tfile")) {
    189         $ERR = "Missing cipher conversion table file.";
    190         return 0;
    191     }
    192     foreach (<TFILE>) {
    193         chop;
    194         /^#.*/ && next;
    195         /^\s*$/ && next;
    196         if ($strCount++ == 0) {
    197             my @sysArr =  split /\s+/;
    198             $colCount = 0;
    199             for (;$colCount <= $#sysArr;$colCount++) {
    200                 last if ($sysArr[$colCount] =~ /(.*:|^)$sysName.*/);
    201             }
    202             next;
    203         }
    204         my @ciphArr =  split /\s+/, $_;
    205         $table{$ciphArr[0]} = $ciphArr[$colCount];
    206         $rtable{$ciphArr[$colCount]} = $ciphArr[0];
    207     }
    208     close(TFILE);
    209     $cipherTablePtr[0] = \%table;
    210     $cipherTablePtr[1] = \%rtable;
    211     return 1
    212 }
    213 
    214 #--------------------------------------------------------------
    215 # Client configuration function. Loads client configuration file.
    216 # Initiates cipher table. Loads cipher list supported by ssl client.
    217 #
    218 sub configClient {
    219 
    220     debug "Entering configClient function";
    221 
    222     my $res = &setFunctRefs();
    223     return $res if (!$res);
    224 
    225     open(CFILE, $osDataArr{'osConfigFile'}) ||
    226         ($ERR = "Missing configuration file." && return 0);
    227     foreach (<CFILE>) {
    228         /^#.*/ && next;
    229         chop;
    230         eval $_;
    231     }
    232     close(CFILE);
    233    
    234     local @cipherTablePtr = ();
    235     $osDataArr{'buildCipherTableFn'}->($cipherTableFile, $clientSys) || return 0;
    236     $osDataArr{cipherTable} = $cipherTablePtr[0];
    237     $osDataArr{rcipherTable} = $cipherTablePtr[1];
    238     
    239     local $suppCiphersTablePrt;
    240     &{$osDataArr{'loadSupportedCipthersFn'}} || return 0;
    241     $osDataArr{suppCiphersTable} = $suppCiphersTablePrt;
    242 }
    243 
    244 #--------------------------------------------------------------
    245 # Verifies that a particular cipher is supported.
    246 # Params:
    247 #    checkCipher: cipher name
    248 # Returns:
    249 #    1 - cipher is supported(also echos the cipher).
    250 #    0 - not supported.
    251 #
    252 sub verifyCipherSupport {
    253     my ($checkCipher) = @_;
    254     my @suppCiphersTable = @{$osDataArr{suppCiphersTable}};
    255 
    256     debug("Entering verifyCipherSupport", $checkCipher);
    257     foreach (@suppCiphersTable) {
    258         return 1 if ($checkCipher eq $_);
    259     }
    260     $ERR = "cipher is not supported.";
    261     return 0;
    262 }
    263 
    264 #--------------------------------------------------------------
    265 # Converts long(?name of the type?) cipher name to 
    266 # openssl/tstclntw cipher name.
    267 # Returns:
    268 #   0 if cipher was not listed. 1 upon success.
    269 #
    270 sub convertCipher {
    271     my ($cipher) = @_;
    272     my @retList;
    273     my $resStr;
    274     my %cipherTable = %{$osDataArr{cipherTable}};
    275 
    276     debug("Entering convertCipher", $cipher);
    277     if (defined $cipher) {
    278         my $cphr = $cipherTable{$cipher};
    279         if (!defined $cphr) {
    280             $ERR = "cipher is not listed.";
    281             return 0;
    282         }        
    283         &{$osDataArr{'cipherIsSupportedFn'}}($cphr) || return 0;
    284         $ciphers = "$cphr";
    285         return 1;
    286     }
    287     return 0;
    288 }
    289 
    290 #################################################################
    291 #  UNIX Apache Specific functions
    292 #----------------------------------------------------------------
    293 
    294 #--------------------------------------------------------------
    295 # Executes ssl client command to get a list of ciphers supported
    296 # by client.
    297 #
    298 sub getSupportedCipherList_Unix {
    299     my @arr, @suppCiphersTable;
    300 
    301     debug "Entering getSupportedCipherList_Unix function";
    302 
    303     eval '$sLisrCmd = "'.$osDataArr{'suppCiphersCmd'}.'"';
    304     if (!open (OUT, "$sLisrCmd|")) {
    305         $ERR="Can not run command to verify supported cipher list.";
    306         return 0;
    307     }
    308     @arr = <OUT>;
    309     chop $arr[0];
    310     @suppCiphersTable = split /:/, $arr[0];
    311     debug("Supported ciphers", $arr[0]);
    312     $suppCiphersTablePrt = \@suppCiphersTable;
    313     close(OUT);
    314     return 1;
    315 }
    316 
    317 #--------------------------------------------------------------
    318 # Lunches ssl client command in response to a request.
    319 #
    320 #
    321 sub execClientCmd_Unix {
    322     my $proto;
    323     local $ciphers;
    324 
    325     debug "Entering execClientCmd_Unix";
    326     if (defined $in_cipher && $in_cipher ne "") {
    327         my @arr = split /_/, $in_cipher, 2;
    328         $proto = "-".$arr[0];
    329         $proto =~ tr /SLT/slt/;
    330         $proto = "-tls1" if ($proto eq "-tls");
    331         return 0 if (!&{$osDataArr{'cipherListFn'}}($in_cipher));
    332         $ciphers = "-cipher $ciphers";
    333         debug("Return from cipher conversion", "$ciphers");
    334     }
    335 
    336     eval '$command = "'.$osDataArr{'clientRunCmd'}.'"';
    337     debug("Executing command", $command);
    338     if (!open CMD_OUT, "$command 2>&1 |") {
    339        $ERR = "can not launch client";
    340        return 0;
    341     }
    342 
    343     my @cmdOutArr = <CMD_OUT>;
    344     
    345     foreach (@cmdOutArr) {
    346         print $_;
    347     }
    348 
    349     my $haveVerify = 0;
    350     my $haveErrors = 0;
    351     foreach (@cmdOutArr) {
    352         chop;
    353         if (/unknown option/) {
    354             $haveErrors++;
    355             svr_error "unknown option\n";
    356             next;
    357         }
    358         if (/:no ciphers available/) {
    359             $haveErrors++;
    360             svr_error "no cipthers available\n";
    361             next;
    362         }
    363         if (/verify error:/) {
    364             $haveErrors++;
    365             svr_error "unable to do verification\n";
    366             next;
    367         }
    368         if (/alert certificate revoked:/) {
    369             $haveErrors++;
    370             svr_error "attempt to connect with revoked sertificate\n";
    371             next;
    372         }
    373         if (/(error|ERROR)/) {
    374             $haveErrors++;
    375             svr_error "found errors in server log\n";
    376             next;
    377         }
    378         /verify return:1/ && ($haveVerify = 1);
    379     }
    380      if ($haveVerify == 0) {
    381          svr_error "no 'verify return:1' found in server log\n";
    382          $haveErrors++;
    383      }
    384 
    385     if ($haveErrors > 0) {
    386         $ERR = "Have $haveErrors server errors";
    387         debug "Exiting execClientCmd_Unix";
    388         return 0;
    389     }
    390     debug "Exiting execClientCmd_Unix";
    391     return 1;
    392 }
    393 
    394 #################################################################
    395 #  Windows IIS Specific functions
    396 #----------------------------------------------------------------
    397 
    398 #--------------------------------------------------------------
    399 # Executes ssl client command to get a list of ciphers supported
    400 # by client.
    401 #
    402 sub getSupportedCipherList_Win {
    403     my @arr, @suppCiphersTable;
    404 
    405     debug "Entering getSupportedCipherList_Win function";
    406 
    407     eval '$sLisrCmd = "'.$osDataArr{'suppCiphersCmd'}.'"';
    408     if (!open (OUT, "$sLisrCmd|")) {
    409         $ERR="Can not run command to verify supported cipher list.";
    410         return 0;
    411     }
    412     my $startCipherList = 0;
    413     foreach (<OUT>) {
    414         chop;
    415         if ($startCipherList) {
    416             /^([a-zA-Z])\s+/ && push @suppCiphersTable, $1;
    417             next;
    418         }
    419         /.*from list below.*/ && ($startCipherList = 1);
    420     }
    421     debug("Supported ciphers", join ':', @suppCiphersTable);
    422     $suppCiphersTablePrt = \@suppCiphersTable;
    423     close(OUT);
    424     return 1;
    425 }
    426 
    427 #--------------------------------------------------------------
    428 # Lunches ssl client command in response to a request.
    429 #
    430 #
    431 sub execClientCmd_Win {
    432     my $proto;
    433     local $ciphers;
    434 
    435     debug "Entering execClientCmd_Win";
    436     if (defined $in_cipher && $in_cipher ne "") {
    437         my @arr = split /_/, $in_cipher, 2;
    438         $proto = "-2 -3 -T";
    439 
    440         $proto =~ s/-T// if ($arr[0] eq "TLS");
    441         $proto =~ s/-3// if ($arr[0] eq "SSL3");
    442         $proto =~ s/-2// if ($arr[0] eq "SSL2");
    443 	return 0 if (!&{$osDataArr{'cipherListFn'}}($in_cipher));
    444         $ciphers = "-c $ciphers";
    445         debug("Return from cipher conversion", $ciphers);
    446     }
    447 
    448     eval '$command = "'.$osDataArr{'clientRunCmd'}.'"';
    449     debug("Executing command", $command);
    450     if (!open CMD_OUT, "$command 2>&1 |") {
    451         $ERR = "can not launch client";
    452         return 0;
    453     }
    454 
    455     my @cmdOutArr = <CMD_OUT>;
    456     
    457     foreach (@cmdOutArr) {
    458         print $_;
    459     }
    460 
    461     my $haveVerify = 0;
    462     my $haveErrors = 0;
    463     foreach (@cmdOutArr) {
    464         chop;
    465         if (/unknown option/) {
    466             $haveErrors++;
    467             svr_error "unknown option\n";
    468             next;
    469         }
    470         if (/Error performing handshake/) {
    471             $haveErrors++;
    472             svr_error "Error performing handshake\n";
    473             next;
    474         }
    475         if (/Error creating credentials/) {
    476             $haveErrors++;
    477             svr_error "Error creating credentials\n";
    478             next;
    479         }
    480         if (/Error .* authenticating server credentials!/) {
    481             $haveErrors++;
    482             svr_error "Error authenticating server credentials\n";
    483             next;
    484         }
    485         if (/(error|ERROR|Error)/) {
    486             $haveErrors++;
    487             svr_error "found errors in server log\n";
    488             next;
    489         }
    490     }
    491 
    492     if ($haveErrors > 0) {
    493         $ERR = "Have $haveErrors server errors";
    494         debug "Exiting execClientCmd_Win";
    495         return 0;
    496     }
    497     debug "Exiting execClientCmd_Win";
    498     return 1;
    499 }
    500 
    501 #################################################################
    502 #  Main line of execution
    503 #----------------------------------------------------------------
    504 &init;
    505 
    506 if ($osDataArr{wservRun}) {
    507     print header('text/html').
    508         start_html('iopr client');
    509 }
    510  
    511 print "SCRIPT=OK\n";
    512 
    513 if (!&getReqData) { 
    514     svr_error($ERR, 1);
    515 }
    516 
    517 if (!&configClient) { 
    518     svr_error($ERR, 1);
    519 }
    520 
    521 &{$osDataArr{'execCmdFn'}} || svr_error;
    522 
    523 if ($osDataArr{wservRun}) {
    524     print "</pre>";
    525     print end_html;
    526 }