| #!/usr/bin/perl |
| |
| # This Source Code Form is subject to the terms of the Mozilla Public |
| # License, v. 2.0. If a copy of the MPL was not distributed with this |
| # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| |
| #-------------------------------------------------------------- |
| # cgi script that parses request argument to appropriate |
| # open ssl or tstclntw options and starts ssl client. |
| # |
| |
| use CGI qw/:standard/; |
| |
| use subs qw(debug); |
| |
| #-------------------------------------------------------------- |
| # Prints out an error string and exits the script with an |
| # exitStatus. |
| # Param: |
| # str : an error string |
| # exitStat: an exit status of the program |
| # |
| sub svr_error { |
| my ($str, $exitStat) = @_; |
| |
| if (!defined $str || $str eq "") { |
| $str = $ERR; |
| } |
| print "SERVER ERROR: $str\n"; |
| if ($exitStat) { |
| print end_html if ($osDataArr{wservRun}); |
| exit $exitStat; |
| } |
| } |
| |
| #-------------------------------------------------------------- |
| # Prints out a debug message |
| # Params: |
| # str: debug message |
| # inVal: additional value to print(optional) |
| # |
| sub debug { |
| my ($str, $inVal) = @_; |
| |
| print "-- DEBUG: $str ($inVal)\n" if ($DEBUG == 1); |
| } |
| |
| |
| #-------------------------------------------------------------- |
| # Initializes execution context depending on a webserver the |
| # script is running under. |
| # |
| sub init { |
| %osDataArr = ( |
| loadSupportedCipthersFn => \&osSpecific, |
| cipherIsSupportedFn => \&verifyCipherSupport, |
| cipherListFn => \&convertCipher, |
| buildCipherTableFn => \&buildCipherTable, |
| execCmdFn => \&osSpecific, |
| ); |
| |
| $scriptName = $ENV{'SCRIPT_NAME'}; |
| if (!defined $scriptName) { |
| $DEBUG=1; |
| debug "Debug is ON"; |
| } |
| $DEBUG=1; |
| |
| $svrSoft = $ENV{'SERVER_SOFTWARE'}; |
| if (defined $svrSoft) { |
| $_ = $svrSoft; |
| /.*Microsoft.*/ && ($osDataArr{wserv} = "IIS"); |
| /.*Apache.*/ && ($osDataArr{wserv} = "Apache"); |
| $osDataArr{wservRun} = 1; |
| } else { |
| $osDataArr{wserv} = "Apache"; |
| $osDataArr{wservRun} = 0; |
| } |
| } |
| |
| #-------------------------------------------------------------- |
| # Function-spigot to handle errors is OS specific functions are |
| # not implemented for a particular OS. |
| # Returns: |
| # always returns 0(failure) |
| # |
| sub osSpecific { |
| $ERR = "This function should be swapped to os specific function."; |
| return 0; |
| } |
| |
| #-------------------------------------------------------------- |
| # Sets os specific execution context values. |
| # Returns: |
| # 1 upon success, or 0 upon failure(if OS was not recognized) |
| # |
| sub setFunctRefs { |
| |
| debug("Entering setFunctRefs function", $osDataArr{wserv}); |
| |
| if ($osDataArr{wserv} eq "Apache") { |
| $osDataArr{osConfigFile} = "apache_unix.cfg"; |
| $osDataArr{suppCiphersCmd} = '$opensslb ciphers ALL:NULL'; |
| $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'; |
| $osDataArr{loadSupportedCipthersFn} = \&getSupportedCipherList_Unix; |
| $osDataArr{execCmdFn} = \&execClientCmd_Unix; |
| } elsif ($osDataArr{wserv} eq "IIS") { |
| $osDataArr{osConfigFile} = "iis_windows.cfg"; |
| $osDataArr{suppCiphersCmd} = '$tstclntwb'; |
| $osDataArr{clientRunCmd} = '$tstclntwb -h $in_host -p $in_port -n $in_cert $proto $ciphers < $reqFile'; |
| $osDataArr{loadSupportedCipthersFn} = \&getSupportedCipherList_Win; |
| $osDataArr{execCmdFn} = \&execClientCmd_Win; |
| } else { |
| $ERR = "Unknown Web Server type."; |
| return 0; |
| } |
| return 1; |
| } |
| |
| #-------------------------------------------------------------- |
| # Parses data from HTTP request. Will print a form if request |
| # does not contain sufficient number of parameters. |
| # Returns: |
| # 1 if request has sufficient number of parameters |
| # 0 if not. |
| sub getReqData { |
| my $debug = param('debug'); |
| $in_host = param('host'); |
| $in_port = param('port'); |
| $in_cert = param('cert'); |
| $in_cipher = param('cipher'); |
| |
| if (!$osDataArr{wservRun}) { |
| $in_host="goa1"; |
| $in_port="443"; |
| $in_cert="TestUser511"; |
| $in_cipher = "SSL3_RSA_WITH_NULL_SHA"; |
| } |
| |
| debug("Entering getReqData function", "$in_port:$in_host:$in_cert:$in_cipher"); |
| |
| if (defined $debug && $debug == "debug on") { |
| $DEBUG = 1; |
| } |
| |
| if (!defined $in_host || $in_host eq "" || |
| !defined $in_port || $in_port eq "" || |
| !defined $in_cert || $in_cert eq "") { |
| if ($osDataArr{wservRun}) { |
| print h1('Command description form:'), |
| start_form(-method=>"get"), |
| "Host: ",textfield('host'),p, |
| "Port: ",textfield('port'),p, |
| "Cert: ",textfield('cert'),p, |
| "Cipher: ",textfield('cipher'),p, |
| checkbox_group(-name=>'debug', |
| -values=>['debug on ']), |
| submit, |
| end_form, |
| hr; |
| } else { |
| print "Printing html form to get client arguments\n"; |
| } |
| $ERR = "the following parameters are required: host, port, cert"; |
| return 0; |
| } else { |
| print "<pre>" if ($osDataArr{wservRun}); |
| return 1; |
| } |
| } |
| |
| |
| #-------------------------------------------------------------- |
| # Building cipher conversion table from file based on the OS. |
| # Params: |
| # tfile: cipher conversion file. |
| # sysName: system name |
| # tblPrt: returned pointer to a table. |
| sub buildCipherTable { |
| my ($tfile, $sysName, $tblPrt) = @_; |
| my @retArr = @$tblPrt; |
| my %table, %rtable; |
| my $strCount = 0; |
| |
| debug("Entering getReqData function", "$tfile:$sysName:$tblPrt"); |
| |
| ($ERR = "No system name supplied" && return 0) if ($sysName =~ /^$/); |
| if (!open(TFILE, "$tfile")) { |
| $ERR = "Missing cipher conversion table file."; |
| return 0; |
| } |
| foreach (<TFILE>) { |
| chop; |
| /^#.*/ && next; |
| /^\s*$/ && next; |
| if ($strCount++ == 0) { |
| my @sysArr = split /\s+/; |
| $colCount = 0; |
| for (;$colCount <= $#sysArr;$colCount++) { |
| last if ($sysArr[$colCount] =~ /(.*:|^)$sysName.*/); |
| } |
| next; |
| } |
| my @ciphArr = split /\s+/, $_; |
| $table{$ciphArr[0]} = $ciphArr[$colCount]; |
| $rtable{$ciphArr[$colCount]} = $ciphArr[0]; |
| } |
| close(TFILE); |
| $cipherTablePtr[0] = \%table; |
| $cipherTablePtr[1] = \%rtable; |
| return 1 |
| } |
| |
| #-------------------------------------------------------------- |
| # Client configuration function. Loads client configuration file. |
| # Initiates cipher table. Loads cipher list supported by ssl client. |
| # |
| sub configClient { |
| |
| debug "Entering configClient function"; |
| |
| my $res = &setFunctRefs(); |
| return $res if (!$res); |
| |
| open(CFILE, $osDataArr{'osConfigFile'}) || |
| ($ERR = "Missing configuration file." && return 0); |
| foreach (<CFILE>) { |
| /^#.*/ && next; |
| chop; |
| eval $_; |
| } |
| close(CFILE); |
| |
| local @cipherTablePtr = (); |
| $osDataArr{'buildCipherTableFn'}->($cipherTableFile, $clientSys) || return 0; |
| $osDataArr{cipherTable} = $cipherTablePtr[0]; |
| $osDataArr{rcipherTable} = $cipherTablePtr[1]; |
| |
| local $suppCiphersTablePrt; |
| &{$osDataArr{'loadSupportedCipthersFn'}} || return 0; |
| $osDataArr{suppCiphersTable} = $suppCiphersTablePrt; |
| } |
| |
| #-------------------------------------------------------------- |
| # Verifies that a particular cipher is supported. |
| # Params: |
| # checkCipher: cipher name |
| # Returns: |
| # 1 - cipher is supported(also echos the cipher). |
| # 0 - not supported. |
| # |
| sub verifyCipherSupport { |
| my ($checkCipher) = @_; |
| my @suppCiphersTable = @{$osDataArr{suppCiphersTable}}; |
| |
| debug("Entering verifyCipherSupport", $checkCipher); |
| foreach (@suppCiphersTable) { |
| return 1 if ($checkCipher eq $_); |
| } |
| $ERR = "cipher is not supported."; |
| return 0; |
| } |
| |
| #-------------------------------------------------------------- |
| # Converts long(?name of the type?) cipher name to |
| # openssl/tstclntw cipher name. |
| # Returns: |
| # 0 if cipher was not listed. 1 upon success. |
| # |
| sub convertCipher { |
| my ($cipher) = @_; |
| my @retList; |
| my $resStr; |
| my %cipherTable = %{$osDataArr{cipherTable}}; |
| |
| debug("Entering convertCipher", $cipher); |
| if (defined $cipher) { |
| my $cphr = $cipherTable{$cipher}; |
| if (!defined $cphr) { |
| $ERR = "cipher is not listed."; |
| return 0; |
| } |
| &{$osDataArr{'cipherIsSupportedFn'}}($cphr) || return 0; |
| $ciphers = "$cphr"; |
| return 1; |
| } |
| return 0; |
| } |
| |
| ################################################################# |
| # UNIX Apache Specific functions |
| #---------------------------------------------------------------- |
| |
| #-------------------------------------------------------------- |
| # Executes ssl client command to get a list of ciphers supported |
| # by client. |
| # |
| sub getSupportedCipherList_Unix { |
| my @arr, @suppCiphersTable; |
| |
| debug "Entering getSupportedCipherList_Unix function"; |
| |
| eval '$sLisrCmd = "'.$osDataArr{'suppCiphersCmd'}.'"'; |
| if (!open (OUT, "$sLisrCmd|")) { |
| $ERR="Can not run command to verify supported cipher list."; |
| return 0; |
| } |
| @arr = <OUT>; |
| chop $arr[0]; |
| @suppCiphersTable = split /:/, $arr[0]; |
| debug("Supported ciphers", $arr[0]); |
| $suppCiphersTablePrt = \@suppCiphersTable; |
| close(OUT); |
| return 1; |
| } |
| |
| #-------------------------------------------------------------- |
| # Lunches ssl client command in response to a request. |
| # |
| # |
| sub execClientCmd_Unix { |
| my $proto; |
| local $ciphers; |
| |
| debug "Entering execClientCmd_Unix"; |
| if (defined $in_cipher && $in_cipher ne "") { |
| my @arr = split /_/, $in_cipher, 2; |
| $proto = "-".$arr[0]; |
| $proto =~ tr /SLT/slt/; |
| $proto = "-tls1" if ($proto eq "-tls"); |
| return 0 if (!&{$osDataArr{'cipherListFn'}}($in_cipher)); |
| $ciphers = "-cipher $ciphers"; |
| debug("Return from cipher conversion", "$ciphers"); |
| } |
| |
| eval '$command = "'.$osDataArr{'clientRunCmd'}.'"'; |
| debug("Executing command", $command); |
| if (!open CMD_OUT, "$command 2>&1 |") { |
| $ERR = "can not launch client"; |
| return 0; |
| } |
| |
| my @cmdOutArr = <CMD_OUT>; |
| |
| foreach (@cmdOutArr) { |
| print $_; |
| } |
| |
| my $haveVerify = 0; |
| my $haveErrors = 0; |
| foreach (@cmdOutArr) { |
| chop; |
| if (/unknown option/) { |
| $haveErrors++; |
| svr_error "unknown option\n"; |
| next; |
| } |
| if (/:no ciphers available/) { |
| $haveErrors++; |
| svr_error "no cipthers available\n"; |
| next; |
| } |
| if (/verify error:/) { |
| $haveErrors++; |
| svr_error "unable to do verification\n"; |
| next; |
| } |
| if (/alert certificate revoked:/) { |
| $haveErrors++; |
| svr_error "attempt to connect with revoked sertificate\n"; |
| next; |
| } |
| if (/(error|ERROR)/) { |
| $haveErrors++; |
| svr_error "found errors in server log\n"; |
| next; |
| } |
| /verify return:1/ && ($haveVerify = 1); |
| } |
| if ($haveVerify == 0) { |
| svr_error "no 'verify return:1' found in server log\n"; |
| $haveErrors++; |
| } |
| |
| if ($haveErrors > 0) { |
| $ERR = "Have $haveErrors server errors"; |
| debug "Exiting execClientCmd_Unix"; |
| return 0; |
| } |
| debug "Exiting execClientCmd_Unix"; |
| return 1; |
| } |
| |
| ################################################################# |
| # Windows IIS Specific functions |
| #---------------------------------------------------------------- |
| |
| #-------------------------------------------------------------- |
| # Executes ssl client command to get a list of ciphers supported |
| # by client. |
| # |
| sub getSupportedCipherList_Win { |
| my @arr, @suppCiphersTable; |
| |
| debug "Entering getSupportedCipherList_Win function"; |
| |
| eval '$sLisrCmd = "'.$osDataArr{'suppCiphersCmd'}.'"'; |
| if (!open (OUT, "$sLisrCmd|")) { |
| $ERR="Can not run command to verify supported cipher list."; |
| return 0; |
| } |
| my $startCipherList = 0; |
| foreach (<OUT>) { |
| chop; |
| if ($startCipherList) { |
| /^([a-zA-Z])\s+/ && push @suppCiphersTable, $1; |
| next; |
| } |
| /.*from list below.*/ && ($startCipherList = 1); |
| } |
| debug("Supported ciphers", join ':', @suppCiphersTable); |
| $suppCiphersTablePrt = \@suppCiphersTable; |
| close(OUT); |
| return 1; |
| } |
| |
| #-------------------------------------------------------------- |
| # Lunches ssl client command in response to a request. |
| # |
| # |
| sub execClientCmd_Win { |
| my $proto; |
| local $ciphers; |
| |
| debug "Entering execClientCmd_Win"; |
| if (defined $in_cipher && $in_cipher ne "") { |
| my @arr = split /_/, $in_cipher, 2; |
| $proto = "-2 -3 -T"; |
| |
| $proto =~ s/-T// if ($arr[0] eq "TLS"); |
| $proto =~ s/-3// if ($arr[0] eq "SSL3"); |
| $proto =~ s/-2// if ($arr[0] eq "SSL2"); |
| return 0 if (!&{$osDataArr{'cipherListFn'}}($in_cipher)); |
| $ciphers = "-c $ciphers"; |
| debug("Return from cipher conversion", $ciphers); |
| } |
| |
| eval '$command = "'.$osDataArr{'clientRunCmd'}.'"'; |
| debug("Executing command", $command); |
| if (!open CMD_OUT, "$command 2>&1 |") { |
| $ERR = "can not launch client"; |
| return 0; |
| } |
| |
| my @cmdOutArr = <CMD_OUT>; |
| |
| foreach (@cmdOutArr) { |
| print $_; |
| } |
| |
| my $haveVerify = 0; |
| my $haveErrors = 0; |
| foreach (@cmdOutArr) { |
| chop; |
| if (/unknown option/) { |
| $haveErrors++; |
| svr_error "unknown option\n"; |
| next; |
| } |
| if (/Error performing handshake/) { |
| $haveErrors++; |
| svr_error "Error performing handshake\n"; |
| next; |
| } |
| if (/Error creating credentials/) { |
| $haveErrors++; |
| svr_error "Error creating credentials\n"; |
| next; |
| } |
| if (/Error .* authenticating server credentials!/) { |
| $haveErrors++; |
| svr_error "Error authenticating server credentials\n"; |
| next; |
| } |
| if (/(error|ERROR|Error)/) { |
| $haveErrors++; |
| svr_error "found errors in server log\n"; |
| next; |
| } |
| } |
| |
| if ($haveErrors > 0) { |
| $ERR = "Have $haveErrors server errors"; |
| debug "Exiting execClientCmd_Win"; |
| return 0; |
| } |
| debug "Exiting execClientCmd_Win"; |
| return 1; |
| } |
| |
| ################################################################# |
| # Main line of execution |
| #---------------------------------------------------------------- |
| &init; |
| |
| if ($osDataArr{wservRun}) { |
| print header('text/html'). |
| start_html('iopr client'); |
| } |
| |
| print "SCRIPT=OK\n"; |
| |
| if (!&getReqData) { |
| svr_error($ERR, 1); |
| } |
| |
| if (!&configClient) { |
| svr_error($ERR, 1); |
| } |
| |
| &{$osDataArr{'execCmdFn'}} || svr_error; |
| |
| if ($osDataArr{wservRun}) { |
| print "</pre>"; |
| print end_html; |
| } |