Server-side Verification Functions
Many form processing servers use programs written in PHP programming language to deal with the data received. These programs typically perform some checking for required variables and range of values. In addition, many publicly accessible forms also include CAPTCHA images that require additional verification in the server.
If the checking process fails, the PHP program generates an error page; otherwise it continues the process storing values in a database and generates a congratulation message.
To implement a digital signature procedure, the program running at the server must be able to check the digital signature that arrives along with the other variables of the form, prior to accepting and storing the information. In this section of the paper three helpful functions for processing signed forms are provided:
- Validation(). Performs digital signature verification.
- GetName(). Returns the name of the user as extracted from the certificate used to generate the signature.
- GetCA(). Returns the name of the certification authority that issued the certificate.
Signature Verification
In Listing Two, Validation() utilizes the two hidden variables varnames and signature created by the JavaScript function signForm. It stores the digital signature in a temporary file called validation_XXX.pem, adding the standard heading and footer for PKCS#7 data stored in PEM format. A number, generated with PHP function uniqid, is added to the name of the temporary file to let the server run in parallel several copies of the program without mixing files.
<html> <head> <title>Verification Results</title> </head> <body> <h1>Verifying and storing the data sent to this server </h1> <?php function Validation($signature,$varnames) { /*** Creates validation file comprising the signature ***/ $uniq_id=uniqid(); $fp=fopen("validation_".$uniq_id.".pem","w"); fwrite($fp,"-----BEGIN PKCS7-----\n"); fwrite($fp,$signature); fwrite($fp,"\n-----END PKCS7-----"); fclose($fp); /*** Creates original_text, based on varnames ***/ /* extract variable names */ $i=0; $beg=0; $len=strlen($varnames); do{ $end=strpos($varnames,',',$beg); if (!($end===false)) { $var_name[$i]=substr($varnames,$beg,$end-$beg); $i=$i+1; $beg=$end+1; } }while(($beg<$len) && !($end===false)); $num_var=$i; /* Builds orginal_text */ $original_text="I affirm the following information:\n"; for($i=0;$i<$num_var;$i++){ $original_text.=$var_name[$i]."=".$_REQUEST[$var_name[$i]]."\n"; } /*** Creates original_text file ***/ $fp=fopen("original_text_".$uniq_id.".txt","w"); fwrite($fp,$original_text); fclose($fp); /*** Identifies CA ***/ $ca=GetCA($signature); if ($ca==="/C=ES/O=FNMT/OU=FNMT Clase 2 CA\n") $root_cert="fnmt.pem"; else if ($ca==="/[email protected]/C=ES/ST=Madrid/L=Madrid/ O=Universidad Pontificia Comillas/OU=STIC/CN=CA www.upcomillas.es\n") $root_cert="comillas.pem"; else $root_cert=NULL; //same as unset /*** Calls openssl ***/ if (isset($root_cert)) { $command="/opt/csw/bin/openssl smime -verify -in"; $command.=" validation_".$uniq_id.".pem"; $command.=" -inform PEM -binary -content"; $command.=" original_text_".$uniq_id.".txt"; $command.=" -CAfile ".$root_cert; //print $command; $rep=shell_exec($command." 2>&1"); } else { $rep='The issuer of your certificate is not trusted by the server'; } /* delete temp files */ unlink("validation_".$uniq_id.".pem"); unlink("original_text_".$uniq_id.".txt"); //print $rep; if (substr($rep,0,23)=="Verification successful") $rep=NULL; //returns NULL if successful return $rep; } function GetName($signature) { //Gets the name of the owner of the certificate /*** Creates validation file comprising the signature ***/ $uniq_id=uniqid(); $fp=fopen("validation_".$uniq_id.".pem","w"); fwrite($fp,"-----BEGIN PKCS7-----\n"); fwrite($fp,$signature); fwrite($fp,"\n-----END PKCS7-----"); fclose($fp); $command="/opt/csw/bin/openssl pkcs7 -inform PEM -in"; $command.=" validation_".$uniq_id.".pem"; $command.=" -print_certs -noout | grep \^subject | head -1 | cut -d'=' -f2-"; $rep=shell_exec($command." 2>&1"); unlink("validation_".$uniq_id.".pem"); //print $rep; return $rep; } function GetCA($signature) { //Gets the name of the issuer of the certifcate /*** Creates validation file comprising the signature ***/ $uniq_id=uniqid(); $fp=fopen("validation_".$uniq_id.".pem","w"); fwrite($fp,"-----BEGIN PKCS7-----\n"); fwrite($fp,$signature); fwrite($fp,"\n-----END PKCS7-----"); fclose($fp); $command="/opt/csw/bin/openssl pkcs7 -inform PEM -in"; $command.=" validation_".$uniq_id.".pem"; $command.=" -print_certs -noout | grep \^issuer | head -1 | cut -d'=' -f2-"; $rep=shell_exec($command." 2>&1"); unlink("validation_".$uniq_id.".pem"); //print $rep; return $rep; } /***************************/ /*** PROGRAM BEGINS HERE ***/ $signature=$_REQUEST["signature"]; $varnames=$_REQUEST["varnames"]; if (!isset($signature) || !isset($varnames)) { die("<p>Error, no digital signature provided<br>Current (2007) version of IE does not support digital signature</p>\n</body></html>"); } $ctrl=Validation($signature,$varnames); if (isset($ctrl)) { die("<p>Error validating signature: ".$ctrl."</p>\n</body></html>"); } /*** Validation OK, continue with normal procedure ***/ //variables verification //storage in database (do not forget to add signature and varnames to the database) //message print "<p>Information signed by: ".GetName($signature); print "<p>Thank you. Data received and stored correctly"; ?> </body> </html>
Then Validation creates a string called original_text in the same way as the text to be signed was created within the JavaScript function signForm. For doing so, the function analyzes varnames to identify variable names in the correct order, then it obtains the values for each variable and creates original_text in the format variable=value.
It is important to note that original_text must be built using the values of the variables received from the form because these are the values that will be stored in the database and therefore the information that needs to be checked. If the string texttbs (created during the signing process within the JavaScript function signForm) were sent as a hidden field, server-side verification would be easier, but there will be no warranty that the values of the form variables match the information stored in texttbs variable. In that scenario an attacker may send any information in the name of the supplanted victim just by using a PKCS#7 digital signature (in signature variable), the original text which created that signature (in texttbs variable), and whatever data in form variables An altered version of signForm function may use the following definitions:
texttbs="hello,..."; signature="MIIGzQYJKoZIhvcNAQ....";
The signature and text used by the attacker could be obtained for example from any email message signed by the victim.
Consequently, the validation function must build the original text concatenating form variables, and the variable varnames is needed for two main reasons:
- varnames holds the names of the form variables actually sent to the server.
- It keeps track of the order in which they were extracted from the form while creating texttbs.
Even though a given application should know the list of variables that it must receive, some objects do not always send variables to the server (for example a checkbox does not send a variable unless it is checked). But even knowing the list of variables actually signed, it is necessary to know in which order they were read. The same set of variables and values but shuffling lines would be essentially the same information for a person, but would fail in signature verification. Therefore using varnames to create orignal_text makes things very easy and Validation becomes a general function independent of the application.
Once original_text has been created it is stored in a temporary file called original_text_XXX.txt. For signature validation both files will be used as argument to the program openssl.
The final step before verifying the signature is to identify the name of the certification authority that issued the certificate, since the system can only verify a signature if it can previously verify the validity of the certificate. In order to obtain the issuer, Validation calls GetCA function and gets the name of the user as a string with the Country, Organization, and so on. If the issuer of the certificate is one of the authorities trusted by the server (the server has its root certificate), then the process can continue. It is also possible to modify the call to openssl adding the option -noverify to avoid signer verification though it is not recommended.
Finally, the function must call the program openssl providing validation_XXX.pem and original_text_XXX.txt as the main arguments along with the root certificate of the authority that issued the certificate. The openssl command used for signature verifications is:
openssl smime -verify -in validation_XXX.pem -inform PEM -binary -content original_text_XXX.txt -CAfile fnmt.pem
Therefore, the call to openssl within PHP for a UNIX environment is performed building such command and calling shell_exec (see PHP Program Execution Functions) in the way in which standard output and standard error are trapped:
$command="/opt/csw/bin/openssl smime -verify -in"; $command.=" validation_".$uniq_id.".pem"; $command.=" -inform PEM -binary -content"; $command.=" original_text_".$uniq_id.".txt"; $command.=" -CAfile ".$root_cert; $rep=shell_exec($command." 2>&1");
The answers that can be obtained are:
Verification successful Verification failure
In UNIX systems, openssl prints the original text on standard output and the result of the verification on standard error. For this reason the argument in the call to shell_exec must include standard error redirection directive as show above.
The result of Validation is NULL in case of success and a string containing the error message in case of failure. The error message can be displayed to the user after calling Validation, as in Listing Two.
Certificate's Owner and Issuer
The owner and the issuer of a certificate are two of the fields stored in a PKCS#7 signature. To access this information easily, a PHP function called GetName is provided to obtain the owner's name and a function called GetCA is provided to obtain the issuer of the certificate; i.e., the name of the Certification Authority.
The program openssl makes available a command called pkcs7 that is used to analyze certificates stored within the signature file. The typical call to openssl would be:
openssl pkcs7 -inform PEM -in validation_XXX.pem -print_certs -noout
To extract just the name of just the issuer, this command is combined with UNIX commands grep and cut.
Conclusion
Listing One is a JavaScript function called signForm that can be added to any existing HTML form, previously created with any HTML editor, to create a digital signature of the data entered in the form. The function was developed in such a general way that it can automatically go through all form objects gathering variable names and values and creating a single string of text to be signed by users. By calling the standard JavaScript function signText, the string to be signed is shown in a dialog window that allows the user to verify the information and to select one of the available personal certificates to sign it. No additional configuration or pre-definition of form variable names is required, ensuring easy implantation in existing forms. The digital signature is sent to the server along with the current set of values.
Listing Two is a PHP function called Validation that must be run in the server to ensure that the data received matches the digital signature, hence allowing to decide if it is legally valid or not. Again this is an automatic function that will check all necessary variables without requiring any pre-definition. In this case a complete PHP program is provided as an example about how to call Validation function. Validation makes use of two additional functions called GetName and GetCA that extract the names of the owner and the issuer of the certificate. These useful functions can also be called directly from the PHP program to obtain such information without requiring any prior deep knowledge on cryptography and personal certificates.