@@ -13645,6 +13645,8 @@ protected function getSignatureAppearanceArray($x=0, $y=0, $w=0, $h=0, $page=-1,
1364513645 * @author Richard Stockinger
1364613646 * @since 6.0.090 (2014-06-16)
1364713647 */
13648+ // other options suggested to be implement: reqPolicy, nonce, certReq, extensions
13649+ // Also option to abort signing if timestamping failed and LTV enable (embed crl and or ocsp revocation info)
1364813650 public function setTimeStamp($tsa_host='', $tsa_username='', $tsa_password='', $tsa_cert='') {
1364913651 $this->tsa_data = array();
1365013652 if (!function_exists('curl_init')) {
@@ -13679,92 +13681,126 @@ protected function applyTSA($signature) {
1367913681 }
1368013682 //@TODO: implement this feature
1368113683 // start timestamping
13682- // by Hida since 5.9.128 (2011-10-06)
13683- if($this->tsa_timestamp) {
13684- //Include asn1 fuction script
13685- require_once(dirname(__FILE__).'/include/asn1_parser_tcpdf.php');
13686- require_once(dirname(__FILE__).'/include/asn1_function_tcpdf.php');
13687- require_once(dirname(__FILE__).'/include/functionLog_tcpdf.php');
13688-
13689- $tsaLog = __FILE__." line:(".__LINE__."). Perform timestamping...\n";
13690- //Parse TCPDF Signature structure to get signed hash sequence
13691- $p = asn1parse($signature);
13692- $p1 = asn1parse($p[0][1]);
13693- $p2 = asn1parse($p1[1][1]);
13694- $p3 = asn1parse($p2[0][1]);
13695- $p2 = asn1parse($p3[4][1]);
13696- $pa1 = asn1parse($p2[0][1]);
13697- $pa2 = asn1parse($pa1[3][1]);
13698-
13699- //Create timestamp request
13700-
13701- //Create hash of encrypted contents TCPDF signature
13702- $hash = hash('sha1', hex2bin($pa1[5][1]));
13703- //Build timestamp request data
13704- $tsReqData = seq(
13705- int(1).
13684+ // by Hida (16 Mei 2023)
13685+
13686+ // Include minimum asn.1 fuctional script
13687+ require_once(dirname(__FILE__).'/include/tcpdf_asn1.min.php');
13688+
13689+ // Parse TCPDF's pkcs#7 Signature structure to get sequence of signed hash
13690+ $pkcs7 = asn1parse($signature);
13691+ $pkcs7ContentInfo = asn1parse($pkcs7[0][1]);
13692+
13693+ $pkcs7content = asn1parse($pkcs7ContentInfo[1][1]);
13694+
13695+ $pkcs7SignedData = asn1parse($pkcs7content[0][1]);
13696+
13697+ $pkcs7signerInfos = asn1parse($pkcs7SignedData[4][1]);
13698+
13699+ $SignerInfo = asn1parse($pkcs7signerInfos[0][1]);
13700+
13701+ $pkcs7EncryptedDigest = $SignerInfo[5][1];
13702+
13703+ // Create timestamp request
13704+
13705+ // Create hash of encrypted contents TCPDF signature
13706+ // $this->setTimeStamp() have no options for change tsa req hash alg yet, so sha1 selected
13707+ $hash = hash('sha1', hex2bin($pkcs7EncryptedDigest));
13708+
13709+ // Build timestamp request data
13710+ $tsReqData = seq(
13711+ int(1).
13712+ seq(
1370613713 seq(
13707- seq(
13708- "06052B0E03021A". // Obj_sha1
13709- "0500" // Null
13710- ).
13711- oct($hash)
13712- ).
13713- int(hash('crc32', rand())).
13714- '0101ff'
13715- );
13716- $raw_data = hex2bin($tsReqData);
13717-
13718- //Send request to TSA Server with Curl
13719- if(extension_loaded('curl')) {
13720- $tsaLog .= __FILE__." line:(".__LINE__."). Curl was already Loaded\n".__FILE__." line:(".__LINE__."). Curl is sending tsRequest to \"".$this->tsa_data['tsa_host']."\" ...\n";
13721- $ch = curl_init();
13722- curl_setopt($ch, CURLOPT_URL, $this->tsa_data['tsa_host']);
13723- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
13724- curl_setopt($ch, CURLOPT_POST, 1);
13725- curl_setopt($ch, CURLOPT_HTTPHEADER, [
13726- 'Content-Type: application/timestamp-query',
13727- 'User-Agent: TCPDF'
13728- curl_setopt($ch, CURLOPT_POSTFIELDS, $raw_data);
13729-
13730- $tsResponse = curl_exec($ch);
13731- if($tsResponse != false) {
13732- $tsaLog .= __FILE__." line:(".__LINE__."). tsRequest is sent.\n";
13733- } else {
13734- tsaLog("$tsaLog".__FILE__." line:(".__LINE__."). can't send tsRequest, Timestamp failed!\n",'w');
13735- }
13736- //parse ts response
13737- $hexTs = bin2hex($tsResponse);
13738- $tsparse = asn1parse($hexTs);
13714+ "06052B0E03021A". // Obj_sha1
13715+ "0500" // Null
13716+ ).
13717+ oct($hash)
13718+ ).
13719+ int(hash('crc32', rand())). // Add random nonce request
13720+ '0101ff' // set certReq true to tell TSA server to include SigningCertificate
13721+ );
13722+
13723+ $raw_data = hex2bin($tsReqData);
13724+
13725+ //Send request to TSA Server with Curl
13726+ if(extension_loaded('curl')) {
13727+ $ch = curl_init();
13728+ curl_setopt($ch, CURLOPT_URL, $this->tsa_data['tsa_host']);
13729+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
13730+ curl_setopt($ch, CURLOPT_POST, 1);
13731+ curl_setopt($ch, CURLOPT_HTTPHEADER, array(
13732+ 'Content-Type: application/timestamp-query',
13733+ 'User-Agent: TCPDF'
13734+ )
13735+ );
13736+ curl_setopt($ch, CURLOPT_POSTFIELDS, $raw_data);
1373913737
13740- $tsparse0 = asn1parse($tsparse[0][1]);
13741- if(count($tsparse0) > 1) { //Remove response status data, only take timeStampToken
13742- $timeStamp = seq($tsparse0[1][1]);
13743- } else {
13744- $timeStamp = seq($tsparse0[0][1]);
13745- }
13746-
13747- //Add timestamp to TCPDF Signature
13748- $timeStamp = seq("060B2A864886F70D010910020E".set($timeStamp));
13749- $pkcs7 = int($pa1[0][1]).seq($pa1[1][1]).seq($pa1[2][1]).explicit(0, $pa1[3][1]).seq($pa1[4][1]).oct($pa1[5][1]);
13750- $time = seq($pkcs7.explicit(1,$timeStamp));
13751- $aa=seq(int(1). set($p3[1][1]).seq($p3[2][1]).explicit(0, $p3[3][1]).set($time));
13752- $hdaSignature = seq("06092A864886F70D010702".explicit(0,($aa)))."0000";
13753-
13754- $signature = $hdaSignature;
13755- // $tsaLog .= $signature;
13756- tsaLog("$tsaLog".__FILE__." line:(".__LINE__."). Timestamp Success.\n");
13757- } else {
13758- $tsaLog .= __FILE__." line:(".__LINE__."). Curl was not loaded, trying to load it...\n";
13759- if(@dl('php_curl.dll')) {
13760- $tsaLog .= __FILE__." line:(".__LINE__."). Curl successfully Loaded.\n";
13761- } else {
13762- tsaLog("$tsaLog\n".__FILE__." line:(".__LINE__."). Curl failed to load. Timestamping failed!", 'w');
13763- }
13738+
13739+ // can't send tsRequest, Timestamp failed!
13740+ if(!$tsResponse = curl_exec($ch)) {
13741+ return $signature;
13742+ }
13743+
13744+ // parse timestamp response data
13745+ $hexTsaResponse = bin2hex($tsResponse);
13746+ if(!$parseTimeStampResp = asn1parse($hexTsaResponse)) { // bad TSA Reponse
13747+ return $signature;
1376413748 }
13749+
13750+ // verify tsa response PKIStatusInfo and TimeStampToken exists
13751+ if(!$TimeStampResp = asn1parse($parseTimeStampResp[0][1])) {
13752+ return $signature;
13753+ }
13754+
13755+ // Select timeStampToken only. must ignore response status data (in first sequence if exist, select 2nd sequence)
13756+ if(count($TimeStampResp) > 1) {
13757+ $TSTInfo = $TimeStampResp[1][1]; // TSTInfo
13758+ } else if (count($TimeStampResp) == 1) {
13759+ $TSTInfo = $TimeStampResp[0][1]; // TSTInfo
13760+ } else { // TimeStampResp not containts 1 or 2 fields
13761+ return $signature;
13762+ }
13763+
13764+ // Add timestamp in TCPDF Signature
13765+ // Create timestamp pkcs#7 data
13766+ $TimeStampToken = seq(
13767+ "060B2A864886F70D010910020E". // OBJ_id_smime_aa_timeStampToken
13768+ set(
13769+ seq(
13770+ $TSTInfo // TSTInfo
13771+ )
13772+ )
13773+ );
13774+
13775+ $time = seq(
13776+ $pkcs7signerInfos[0][1].
13777+ explicit(1,
13778+ $TimeStampToken
13779+ )
13780+ );
13781+
13782+ $pkcs7contentSignedData=seq(
13783+ int(1). // version
13784+ set($pkcs7SignedData[1][1]). // digestAlgorithms
13785+ seq($pkcs7SignedData[2][1]). // contentInfo
13786+ explicit(0,
13787+ $pkcs7SignedData[3][1]
13788+ ). // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates
13789+ set(
13790+ $time
13791+ )
13792+ );
13793+ $pkcs7ContentInfo = seq(
13794+ "06092A864886F70D010702". // ContentType OBJ_pkcs7_signed
13795+ explicit(0,($pkcs7contentSignedData)) // content
13796+ ).
13797+ // "0000"; // sometime needed for backward compatibility
13798+ "";
13799+
13800+ $signature = $pkcs7ContentInfo;
1376513801 }
13766- // end timestamping
1376713802 return $signature;
13803+ // End timestamping
1376813804 }
1376913805
1377013806 /**
0 commit comments