openssl_private_encrypt() (individual module)
This demo uses the
openssl_private_encrypt() function to create the signature value wrapped in
an
individual signature module.
The module makes use of the
\setasign\SetaPDF2\Signer\Signature\Module\PadesProxyTrait
trait.
PHP
<?php
use setasign\SetaPDF2\Demos\Signer\Module\Signature\OpenSslPrivateEncryptModule;
use setasign\SetaPDF2\Core\Document;
use setasign\SetaPDF2\Core\Writer\HttpWriter;
use setasign\SetaPDF2\Core\Writer\TempFileWriter;
use setasign\SetaPDF2\Signer\Digest;
use setasign\SetaPDF2\Signer\Signer;
// load and register the autoload function
require_once __DIR__ . '/../../../../../../bootstrap.php';
// load the module class
require_once __DIR__ . '/../../../../../../classes/Signer/Module/Signature/OpenSslPrivateEncryptModule.php';
// the file to sign
$fileToSign = $assetsDirectory . '/pdfs/tektown/Laboratory-Report.pdf';
// create a temporary path
$tempFile = TempFileWriter::createTempPath();
// create a writer instance
$writer = new HttpWriter('signed-with-php-openssl.pdf');
// create the document instance
$document = Document::loadByFilename($fileToSign, $writer);
// create the signer instance
$signer = new Signer($document);
// let's use the PAdES modul and configure it
$module = new OpenSslPrivateEncryptModule();
$module->setDigest(Digest::SHA_256);
$module->setCertificate('file://' . $assetsDirectory . '/certificates/setapdf-no-pw.pem');
$privateKey = \openssl_pkey_get_private('file://' . $assetsDirectory . '/certificates/setapdf-no-pw.pem', '');
$module->setPrivateKey($privateKey);
$signer->sign($module);
PHP
<?php
namespace setasign\SetaPDF2\Demos\Signer\Module\Signature;
use setasign\SetaPDF2\Core\Reader\FilePath;
use setasign\SetaPDF2\Signer\Asn1\Element as Asn1Element;
use setasign\SetaPDF2\Signer\Asn1\Oid as Asn1Oid;
use setasign\SetaPDF2\Signer\Digest;
use setasign\SetaPDF2\Signer\Exception;
use setasign\SetaPDF2\Signer\Signature\Module\DictionaryInterface;
use setasign\SetaPDF2\Signer\Signature\Module\DocumentInterface;
use setasign\SetaPDF2\Signer\Signature\Module\ModuleInterface;
use setasign\SetaPDF2\Signer\Signature\Module\PadesProxyTrait;
class OpenSslPrivateEncryptModule implements ModuleInterface, DictionaryInterface, DocumentInterface
{
use PadesProxyTrait;
/**
* @var \OpenSSLAsymmetricKey|resource
*/
protected $_privateKey;
/**
* @param \OpenSSLAsymmetricKey|resource $privateKey
* @return void
*/
public function setPrivateKey($privateKey)
{
$details = \openssl_pkey_get_details($privateKey);
if (!is_array($details)) {
throw new \InvalidArgumentException('Cannot get details from private key.');
}
if ($details['type'] !== \OPENSSL_KEYTYPE_RSA) {
throw new \InvalidArgumentException('Only RSA keys are supported in this demo.');
}
$this->_privateKey = $privateKey;
}
/**
* @param string $digest
* @return void
*/
public function setDigest($digest)
{
$this->_getPadesModule()->setDigest($digest);
}
/**
* @param FilePath $tmpPath
* @return string
* @throws Exception
*/
public function createSignature(FilePath $tmpPath)
{
$padesModule = $this->_getPadesModule();
// get the hash data from the module
$padesDigest = $padesModule->getDigest();
$hashData = hash($padesDigest, $padesModule->getDataToSign($tmpPath), true);
// let's sign only the hash, so we create the ASN.1 container manually
$digestInfo = new Asn1Element(
Asn1Element::SEQUENCE | Asn1Element::IS_CONSTRUCTED, '',
[
new Asn1Element(
Asn1Element::SEQUENCE | Asn1Element::IS_CONSTRUCTED, '',
[
new Asn1Element(
Asn1Element::OBJECT_IDENTIFIER,
Asn1Oid::encode(
Digest::getOid($padesModule->getDigest())
)
),
new Asn1Element(Asn1Element::NULL)
]
),
new Asn1Element(
Asn1Element::OCTET_STRING,
$hashData
)
]
);
if (@\openssl_private_encrypt($digestInfo, $signatureValue, $this->_privateKey) === false) {
$lastError = \error_get_last();
throw new Exception(
'An OpenSSL error occurred during signature process' .
(isset($lastError['message']) ? ': ' . $lastError['message'] : '') . '.'
);
}
$padesModule->setSignatureValue($signatureValue);
return (string)$padesModule->getCms();
}
}
