public function testOpenSSLSignature() { if (!extension_loaded('OpenSSL')) { $this->markTestSkipped("Need OpenSSL extension"); } // Generate a private key on the fly. $passphrase = uniqid(); $passfile = PHING_TEST_BASE . '/etc/tasks/ext/pharpackage/pass.txt'; file_put_contents($passfile, $passphrase); $pkey = openssl_pkey_new(); openssl_pkey_export_to_file($pkey, PHING_TEST_BASE . '/etc/tasks/ext/pharpackage/priv.key', $passphrase); $this->executeTarget(__FUNCTION__); // Make sure we are dealing with an OpenSSL signature. // (Phar silently falls back to an SHA1 signature // whenever it fails to add an OpenSSL signature) $dest = PHING_TEST_BASE . '/etc/tasks/ext/pharpackage/pharpackage.phar'; $this->assertFileExists($dest); $phar = new Phar($dest); $signature = $phar->getSignature(); $this->assertEquals('OpenSSL', $signature['hash_type']); unlink(PHING_TEST_BASE . '/etc/tasks/ext/pharpackage/priv.key'); unlink(PHING_TEST_BASE . '/etc/tasks/ext/pharpackage/pharpackage.phar.pubkey'); unlink(PHING_TEST_BASE . '/etc/tasks/ext/pharpackage/pass.txt'); unlink($dest); }
/** * @return string */ public static function Signature() { $sSignature = ''; if (\defined('MAILSO_LIBRARY_USE_PHAR')) { $oPhar = new \Phar('mailso.phar'); $sSignature = $oPhar->getSignature(); } return $sSignature; }
/** * Executes the current command. * * @param InputInterface $input An InputInterface instance * @param OutputInterface $output An OutputInterface instance * * @return null|int null or 0 if everything went fine, or an error code */ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln(''); $output->writeln('<comment>Validating signature</comment>'); $this->validate($input, $output); $rutaPhar = $input->getOption('phar'); $sign = $input->getOption('hash-string'); $signFile = $input->getOption('hash-file'); if (null !== $signFile) { $sign = file_get_contents($signFile); } $phar = new \Phar($rutaPhar); $sig = $phar->getSignature(); if ($sig['hash'] === $sign) { $output->writeln('<info>Sign validated!</info>'); return 0; } else { $output->writeln('<error>Invalid sign</error>'); return 1; } }
/** * Test that the Writing is successful. * * @return void * * @dataProvider testWritingFlagsProvider */ public function testWriting($compression, $signatureName, $signatureFlag) { $pharfile = $this->getTempFile('temp.phar'); $phar = new Pharchive(); $phar->setStub($stubData = <<<EOF #!/usr/bin/php <?php /*STUB!*/ __HALT_COMPILER(); EOF )->setSignatureFlags($signatureFlag); $file = new FileEntry(); $file->setFilename('/bin/script')->setContent($fileData = <<<EOF #!/usr/bin/php <?php echo 'hello world'; EOF ); if ($compression) { $file->setCompression($compression); } $phar->addFile($file); $writer = new PharWriter(); $writer->save($phar, $pharfile); unset($writer); $phar = new \Phar($pharfile); // As we did not set an alias, php defaults to the file name. $this->assertEquals($pharfile, $phar->getAlias()); $signature = $phar->getSignature(); $this->assertEquals($signatureName, strtolower(str_replace('-', '', $signature['hash_type']))); /** @var \PharFileInfo[] $files */ $files = array_values(iterator_to_array($phar->getChildren())); $this->assertEquals('phar://' . $pharfile . '/bin/script', $files[0]->getPathname()); $this->assertEquals($fileData, $files[0]->getContent()); }
/** * Function: isVerified * * This will help verify the content, integrity, oversight, and origin * of plugins, language packs and other modules distributed for * osTicket. * * This idea is that the signature of the PHAR file will be registered * in DNS, for instance, * `7afc8bf80b0555bed88823306744258d6030f0d9.updates.osticket.com`, for * a PHAR file with a SHA1 signature of * `7afc8bf80b0555bed88823306744258d6030f0d9 `, which will resolve to a * string like the following: * ``` * "v=1; i=storage:s3; s=MEUCIFw6A489eX4Oq17BflxCZ8+MH6miNjtcpScUoKDjmb * lsAiEAjiBo9FzYtV3WQtW6sbhPlJXcoPpDfYyQB+BFVBMps4c=; V=0.1;" * ``` * Which is a simple semicolon separated key-value pair string with the * following keys * * Key | Description * :----|:--------------------------------------------------- * v | Algorithm version * i | Plugin 'id' registered in plugin.php['id'] * V | Plugin 'version' registered in plugin.php['version'] * s | OpenSSL signature of the PHAR SHA1 signature using a * | private key (specified on the command line) * * The public key, which will be distributed with osTicket, can be used * to verify the signature of the PHAR file from the data received from * DNS. * * Parameters: * $phar - (string) filename of phar file to verify * * Returns: * (int) - * Plugin::VERIFIED upon success * Plugin::VERIFY_DNS_PASS if found in DNS but cannot verify sig * Plugin::VERIFY_NO_KEY if public key not found in include/plugins * Plugin::VERIFY_FAILED if the plugin fails validation * Plugin::VERIFY_EXT_MISSING if a PHP extension is required * Plugin::VERIFY_ERROR if an unexpected error occurred */ static function isVerified($phar) { static $pubkey = null; if (!class_exists('Phar')) { return self::VERIFY_EXT_MISSING; } elseif (!file_exists(INCLUDE_DIR . '/plugins/updates.pem')) { return self::VERIFY_NO_KEY; } if (!isset($pubkey)) { $pubkey = openssl_pkey_get_public(file_get_contents(INCLUDE_DIR . 'plugins/updates.pem')); } if (!$pubkey) { return self::VERIFY_ERROR; } $P = new Phar($phar); $sig = $P->getSignature(); $info = array(); if ($r = dns_get_record($sig['hash'] . '.' . self::$verify_domain, DNS_TXT)) { foreach ($r as $rec) { foreach (explode(';', $rec['txt']) as $kv) { list($k, $v) = explode('=', trim($kv)); $info[$k] = trim($v); } if ($info['v'] && $info['s']) { break; } } } if (is_array($info) && isset($info['v'])) { switch ($info['v']) { case '1': if (!($signature = base64_decode($info['s']))) { return self::VERIFY_FAILED; } elseif (!function_exists('openssl_verify')) { return self::VERIFY_DNS_PASS; } $codes = array(-1 => self::VERIFY_ERROR, 0 => self::VERIFY_FAILED, 1 => self::VERIFIED); $result = openssl_verify($sig['hash'], $signature, $pubkey, OPENSSL_ALGO_SHA1); return $codes[$result]; } } return self::VERIFY_FAILED; }
function _sign($plugin, $options) { if (!file_exists($plugin)) $this->fail($plugin.': Cannot find file'); elseif (!file_exists("phar://$plugin/MANIFEST.php")) $this->fail($plugin.': Should be a plugin PHAR file'); $info = (include "phar://$plugin/MANIFEST.php"); $phar = new Phar($plugin); if (!function_exists('openssl_get_privatekey')) $this->fail('OpenSSL extension required for signing'); $private = openssl_get_privatekey( file_get_contents($options['pkey'])); if (!$private) $this->fail('Unable to read private key'); $signature = $phar->getSignature(); $seal = ''; openssl_sign($signature['hash'], $seal, $private, OPENSSL_ALGO_SHA1); if (!$seal) $this->fail('Unable to generate verify signature'); $this->stdout->write(sprintf("Signature: %s\n", strtolower($signature['hash']))); $seal = sprintf('"v=1; i=%s; s=%s; V=%s;"', $info['Id'], base64_encode($seal), $info['Version']); if ($options['dns']) { if (!is_file(INCLUDE_DIR . 'aws.phar')) $this->fail('Unable to include AWS phar file. Download to INCLUDE_DIR'); require_once INCLUDE_DIR . 'aws.phar'; $aws = Aws\Common\Aws::factory(array()); $client = $aws->get('Route53'); try { $resp = $client->changeResourceRecordSets(array( 'HostedZoneId' => $options['dns'], 'ChangeBatch' => array( 'Changes' => array( array( 'Action' => 'CREATE', 'ResourceRecordSet' => array( 'Name' => "{$signature['hash']}.updates.osticket.com.", 'Type' => 'TXT', 'TTL' => 172800, 'ResourceRecords' => array( array( 'Value' => $seal, ), ), ), ), ), ), )); $this->stdout->write(sprintf('%s: %s', $resp['ChangeInfo']['Comment'], $resp['ChangeInfo']['Status'])); } catch (Exception $ex) { $this->stdout->write("Seal: $seal\n"); $this->fail('!! AWS Update Failed: '.$ex->getMessage()); } } else { $this->stdout->write("Seal: $seal\n"); } }
protected function validatePhar($phar) { $phar = realpath($phar); if ($this->hasPubKey()) { copy($this->getLocalPubKeyFile(), $phar . '.pubkey'); } chmod($phar, fileperms($this->getLocalPharFile())); /** Switch invalid key errors to RuntimeExceptions */ set_error_handler(array($this, 'throwRuntimeException')); $phar = new \Phar($phar); $signature = $phar->getSignature(); if ($this->hasPubKey() && strtolower($signature['hash_type']) !== 'openssl') { throw new NoSignatureException('The downloaded phar file has no OpenSSL signature.'); } restore_error_handler(); if ($this->hasPubKey()) { @unlink($phar . '.pubkey'); } unset($phar); }
function toPhar() { if (isset($this->phar)) { return; } if (file_exists($this->file . '.phar')) { try { $p = new \Phar($this->file . '.phar'); } catch (\Exception $e) { } if ($p->getSignature() === $this->phar->getSignature()) { $this->phar = $p; if ($this->outfile) { copy($this->file . '.phar', $this->outfile . '.phar'); } return; } unset($p); \Phar::unlinkArchive($this->file . '.phar'); } if (isset($this->tar)) { if ($this->signature_algo == \Phar::OPENSSL) { throw new Exception('Cannot create tar archive, signature is OpenSSL, ' . 'you must directly create it using the package command'); } if (file_exists($this->file . '.phar')) { \Phar::unlinkArchive($this->file . '.phar'); unlink($this->file . '.phar'); } $this->phar = $this->tar->convertToExecutable(\Phar::PHAR, \Phar::NONE, $this->ext . '.phar'); if ($this->outfile) { copy($this->file . '.phar', $this->outfile . '.phar'); } $this->tar = new \PharData($this->file . '.tar'); return; } if (isset($this->tgz)) { if ($this->signature_algo == \Phar::OPENSSL) { throw new Exception('Cannot create tar archive, signature is OpenSSL, ' . 'you must directly create it using the package command'); } if (file_exists($this->file . '.phar')) { \Phar::unlinkArchive($this->file . '.phar'); unlink($this->file . '.phar'); } $this->phar = $this->tar->convertToExecutable(\Phar::PHAR, \Phar::NONE, $this->ext . '.phar'); if ($this->outfile) { copy($this->file . '.phar', $this->outfile . '.phar'); } $this->tgz = new \PharData($this->file . '.tgz'); return; } // by process of elimination, the phar is in zip format if (file_exists($this->file . '.phar')) { \Phar::unlinkArchive($this->file . '.phar'); unlink($this->file . '.phar'); } $this->phar = $this->tar->convertToExecutable(\Phar::PHAR, \Phar::NONE, $this->ext . '.phar'); if ($this->outfile) { copy($this->file . '.phar', $this->outfile . '.phar'); } $this->zip = new \PharData($this->file . '.zip'); }
/** * Function: isVerified * * This will help verify the content, integrity, oversight, and origin * of plugins, language packs and other modules distributed for * osTicket. * * This idea is that the signature of the PHAR file will be registered * in DNS, for instance, * `7afc8bf80b0555bed88823306744258d6030f0d9.updates.osticket.com`, for * a PHAR file with a SHA1 signature of * `7afc8bf80b0555bed88823306744258d6030f0d9 `, which will resolve to a * string like the following: * ``` * "v=1; i=storage:s3; s=MEUCIFw6A489eX4Oq17BflxCZ8+MH6miNjtcpScUoKDjmb * lsAiEAjiBo9FzYtV3WQtW6sbhPlJXcoPpDfYyQB+BFVBMps4c=; V=0.1;" * ``` * Which is a simple semicolon separated key-value pair string with the * following keys * * Key | Description * :----|:--------------------------------------------------- * v | Algorithm version * i | Plugin 'id' registered in plugin.php['id'] * V | Plugin 'version' registered in plugin.php['version'] * s | OpenSSL signature of the PHAR SHA1 signature using a * | private key (specified on the command line) * * The public key, which will be distributed with osTicket, can be used * to verify the signature of the PHAR file from the data received from * DNS. * * Parameters: * $phar - (string) filename of phar file to verify * * Returns: * (int) - * Plugin::VERIFIED upon success * Plugin::VERIFY_DNS_PASS if found in DNS but cannot verify sig * Plugin::VERIFY_NO_KEY if public key not found in include/plugins * Plugin::VERIFY_FAILED if the plugin fails validation * Plugin::VERIFY_EXT_MISSING if a PHP extension is required * Plugin::VERIFY_ERROR if an unexpected error occurred */ static function isVerified($phar) { static $pubkey = null; if (!class_exists('Phar')) { return self::VERIFY_EXT_MISSING; } elseif (!file_exists(INCLUDE_DIR . '/plugins/updates.pem')) { return self::VERIFY_NO_KEY; } if (!isset($pubkey)) { $pubkey = openssl_pkey_get_public(file_get_contents(INCLUDE_DIR . 'plugins/updates.pem')); } if (!$pubkey) { return self::VERIFY_ERROR; } require_once PEAR_DIR . 'Net/DNS2.php'; $P = new Phar($phar); $sig = $P->getSignature(); $info = array(); try { $q = new Net_DNS2_Resolver(); $r = $q->query(strtolower($sig['hash']) . '.' . self::$verify_domain, 'TXT'); foreach ($r->answer as $rec) { foreach ($rec->text as $txt) { foreach (explode(';', $txt) as $kv) { list($k, $v) = explode('=', trim($kv)); $info[$k] = trim($v); } if ($info['v'] && $info['s']) { break; } } } } catch (Net_DNS2_Exception $e) { // TODO: Differenciate NXDOMAIN and DNS failure } if (is_array($info) && isset($info['v'])) { switch ($info['v']) { case '1': if (!($signature = base64_decode($info['s']))) { return self::VERIFY_FAILED; } elseif (!function_exists('openssl_verify')) { return self::VERIFY_DNS_PASS; } $codes = array(-1 => self::VERIFY_ERROR, 0 => self::VERIFY_FAILED, 1 => self::VERIFIED); $result = openssl_verify($sig['hash'], $signature, $pubkey, OPENSSL_ALGO_SHA1); return $codes[$result]; } } return self::VERIFY_FAILED; }
/** * allInfos * * Scans the plugin folders for installed plugins. For each one, the * plugin.php file is included and the info array returned in added to * the list returned. * * Returns: * Information about all available plugins. The registry will have to be * queried to determine if the plugin is installed */ static function allInfos() { foreach (glob(INCLUDE_DIR . 'plugins/*', GLOB_NOSORT | GLOB_BRACE) as $p) { $is_phar = false; if (substr($p, strlen($p) - 5) == '.phar' && class_exists('Phar') && Phar::isValidPharFilename($p)) { try { // When public key is invalid, openssl throws a // 'supplied key param cannot be coerced into a public key' warning // and phar ignores sig verification. // We need to protect from that by catching the warning // Thanks, https://github.com/koto/phar-util set_error_handler(array('self', 'throwException')); $ph = new Phar($p); restore_error_handler(); // Verify the signature $ph->getSignature(); $p = 'phar://' . $p; $is_phar = true; } catch (UnexpectedValueException $e) { // Cannot find signature file } catch (RuntimeException $e) { // Invalid signature file } } if (!is_file($p . '/plugin.php')) { // Invalid plugin -- must define "/plugin.php" continue; } // Cache the info into static::$plugin_info static::getInfoForPath($p, $is_phar); } return static::$plugin_info; }
<?php file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php', 'brand new!'); $phar = new Phar(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'); var_dump($phar->getSignature()); ?> ===DONE===
/** * @return string */ public static function Signature() { $oPhar = new \Phar('mailso.phar'); return $oPhar->getSignature(); }
function _sign($plugin, $options) { if (!file_exists($plugin)) { $this->fail($plugin . ': Cannot find file'); } elseif (!file_exists("phar://{$plugin}/MANIFEST.php")) { $this->fail($plugin . ': Should be a plugin PHAR file'); } $info = (include "phar://{$plugin}/MANIFEST.php"); $phar = new Phar($plugin); if (!function_exists('openssl_get_privatekey')) { $this->fail('OpenSSL extension required for signing'); } $private = openssl_get_privatekey(file_get_contents($options['pkey'])); if (!$private) { $this->fail('Unable to read private key'); } $signature = $phar->getSignature(); $seal = ''; openssl_sign($signature['hash'], $seal, $private, OPENSSL_ALGO_SHA1); if (!$seal) { $this->fail('Unable to generate verify signature'); } $this->stdout->write(sprintf("Signature: %s\n", strtolower($signature['hash']))); $this->stdout->write(sprintf("Seal: \"v=1; i=%s; s=%s; V=%s;\"\n", $info['Id'], base64_encode($seal), $info['Version'])); }
//Get fixed filename if (strtolower(substr($argv[2], -5)) == ".phar" || strpos($argv[2], '.') !== false) { $file = $argv[2]; } else { $file = $argv[2] . ".phar"; } if (file_exists($file)) { try { $phar = new Phar($file, 0); if ($phar->hasMetadata()) { $metadata = metadataToString($phar->getMetadata()); } else { $metadata = "No metadata found\n"; } echo "Size: " . round(filesize($file) * 0.0009765625 * 0.0009765625, 2) . " MB (" . round(filesize($file) * 0.0009765625, 3) . " KB)\n"; echo "Signature: " . $phar->getSignature()["hash"] . "\n"; echo "Signature type: " . $phar->getSignature()["hash_type"] . "\n"; echo "Writable: " . strbool($phar->isWritable()) . "\n"; echo "Readable: " . strbool($phar->isReadable()) . "\n"; echo "Metadata: " . $metadata; echo "Show stub (y, n)? "; $input = fopen("php://stdin", "r"); $line = fgets($input); if (trim($line) == 'y') { echo $phar->getStub(); } echo "\n"; } catch (Exception $e) { echo "Invalid phar file\n"; } } else {
/** * Verifies that a Phar archive has is OpenSSL-signed and the signature is valid * @param string path to Phar archive * @throws SignatureVerificationException */ protected function verifyPharSignature($local_path) { try { // When public key is invalid, openssl throws a // 'supplied key param cannot be coerced into a public key' warning // and phar ignores sig verification. // We need to protect from that by catching the warning set_error_handler(array($this, 'throwException')); $phar = new Phar($local_path); // here the verification happens restore_error_handler(); $sig = $phar->getSignature(); unset($phar); if ($this->pub_key_file && $sig['hash_type'] !== 'OpenSSL') { throw new PharUtil_SignatureVerificationException("This phar is not signed with OpenSSL!"); } } catch (UnexpectedValueException $e) { throw new PharUtil_SignatureVerificationException($e->getMessage()); } catch (RuntimeException $e) { throw new PharUtil_SignatureVerificationException($e->getMessage()); } return true; }
} echo "@PACKAGE_NAME@ @PACKAGE_VERSION@\n"; if (version_compare(phpversion(), '5.3.0', '<')) { echo "\nERROR: This package requires PHP 5.3.0 or later.\n"; exit(1); } $available_extensions = array(); foreach (array('apc', 'apcu', 'wincache') as $ext) { if (extension_loaded($ext)) { $available_extensions[] = $ext; } } if (extension_loaded('phar')) { try { $phar = new Phar(__FILE__); $sig = $phar->getSignature(); echo "{$sig['hash_type']} hash: {$sig['hash']}\n\n"; } catch (Exception $e) { echo <<<HEREDOC The PHAR extension is available, but was unable to read this PHAR file's hash. HEREDOC; if (false !== strpos($e->getMessage(), 'file extension')) { echo <<<HEREDOC This can happen if you've renamed the file to ".php" instead of ".phar". Regardless, you should be able to include this file without problems. HEREDOC; } echo "\n";
/** * Executes the current command. * * @param InputInterface $input An InputInterface instance * @param OutputInterface $output An OutputInterface instance * * @return null|int null or 0 if everything went fine, or an error code */ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln(''); $output->writeln('<comment>Generating signature</comment>'); $this->validate($input, $output); $rutaPhar = $input->getOption('phar'); $sigtypeaux = $input->getOption('encrypt-type'); $saveHashIn = $input->getOption('output'); $phar = new \Phar($rutaPhar); $sigtypeaux = strtoupper($sigtypeaux); switch ($sigtypeaux) { case 'MD5': $signType = \Phar::MD5; break; case 'SHA1': $signType = \Phar::SHA1; break; case 'SHA256': $signType = \Phar::SHA256; break; case 'SHA512': $signType = \Phar::SHA512; break; default: $signType = \Phar::SHA256; $sigtypeaux = 'SHA256'; break; } $phar->setSignatureAlgorithm($signType); $sig = $phar->getSignature(); $output->writeln("Hash created: " . $sig['hash']); if (null !== $saveHashIn) { $saveHashIn = rtrim($saveHashIn, '/') . '/hash.' . $sigtypeaux; file_put_contents($saveHashIn, $sig['hash']); $output->writeln(''); $output->writeln("<info>Hash saved in: </info>" . $saveHashIn); } }
<?php $p = new Phar(__FILE__); var_dump($p->getSignature()); $p2 = new Phar(__FILE__); $p->setSignatureAlgorithm(Phar::MD5); var_dump($p->getSignature()); echo "ok\n"; __halt_compiler(); ?> 6test.txt���H���E�<?php __HALT_COMPILER();c�qF�Ov6&�((����rGBMB
<?php $a = new Phar(dirname(__FILE__) . '/files/sha1.phar'); $r = $a->getSignature(); var_dump($r['hash_type']); $a = new Phar(dirname(__FILE__) . '/files/sha512.phar'); $r = $a->getSignature(); var_dump($r['hash_type']); $a = new Phar(dirname(__FILE__) . '/files/sha256.phar'); $r = $a->getSignature(); var_dump($r['hash_type']); $a = new Phar(dirname(__FILE__) . '/files/md5.phar'); $r = $a->getSignature(); var_dump($r['hash_type']); $a = new Phar(dirname(__FILE__) . '/files/openssl.phar'); $r = $a->getSignature(); var_dump($r['hash_type']); ?> ===DONE===