php iTransact pgp signature verification

If you're using http://www.itransact.com or http://www.paymentclearing.com/ merchant credit card service, below code may be of use to you. This script verifies the PGP Signature used to Authenticate Transactions.

iTransact PGP

This code was written by a non-profit organization http://hibm.org and provided here for other non-profits and one-man small home-based businesses who use iTransact merchant CC services.

Usage Example

<?php
/**
 * Verify iTransact Signature used with LOOKUP and PASSBACK
 * http://itransact.com/support/pgp.html
 * 
 * Usage:
 * 	include 'verify_iTransact_pgp.php'; //at top of the ret_addr page
 * 	if pgp verification fails, the script will tell you why it failed
 * 	and prevent further processing of 'ret_addr' page
 *
 * @author = ddarvish@hibm.org
 * @date/version = 2009-02
 * @copyright DDarvish
 * @return string 'PASSED' or string of other messages.
 */
 
// error_reporting(E_ALL);
 
function iTransactPGPverify () {
/************** BEGIN CONFIG ************/
 
//create the folder ".gnupg" and set appropriate permissions 
// e.g. in older php, not running in safe mode, chmod to 757.
$GNUPGHOME = '/home/hibm/.gnupg';
 
//iTransact public (Signed key) public nneded to verify sigs
$key = '-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: 4.5
 
mQCNAjZu+eUAAAEEAOBmQnbjWz8uyyZ3uMqAE9sbSvXDAA98qN/HG4Bp+A7oPk9i
vH1x27e7dA4A3DflBJLkImALsEhd+npcM33jvao7M4HQUGnZo+bCFkP6aK8eRO4K
bu9nmO1xuFl16jDlP413qpSzylhIoSvmDHbYj+Cs45hFyzJcd7HOJqLFYyxlAAUR
tBZpVHJhbnNhY3QgdjQgU2lnbmF0dXJliQCVAgUQOzEmwbHOJqLFYyxlAQE83gP/
T7H+XNhKz2kWE+dTTcO2O+XwG1Wjjc6FDVgmQ47qSjDZ0oIbxfBiPF33Zv4dlAc/
8OkRYs1qsTNbYoy3cyG2WY1Rx+NhfHbVPM9SS3sUMF0aRL3b+8hvhU9OnvPLP8aq
R9g8lEpASzngkAFdnzAwohD4ltAsDICw4OnTUQTgLcqJAFUDBRA2bvqrcnBcq/4x
V/EBAaVZAf9WHI7lzMl3poaGE6MJyVsXe/2IIrtmNtsVUXpjkbEyqcZ5pJd2kLNZ
jIZBYcBgQAzFFSp/rSg7IJW6q9ZcWsqG
=brHz
-----END PGP PUBLIC KEY BLOCK-----';
 
// if you change above, you need to change below to match
$keyuid = 'iTransact v4 Signature'; //used as pattern in keyinfo($gpg,$pattern)
 
 
/************** END CONFIG ************/
 
$plaintextmessage = '';	
$uri = ''; //needle- unencrypted message/uri
$r = ''; // value to return
 
if(!function_exists('gnupg_init')) {
	$r .= 'GnuPG PECL extention for PHP is not loaded.  Ask your system administrator to please <a href="http://pecl.php.net/package/gnupg">intall it</a>.';
} else {
	putenv('GNUPGHOME='.trim($GNUPGHOME));	//set environment variable
	$gpg = gnupg_init(); //initialize GnuPG resource
 
	$keyinfo = gnupg_keyinfo($gpg, $keyuid);
	//check to see if the key exists
	if($keyinfo[0]['subkeys'][0]['fingerprint']) {
		// all ok, just get the fingerprint
		//$keyid = $keyinfo[0]['subkeys'][0]['keyid'];
		$keyfp = $keyinfo[0]['subkeys'][0]['fingerprint'];
	} else {	//import key then check fingerprint
		$importresult = gnupg_import($gpg, $key);
		$keyinfo = gnupg_keyinfo($gpg, $importresult['fingerprint']);
		if($importresult['imported']== 1) {
			//import succeeded, most likely due to write/read permissions
			$keyuid = $keyinfo[0]['uids'][0]['uid'];
			//$keyid = $keyinfo[0]['subkeys'][0]['keyid'];
			$keyfp = $keyinfo[0]['subkeys'][0]['fingerprint'];
		} elseif($importresult['unchanged']== 1) {
			//should not have reached here, keyuid much be wrong
			$r .= "Please check your keyuid, it does not match your key.<br/>"; 
			//obtain the key uid;
			$keyinfo = gnupg_keyinfo($gpg, $importresult['fingerprint']);
			$keyuid = $keyinfo[0]['uids'][0]['uid'];
			//$keyid = $keyinfo[0]['subkeys'][0]['keyid'];
			$keyfp = $keyinfo[0]['subkeys'][0]['fingerprint'];
			$r .= "Your keyuid should be changed to '$keyuid' <br/>";
		} else { //there must be write/read permission issues on 
			$r .=  "Either the folder '$GNUPGHOME' does not exists or I cannot read/write to it.  Please ask your system administrator to create the folder and set correct the folder permission, or set the \$GNUPGHOME variable to the another folder. <p>";
		}
	}
}
 
if(isset($_REQUEST['signature'])) {
	$PGPsig = $_REQUEST['signature']; //haystack- PGPsig/message
 
	//if PGPsig has http string, then it's unencrypted
	if(preg_match('#http(s)?://.+\..+/.+\?(.+=.+)(&?.+=.+)+#',$PGPsig)) {
		$r .= "Message is not encrypted.<br/>";
		$resultOfVerify = gnupg_verify($gpg,$PGPsig,false,$plaintextmessage);
	} else { //encrypted message
		$r .= "Message is encrypted, trying to decrypt it ...<br/>";
		if(gnupg_adddecryptkey ($gpg,$keyuid,'')) {
			//added key ok
			$r .= "Decrypt key added successfully.<br/>";
			$resultOfVerify = gnupg_decryptverify($gpg,$PGPsig,$plaintextmessage);
			if($resultOfVerify) {
				$r .= "Message decrypted successfully.<br/>";
			}
		} else {
			$r .= "Unable to add decryptkey, unable to decrypt message.<br/>";
		}
	}
 
	// $resultOfVerify is an array with fingerprint matching $keyfp
	if($resultOfVerify[0]['fingerprint'] == $keyfp) { //sig verified
		$r .= "Signature verified.  Message integrity not verified yet.<br/>";
		$sigVerified = TRUE;
	} else {
		//$r .= "ResultOfVerify '".$resultOfVerify[0]['fingerprint'] . "' didn't match iTransact '$keyfp'.<br/>";
 
		//some debug info
		// echo "<pre>\$resultOfVerify "; print_r($resultOfVerify);
		// echo "\n\n\$keyinfo "; print_r($keyinfo);
 
	}
 
	//Message Integrity:
	// NEED A HASH TEST TO VERIFY $plaintextmessage INTEGRITY
	// UNSURE HOW THE HASH VALUE IS STORED IN SIG
	// hash($plaintextmessage) == something in resultOfVerify
 
	//Poorman's method: just $plaintextmessage should match url
	$uriFull = $_SERVER['REQUEST_URI']; //must always exist 
	$uriEnd ='&signature=';
	$uriEndPos = strpos($uriFull,$uriEnd);
	if($uriEndPos===FALSE) { 
		$r .= "Signature demarker in url not found.<br/>"; //must be in post
		$uri = $uriFull;
	} else {
		$uri = substr($uriFull,0,$uriEndPos); 
	}
 
	$uriInMessage = strpos($plaintextmessage, $uri);
	if($uriInMessage) {
		$r .= "URI in message begins at position $uriInMessage<br/>";
	} else {
		$r .= "URI is not in message.<br/>";
	}
 
	if($sigVerified && $uriInMessage) {
		$r = 'PASSED';
	} else {
		$r .= "Signature verification FAILED because: <br/>";
		if(!$sigVerified) { $r .= "&nbsp;&nbsp;Signature does not match key."; }
		if(!$uriInMessage) { 
			$r .= "&nbsp;&nbsp;URI is not in Message.<br/>"; 
			//$r .= "&nbsp;&nbsp;URI = $uri<br/>";
			//$r .= "&nbsp;&nbsp;Message = $plaintextmessage<br/>";
		}
	}
 
} else {
	$r .= "Signature is not sent.<br/>";
}
 
return $r;
}
 
 
if(($pgpresult = iTransactPGPverify()) == 'PASSED') {
	//continue
} else {
	echo $pgpresult; 
	exit;
}

Candidate Code Suggestions

Add your suggestions and links here.